最近接到一個老項目,由於老項目之前適配的是ie瀏覽器。該老項目中有很多wmv和avi格式的視頻。最近需要更換視頻其他瀏覽器訪問,需要對除ie瀏覽器的其他瀏覽器進行適配。ie瀏覽器播放視頻沒有任何問題,但是在主流瀏覽器中,無法識別<embed>標簽,只支持<video>、<audio>標簽,然而這些標簽支持的視頻格式為主流的mp4格式的視頻。導致兼容性問題,無法播放,以及主流瀏覽器無法播放非mp4格式的視頻。嘗試了很多,查閱了很多資料,前端無法解決該問題,最后嘗試使用后端來解決該問題。通過java調用ffmpeg來對已經存儲在系統中的視頻進行自主的格式轉換為mp4,前端通過判斷是否為ie瀏覽器,而執行對應的js腳本。如果發現為非ie瀏覽器,並且視頻為非mp4格式的視頻,則主動調用后台接口,對該視頻進行格式轉換,同時更新數據庫存儲視頻的目標位置,之后再訪問該視頻時,就查詢到的是mp4格式的視頻,就無需再做格式轉換操作了。
文末附相關安裝包、ffmpeg相關命令介紹
ffmpeg
ffmpeg是一個支持多個格式視頻轉換(包括asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv格式)的軟件。在windows和linux環境下使用的方式不同。
首先需要下載ffmpeg軟件,解壓之后將ffmpeg.exe放入到項目目錄中。通過java去調用該程序,執行命令對目標視頻進行格式轉換。

相關java代碼
ConvertVideo 是接收需要轉換的視頻的類。需要注意的是,其中window環境下獲取的ffmpeg目錄與linux環境下獲取ffmpeg目錄是不同的。
public class ConvertVideo {
public static Boolean convertVedio(String inputPath) throws FFmpegException {
if (inputPath.substring(inputPath.lastIndexOf(".")).equals(".mp4") || inputPath.substring(inputPath.lastIndexOf(".")).equals(".MP4")){
return true;
}
String ffmpegPath = getFfmpegPath();
String outputPath = getOutputPath(inputPath);
if (new File(outputPath).exists()){
return true;
}
return FFmpegUtil.ffmpeg(ffmpegPath, inputPath, outputPath);
}
/**
* 獲取ffmpeg執行文件的路徑
*
* @return
*/
private static String getFfmpegPath() {
// windows環境
return new Object(){
public String getPath(){
return this.getClass().getResource("/").getPath().replaceAll("WEB-INF/classes/", "")+"ffmpeg/";
}
}.getPath();
// linux環境
//return "/opt/ffmpeg/ffmpeg-release.4.1/";
}
/**
* 獲取輸出文件名
*
* @param inputPath
* @return
*/
private static String getOutputPath(String inputPath) {
return inputPath.substring(0, inputPath.lastIndexOf(".")) + ".mp4";
}
public static String getNewFileUrl(String inputPath) {
return inputPath.substring(0, inputPath.lastIndexOf(".")) + ".mp4";
}
}
FFmpegException 這是定義ffmpeg異常類
public class FFmpegException extends Exception {
private static final long serialVersionUID = 1L;
public FFmpegException() {
super();
}
public FFmpegException(String message) {
super(message);
}
public FFmpegException(Throwable cause) {
super(cause);
}
public FFmpegException(String message, Throwable cause) {
super(message, cause);
}
}
FFmpegUtil 主要對視頻進行格式轉換的類
public class FFmpegUtil {
/**
* 將視頻轉換為mp4
*
* @param ffmpegPath ffmpegPath bin路徑
* @param inputPath 源文件路徑
* @param outputPath 輸出文件路徑
* @return
*/
public static Boolean ffmpeg(String ffmpegPath, String inputPath, String outputPath) throws FFmpegException{
if (!checkfile(inputPath)) {
throw new FFmpegException("文件格式不合法");
}
int type = checkContentType(inputPath);
List<String> command = getFfmpegCommand(type, ffmpegPath, inputPath, outputPath);
if (null != command && command.size() > 0) {
return process(command);
}
return false;
}
/**
* 檢查視頻的格式
*
* @param inputPath 源文件
* @return
*/
private static int checkContentType(String inputPath) {
String type = inputPath.substring(inputPath.lastIndexOf(".") + 1, inputPath.length()).toLowerCase();
// ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
if (type.equals("avi")) {
return 0;
} else if (type.equals("mpg")) {
return 0;
} else if (type.equals("wmv")) {
return 0;
} else if (type.equals("3gp")) {
return 0;
} else if (type.equals("mov")) {
return 0;
} else if (type.equals("mp4")) {
return 0;
} else if (type.equals("asf")) {
return 0;
} else if (type.equals("asx")) {
return 0;
} else if (type.equals("flv")) {
return 0;
}
// 對ffmpeg無法解析的文件格式(wmv9,rm,rmvb等)
else if (type.equals("wmv9")) {
return 1;
} else if (type.equals("rm")) {
return 1;
} else if (type.equals("rmvb")) {
return 1;
}
return 9;
}
/**
* 檢查文件的合法性
*
* @param path 文件路徑
* @return
*/
private static boolean checkfile(String path) {
File file = new File(path);
return file.isFile();
}
/**
* ffmpeg能解析的格式:(asx,asf,mpg,wmv,3gp,mp4,mov,avi,flv等)
*
* @param command ffmpeg的命令
* @throws FFmpegException
*/
private static boolean process(List<String> command) throws FFmpegException{
try {
if (null == command || command.size() == 0) {
return false;
}
Process videoProcess = new ProcessBuilder(command).redirectErrorStream(true).start();
new PrintStream(videoProcess.getErrorStream()).start();
new PrintStream(videoProcess.getInputStream()).start();
int exitcode = videoProcess.waitFor();
return exitcode != 1;
} catch (Exception e) {
throw new FFmpegException("file upload failed",e);
}
}
/**
* 根據文件類型設置ffmpeg命令
*
* @param type 該視頻對應的類型
* @param ffmpegPath ffmpeg執行文件的路徑
* @param oldfilepath 需要被轉換的視頻路徑
* @param outputPath 轉換后輸出的路徑
* @return
* @throws FFmpegException
*/
private static List<String> getFfmpegCommand(int type, String ffmpegPath, String oldfilepath, String outputPath) throws FFmpegException {
List<String> command = new ArrayList<String>();
if (type == 0) {
command.add(ffmpegPath+"ffmpeg");
command.add("-y");
command.add("-i");
command.add(oldfilepath);
command.add("-c:v");
command.add("libx264");
command.add("-mbd");
command.add("0");
command.add("-c:a");
command.add("aac");
command.add("-strict");
command.add("-2");
command.add("-pix_fmt");
command.add("yuv420p");
command.add("-movflags");
command.add("faststart");
command.add(outputPath);
} else{
throw new FFmpegException("不支持當前上傳的文件格式");
}
return command;
}
}
// 開啟新的線程對視頻進行格式轉換
class PrintStream extends Thread {
private static final Logger log = LoggerFactory.getLogger(PrintStream.class);
java.io.InputStream inputStream = null;
public PrintStream(java.io.InputStream is) {
inputStream = is;
}
@Override
public void run() {
try {
while (this != null) {
int ch = inputStream.read();
if (ch == -1) {
break;
} else {
System.out.print((char) ch);
}
}
} catch (Exception e) {
log.error("convert media error!", e);
}
}
}
linux環境下使用ffmpeg
安裝GCC
yum install gcc
查看安裝結果gcc --version
安裝yasm
1.下載yasm
wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
2.解壓yasm
執行:tar -zxvf yasm-1.3.0.tar.gz
3.進入解壓目錄
執行: cd yasm-1.3.0
4.編譯和安裝
執行1:./configure
執行2:make
執行3:make install
5.查看安裝結果
執行yasm --version
安裝nasm
1.下載nasm
wget http://www.nasm.us/pub/nasm/releasebuilds/2.13/nasm-2.13.tar.gz
2.解壓nasm
執行 tar xzvf nasm-2.13.tar.gz
3.進入目錄
執行:cd nasm-2.13
4.編譯和安裝
執行1:./configure
執行2:make
執行3:make install
5.查看安裝結果
執行nasm --version
安裝x264
1,下載x264 或解壓x264
git clone https://code.videolan.org/videolan/x264.git
2.進入x264目錄
cd x264
3.編譯和安裝
執行1:./configure --enable-shared
執行2:make
執行3:make install
4.查看安裝結果
執行x264 --version
安裝ffmpeg
1.下載ffmpeg4.1
wget https://git.ffmpeg.org/gitweb/ffmpeg.git/snapshot/refs/heads/release/4.1.tar.gz
2.解壓ffmpeg4.1
執行: tar xzfv 4.1.tar.gz
3.進入解壓目錄
解壓之后目錄名為ffmpeg-release.4.1-d44da66,請將目錄名修改為ffmpeg-release.4.1
執行: cd ffmpeg-release.4.1/
4.編譯和安裝
執行1:./configure --enable-gpl --enable-libx264
如果出現類似error如下:
WARNING: using libfdk without pkg-config WARNING: using libx264 without pkg-config ERROR: x265 not found using pkg-config If you think configure made a mistake, make sure you are using the latest version from Git. If the latest version fails, report the problem to the ffmpeg-user@ffmpeg.org mailing list or IRC #ffmpeg on irc.freenode.net. Include the log file "ffbuild/config.log" produced by configure as this will help solve the problem.原因是需要設置PKG_CONFIG_PATH,通過pkg-config去指定路徑自動尋找需要鏈接的依賴庫,解決方法如下,執行命令:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig echo $PKG_CONFIG_PATH 查看結果為 /usr/local/lib/pkgconfig解釋:PKG_CONFIG_PATH (此路徑為.pc文件所在路徑,里面有x264.cp)
然后重新編譯就ok了!
執行2:make
執行3:make install(大概30分鍾左右)
5.查看安裝結果 ffmpeg -version
如果出現如下:

6.編輯id.so.conf文件
執行vim /etc/ld.so.conf
在include ld.so.conf.d/*.conf后換行添加
/usr/local/lib (如果有這句話,直接保存退出,沒有就添加這句話)
:x 保存退出
在ffmpeg目錄下,執行 ldconfig
然后再執行 ffmpeg -version

測試
將2.wmv轉換成2.mp4
本人安裝ffmpeg時,是將ffmpeg安裝在/home/herocheung/ffmpeg/目錄下的,因此有了一下測試命令:
/home/herocheung/ffmpeg/ffmpeg-release.4.1/ffmpeg -i ./2.wmv -c:v libx264 -mbd 0 -c:a aac -strict -2 -pix_fmt yuv420p -movflags faststart ./2.mp4
-- 命令解釋:
(指定ffmpeg安裝目錄下的ffmpeg) -i (需要轉換的視頻位置) -c:v libx264 -mbd 0 -c:a aac -strict -2 -pix_fmt yuv420p -movflags faststart (轉換后視頻存放位置)



安裝完成之后,把java中相關的代碼切換到linux環境下能夠正確識別的路徑即可實現java調用ffmpeg程序,實現視頻格式轉。
截取視頻中的圖片
從視頻中截取第60s處的圖片 ffmpeg -i test.mp4 -y -f image2 -ss 60 -vframes 1 test1.jpg
附件
【相關安裝包(windows ffmpeg、linux ffmpeg相關包)】

鏈接:https://pan.baidu.com/s/1GFt-i4l4r_IlgscAVqcmkQ
提取碼:ef26
【ffmpeg相關命令】http://linux.51yip.com/search/ffmpeg
