RV1126+FFMPEG推流项目(10) FFMPEG 时间概念的讲解

        本节聊一聊ffpmeg时间概念的讲解,主要介绍 FFMPEG 的时间概念,包括时间基、时间戳、时间转换、时间比较等知识点。这些知识点对于我们了解推流至关重要,因为音视频合成本质上是各种时间转换的过程。

二. FFMPEG 时间基、时间戳的讲解

2.1 时间基(Time Base)

时间基,也称为时间基准,代表每个刻度是多少秒。例如,视频帧率是 30 FPS,那么时间基就是 {1, 30},也就是说每 1 秒钟划分为 30 个等分,视频每隔 1/30 秒显示一帧。

在 FFMPEG 中,时间基使用 AVRational 结构体表示:

  • num:分子,代表刻度的分子
  • den:分母,代表刻度的分母

        在视频时间基都是以帧率为单位,比方说 50 帧。FFMPEG 就以 AVRational video_timebase= {1, 50}来表示。

        在音频时间基都是以采样率为单位,比方说音频采样率是 48000HZ。FFMPEG 就以
AVRational audio_timebase = {1, 48000}来表示。

        对于封装格式来说:flv 封装格式的 time_base 为{1,1000},ts 封装格式的 time_base 为
{1,90000}

        从上图 ffplay 的信息我们可以看到有很多关于时间基的信息:
tbr:表示帧率,该帧率是一个基准,通常来说 tbr 和 fps 是一致的
tbn:表示视频流 timebase(时间基),比方说:TS 格式的数据 timebase 是 90000,flv 格式
的视频流 timebase 为 1000
tbc:表示视频流 codec timebase,这个值一般为帧率的两倍。比方说:帧率是 30fps,则 tbc
是 60 

时间戳(PTS 和 DTS)

        首先时间戳它指的是在时间轴里面占了多少个格子,时间戳的单位不是具体的秒数,而是时
间刻度。只有当时间基和时间戳结合在一起的时候,才能够真正表达出来时间是多少。比如钱,单单一个数字1是没有如何意义的。后面要有单位,比如是美元还是人民币,这样才有意义。

        比方说:
有一把尺子 pts = 30 个刻度,time_base = {1,30} 每一个刻度是 1/30 厘米
所以这把尺子的长度 = pts * time_base = 30 * 1/30 = 1 厘米

        PTS:全称是 Presentation Time Stamp(显示时间戳),它主要的作用是度量解码后的视频帧
什么时候显示出来
。视频 PTS 计算:n 为第 n 帧视频帧,timebase 是{1,framerate},fps 是 framerate
        pts = n *(( 1 / timebase) / fps):
        pts = pts++;
        举例子:n = 1, pts = 1
        n = 2, pts = 2
        n =3, pts = 3


        音频 PTS 计算:n 为第 n 帧音频帧,nb_samples 指的是采样个数(AAC 默认 1024),timebase是{1,samplerate},samplerate 是采样率

num_pkt = samplerate/nb_samples

pts = n * ( ( 1/ timebase) / num_pkt)
pts = pts+1024
举例子:n = 1, pts = 1024
              n = 2, pts = 2048
              n = 3, pts = 3072

        DTS:表示的是压缩解码的时间戳,在没有 B 帧的情况下 PTS 等于 DTS。假设编码
的里面引入了 B 帧,则还要计算 B 帧的时间。
没有 B 帧:dts = pts
存在 B 帧:dts = pts + b_time

时间转换的原理:

        在 FFMPEG 中由于不同的复合流,时间基是不同的,比方说:ts 的时间基 time_base=
{1,90000},假设一个视频 time_base = {1,30},我们需要合成 mpegts 文件,它就需要把
time_base = {1,30}占的格子转换成 time_base = {1,90000}占的格子。
在 FFMPEG 中用以下的 API 进行时间基转换:

        转换的函数已经ffmpeg已经准备好了,我们不需要手动转换,但是我们要搞明白转换的原理是什么。 

void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst);

  1. 第一个参数:AVPacket 结构体指针
  2. 第二个参数:源时间基
  3. 第三个参数:目的时间基

        上面这个 api 的用法是,把 AVPacket 的时间基 tb_src 转换成时间基 tb_dst。下面我们用 H264和 AAC 时间基 TS 转换的例子来说明这个转换时间基的用法: 

        视频 H264 时间基转换成 MPEGTS 时间基:公式

H264 {1,30}                                            MPEGTS {1,90000}
pts = 1                                                    pts = 3000
pts = 2         av_packet_rescale_ts          pts = 6000
pts = 3                                                    pts = 9000
pts = 4                                                    pts = 12000 

        音频 AAC 时间基转换成 MPEGTS 时间基公式 

AAC {1,48000}                                      MPEGTS {1,90000}
pts =1024                                              pts = 1920
pts =2048     av_packet_rescale_ts        pts = 3840
pts =3072                                              pts = 5760
pts =4096                                              pts = 7680

        从上述推导的结果可以看出来,如果使用 av_packet_rescale_ts 的 API 对视频时间基进行
转 换 , 实 际 上 是 使 用 DST_VIDEO_PTS = VIDEO_PTS * VIDEO_TIME_BASE /
DST_TIME_BASE 去计算推流的视频时间戳。

        同理用 av_packet_rescale_ts 对音频时间基进行转换,实际上是使用 DST_AUDIO_PTS =
AUDIO_PTS * AUDIO_TIME_BASE / DST_TIME_BASE 去计算我们真实推流的音频时间
戳。

FFMPEG 时间戳的比较:

        所谓的时间转换,就是把音频视频的时间,用ts留的时间基作为标准,然后风别计算他们的时间,看谁的时间快,就有限处理谁的,就先把它写到复合流里面

int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b) 这些都是成对出现的,1,2是参数,34是参数。

  1. 第一个参数:ts_a 它指的是当前相对 tb_a 的时间戳
  2. 第二个参数:ts_a 相对应的时间基
  3. 第三个参数:ts_b 它指的是当前相对 tb_a 的时间戳
  4. 第四个参数:ts_b 相对应的时间基

返回值判断:

  1. 当 ret == -1, ts_a 的时间戳快过 ts_b 时间戳。
  2. 当 ret == 1, ts_a 的时间戳慢过 ts_b 时间戳。
  3. 当 ret == 0, ts_a 的时间戳等于 ts_b 时间戳

        av_compare_ts 它的主要作用是进行时间戳进行实时比较,它能够实时保证当前的时间戳是
准确无误的。它不会出现时间戳混乱的情况,所谓混乱的情况就相当于:视频时间戳当成音
频时间戳处理,音频时间戳当成视频时间戳处理。

        下面这张图是编码视频、音频然后进行时间戳比较然后合成复合流的流程:

        视频时间戳参考视频帧率进行比较、音频时间戳进行比较(这里我们默认 tb_a 时间基是视频
时间基、tb_b 时间基是音频时间基)。所以当比较的结果 ret <= 0 的时候,则要取出视频数
据,否则就取出音频数据。取出视频数据后则利用 av_packet_rescale_ts 进行时间转换、同
样 取 出 音 频 数 据 后 也 要 对 其 进 行 时 间 转 换 。 音 视 频 数 据 进 行 时 间 转 换 后 , 则 用av_interleaved_write_frame 对复合流进行写入操作。 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值