问题引入
最近笔者在写一个多线程下载视频文件的程序,打算让这个程序在我的空闲服务器上运行,但是几轮测试之后发现,有时候会存在下载的视频文件不完整的情况,这就导致了有些文件无法正常播放
问题排查
经过一周的排查后,排除了多线程下载代码部分的问题,已经确定是对方的资源服务器有时会抽风,导致获取到的数据并不是正确的数据,所以就导致了视频文件中部分内容错误,所以解决方法也很简单,就是在文件下载完成后,对文件完整性进行检验,如果文件无法正常播放就重新下载
mp4完整性检验
笔者在网上找了很久的方法,最终找到最有效的方法就是使用ffmpeg这个工具来帮助我们完成视频完整性的检验
参考这篇文章,使用指令
ffmpeg -i your_file.mp4 -v error -map 0:1 -f null -
如果有输出,就说明文件有错误,否则文件就是完整的
安装ffmpeg
首先需要在服务器上安装ffmpeg
在 https://johnvansickle.com/ffmpeg/ 链接中找到linux版本的ffmpeg编译完成的包
使用wget下载到服务器上
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
再通过tar命令解压
tar -xvf ffmpeg-release-amd64-static.tar.xz
把文件复制到/opt目录下
mv ffmpeg-release-amd64-static /opt/
最后添加PATH环境变量,用vim打开/etc/profile,添加如下内容
export PATH=$PATH:/opt/ffmpeg-5.1.1-amd64-static/
再在控制台中执行一次这条指令,使得PATH环境变量的更改立刻生效
最后测试一下,输入
ffmpeg
有输出
说明安装成功
java实现
java实现就是简单的使用Runtime来执行linux指令即可
但要注意,有一个坑,就是当文件路径有空格时,就只能使用String数组的方式来调用Runtime的exec
这里为了普适性,就采用String数组的方式来调用exec
具体代码如下
public static boolean checkMP4L2(String filePath){
String[] cmd={"ffmpeg","-v","error","-i",filePath,"-map","0:1","-f","null","-"};
//下面注释了的这一行,在绝对路径中包含空格时会导致检测失败,会提示文件不存在
// String command="ffmpeg -v error -i "+filePath.replaceAll(" ","\" \"")+" -map 0:1 -f null -";
try {
Process process=Runtime.getRuntime().exec(cmd);
InputStream is=process.getErrorStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String line=br.readLine();
if(line==null)
return true;
log.trace("L2 check error message "+line+" (for "+filePath+")");
return false;
}catch (Exception e){
log.error("Failed to do l2 check for "+filePath,e);
return false;
}
}