背景

项目中有一个需求,要获取前端上传过来的视频的时长、分辨率等信息。网上查了下,java后端基本上都是用的jave获取视频信息,jave的官网在此

不过网上的教程都是获取本地视频的信息,jave提供的功能也不支持获取网络视频的信息。那要怎么搞咧?

首先看下jave的原理,jave使用FFmpeg处理多媒体文件。

jave将FFmpeg的可执行文件放到了jar包里面,在运行的时候将FFmpeg可执行文件拷贝到操作系统的临时文件夹中,并通过命令行来调用FFmpeg。这里面包含了windows的可执行文件和linux的可执行文件。jave源码包结构如下图:

所以现在就要看FFmpeg是否支持通过网络URL获取视频信息,FFmpeg官网在此,可以查看到FFmpeg是支持网络URL的。我们打开cmd,cd到FFmpeg所在目录,执行如下命令

ffmpeg.exe -i http://vd3.bdstatic.com/mda-jk060vvmi12xmdc9/mda-jk060vvmi12xmdc9.mp4

发现是可以获取到视频信息的,红框是视频信息

那么我们就需要改源码了,源码在文章的最后面,可以直接使用。

方案

修改Encoder.java这个类,增加一个方法如下:

public MultimediaInfo getInfo(String httpUrl) throws InputFormatException,
        EncoderException {
    // 将开头的https替换成http,ffmpeg获取https视频会报错
    httpUrl = httpUrl.replaceAll("^https", "http");
    FFMPEGExecutor ffmpeg = locator.createExecutor();
    ffmpeg.addArgument("-i");
    ffmpeg.addArgument(httpUrl);
    try {
        ffmpeg.execute();
    } catch (IOException e) {
        throw new EncoderException(e);
    }
    try {
        RBufferedReader reader = new RBufferedReader(new InputStreamReader(ffmpeg
                .getErrorStream()));
        return parseMultimediaInfo(httpUrl, reader);
    } finally {
        ffmpeg.destroy();
    }
}

此处有个坑,这个FFmpeg不支持https的URL,需将https替换成http,使用https的视频url会报错no such file or directory

然后将原有的getInfo方法修改如下:

public MultimediaInfo getInfo(File source) throws InputFormatException,
        EncoderException {
    return getInfo(source.getAbsolutePath());
}

注释掉parseMultimediaInfo方法的这两行,原因是这篇文章后面替换成新版的FFmpeg,解析的文本内容格式不一样,需要调整下。

} else if (step == 1) {
    Matcher m = p2.matcher(line);
    if (m.matches()) {
        long hours = Integer.parseInt(m.group(1));
        long minutes = Integer.parseInt(m.group(2));
        long seconds = Integer.parseInt(m.group(3));
        long dec = Integer.parseInt(m.group(4));
        long duration = (dec * 100L) + (seconds * 1000L)
                + (minutes * 60L * 1000L)
                + (hours * 60L * 60L * 1000L);
        info.setDuration(duration);
        step++;
    }/* else {
        step = 3;
    }*/
} else if (step == 2) {
  

使用方式如下:

Encoder encoder = new Encoder();
MultimediaInfo info = encoder.getInfo(sourceUrl);
log.info("ffmpeg解析结果:" + JSONObject.toJSONString(info));
long duration = info.getDuration();
log.info("视频时长:" + duration);

然后将代码打成jar包,放入工程里的resources的lib目录下,pom增加如下

<dependency>
    <groupId>com.baqi</groupId>
    <artifactId>jave</artifactId>
    <version>1.0.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/src/main/resources/lib/myJave-1.0.0.jar</systemPath>
</dependency>

然后因为是SpringBoot项目编译后的路径问题,引入本地包时,还需要在编译插件增加一个配置

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <!-- 包含本地jar -->
    <configuration>
        <includeSystemScope>true</includeSystemScope>
    </configuration>
</plugin>

将项目发布到linux服务器上运行时,又遇到另一个坑,发现运行时会报错,获取不了视频时长和分辨率等信息。把项目中的linux版本的可执行FFmpeg文件拷贝到linux服务器上,执行

./ffmpeg -i http://vd3.bdstatic.com/mda-jk060vvmi12xmdc9/mda-jk060vvmi12xmdc9.mp4

会报错 I/O error occured

也许是系统不兼容吧,我们公司的服务器是CentOS 7.2版。然后去FFmpeg官网下载linux的可执行文件放入jar包,替换掉原有的linux可执行文件。我下载的是amd64版,下载地址在此

搞完之后,终于可以通过网络URL获取视频信息了,而且FFmpeg效率很快。

结语

源码传到git了,下载地址在此,里面包含了上面的改动和最新的linux版的FFmpeg,可以下载后打成jar包放入项目中使用。