ffmpeg 之 时间戳

来源:互联网 发布:php购物网站 编辑:程序博客网 时间:2024/05/16 15:26

原始博客地址:

http://blog.csdn.net/qqfeng0908/article/details/61195527




看到好多人对时间戳这个概念不明白啊;简单写一下我的理解


第一,时间戳是什么

时间戳就是一个能够表示一个事物发生时间的东西,她有个单位,比如秒,毫秒等


第二,timebase是个什么

timebase是个有点抽象的东西, 在这里不说抽象的概念,你就把它当成时间的单位;

例如25帧的视频,如果不存在timebase这个东西, 我们打时间戳应该是这样的,0-40-80-120-以此类推,40毫秒一帧图像

可是出现了timebase之后就不能这么处理了;

例如,同样25帧的视频, timebase设置为1/25, 那这个1/25是什么意思呢? 就是把1秒分成25份, 你的时间戳每增加1,就代表增加了1/25秒;

视频是25帧的, 也就是每帧之间的间隔恰好就是1/25秒, 那么,我们的时间戳就可以每次递增1了;

同理,timebase设置为1/50, 那么我们的时间戳就可以每次递增2了;

上面三句话非常重要,是时间戳的核心原理;


第三,如何去确定编码器的timebase

那怎么去确定timebase是多少合适呢? 2/25可以吗?3/456可以吗?

理论上来说都是可以的,但是有个精度问题;

例如,同样25帧的视频,我们设置timebase为2/25;

假设如果第一帧是时间: 0毫秒,

换算成1/25的时间戳:0*(2/25) = 0;

再还原成原始时间就是0/(2/25) = 0;

在经过40毫秒后产生第二帧,这一帧的时间是40毫秒,换算成时间戳:

40*(2/25)=3.2,由于ffmpeg记录时间戳的变量类型为long long ,所以下取整后为3

这时候我们在还原一下原始时间:

3/(2/25) = 37.5毫秒,下取整后为37,这就与原始时间40产生了3毫秒的误差

实际上2/25就是1/12.5,也就是把一秒分成了12.5份,如果timebase的num/den不是帧率的整数倍都会产生误差;

所以一般建议都设置成 1/帧率

注意下,这个误差是帧间误差


第四,上面为什么要计算还原后的误差?

编码->解码这是一个永恒不变的过程,任何编码后的数据,都需要逆操作,也就是解码来复原;

在图像中,为了更好的还原图像,以及音视频的同步,就要保证尽可能高精度的时间戳;这样我们才能更精确的知道某一幅图像应该在什么时候显示;


第五,解码时间戳是个什么东西?

前面说的都是编码时间戳,那么解码时间戳是什么? 从计算过程上来说,与编码时间戳是一样的;只不过这个时间代表了他应该何时被送入解码器;

编码器会去设置这个值,用户不需要关心,只需要按编码的输出顺序送入解码器即可;这部分也不属于本文的内容,不再敖述;


第六,第一帧图像的时间戳一定0么?

不一定,可能是任意值,但一定是通过timebase计算得来的; 否则无法正确的知道解码后的显示顺序和时间


第七,如果timebase是1/25,时间戳只需要每次递增1就可以吗?

不是的,可能由于调用层卡顿,转入后台等情况导致帧率不稳定现象,也就是说很可能实际帧率是达不到设置的帧率的,如果你的时间戳依旧按照每次+1来设置,图像就会渐渐的与实际时间越拉越大;


第八,音频的timebase是如何确定的?

与视频类似, 只是音频换做采样率这个概念,采样率代表麦克风一秒有多少个采样产生,这个频率是极为精确的.所以我的一般做法是设置为 1/采样率; 时间戳每次递增输入的采样数;


第九,音频和视频如何去确定起始的时间戳

虽说时间戳不必从0开始,但是为了调试或者强迫症,我还是尽量保证从0开始...

我的做法是这样的;

不管音视频,上层都使用绝对的毫秒时间,编码层收到后,记录下第一个时间(音频和视频,那个早取哪个)

例如,

音频采样率: 44100

视频帧率     :25

第一个音频采样时间:140029123,记做AT1

第一个视频帧时间   :140029143,记做VT1

取140029123作为FRISTTIME;

然后每次都用下面的公式进行计算即可以得出时间戳:

用 (FRISTTIME - ATn) * (1/44100) ;

用 (FRISTTIME - VTn) * (1/25);



第十,ffmpeg里面的计算方式

//目标时间戳 = f(原时间戳, 原timebase, 目标timebase, 取整方式);

dst = av_rescale_q_rnd(src, src->time_base, dst->time_base, AV_ROUND_NEAR_INF);

如果src是毫秒时间, 那么src的timebase是多少呢?

考虑下上面的,1/25表示1/25秒, 1毫秒的话是1/多少?

应该是1/1000,也就是 AVRational{1, 1000}

当然,你应该能想到,颠倒几个参数就能还原回去,虽说还是有点点误差....

不同模块之间的转换也是使用这个方式


第十一,播放时如何去同步?

同样的, 解码后,不管音视频,解码后拿到时间戳,通过前面所说的计算公式还原回去,然后都以第一个为基准, 后面的按照这个时间来计算应该显示的时间;




1 0