本系列 以 ffmpeg4.4 源码为准,主要讲解 ffplay 的 RTMP 协议解析,播放。本文使用的命令如下:
ffplay -loglevel quiet -fflags nobuffer -i rtmp://192.168.0.122/live/livestream
播放音视频流最重要的是同步,同步需要用到各个帧的pts,下面就来分析一下 ffplay
从 RTMP 地面读取到的帧的 pts 是从哪个字段提取出来的。
前面几篇文章《FFplay源码分析-rtmp入口》《FFplay源码分析-rtmp_open》《FFplay源码分析-avformat_open_input》已经讲解了 RTMP 的建立,以及部分的数据读取。本文是基于之前的基础进行讲解的。
从之前的文章知道,所有的 RTMP 音视频帧都是通过 append_flv_data()
函数丢进去 RTMPContext
做临时存储,但是播放不是从这里拿数据,播放是从 ic->internal->packet_buffer
拿数据, append_flv_data()
函数函数里面有个 pkt 变量,里面有个 timestamp 字段,如下如:
这个 timestamp 字段应该就是音频帧的pts,时间是微妙。只需要对照一个这个时间戳跟 data字段的数据,就能知道 pts 是不是从这里取的。
由于我知道 find_stream_info() 会读取一部分的视频数据,探测之后丢弃。所以 av_read_frame()
拿到的第一个 数据包的 pts 是 1689 ,如下图:
所以我在 append_flv_data()
函数加个判断,如下:
上图我打印了一下 pts 跟 头 4个字节的内存,然后,我在 ffplay.c 文件的 av_read_frame()
后面打一个断点,查看 AVPacket 的内容,如下图:
最后,两个断点处 的 变量 pkt 的 pts 跟 timestamp 字段值都是 1696,时间戳一直,然后 data 截图如下:
所以 AVPacket 的 pts 就是从 RTMPPacket 的 timestamp 拿出来的,data 也是基本相同,只是 RTMPPacket 的data 头两个字节是 0xaf 0x01。至此我们已经找到 AVPacket 的 pts 的来源,RTMPPacket 的 timestamp 就是 RTMP 格式中的 timestamp,封装 RTMP 包的时候,要把时间戳往这个字段上填。如下图:
纠正,上面那个应该是 dts 不是 pts,然后 pts 应该是通过这个 CompositionTime
计算出来的,如下:
这个 CompositionTime 应该是在 RTMP body 里面的,可能是 H264 的一些东西。后面研究H264编码再做分析。
由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,或者希望交流音视频技术的,可以加我微信 Loken1。