深入理解音视频pts,dts,time_base以及时间数学公式

引入

首先介绍一下基础名词

DTS(Decoding Time Stamp):即解码时间戳,这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。当数据没b帧时,dts = pts,有兴趣可参阅我前面视频知识类文章。

PTS(Presentation Time Stamp):即显示时间戳,这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。

time_base : 时间基用于表示时间基准,即时间戳的单位。它也是用来度量时间的,在我们生活世界中,有各种时间单位比如年月日时分秒,这都可用理解为时间基。在ffmpeg是这样设计的

typedef struct AVRational{
    int num; ///< Numerator
    int den; ///< Denominator
} AVRational;
转化成double类型 方便计算 比如原子单位是秒 则分表示AVRational{1,60};
static inline double av_q2d(AVRational a){
    return a.num / (double) a.den;
}

        不同时间基与相同时间戳组合,就把时间具体化了,比如2小时后买菜,那是不是可以说120分钟或者7200秒后买菜,这种转化过程在人类世界看着很鸡肋,但是可以转化成“原子时间”(最终单位 不可再往下面转换),这对于计算机处理音视频打下根基,因为不同的封装格式,timebase是不一样的。


time_base={1,60}  pts = 2h
显示未来时间戳预测值= pts * time_base =120分钟
编程处理则是:pts*av_q2d(time_base) 是帧的显示时间戳。

结合音视频实践讨论

在一个视频播放时会进行解复用得到音视频分离的压缩数据再进行解码得到原始数据,进行播放(这里暂且跳过队列,同步讨论)。为什么要这么麻烦? 假设电影大小压缩是5g 那原始数据可能高达30g,所以这个编解码过程是很有必要的。(ffmpeg的时间基都是以秒为单位)

在ffmpeg中对应的结构体为AVFrame,它的时间基为AVCodecContext 的time_base ,AVRational{1,25} 

压缩后的数据(对应的结构体为AVPacket)对应的时间基为AVStream的time_base,AVRational{1,90000}。 

因为数据状态不同,时间基不一样,所以我们必须转换,在1/25时间刻度下占10格,在1/90000下是占多少格。这就是pts的转换。

常用数学公式

每帧采样点数 即是帧讨论

音视频很多是相通但不相同知识点,具体是有差异的比如

音频视频
采样率常见的采样率有 44.1 kHz、48 kHz帧率常见的帧率有 24 fps、30 fps、60 fps
采样精度(sample depth)指的是每个音频样本的位数,常见的有 16 位、24 位等。视频色深(bit depth)指的是每个像素点的颜色位数,常见的有 8 位(256 色)、10 位(1024 色)、12 位(4096 色)等
声道数(channels)指的是音频的声道数,常见的有单声道(1)、立体声(2)、5.1 声道(6)等分辨率(resolution)指的是视频图像的宽度和高度,常见的有 1920x1080(Full HD)、3840x2160(4K)等

timestamp(秒) = pts * av_q2d(st->time_base)
根据pts来计算一帧在整个视频中的时间位置:

time(秒) = st->duration * av_q2d(st->time_base)
计算视频长度


af->duration = av_q2d((AVRational){frame->nb_samples, frame->sample_rate});
⾳频播放时间计算:
每帧持续时间(秒) = 每帧采样点数 / 采样频率(HZ)
以采样率44100Hz来计算,每秒44100个sample,⽽正常⼀帧为1024个sample,可知每帧播放时间/1024=44100,得到
每帧播放时间=1024/44100=0.02321995464852608s (23.21995464852608 ms)。
如果我们在处理浮点数不当,直接截取前n位,这里就存在音视频同步问题,
比如如果累计10万帧,误差>1199毫秒,那视频的音视频不对称了。


int av_get_audio_frame_duration(AVCodecContext *avctx, int nb_samples)
比特率 = 采样率 * 采样精度 * 声道数
例如,如果采样率是44100Hz,采样精度是16位,双声道立体声,则比特率为 44100 × 16 × 2 = 1,372,800bps。


data_size = av_samples_get_buffer_size(NULL, af->frame->channels,
                                           af->frame->nb_samples,
                                           af->frame->format, 1);
⾳频帧数据量 = 每帧采样点数 * 采样精度 * 声道数
例如,一个音频帧如果有1024个样本,每个样本是16位(2字节),并且有两个声道,则该帧的数据量为1024样本 × 2字节样本 × 2声道 = 4096字节。
以上两者关系: 音频帧数据量 * 播放时长 = 比特率 



frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb);
输出采样点 = (输入采样点 * 输出采样率/ 输入采样率)
,即上面提到的pkt由于数据量较小,而frame数据量大,所以需要pts时间戳转化。



关于音频pts的计算 很好理解 因为分成了原子块,那不就是等差数列吗:
pts = n*duration = n*nb_samples  
next_pts-current_pts=current_duration
根据数学等差公式an=a1+(n-1)*d可得pts=n*d

码率 = 音频文件大小/时长

int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align)
一帧图像大小 = 宽 * 高 * 像素格式大小字节数

 具体音视频采样点这些基础知识,看一看我之前的文章,这里不详细深入。

不同结构体的time_base/duration分析

ffmpeg存在多个时间基准(time_base),对应不同的阶段(结构体),每个time_base具体的值不⼀样, ffmpeg提供函数在各个time_base中进⾏切换。

AVFormatContext
duration:整个码流的时⻓,获取正常时⻓的时候要除以AV_TIME_BASE,得到的结果单位是秒

AVStream

time_base:单位为秒,⽐如AAC⾳频流,他可能是{1,44100} TS流,按{1, 90000} duration:表示该数据流的时⻓,以AVStream->time_base 为单位

AVPacket

pts:以AVStream->time_base为单位

dts:以AVStream->time_base为单位

duration:以AVStream->time_base为单位

AVFrame

pts:以AVStream->time_base为单位

pkt_pts和pkt_dts:拷⻉⾃AVPacket,同样以AVStream->time_base为单位

duration:以AVStream->time_base为单位

总结

总结:ffmpeg提供了很多现成的api函数,我们在使用前需要知道它们之间的关系,不然在求学的道路上,很难快速学习。必须佩服开发人员对时间的理解,我们在求学也要多留意世界的奥妙,参悟宇宙法则,再结合实际进行创新。

        

 学习资料分享

0voice · GitHub

AV_TIME_BASE是FFmpeg中定义的一个宏,它表示时间单位的基准。具体地说,它表示每秒钟的时间单位数。在FFmpeg中,时间单位被表示为有理数,即分子和分母的形式。AV_TIME_BASE的值为1000000,表示每秒钟有1000000个时间单位。 中提到了不同的time_base。在FFmpeg中,每个AVStream(音视频流)都有一个time_base字段,用于表示该流中的时间单位。AVStream的time_base与AVCodecContext的time_base字段有关。AVStream的time_base比AVCodecContext的time_base精度更高,即分子的值更小。例如,AVStream的time_base为1/90000,而AVCodecContext的time_base为1/30(假设frame_rate为30)。在相同的ptsdts情况下,以AVStream的time_base单位的数值会比以AVCodecContext的time_base单位的数值大。 因此,AV_TIME_BASE是一个重要的宏,用于在FFmpeg中进行时间单位的换算和处理。了解AV_TIME_BASE的含义和使用方式对于阅读和理解FFmpeg的代码非常重要。 来源:ffmpeg存在多个时间基准(time_base),对应不同的阶段(结构体),每个time_base具体的值不一样,ffmpeg提供函数在各个time_base中进行切换。搞清楚各个time_base的来源,对于阅读ffmpeg的代码很重要。 来源:InputStream(AV_TIME_BASE) 到 AVPacket(AVStream->time_base) 来源:AVStream->time_base 比 AVCodecContext->time_base 精度要高(数值要小),比如AVStream->time_base为1/90000,而AVCodecContext->time_base为1/30(假设frame_rate为30);同样的ptsdts,以AVStream->time_base单位,数值要比以AVCodecContext->time_base单位要大。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值