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);

 

參考鏈接:

1.理解ffmpeg中的pts,dts,time_base

2.FFmpeg時間戳整理

3.C++編程音視頻庫ffmpeg的pts時間怎么換算

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM