關於ffmpeg解決主流瀏覽器無法播放wmv、avi等格式視頻問題(內附linux環境相關安裝包nasm、yasm、x264等)


最近接到一個老項目,由於老項目之前適配的是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


相關博客:
【linux安裝ffmpeg】https://blog.csdn.net/chaos1/article/details/110440426?utm_medium=distribute.pc_relevant_download.none-task-blog-baidujs-4.nonecase&depth_1-utm_source=distribute.pc_relevant_download.none-task-blog-baidujs-4.nonecase


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM