FFmpeg是一个开源免费跨平台的视频和音频流方案,属于自由软件,采用LGPL或GPL许可证(依据你选择的组件)。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多codec都是从头开发的。FFmpeg在Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行。
在java开发中,FFmpeg也常被调用用来进行视频的转码,录播和直播,总的来说,FFmpeg是一款非常强大的,而且做与视频相关的业务平台开发人员必须要学会的工具,那具体怎么实习呢,第一章我们先从分别windows和linux下调用FFmpeg进行视频的转码,和对视频的截图做出说明解释。
ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等),而对于ffmpeg无法解析的文件格式(wmv9,rm,rmvb等),我们在下面采用了mencoder工具,先将视频转换成AVI格式再用ffmpeg进行转码;
windows下:
1.首先需要FFmpeg和mencoder的工具。一共五个文件,点此下载,将他解压放在你的D盘FFmpeg文件夹下。
linux下:
依次执行下面的指令
1.下载yasm-1.3.0.tar.gz这个版本:
1 | yasm是一个完全重写的NASM汇编。目前,它支持x86和AMD64指令集,接受NASM和气体汇编语法,产出二进制, ELF32 , ELF64 , COFF , Mach - O的( 32和64 ) , RDOFF2 ,的Win32和Win64对象的格式,并生成STABS 调试信息的来源,DWARF 2 ,CodeView 8格式。之所以在FFmpeg中用这个,主要是支持编译ffmpeg-x264. |
wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz tar xzvf yasm-1.3.0.tar.gz cd yasm-1.3.0 ./configure make make install
2.下载3.1.3 release ffmpeg
wget http://ffmpeg.org/releases/ffmpeg-3.1.3.tar.gz
tar -zxvf ffmpeg-3.1.3.tar.gz
cd ffmpeg-3.1.3
./configure
make
make install
第二步的时间可能会有点长,耐心等待~!安装完成之后输入 ffmpeg -version 可以看到版本说明安装成功
下面直接上代码,都写好注释的,很清楚。
package wordtopdf; import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List; public class ConvertVideo {
private final static String PATH = "【需要转码的视频路径】";</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> main(String[] args) { </span><span style="color: #0000ff;">if</span> (!checkfile(PATH)) { <span style="color: #008000;">//</span><span style="color: #008000;">判断路径是不是一个文件</span> System.out.println(PATH + " is not file"<span style="color: #000000;">); </span><span style="color: #0000ff;">return</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">if</span> (process()) { <span style="color: #008000;">//</span><span style="color: #008000;">执行转码任务</span> System.out.println("ok"<span style="color: #000000;">); } } </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">boolean</span><span style="color: #000000;"> checkfile(String path) { File file </span>= <span style="color: #0000ff;">new</span><span style="color: #000000;"> File(path); </span><span style="color: #0000ff;">if</span> (!<span style="color: #000000;">file.isFile()) { </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">boolean</span><span style="color: #000000;"> process() { </span><span style="color: #008000;">//</span><span style="color: #008000;"> 判断视频的类型</span> <span style="color: #0000ff;">int</span> type =<span style="color: #000000;"> checkContentType(); </span><span style="color: #0000ff;">boolean</span> status = <span style="color: #0000ff;">false</span><span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">如果是ffmpeg可以转换的类型直接转码,否则先用mencoder转码成AVI</span> <span style="color: #0000ff;">if</span> (type == 0<span style="color: #000000;">) { System.out.println(</span>"直接将文件转为flv文件"<span style="color: #000000;">); status </span>= processFLV(PATH);<span style="color: #008000;">//</span><span style="color: #008000;"> 直接将文件转为flv文件 </span> } <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type == 1<span style="color: #000000;">) { String avifilepath </span>=<span style="color: #000000;"> processAVI(type); </span><span style="color: #0000ff;">if</span> (avifilepath == <span style="color: #0000ff;">null</span><span style="color: #000000;">) </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span>;<span style="color: #008000;">//</span><span style="color: #008000;"> avi文件没有得到 </span> status = processFLV(avifilepath);<span style="color: #008000;">//</span><span style="color: #008000;"> 将avi转为flv </span>
}
return status;
}</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> checkContentType() { String type </span>= PATH.substring(PATH.lastIndexOf(".") + 1<span style="color: #000000;">, PATH.length()) .toLowerCase(); </span><span style="color: #008000;">//</span><span style="color: #008000;"> ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等) </span> <span style="color: #0000ff;">if</span> (type.equals("avi"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("mpg"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("wmv"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("3gp"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("mov"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("mp4"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("asf"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("asx"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("flv"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 0<span style="color: #000000;">; } </span><span style="color: #008000;">//</span><span style="color: #008000;"> 对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等), </span><span style="color: #008000;">//</span><span style="color: #008000;"> 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式. </span> <span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("wmv9"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 1<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("rm"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 1<span style="color: #000000;">; } </span><span style="color: #0000ff;">else</span> <span style="color: #0000ff;">if</span> (type.equals("rmvb"<span style="color: #000000;">)) { </span><span style="color: #0000ff;">return</span> 1<span style="color: #000000;">; } </span><span style="color: #0000ff;">return</span> 9<span style="color: #000000;">; } </span><span style="color: #008000;">//</span><span style="color: #008000;"> 对ffmpeg无法解析的文件格式(wmv9,rm,rmvb等), 可以先用别的工具(mencoder)转换为avi(ffmpeg能解析的)格式. </span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> String processAVI(<span style="color: #0000ff;">int</span><span style="color: #000000;"> type) { List</span><String> commend = <span style="color: #0000ff;">new</span> ArrayList<String><span style="color: #000000;">(); commend.add(</span>"D:\ffmpeg\mencoder"<span style="color: #000000;">); commend.add(PATH); commend.add(</span>"-oac"<span style="color: #000000;">); commend.add(</span>"lavc"<span style="color: #000000;">); commend.add(</span>"-lavcopts"<span style="color: #000000;">); commend.add(</span>"acodec=mp3:abitrate=64"<span style="color: #000000;">); commend.add(</span>"-ovc"<span style="color: #000000;">); commend.add(</span>"xvid"<span style="color: #000000;">); commend.add(</span>"-xvidencopts"<span style="color: #000000;">); commend.add(</span>"bitrate=600"<span style="color: #000000;">); commend.add(</span>"-of"<span style="color: #000000;">); commend.add(</span>"avi"<span style="color: #000000;">); commend.add(</span>"-o"<span style="color: #000000;">); commend.add(</span>"【存放转码后视频的路径,记住一定是.avi后缀的文件名】"<span style="color: #000000;">); </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { </span><span style="color: #008000;">//</span><span style="color: #008000;">调用线程命令启动转码</span> ProcessBuilder builder = <span style="color: #0000ff;">new</span><span style="color: #000000;"> ProcessBuilder(); builder.command(commend); builder.start(); </span><span style="color: #0000ff;">return</span> "【存放转码后视频的路径,记住一定是.avi后缀的文件名】"<span style="color: #000000;">; } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) { e.printStackTrace(); </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">; } } </span><span style="color: #008000;">//</span><span style="color: #008000;"> ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等) </span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">boolean</span><span style="color: #000000;"> processFLV(String oldfilepath) { </span><span style="color: #0000ff;">if</span> (!<span style="color: #000000;">checkfile(PATH)) { System.out.println(oldfilepath </span>+ " is not file"<span style="color: #000000;">); </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #000000;">; } </span><span style="color: #008000;">//</span><span style="color: #008000;"> 文件命名 </span> Calendar c =<span style="color: #000000;"> Calendar.getInstance(); String savename </span>= String.valueOf(c.getTimeInMillis())+ Math.round(Math.random() * 100000<span style="color: #000000;">); List</span><String> commend = <span style="color: #0000ff;">new</span> ArrayList<String><span style="color: #000000;">(); commend.add(</span>"D:\ffmpeg\ffmpeg"<span style="color: #000000;">); commend.add(</span>"-i"<span style="color: #000000;">); commend.add(oldfilepath); commend.add(</span>"-ab"<span style="color: #000000;">); commend.add(</span>"56"<span style="color: #000000;">); commend.add(</span>"-ar"<span style="color: #000000;">); commend.add(</span>"22050"<span style="color: #000000;">); commend.add(</span>"-qscale"<span style="color: #000000;">); commend.add(</span>"8"<span style="color: #000000;">); commend.add(</span>"-r"<span style="color: #000000;">); commend.add(</span>"15"<span style="color: #000000;">); commend.add(</span>"-s"<span style="color: #000000;">); commend.add(</span>"600x500"<span style="color: #000000;">); commend.add(</span>"【存放转码后视频的路径,记住一定是.flv后缀的文件名】"<span style="color: #000000;">); </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { Runtime runtime </span>=<span style="color: #000000;"> Runtime.getRuntime(); Process proce </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;">视频截图命令,封面图。 8是代表第8秒的时候截图</span> String cmd = ""<span style="color: #000000;">; String cut </span>= " c:\ffmpeg\ffmpeg.exe -i " +<span style="color: #000000;"> oldfilepath </span>+ " -y -f image2 -ss 8 -t 0.001 -s 600x500 c:\ffmpeg\output\" + "a.jpg"<span style="color: #000000;">; String cutCmd </span>= cmd +<span style="color: #000000;"> cut; proce </span>=<span style="color: #000000;"> runtime.exec(cutCmd); </span><span style="color: #008000;">//</span><span style="color: #008000;">调用线程命令进行转码</span> ProcessBuilder builder = <span style="color: #0000ff;">new</span><span style="color: #000000;"> ProcessBuilder(commend); builder.command(commend); builder.start(); </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) { e.printStackTrace(); </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #000000;">; } }
}
注:ffmpeg的功能十分强大,但是命令也非常多,转换每种格式的命令都不相同!需要转换其他格式的,请写对命令。
命令格式:
普通转码:
ffmpeg -i [输入文件名] [参数选项] -f [格式] [输出文件]
比如:MP4转avi c:ffmpegffmpeg -i c:ffmpeginputc.mp4 -f avi c:ffmpegoutputa.avi
参数:-an 去掉音频
-b 1000K 压缩码率为1000K
-s 800*500 压缩尺寸为800*500
-aspect 宽高比,格式 16:9 或 1.778
(当源尺寸是16:9,要压缩成非16:9的,一方面要设定 -s,另一方面要给出 -aspect)
-ss 开始时间
-t 持续时长