java使用MEncoder将mp4和srt合成为flv格式的视频文件

本片文章主要介绍如何使用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过程中已经将一部分注释写上了,以后完善

猜你喜欢

转载自crazzylee.iteye.com/blog/1754919