8

我正在使用一个使用 IBBP... GOP 序列的 mpeg 流。前 4 个 AVPackets 返回的(DTS,PTS)值如下:I=(0,3) B=(1,1) B=(2,2) P=(3,6)

I 帧上的 PTS 看起来是合法的,但 B 帧上的 PTS 不可能正确,因为 B 帧不应显示在 I 帧之前,如其 PTS 值所示。我还尝试解码数据包并在生成的 AVFrame 中使用 pts 值,将 PTS 始终设置为零。

有什么方法可以从 ffmpeg 中获得准确的 PTS 吗?如果没有,那么同步音频的最佳方式是什么?

4

3 回答 3

11

我想我终于根据http://www.dranger.com/ffmpeg/tutorial05.html中的评论弄清楚了发生了什么:

ffmpeg 对数据包重新排序,以便 avcodec_decode_video() 处理的数据包的 DTS 将始终与其返回的帧的 PTS相同

翻译:如果我向 avcodec_decode_video() 提供一个 PTS 为 12 的数据包,avcodec_decode_video() 将不会返回该数据包中包含的解码帧,直到我向它提供一个 DTS 为 12 的后续数据包。如果数据包的 PTS 是与它的 DTS 相同,则给定的数据包与返回的帧相同。如果数据包的 PTS 比其 DTS 晚 2 帧,则 avcodec_decode_video() 将延迟该帧并且在我再提供 2 个数据包之前不会返回它。

基于这种行为,我猜测 av_read_frame() 可能正在将数据包从 IPBB 重新排序到 IBBP,因此 avcodec_decode_video() 只需将 P 帧缓冲 3 帧而不是 5 帧。例如,输入和具有此排序的 P 帧的输出为 3 (6 - 3):

|                  I B B P B B P
|             DTS: 0 1 2 3 4 5 6
| decode() result:       I B B P

与标准排序 (6 - 1) 的差异为 5:

|                  I P B B P B B
|             DTS: 0 1 2 3 4 5 6
| decode() result:       I B B P

<shrug/> 但这纯粹是猜想。

于 2008-09-19T19:39:45.907 回答
2

好的,划掉我之前困惑的回复。

对于 IBBPBBI 电影,您希望 PTS 看起来像这样(按解码顺序)

0, 3, 1, 2, 6, 4, 5, ...

对应于帧

I, P, B, B, I, B, B, ...

因此,您似乎在序列开始时缺少一个 I,但时间戳看起来是正确的。

于 2008-09-18T21:03:16.583 回答
0

我相当肯定你得到了准确的值。如果您将 MPEG 流视为流,它可能会有所帮助。在这种情况下,在您看到的 IBBPBB 之前,通常会有另一个 GOP。也许是这样的(使用与原始问题相同的符号):

P(-3,-2)  B(-2,-1)  B(-1,0)

基本上,I 帧之后的 B 帧是基于前一个GOP 的 I 帧和最后一个 P 帧。

虽然视频从这个开始是合乎逻辑的:

Start GOP: IPBBPBBPBB...

以后应该是

Start GOP: IBBPBBPBBPBB
Start GOP: IBBPBBPBBPBB
Start GOP: IBB... 

请记住,解码任何 B 帧都需要它之前和之后的完整帧。因此,每对 B 帧都应显示在文件中的 I 或 P 帧之前。

FFMPEG 可能刚刚放弃了第一个 GOP 的“特殊情况”。

由于前两个 B 帧没有要操作的先前帧,因此您应该能够安全地丢弃它们。只需将您的时间戳从第一个 I 帧重新设置为基准,然后将音频流调整为相同的量。

这是否真的会导致帧丢失将取决于 FFMPEG 的实现,但更糟糕的情况是您丢失 83 毫秒(2 帧,24 帧/秒)。

于 2008-09-20T15:23:04.517 回答