背景
项目中有一个需求,要获取前端上传过来的视频的时长、分辨率等信息。网上查了下,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包放入项目中使用。