关于ffmpeg解决主流浏览器无法播放wmv、avi等格式视频问题(内附linux环境相关安装包nasm、yasm、x264等)

摘要:
最近,我收到了一个旧项目,因为旧项目被改编为Internet Explorer。在这个旧项目中有许多wmv和avi格式的视频。这导致兼容性问题,无法播放,主流浏览器无法播放非mp4格式的视频。通过java调用ffmpeg,将存储在系统中的视频独立转换为mp4格式。前端通过判断是否是ie浏览器来执行相应的js脚本。首先,您需要下载ffmpeg软件。将Exe解压缩到项目目录后。需要注意的是,在windows环境中获得的ffmpeg目录与在linux环境中获得不同。

最近接到一个老项目,由于老项目之前适配的是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去调用该程序,执行命令对目标视频进行格式转换。

关于ffmpeg解决主流浏览器无法播放wmv、avi等格式视频问题(内附linux环境相关安装包nasm、yasm、x264等)第1张


相关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

如果出现如下:

关于ffmpeg解决主流浏览器无法播放wmv、avi等格式视频问题(内附linux环境相关安装包nasm、yasm、x264等)第2张

6.编辑id.so.conf文件
执行vim /etc/ld.so.conf
在include ld.so.conf.d/*.conf后换行添加
/usr/local/lib (如果有这句话,直接保存退出,没有就添加这句话)
:x 保存退出
在ffmpeg目录下,执行 ldconfig
然后再执行 ffmpeg -version

关于ffmpeg解决主流浏览器无法播放wmv、avi等格式视频问题(内附linux环境相关安装包nasm、yasm、x264等)第3张


测试

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 (转换后视频存放位置)

关于ffmpeg解决主流浏览器无法播放wmv、avi等格式视频问题(内附linux环境相关安装包nasm、yasm、x264等)第4张

关于ffmpeg解决主流浏览器无法播放wmv、avi等格式视频问题(内附linux环境相关安装包nasm、yasm、x264等)第5张

关于ffmpeg解决主流浏览器无法播放wmv、avi等格式视频问题(内附linux环境相关安装包nasm、yasm、x264等)第6张

安装完成之后,把java中相关的代码切换到linux环境下能够正确识别的路径即可实现java调用ffmpeg程序,实现视频格式转。


截取视频中的图片

从视频中截取第60s处的图片 ffmpeg -i test.mp4 -y -f image2 -ss 60 -vframes 1 test1.jpg


附件

【相关安装包(windows ffmpeg、linux ffmpeg相关包)】

关于ffmpeg解决主流浏览器无法播放wmv、avi等格式视频问题(内附linux环境相关安装包nasm、yasm、x264等)第7张
链接: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

免责声明:文章转载自《关于ffmpeg解决主流浏览器无法播放wmv、avi等格式视频问题(内附linux环境相关安装包nasm、yasm、x264等)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇只需两步快速获取微信小程序源码vscode设置tab缩进字符数下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【spring boot】捕获全局异常@RestControllerAdvice

一.由来场景:  使用 Java的validation做入参的校验  ,但是这种入参校验在还没有进入controller就会字段校验不通过,从而直接返回异常信息给前端,     前端的异常提醒, 类似于下面这种 很不友好的  后端接口报错提示信息:   二.解决方法1.解决如上问题,需要对异常做捕获处理,Spring boot 提供了@RestContr...

浏览器内核Trident/Gecko/WebKit/Presto

“浏览器内核”主要指渲染引擎(Rendering Engine),负责解析网页语法(如HTML、JavaScript)并渲染、展示网页。因此,所谓的浏览器内核通常也就是指浏览器所采用的渲染引擎, 渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。不同的浏览器内核对网页编写语法的解析也有所不同,因此同一网页在不同的内核浏览器里的渲 染、展示效果也可能...

winform窗体(六)——DataGridView控件及通过此控件中实现增删改查

DataGridView:显示数据表,通过此控件中可以实现连接数据库,实现数据的增删改查 一、后台数据绑定:    List<xxx> list = new List<xxx>();      dataGridView1.DataSource = list;      //设置不自动生成列,此属性在属性面板中没有      data...

6.1 路由router

路由将信息由源地址传递到目的地的一种角色. 一、路由简单应用举个例子: let express=require('express'); let app=express(); app.use(express.static('public')); // GET /home 显示 网站首页 app.get('/home',function(req,res...

WebApi使用Token(OAUTH 2.0方式)

1.在项目中添加引用 Microsoft.AspNet.WebApi.Owin Microsoft.Owin.Host.SystemWeb Microsoft.Owin.Security.OAuth Microsoft.Owin.Security.Cookies Microsoft.AspNet.Identity.Owin Microsoft.Owin.C...

公众号开发笔记二

前言 微信公众平台开发模板消息,用于公众号向用户发送服务通知,如学生进校门,用校卡滴,就可以在公众号接收服务通知,表明学生进校.在公众号内申请功能,添加模板消息. 只有认证后的服务号才能申请模板消息,需要选择2个行业,MP(维基百科,自由的百科全书),模板消息需要模板的ID,和模板中各种参数,内容以".DATA"结尾,否则视为保留字,模板保留符号"{{...