准备工作:
1.下载ffmpeg插件包
地址:http://ffmpeg.org/download.html#releases
解压后目录结构为:
|-ffmpeg.exe
|-bin ---|-...
| |-...
|
ffmpeg |-doc ---..
|-licenses ---..
|-presets ---..
|-README.TXT
2.下载mencoder插件包(也就是linux的MPlayer的整个包,mencoder是Mplayer的编码工具,MPlayer包内有这个插件mencoder.exe)
地址:http://www.mplayerhq.hu/design7/dload.html
|-codecs ..
| |-font.conf
mencoder |-fonts-----|-conf.avail
| |-conf.d
|
| |-codecs.conf
|-mplayer---|-config
| |-input.conf
| |-subfont.ttf
|
|-mencoder.exe
|-mplayer.exe
|-vfw2menc.exe
|-dsnative.dll
3.Eclipse建立一个简单的项目transferVideo
正式开始
1.创建一个接口:ICMDResponseGetter.java
package com.edu.ccnu.videocourse.ffmpeg; /** * FFMPEG插件接口 * @author Si.Li * */ public interface ICMDResponseGetter { /** * 用来抓取命令行返回的信息 * @param str */ public void controlString(String str); }
2.创建能够执行命令行并抓取命令行响应的Excuter类
package com.edu.ccnu.videocourse.ffmpeg; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.List; /** * 执行cmd的执行 * @author Si.Li * */ public class CMDExcuter { public static void exec(List<String> cmd,ICMDResponseGetter getter){ try{ ProcessBuilder builder = new ProcessBuilder(); builder.command(cmd); builder.redirectErrorStream(true); Process proc = builder.start(); BufferedReader stdout = new BufferedReader( new InputStreamReader(proc.getInputStream())); String line; while ((line = stdout.readLine()) != null) { if( getter != null ) getter.controlString(line); } proc.waitFor(); stdout.close(); } catch (Exception e) { e.printStackTrace(); } } }
3.创建主类 VideoTransfer.java进行视频转码的工作,代码如下:
package com.edu.ccnu.videocourse.ffmpeg; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.edu.ccnu.videocourse.base.CommonConstants; /** * VideoTransfer * @author Si.Li * */ public class VideoTransfer implements ICMDResponseGetter{ /** * 用来记录视频时长 */ private int videoTimeCount=0; /** * 可执行文件的路径 */ private String ffmpegPath; /** * 视频源文件地址 */ private String sourceFilePath; /** * FFMPEG 的一些自述状态 */ private enum FFMpegUtilStatus { Empty, CheckingFile, GettingRuntime }; /** * 初始状态为Empty */ private FFMpegUtilStatus status = FFMpegUtilStatus.Empty; /** * 用来装载cmd命令 */ private List<String> cmd = new ArrayList<String>(); /** * 是否支持源文件格式的转换 Method : isSupported() */ private boolean isSupported; /** * 构造函数 * @param ffmpegPath FFMPEG可执行文件的绝对路径 例如 WINDOWS: e:/ffmpeg/ffmpeg.exe LINUX: /root/ffmpeg/bin/ffmpeg * @param sourceFilePath 处理视频的源文件绝对路径 * @param destinationFile 视频转换成FLV后的存储路径 */ public VideoTransfer(String ffmpegPath,String sourceFilePath){ this.ffmpegPath=ffmpegPath; this.sourceFilePath=sourceFilePath; } /** * 获取视频时长 * @return */ public int getVideoTimeCount(){ videoTimeCount = 0; //设置当前状态为获取时长 status=FFMpegUtilStatus.GettingRuntime; cmd.clear(); cmd.add(ffmpegPath); cmd.add("-i"); cmd.add(sourceFilePath); CMDExcuter.exec(cmd, this); return videoTimeCount; } /** * FFMPEG是否支持转换的源视频文件格式 * @return */ public boolean isSupported(){ isSupported=true; status=FFMpegUtilStatus.CheckingFile; cmd.clear(); cmd.add(ffmpegPath); cmd.add("-i"); cmd.add(sourceFilePath); CMDExcuter.exec(cmd, this); return isSupported; //通过回调,isSupported值根据命令行响应会调整该值 } /** * 视频转换 * @param saveFilePath 存储路径,精确到 xxx.flv * @param screenSize 屏幕分辨率 以:720x576 格式为准 * @param autoByte 音频比特率 Kbps * @param autocollection 音频采样率 HZ * @param quality 视频质量 (官方文档 1-31) * @param fps 每秒帧率 */ public void videoTransfer(String saveFilePath,String screenSize,Integer autoByte,Integer autocollection,Integer quality,Integer fps){ cmd.clear(); cmd.add(ffmpegPath); //执行文件目录绝对路径例如 WINDOWS: e:/ffmpeg/ffmpeg.exe LINUX: /root/ffmpeg/bin/ffmpeg cmd.add("-i"); //-i 后面指明源文件绝对路径,精确到 xx.视频格式 cmd.add(sourceFilePath); //源文件绝对路径 cmd.add("-y"); //设置转换的文件如果存在,那么直接覆盖 cmd.add("-ab"); //设置音频比特率 cmd.add(autoByte.toString()); //音频比特率值 Kbps为单位 cmd.add("-ar"); //设置音频采样率 cmd.add(autocollection.toString()); //音频采样率值 HZ为单位 cmd.add("-qscale"); //设置视频质量,目前设置为1 cmd.add(quality.toString()); cmd.add("-r"); //设置视频每秒帧数 cmd.add(fps.toString()); cmd.add("-s"); //设置视频分辨率 cmd.add(screenSize); cmd.add(saveFilePath); CMDExcuter.exec(cmd, null); } /** * 视频合成字幕转换 * @param saveFilePath 存储的FLV路径 * @param srtPath 字幕文件的物理路径 * @param mencoderPath mencoder.exe的物理路径 */ public void videoTransferByMencoder(String saveFilePath,String srtPath,String mencoderPath){ cmd.clear(); cmd.add(mencoderPath); //mencoder.exe的物理地址 cmd.add(sourceFilePath); //源文件的物理地址 cmd.add("-o"); //目标文件地址(也就是转换后的物理地址,要精确到 xx.flv) cmd.add(saveFilePath); cmd.add("-of"); //指定输出格式 cmd.add("lavf"); cmd.add("-oac"); //指定输出音频编码 cmd.add("mp3lame"); cmd.add("-lameopts"); cmd.add("abr:br="+CommonConstants.SOUND_AUDIOBYTE); cmd.add("-ovc"); //指定输出编码选择, cmd.add("lavc"); cmd.add("-lavcopts"); //输出视频编码选项,参数较多,自行查询 cmd.add("vcodec=flv"); cmd.add("-srate"); //音频采样率 cmd.add(CommonConstants.SOUND_SAMPLING.toString()); cmd.add("-sub"); //字幕地址 cmd.add(srtPath); cmd.add("-subfont"); //字幕ziti cmd.add("SimSun"); cmd.add("-subcp"); cmd.add("GB18030"); cmd.add("-fontconfig"); System.out.println(cmd.toString()); CMDExcuter.exec(cmd, null); } /** * 根据视频开始后的描述进行视频截图 * @param imagesSavePath 存储图片的全路径 精确到 xxx.jpg * @param begin 设置视频截图在视频的第几秒内 * @param screenSize 截图的分辨率 格式参照:720x576 * */ public void makeScreenImage(String imagesSavePath,Integer begin,String screenSize){ cmd.clear(); cmd.add(ffmpegPath); cmd.add("-i"); cmd.add(sourceFilePath); cmd.add("-y"); cmd.add("-f"); cmd.add("image2"); cmd.add("-ss"); cmd.add(begin.toString()); cmd.add("-t"); cmd.add("0.001"); cmd.add("-s"); cmd.add(screenSize); cmd.add(imagesSavePath); CMDExcuter.exec(cmd,null); } /** * 执行CMDExcuter后,获取响应会回调本方法 * 本类主要用于 视频格式支持判断函数【isSupported()】和 获取视频时长函数【 getRunTime()】 */ @Override public void controlString(String str) { switch( status ) { case Empty: break; case CheckingFile:{ //检查是否能够支持当前文件的转换 Matcher m = Pattern.compile("Unknown format").matcher(str); if( m.find() ) this.isSupported = false; break; } case GettingRuntime:{ //获取视频截图的时间 String zz="Duration: ([0-9][0-9]:[0-9][0-9]:[0-9][0-9])"; Matcher m = Pattern.compile(zz).matcher(str); while (m.find()) { String msg = m.group(); msg = msg.replace("Duration: ", ""); videoTimeCount=changeMsgToVideoCount(msg); /** * TODO msg Duration: 00:06:17,替换之后,不知道是否是 00:06:17先输出 */ } break; } } } /** * 将获取的视频时长字符串解析成 */ private Integer changeMsgToVideoCount(String msg){ Integer count=0; String [] times=msg.split(":"); count+=Integer.parseInt(times[2]); count+=Integer.parseInt(times[1])*60; count+=Integer.parseInt(times[0])*60*60; return count; } }
暂时这样吧,coding过程中已经将一部分注释写上了,以后完善