如何使用ffmpeg库同步音频和视频?

时间:2013-10-19 07:23:46

标签: video ffmpeg sync pts

使用SDL和ffmpeg库在C中编写一个非常基本的媒体播放器。最初,按照this页面中的理论来了解整个程序和库的使用。在从头开始编码之后,感谢该教程和许多其他资源,最后我使用最新的ffmpeg和SDL(2.0)库使我的代码工作。但我的代码缺乏适当的同步机制(实际上它没有同步机制!)。

我仍然不清楚如何将音频和视频同步在一起,因为链接中提供的理论只是非常部分正确(至少在使用最新的开发时)库)。
例如,this页面中的句子如下:

  

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

我正在使用 avcodec_decode_video2(),并且数据包的DTS绝对与它解码的帧的pts(通常)不同。

我阅读了this非常有用的BBC报告,这完全合情合理。我对PTS和DTS有一个清晰的认识。但是ffmpeg用于数据包和解码帧的PTS和DTS值令人困惑。我希望有一些关于这方面的文件。

有人可以解释同步音频和视频的步骤吗?我只需要这些步骤。我很乐意实现它们。任何帮助是极大的赞赏。谢谢 !

PS:这是我所说的截图:

enter image description here

巨大的负值是,我假设AV_NOPTS_VALUE。

1 个答案:

答案 0 :(得分:3)

这不是一个直接的答案,但对于上述问题有很多有用的信息。经过更多信息和编码后,我的观察结果如下:

我提供了一个.mpg文件作为输入,这些是我的观察结果:

BBC RD 1996/3在其内容非常丰富的报道中说:

  

为了从未来的帧启用后向预测,编码器从中重新排序图片   自然显示顺序为“传输”(或“比特流”)顺序,以便在过去之后传输B图像   以及它引用的未来图片。 (见图14)。   这引入了一个延迟,取决于   连续B图像的数量。

  • 提供的输入文件的前几个视频帧如下:(按其自然显示顺序)

    I0 B0 B1 P0 B2 B3 P1 B4 B5 P2 B6 B7 P3 B8 B9 I1 ...

  • 但是编码器(在编码过程中,在编码文件的过去的某个时间)将数据包放入视频流中:(这是为了能够解码PB帧)

    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)

      Next Input Packet ---------> DECODER ---------->  Next Output Frame   
     (pts_PKT, dts_PKT)                                I1 (pts_I1, dts_PKT) 

我想您现在可以注意到,在解码的每一步,解码器已经 其他帧(过去帧或自然显示顺序的未来帧) )成功解码输入数据包。解码器以自然显示顺序输出帧。另据我观察,通常包含I或P帧的访问单元(数据包)的 pts 是AV_NOPTS_VALUE。

PS:我不懂ASCII艺术!对不起,如果插图不太好。希望它能帮助别人。
知道这一点后,我想这有助于更好地理解pts和dts This linkthis link是我认为有用的其他内容。