【问题标题】:avformat code produce slightly different output than ffmpeg with same parameters - why?avformat 代码产生的输出与具有相同参数的 ffmpeg 略有不同 - 为什么?
【发布时间】:2020-05-30 14:16:55
【问题描述】:

我想从代码中获得与此 ffmpeg 命令行调用完全相同的结果:

ffmpeg -i CAMERARTSPLINK -c:v copy -an -movflags +frag_keyframe+empty_moov -f mp4

当我运行上面的命令时,它会给出这个二进制结果:

got 36 bytes:  0, 0, 0, 36, 102, 116, 121, 112, ..., 111, 54, 109, 112, 52, 49, 
got 512 bytes: 0, 0, 3, 76, 109, 111, 111, 118, 0, 0, 0, ..., 132, 0, 0, 3, 0, 4, 0, 0, 3, 0, 202,

代码可以利用 ffmpeg 库和包含,但我不想将 ffmpeg 用作程序调用(即不首选 exec* 函数)。

我使用avformat 创建了一个小型演示代码示例,用于 RTSP H264 到 MP4 再复用。 该代码高度重用了horgh的漂亮videostreamer库。

我将sample code 发布到 pastebin.com(400 位置)。它构建成功,但您需要将其与avformatavdeviceavcodecavutil 链接。

我尽力达到相同的结果,但是当我运行此代码时,字节 #38 之后的前几个字节是不同的(可能不仅仅是那些,我没有比较字节 #548 之后的任何内容):

writeOutput: writing 36 bytes: 0, 0, 0, 36, 102, 116, 121, 112, ..., 111, 54, 109, 112, 52, 49, 
writeOutput: writing 512 bytes: 0, 0, 0, 0, 109, 111, 111, 118, 0, 0, 0, ..., 132, 0, 0, 3, 0, 4, 0, 0, 3, 0, 202, 

您可以在我的代码输出的第二行看到以 0 0 0 0 109 开头,

而 ffmpeg 给了 0 0 3 76 109.

所有其余的(甚至这里没有粘贴字节)数据都是完全一样的(至少前 548 个字节)。

我的代码有什么问题?这 2 个字节似乎对于解码此流非常重要。

【问题讨论】:

    标签: ffmpeg libavcodec libavformat


    【解决方案1】:

    102, 116, 121, 112 in ascii 是ftyp 这是mp4格式类型框。 0, 0, 0, 36 是框的大小

    109, 111, 111, 118 in ascii 是mdat 这是数据框。 0, 0, 0, 0 是盒子的大小。

    在这种情况下,mdat 框的大小是未知的,因为我们还不知道所有视频和音频帧的大小。因此使用零占位符。当文件完成后,大小值应该被正确的大小覆盖

    【讨论】:

    • 谢谢。说得通。但是 ffmpeg 命令没有输出到文件,它直接到标准输出。所以一旦打印到标准输出,它就无法改变盒子的大小。我怎样才能用 avformat 达到同样的效果?
    • 我需要什么:avformat 不能打印 mdat 框,直到它的大小未知
    • 即在我的自定义 io 回调中,没有定义 seek 函数。
    • 或者,换个问题:ffmpeg 如何知道 mdat 的大小(在打印到标准输出时)而我的代码不是?
    • Ffmpeg 在写入之前无法知道 mdat 框的大小。将 mp4 写入标准输出不是有效操作。您必须使用分段的 mp4 或其他可流式传输的容器,例如 mkv。
    【解决方案2】:

    这是 ffmpeg 有限的日志记录功能加上我对视频编解码器的有限知识的愚蠢错误。

    问题在于 ffmpeg(使用 h264 输入)将原子写入输出缓冲区时:

    • 首先将原子大小设为 0 (movenc.c#L3981)
    • 然后填充缓冲区的其余部分
    • 然后在最后它在缓冲区中寻找原子的大小并更新大小 (movenc.c#L4049)

    这一切都很好,但是在填充缓冲区的其余部分时,它使用avio_w8 和 avio_w8 将刷新缓冲区,如果它到达它的末尾。

    如果您使用带有avio_alloc_context 的自定义 IO 并且您没有定义足够大的缓冲区并且您也没有定义查找操作并且正在写入的原子大于您的缓冲区大小,它将是被刷新,ffmpeg 将无法返回更新原子的大小。

    这可能会导致视频输出文件或流损坏(且无法播放)。

    因此解决方案是将缓冲区大小从 512 增加到 4096,在这种情况下,即使不查找操作也可以适应 moov atom。

    如果您知道 moov atom 的长度大于 512 字节并查看我的示例代码,这将非常简单。

    【讨论】:

      猜你喜欢
      • 2022-12-05
      • 2014-07-10
      • 2021-04-17
      • 2012-06-24
      • 1970-01-01
      • 1970-01-01
      • 2012-11-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多