本片文章主要介绍如何使用MEncoder进行视频转码(也包含使用ffmpeg插件进行无字幕视频转码)
准备工作:
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过程中已经将一部分注释写上了,以后完善