坚持使用 SDL 和 ffmpeg 库用 C 语言编写一个非常基本的媒体播放器。最初,遵循 this 中的理论页面以了解整个程序和库的使用情况。在从头开始编码之后,感谢该教程和许多其他资源,最后我使用最新的 ffmpeg 和 SDL (2.0) 库完成了我的代码工作。但是我的代码缺少适当的同步机制(实际上它缺少同步机制!)。
我仍然不清楚如何将音频和视频同步在一起,因为链接中提供的理论只是部分正确(至少在使用最新的开发库时)。
例如this中的一句话页面如下:
However, ffmpeg reorders the packets so that the DTS of the packet being processed by avcodec_decode_video() will always be the same as the PTS of the frame it returns.
我正在使用 avcodec_decode_video2() 并且数据包的 DTS 绝对与它解码的帧的 pts 不同(通常)。
我读了this非常翔实的 BBC 报道,这完全有道理。我对 PTS 和 DTS 有一个清晰的认识。但是 ffmpeg 用于数据包和解码帧的 PTS 和 DTS 值令人困惑。我希望有一些关于这方面的文件。
有人可以解释同步音频和视频的步骤吗?我只需要步骤。我很乐意实现它们。任何帮助是极大的赞赏。谢谢 !
PS:这是我正在谈论的截图:
巨大的负值是,我假设 AV_NOPTS_VALUE。
最佳答案
这不是一个直接的答案,但对于上述问题有很多有用的信息。在浏览了更多信息并进行了一些编码之后,以下是我的观察结果:
我提供了 .mpg
文件作为输入,这些是我的观察:
BBC RD 1996/3 在其内容丰富的报告中说:
To enable backward prediction from a future frame, the coder re-orders the pictures from natural display order to ‘transmission’ (or ‘bitstream’) order so that the B-picture is transmitted after the past and future pictures which it references. (See Fig. 14). This introduces a delay which depends upon the number of consecutive B-pictures.
I0 B0 B1 P0 B2 B3 P1 B4 B5 P2 B6 B7 P3 B8 B9 I1
... P
和 B
帧的解码)I0 P0 B0 B1 P1 B2 B3 P2 B4 B5 P3 B6 B7 I1 B8 B9
... av_read_frame()
从视频流中读取数据包,它们的获取顺序与上述相同:I0 P0 B0 B1 P1 B2 B3 P2 B4 B5 P3 B6 B7 I1 B8 B9
... avcodec_decode_video2()
做(或至少在这种情况下正在做):输入
I0
(pts_I0, dts_I0)
-----> DECODER
----> 无输出帧输入
P0
(pts_P0, dts_P0)
-----> DECODER
----> 输出 I0
(pts_I0, dts_P0)
输入 B0
(pts_B0, dts_B0)
-----> DECODER
----> 输出 B0
(pts_B0, dts_B0)
输入 B1
(pts_B1, dts_B1)
-----> DECODER
----> 输出 B1
(pts_B1, dts_B1)
输入 P1
(pts_P1, dts_P1)
-----> DECODER
----> 输出 P0
(pts_P0, dts_P1)
输入 B2
(pts_B2, dts_B2)
-----> DECODER
----> 输出 B2
(pts_B2, dts_B2)
输入 B3
(pts_B3, dts_B3)
-----> DECODER
----> 输出 B3
(pts_B3, dts_B3)
输入 P2
(pts_P2, dts_P2)
-----> DECODER
----> 输出 P1
(pts_P1, dts_P2)
输入 B4
(pts_B4, dts_B4)
-----> DECODER
----> 输出 B4
(pts_B4, dts_B4)
输入 B5
(pts_B5, dts_B5)
-----> DECODER
----> 输出 B5
(pts_B5, dts_B5)
输入 P3
(pts_P3, dts_P3)
-----> DECODER
----> 输出 P2
(pts_P2, dts_P3)
输入 B6
(pts_B6, dts_B6)
-----> DECODER
----> 输出 B6
(pts_B6, dts_B6)
输入 B7
(pts_B7, dts_B7)
-----> DECODER
----> 输出 B7
(pts_B7, dts_B7)
输入 I1
(pts_I1, dts_I1)
-----> DECODER
----> 输出 P3
(pts_P3, dts_I1)
输入 B8
(pts_B8, dts_B8)
-----> DECODER
----> 输出 B8
(pts_B8, dts_B8)
输入 B9
(pts_B9, dts_B9)
-----> DECODER
----> 输出 B9
(pts_B9, dts_B9)
下一个输入包 ---------> 解码器 ----------> 下一个输出帧
(pts_PKT, dts_PKT) I1 (pts_I1, dts_PKT)
我想你现在可以注意到,在解码的每一步,解码器已经有其他帧(自然显示顺序的过去帧或 future 帧)来成功解码输入数据包。解码器以自然显示顺序输出帧。同样据我观察,通常包含 I 或 P 帧的访问单元(数据包)的 pts 是 AV_NOPTS_VALUE。
PS:我不懂ASCII艺术!如果插图不太好,请见谅。希望它对其他人有所帮助。
现在知道这一点后,我想它有助于更好地理解 pts 和 dts。
This link和 this link是我发现其他有用的。
关于video - 如何使用 ffmpeg 库同步音频和视频?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19463550/