FFmpeg中的时间基(time_base), AV_TIME_BASE

本文详细介绍了FFmpeg中时间基time_base和AV_TIME_BASE的概念,以及它们在处理视频时间戳如PTS和DTS时的作用。AV_TIME_BASE表示1微秒,用于精确度量时间。时间基time_base是将时间分成多个刻度,每个刻度的长度由time_base定义。PTS和DTS是基于time_base的时间戳,分别指示解码和显示的时间。通过time_base转换,可以计算视频总时长、根据PTS求出帧的位置,以及进行视频Seek操作。

FFmpeg中的时间基(time_base), AV_TIME_BASE

一. AV_TIME_BASE

经常在FFmpeg的代码中看到一个奇怪的单位 AV_TIME_BASE ,比如 AVFormatContext 结构体中就有这样一个字段: duration ,它在FFmpeg中的解释如下:

/**
     * Duration of the stream, in AV_TIME_BASE fractional
     * seconds. Only set this value if you know none of the individual stream
     * durations and also do not set any of them. This is deduced from the
     * AVStream values if not set.
     *
     * Demuxing only, set by libavformat.
     */
    int64_t duration;

以一段时长为60s的视频为例,用FFmpeg将其读入到内存,并打印出它的 duration 后发现:

AVFormatContext *ic = NULL;
int re = avformat_open_input(&ic, path, 0, 0);
    if (re != 0) {
        LOGE("avformat_open_input failed: %s", av_err2str(re));
        return;
    }
    LOGI("avformat_open_input %s success", path);
    re = avformat_find_stream_info(ic, 0);
    if (re != 0) {
        LOGE("avformat_find_stream_info failed: %s", av_err2str(re));
    }
    LOGI("duration is: %lld, nb_streams = %d, input filename is: %s, bitrate = %lld", ic->duration, ic->nb_streams, ic->filename, ic->bit_rate);
 

 duration 此时为60000000,而它的注释也说得很清楚,是以 AV_TIME_BASE 为单位,找到 AV_TIME_BASE  :

/**
 * Internal time base represented as integer
 */

#define AV_TIME_BASE            1000000

/**
 * Internal time base represented as fractional value
 */

#define AV_TIME_BASE_Q          (AVRational){1, AV_TIME_BASE}

发现该值为1000000,60000000/1000000刚好为60,而1s = 1000000μs 由此可见,FFmpeg内部的时间单位其实是微秒(μs),而 AV_TIME_BASE_Q 其实是一种分数的表示形式,其中的1表示分子, AV_TIME_BASE 也就是1000000,表示的是分母,所以它其实就是1微秒,也就是 1/1000000 秒。

事实上,除了 AVFormatContext  中的 duration ,FFmpeg中的pts,dts也是基于timebase来换算的,时间基(time_base)是FFmpeg中作为时间单位的概念,比如上面的 AV_TIME_BASE_Q ,它就相当于是 1/1000000 秒,也就是把1s分成1000000份,可以理解成是一把尺,那么每一格就是 1/1000000 秒,此时的time_base就是{1, 1000000}。所谓的时间基就是指每个刻度是多少秒。那么它的作用是什么呢?其实就是为了更精确的度量时间。

二. pts/dts的时间戳究竟代表什么

之前解释过PTS和DTS的基本概念:

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

光看字面意思,它也是一种时间戳,那它这种时间戳到底是什么样子的?是传统意义上 yyyy-MM-dd HH:mm:ss ?首先可以肯定的是绝不是 yyyy-MM-dd HH:mm:ss,因为这种时间戳的控制精度不够,上面甚至都用μs来表示了,那这个PTS和DTS的值到底是个什么东西?

pts和dts的值指的是占多少个时间刻度(占多少个格子)。它的单位不是秒,而是时间刻度。只有pts与time_base两者结合在一起,才能表达出具体的时间是多少。好比我只告诉你,某个物体的长度占某一把尺上的20个刻度。但是我不告诉你,每个刻度是多少厘米,你仍然无法知道物体的长度。pts 就是这样的东西,pts(占了多少个时间刻度) , time_base(每个时间刻度是多少秒) ,而帧的显示时间戳 =  pts(占了多少个时间刻度)  * time_base(每个时间刻度是多少秒)。

三. 一些时间基转换的场景

【计算视频总时长】

AVFormatContext *ifmt_ctx = NULL;
avformat_open_input(&ifmt_ctx, filename, NULL, NULL);
double totle_seconds = ifmt_ctx->duration * av_q2d(AV_TIME_BASE_Q);

【根据PTS求出一帧在视频中对应的秒数位置】

double sec = enc_pkt.pts * av_q2d(ofmt_ctx->streams[stream_index]->time_base);

【ffmpeg内部的时间戳与标准的时间转换方法】

timestamp(ffmpeg内部时间戳) = AV_TIME_BASE * time(秒)
time(秒) = AV_TIME_BASE_Q * timestamp(ffmpeg内部时间戳)

【当需要把视频Seek到N秒的时候】

// 指定流索引
int pos = 20 * r2d(ic->streams[videoStream]->time_base);
av_seek_frame(ic,videoStream, pos, AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME );
// 未指定指定流索引
int64_t timestamp = N * AV_TIME_BASE; 
av_seek_frame(fmtctx, -1, timestamp, AVSEEK_FLAG_BACKWARD);

 

AV_TIME_BASEFFmpeg中定义的一个宏,它表示时间单位的基准。具体地说,它表示每秒钟的时间单位数。在FFmpeg中,时间单位被表示为有理数,即分子和分母的形式。AV_TIME_BASE的值为1000000,表示每秒钟有1000000个时间单位。 中提到了不同的time_base。在FFmpeg中,每个AVStream(音视频流)都有一个time_base字段,用于表示该流中的时间单位。AVStream的time_baseAVCodecContext的time_base字段有关。AVStream的time_baseAVCodecContext的time_base精度更高,即分子的值更小。例如,AVStream的time_base为1/90000,而AVCodecContext的time_base为1/30(假设frame_rate为30)。在相同的pts和dts情况下,以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_baseAVCodecContext->time_base 精度要高(数值要小),比如AVStream->time_base为1/90000,而AVCodecContext->time_base为1/30(假设frame_rate为30);同样的pts和dts,以AVStream->time_base为单位,数值要比以AVCodecContext->time_base为单位要大。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值