ffprobe - 从文件块中获取视频信息
ffprobe - getting video info from file chunk
在我的网站上,用户可以上传视频,这些视频是即时加密并存储在另一台服务器上的。我想存储视频比特率、帧率等,但我无法直接访问它们,我不能只使用以下命令:
ffprobe -show_streams -i file.mp4
我尝试在我的服务器上保存最后一个块,其中包含 moov 原子,但 ffprobe 正在输出:
Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
moov atom not found
C:\file.mp4: Invalid data found when processing input
我检查并截断了至少一个字节导致了这一点,尽管 moov 原子是完整的。
从包含 moov 原子的文件片段中获取视频元数据的正确方法是什么?从 mdata 原子中获取信息怎么样?
我认为 ffmpeg 解析器不知道如何找到分块文件的 moov 原子。它逐块解析(读取或跳过)mp4 文件,直到找到 moov 原子,如果你切断开头的一部分,块结构就会被破坏,因此它不会找到 moov 原子。
一个可能的解决方案是检测末尾有 moov 原子的文件,并通过使用 -movflags +faststart(或 c/c++代码)。然后你可以 t运行 在 moov 原子之后对文件进行分类并且解析 header 仍然有效。
[编辑]
因此,对于为 mov 分离器编写 truncated-fragment-aware 修改的情况(请参阅评论),您可以按照以下方式进行。首先,尽量不要修改 mov_read_default(),它是中央递归引擎,此处的任何更改都可能会破坏大多数常规功能。相反,对 mov_read_header() 进行更改(因为您只关心 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) {
这试图解码 header 树结构,其中 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 文件解析将不再正常工作的风险。
在我的网站上,用户可以上传视频,这些视频是即时加密并存储在另一台服务器上的。我想存储视频比特率、帧率等,但我无法直接访问它们,我不能只使用以下命令:
ffprobe -show_streams -i file.mp4
我尝试在我的服务器上保存最后一个块,其中包含 moov 原子,但 ffprobe 正在输出:
Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
moov atom not found
C:\file.mp4: Invalid data found when processing input
我检查并截断了至少一个字节导致了这一点,尽管 moov 原子是完整的。
从包含 moov 原子的文件片段中获取视频元数据的正确方法是什么?从 mdata 原子中获取信息怎么样?
我认为 ffmpeg 解析器不知道如何找到分块文件的 moov 原子。它逐块解析(读取或跳过)mp4 文件,直到找到 moov 原子,如果你切断开头的一部分,块结构就会被破坏,因此它不会找到 moov 原子。
一个可能的解决方案是检测末尾有 moov 原子的文件,并通过使用 -movflags +faststart(或 c/c++代码)。然后你可以 t运行 在 moov 原子之后对文件进行分类并且解析 header 仍然有效。
[编辑]
因此,对于为 mov 分离器编写 truncated-fragment-aware 修改的情况(请参阅评论),您可以按照以下方式进行。首先,尽量不要修改 mov_read_default(),它是中央递归引擎,此处的任何更改都可能会破坏大多数常规功能。相反,对 mov_read_header() 进行更改(因为您只关心 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) {
这试图解码 header 树结构,其中 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 文件解析将不再正常工作的风险。