目录
第一点:AVCodecContext的time_base变量含义
第二点:AVFrame 结构体的 repeat_pict 变量含义
第三点:AVFrame 结构体的 best_effort_timestamp 变量含义
get_audio_clock(VideoState * videoState)函数实现含义
其实在前面的视频播放器实现的过程中我们就已经视频和音频的运行比较流畅(链接),但是其实很多视频并不是这样的,因此,我们需要将视频和音频进行同步,就像参考1 所说的,可以将音频同步到视频,或者将视频同步到音频,再或者两者同步到外部时钟。虽然我们前面都采用了多线程,互斥量和条件变量操作,但是还是需要进行改进,这一系列的改进不仅仅是因为实现视频和音频的同步播放,而且方便功能的拓展。参考2
从前面的改进到现在,我们一直都在说这样的改进,比如使用链队列来存储视频帧和音频数据,使用多线程,互斥量和条件变量(其实我们在实施改进之前就已经使用了这些技术)等操作将视频帧或者音频播放部分进行进一步的拆解,那么这些操作真的是在为后面的功能拓展做铺垫吗?看完这篇文章之后,小伙伴就应该有感受了。视频帧有解码时间戳(DTS)(视频帧或音频解码)和显示时间戳(PTS)(视频帧显示或音频播放),那么这些是不是影响着视频或者音频的播放速度和播放时间以及视频帧是否会丢失的问题,也就是我们的视频帧的解码和播放之间可能并不同步,本篇文章主要基于上面给出的参考链接1和参考链接2来视频帧播放的同步,正是利用实现同步为后期实现快进和快退等功能打下基础。
视频帧播放和音频播放(buffer size)时间轴参考:也就是视频帧和音频在播放的过程可能不同步。建议看这个时间轴之前先去看视频和代码实现,然后来看时间轴会更好理解一点。
注:图中涉及的变量名称和代码中是提到的名称是对应的。
注:这里之所以没有给出一个流程图,是因为整个改进的过程虽然代码不多,但是逻辑上不好去绘制流程图给大家看,大家可以看一下上面给出的视频大致讲解。
前置知识点(官方 + 网上查询)
第一点:AVCodecContext的time_base变量含义
- 时间基准:
time_base
是一个AVRational
结构体,表示时间戳的分数形式。它的含义是“每一秒钟有多少个时间单位”,即:
time_base = numerator / denominator(可以理解为播放一帧所需要的间)
- 时间戳计算:在解码和播放视频时,帧的时间戳(
pts-显示时间戳
和dts-解码时间戳
)通常是以time_base
为单位的。通过将时间戳与time_base
相乘,可以将其转换为秒:
seconds = pts×(time_base.numerator / time_base.denominator)
第二点:AVFrame
结构体的 repeat_pict
变量含义
repeat_pict
是一个整数值,表示当前帧的重复次数。它指示当前帧在播放时需要重复的次数。该变量的值通常与视频的时间基准(time_base
)和帧率(frame rate)结合使用,以确定帧的实际播放时间。
-
repeat_pict
值的含义:0
:表示当前帧不需要重复。1
:表示当前帧需要重复一次(即播放两次)。2
:表示当前帧需要重复两次(即播放三次)。- 以此类推。
第三点:AVFrame
结构体的 best_effort_timestamp
变量含义
best_effort_timestamp
是一个 int64_t
类型的变量,表示当前帧的最佳努力 PTS(显示时间戳,Presentation Time Stamp)
与 PTS 和 DTS 的关系
- PTS(Presentation Time Stamp):表示帧应该在播放时显示的时间。它是帧的实际显示时间。
- DTS(Decoding Time Stamp):表示帧应该在解码时被处理的时间。它通常用于确定解码顺序。
- best_effort_timestamp:在无法获取精确 PTS 的情况下,使用
best_effort_timestamp
作为最佳努力的时间戳,以尽量保持播放的顺序和同步。
注:如果不理解“最佳努力 PTS”就认为是“最佳时刻视频帧的显示时间戳”,让视频帧在解码时间戳和显示时间戳之间是保持同步的。
最后一点:每秒钟总的字节数
- 采样率(
sample_ratio
):44100 Hz (samples/second) - 位深度(音频格式):16 位(即每个样本 2 字节)(bytes/sample)
- 声道数(
channels
):2(立体声,1-单声道)(channels)
那么每秒钟的字节数计算如下:
每秒字节数=44100 * 2 * 2 = 176400 bytes / second
特别的“加权平均”
注:我这里所说的“特别”是表达和我们之前所想的的求解加权平均的方式不同,没有其他的意思。
标准的加权平均求解方式 -求解x的平均值 (1)
根据教程的作者所说的,采用几何级数作为权重实现加权平均。
(2)
作者的描述是当n趋近于无穷大的时候,级数的结果为1 / (1 - C),其实关于上面公式2是怎么推来的,大家直接看高数或者网上搜索推理过程即可知道(提醒:从等比数列推来)。
注:这也就是代码中所对应的大致公式。