一种快速检测Mp4是否损坏的方法
由于项目上的需求,需要一种能快速检测MP4文件是否有效(即能正常播放)的方法。
网络上搜索到的绝大多数方案是使用ffmpeg
或者ffprobe
。以ffprobe
为例:
ffprobe -v quiet -print_format json -show_format -show_streams -i '/root/**/test.mp4'
如果能查询到类似于下图的video信息,表示该MP4文件是可以正常播放的
ffprobe
方案在绝大多数情况下都是正确的,但是在实际项目使用上,有时候莫名会检测不到上图的流结果。(即针对一个有效的MP4文件,有0.1%的可能会出现检测不到流信息。)
为了绝对的准确性,所以需要寻找另外一种方法进行再次检测。
网上找了一圈,发现了这个专利:https://patents.google.com/patent/CN104486614A/nl
该专利的核心思想是读取MP4文件里每个box的大小,然后相加起来。最终和文件的原始大小进行比较,如果相等,那么认为这个MP4文件是未损坏的。
MP4文件格式我参考了这篇博文:https://www.cnblogs.com/chyingp/p/mp4-file-format.html
最终形成了下面这个检测方法:
package com.soyuan.mh.srs.util;
import java.io.*;
import java.nio.ByteBuffer;
public class Mp4Checker {
public static boolean check(String filePath) {
long total = 0;
try (InputStream is = new FileInputStream(filePath)) {
long realSize = new File(filePath).length();
boolean readLarge = false;
long size;
byte[] buff = new byte[8];
while (is.read(buff,0,buff.length) != -1) {
ByteBuffer wrap = ByteBuffer.wrap(buff);
if (readLarge) {
size = wrap.getLong();
}else {
size = Integer.toUnsignedLong(wrap.getInt());
}
if (size == 0) {
break;
}
if (size == 1) {
//读取largeSize
readLarge = true;
}else {
total += size;
long skip;
if (readLarge) {
skip = size - 16;//跳过size + type + largeSize
}else {
skip = size - 8;
}
if (skip > 0) {
is.skip(skip);
}
readLarge = false;
}
}
return realSize==total?true:false;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
测试结果:
20220308141023.mp4 合法: true
20220308141541.mp4 合法: false
20220308141120.mp4 合法: true
20220308141310.mp4 合法: true
20220308141502.mp4 合法: true
20220308141405.mp4 合法: true