我认为ffmpeg解析器不知道如何找到分块文件的moov原子。它会逐个分块(读取或跳过)mp4文件,直到找到moov原子,如果你截取了开头的一部分,分块结构就会被破坏,因此它将无法找到moov原子。
你可以通过使用带有-movflags +faststart(或在c/c++代码中使用类似的AVOptions)的ffmpeg重新混合来检测末尾带有moov原子的文件,并将moov原子移到开头。然后,你可以在moov原子之后截断文件,并且仍然可以解析头文件。
对于写一个针对截断片段感知修改mov解复用器的情况(请参见评论),以下是你应该采取的步骤。首先,尽量不要修改mov_read_default(),它是中心递归引擎,任何在这里进行的更改都可能破坏大多数常规功能。相反,对mov_read_header()进行更改(因为你只关心头部解析,而不是帧的解复用)。你会找到以下代码:
if (mov->moov_retry)
avio_seek(pb, 0, SEEK_SET);
if ((err = mov_read_default(mov, pb, atom)) < 0) {
av_log(s, AV_LOG_ERROR, "error reading header\n");
mov_read_close(s);
return err;
}
} while (pb->seekable && !mov->found_moov && !mov->moov_retry++);
if (!mov->found_moov) {
这是尝试解码头部树结构,其中moov是上层原子。在文件中,它寻找以下类似序列:
$ hexdump -n 32 -s 41934133 -C somefile.mov
027fdd35 00 00 3e b4 6d 6f 6f 76 00 00 00 6c 6d 76 68 64 |..>.moov...lmvhd|
027fdd45 00 00 00 00 c9 6b 7b f5 c9 6b 7c 02 00 00 02 58 |.....k{..k|....X|
0x00003eb4是'moov'原子的字节大小,其中有一个名为'mvhd'的子原子,大小为0x0000006c字节(树形结构在此之后继续)。如果在解复用文件时将文件指针设置为该确切偏移量,则可以正确解码:
$ tail -c +41934134 somefile.mov > /tmp/hdr.mov
$ ffprobe /tmp/hdr.mov
[..]
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f871b002a00] stream 0, offset 0x3f3e: partial file
[mov,mp4,m4a,3gp,3g2,mj2 @ 0x7f871b002a00] Could not find codec parameters for stream 0 (Video: h264 (avc1 / 0x31637661), none(bt709), 1280x720, 10695 kb/s): unspecified pixel format
[..]
Stream #0:0(und): Video: h264 (avc1 / 0x31637661), none(bt709), 1280x720, 10695 kb/s, 29.97 fps, 29.97 tbr, 600 tbn, 1200 tbc (default)
[..]
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz, mono, fltp, 63 kb/s (default)
如何获取文件偏移量取决于您:
- 您可以在 mov_read_header() 函数中添加一些代码来扫描文件以查找“moov”(0x6d6f6f76)并将文件指针设置为该位置前面的 4 个字节。
- 在创建此片段的代码中,您可以扫描 moov 并且在将该片段保存到文件之前,去掉 moov 原子之前的无用数据。
如果您要更改 ffmpeg 并将其放入用于其他功能的 ffmpeg 版本中,我建议您将其放在某种选项下,以便它不会对默认文件读取产生影响。否则,您将有可能导致常规的 mov/mp4 文件解析无法正常工作。