视频流中的DTS/PTS到底是什么?
DTS (解码时间戳)和 PTS (显示时间戳)分别是×××进行解码和显示帧时相对于 SCR (系统参考)的时间戳。 SCR 可以理解为×××应该开始从磁盘读取数据时的时间。
mpeg 文件中的每一个包都有一个 SCR 时间戳并且这个时间戳就是读取这个数据包时的系统时间。通常情况下,×××会在它开始读取 mpeg 流时启动系统时钟(系统时钟的初始值是第一个数据包的 SCR 值,通常为 0 但也可以不从 0 开始)。
DTS 时间戳决定了×××在 SCR 时间等于 DTS 时间时进行解码, PTS 时间戳也是类似的。通常, DTS/PTS 时间戳指示的是晚于音视频包中的 SCR 的一个时 间。例如,如果一个视频数据包的 SCR 是 100ms (意味着此包是播放 100ms 以后从磁盘中读取的),那么 DTS/PTS 值就差不多是 200 /280ms ,表明当 SCR 到 200ms 时这个视频数据应该被解码并在 80ms 以后被显示出来(视频数据在一个 buffer 中一直保存到开始解码)下 溢通常发生在设置的视频数据流相关 mux 率太高。
如果 mux 率是 1000000bits/sec (意味着×××要以 1000000bits/sec 的速率 读取文件),可是视频速率是 2000000bits/sec (意味着需要以 2000000bits/sec 的速率显示视频数据),从磁盘中读取视频数据时 速度不够快以至于 1 秒钟内不能够读取足够的视频数据。这种情况下 DTS/PTS 时间戳就会指示视频在从硬盘中读出来之前进行解码或显示( DTS/PTS 时间戳就要比包含它们的数据包中的 SCR 时间要早了)。
如今依靠×××,这基本已经不是什么问题了(尽管 MPEG 文件因为应该没有下溢而并不完全符合 MPEG 标准)。一些×××(很多著名的基于 PC 的播放器)尽可能快的读取文件以便显示视频,可以的话直接忽略 SCR 。
注意在你提供的列表中,平均的视频流速率为~ 3Mbps ( 3000000bits/sec )但是它的峰值达到了 14Mbps (相当大, DVD 限制在 9.8Mbps 内)。这意味着 mux 率需要调整足够大以处理 14Mbps 的部分, bbMPEG 计算出来的 mux 率有时候太低而导致下溢。
你计划让视频流速率这么高么?这已经超过了 DVD 的说明了,而且很可能在大多数独立播放其中都不能播放。如果你不是这么计划,我会从 1 增加 mquant 的值并且在视频设置中将最大码流设置为 9Mbps 以保持一个小一点的码流。
如果你确实想让视频码率那么高,你需要增大 mux 率。从提供的列表可以得出 bbMPEG 使用 14706800bits/sec 或者 1838350bytes /sec 的 mux 率(总数据速率为: 1838350bytes/sec ( 14706800bits/sec )行)。你在强制 mux 率字段设置的值应该是以 bytes/sec 为单位并被 50 整除。所以我会从 36767 ( 1838350/50 )开始,一直增加直到不会再出现下溢错误为止。
音视频同步原理[ffmpeg]
ffmpeg 对视频文件进行解码的大致流程:
1. 注册所有容器格式和 CODEC: av_register_all()
2. 打开文件 : av_open_input_file()
3. 从文件中提取流信息 : av_find_stream_info()
4. 穷举所有的流,查找其中种类为 CODEC_TYPE_VIDEO
5. 查找对应的××× : avcodec_find_decoder()
6. 打开编××× : avcodec_open()
7. 为解码帧分配内存 : avcodec_alloc_frame()
8. 不停地从码流中提取中帧数据 : av_read_frame()
9. 判断帧的类型,对于视频帧调用 : avcodec_decode_video()
10. 解码完后,释放××× : avcodec_close()
11. 关闭输入文件 :av_close_input_file()
output_example.c 中 AV 同步的代码如下 ( 我的代码有些修改 ) ,这个实现相当简单,不过挺说明问题。
音视频同步-时间戳
媒体内容在播放时,最令人头痛的就是音视频不同步。从技术上来说,解决音视频同步问题的最佳方案就是时间戳:首先选择一个参考时钟(要求参考时钟上的时间是线性递增的);生成数据流时依据参考时钟上的时间给每个数据块都打上时间戳(一般包括开始时间和结束时间);在播放时,读取数据块上的时间戳,同时参考当前参考时钟上的时间来安排播放(如果数据块的开始时间大于当前参考时钟上的时间,则不急于播放该数据块,直到参考时钟达到数据块的开始时间;如果数据块的开始时间小于当前参考时钟上的时间,则 “ 尽快 ” 播放这块数据或者索性将这块数据 “ 丢弃 ” ,以使播放进度追上参考时钟)。
可见,避免音视频不同步现象有两个关键 —— 一是在生成数据流时要打上正确的时间戳。如果数据块上打的时间戳本身就有问题,那么播放时再怎么调整也于事无补。假如,视频流内容是从 0s 开始的,假设 10s 时有人开始说话,要求配上音频流,那么音频流的起始时间应该是 10s ,如果时间戳从 0s 或其它时间开始打,则这个混合的音视频流在时间同步上本身就出了问题。打时间戳时,视频流和音频流都是参考参考时钟的时间,而数据流之间不会发生参考关系;也就是说,视频流和音频流是通过一个中立的第三方(也就是参考时钟)来实现同步的。第二个关键的地方,就是在播放时基于时间戳对数据流的控制,也就是对数据块早到或晚到采取不同的处理方法。图 2.8 中,参考时钟时间在 0-10s 内播放视频流内容过程中,即使收到了音频流数据块也不能立即播放它,而必须等到参考时钟的时间达到 10s 之后才可以,否则就会引起音视频不同步问题。
基于时间戳的播放过程中,仅仅对早到的或晚到的数据块进行等待或快速处理,有时候是不够的。如果想要更加主动并且有效地调节播放性能,需要引入一个反馈机制,也就是要将当前数据流速度太快或太慢的状态反馈给 “ 源 ” ,让源去放慢或加快数据流的速度。熟悉 DirectShow 的读者一定知道, DirectShow 中的质量控制( Quality Control )就是这么一个反馈机制。 DirectShow 对于音视频同步的解决方案是相当出色的。但 WMF SDK 在播放时只负责将 ASF 数据流读出并解码,而并不负责音视频内容的最终呈现,所以它也缺少这样的一个反馈机制。
音视频同步通讯 SDK 源码包分享:
Android : http://down.51cto.com/data/711001
Windows : http://down.51cto.com/data/715497
Linux : http://download.csdn.net/detail/weixiaowenrou/5169796
IOS : http://down.51cto.com/data/715486
WEB : http://down.51cto.com/data/710983