繁体   English   中英

碎片化 MP4 中出现故障音频或视频损坏

[英]Glitchy audio or broken video in fragmented MP4

我正在研究用于混合音频和视频的小型 C++ 库。 这基本上是 FFMPEG 功能和结构的外观。 代码在这里这里有最少的复制测试代码,到目前为止,它似乎工作正常......几乎。

作为记录 - 我的 MP4 文件是所谓的“分段 MP4”,标题移动到文件的开头,以允许 stream 该文件(即在缓冲时在浏览器中播放它)。 这就是我在Mp4Muxer::writeHeader()中设置的这些movflags的用途。

在使用原始 H264 视频 stream 和 MP3 文件(视频长度小于 1 分钟,MP3 - 几分钟)测试这个库时,我观察到:

  • 如果我不限制混合音频 stream 当它“领先”视频时(因为 MP3 更长,所以最终视频帧停止出现但音频帧仍然出现),所有复用器都很好,没有错误,但是在几秒钟后使用ffplay播放 output MP4 会导致以下日志(以及冻结的视频,而音频继续播放):
[h264 @ 0x7f90a40ae2c0] Invalid NAL unit size (2162119 > 76779).0
[h264 @ 0x7f90a40ae2c0] Error splitting the input into NAL units.
[mp3float @ 0x7f90a4009540] Header missing  515KB sq=    0B f=0/0
[h264 @ 0x7f90a40cb0c0] Invalid NAL unit size (-860010620 > 17931).
[h264 @ 0x7f90a40cb0c0] Error splitting the input into NAL units.
[h264 @ 0x7f90a42bf440] Invalid NAL unit size (-168012642 > 8000).
[h264 @ 0x7f90a42bf440] Error splitting the input into NAL units.
[h264 @ 0x7f90a42fa780] Invalid NAL unit size (-1843711407 > 5683).
[ and it repeats...]
  • 即使我限制 stream 可以“领先”于另一个,限制太多会导致 output 中没有多路数据
  • 任何其他中间级别限制一个 stream 相对于另一个 stream 可以在多路复用器中缓冲多少会导致音频出现故障,在ffplay中不时弹出以下错误(越严格的限制是,它们被打印的频率越高):
[mp3float @ 0x7f744c01b640] overread, skip -6 enddists: -1 -1=0/0 

相对于混合视频不限制混合音频(完全或足够)也会导致我的混合应用程序中出现以下消息:

[mp4 @ 0x55d0c6c21940] Delay between the first packet and last packet in the muxing queue is 10004898 > 10000000: forcing output

目前,该修复非常难看,我什至不明白它为什么会起作用,但在编写 MP4 header 之前,我手动设置了 muxer 缓冲的帧的限制,如下所示:

formatCtxt->max_interleave_delta = 10000000LL * 10LL;

这样,多路复用器可以存储一个 ZF7B44CFFAFD5C52223D5498196C8A2E7BZ 的更多数据包,该数据包“领先”于另一个(队列开头和结尾的数据包的 DTS 之间的最大差异设置为比默认值大 10 倍;它还消除了信息上面提到的日志)。 显然,我想更正确地解决它,而不是像那样做黑客攻击。

我正在尝试各种事情,包括手动跳过 MP3 文件中的 ID3 标签(但似乎 FFMPEG 可以很好地处理它们并且它没有改变任何东西)。 我还在 MP4 中尝试使用 FLAC,而不是 MP3。 虽然我知道这是相当实验性的事情,但我遇到了非常类似的音频故障问题(不过,当大量音频数据被混合时,视频被冻结没有问题)。 似乎故障音频或冻结视频的问题在规模上也有所不同,具体取决于我为复用器提供的输入数据块的大小。 现在,老实说,我没有想法。

我正在回答我自己的问题,也许有人会从我的错误中吸取教训。 顺便说一句,主分支上的代码发生了显着变化,但故障部分仍然可以突出显示。

看起来有问题的代码是Mp4Muxer::muxMediaData()方法中的这个片段:

for(auto packet = mediaCtxt.getNextFrame();
    packet.size > 0 && checkLimit(audioAheadOfVideoInCommonTimebase, timeAheadInCommonTimebaseLimit);
    packet = mediaCtxt.getNextFrame(), ++packetsMuxedCnt)

在这个循环中,我首先获取媒体数据包,然后检查 stream 是否由于领先于其他 stream 太多而受到限制。 如果是,则媒体包丢失。 而且由于音频几乎总是领先于视频,因此由于样本丢失而出现故障。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM