ijkplayer 音視訊同步時間的計算

天星技術團隊發表於2018-06-18
作者: 土豆, 時間: 2018.6 .18

ijkplayer 音視訊同步時間的計算


從上一篇文章 ijkplayer音視訊同步流程分析 中對Ijkplayer的音視訊同步有所瞭解之後,那麼 這個音視訊的時間是怎麼計算的呢?

首先得理解ipb 幀的概念,可以閱讀這篇文章 An ffmpeg and SDL Tutorial

其次就是 AVRational 這個結構體了, ijkplayer 原始碼中的很多結構體中都有這個成員,比如 AVStreamAVPacket 等等。

AVRational 的定義如下:

typedef struct AVRational{
    int num; //numerator
    int den; //denominator
} AVRational;複製程式碼

從程式碼中得知得到某一幀的播放時間的計算方式是

pts = (frame->pts == AV_NOPTS_VALUE) ? NAN : frame->pts * av_q2d(tb)複製程式碼

av_q2d 方法如下

static inline double av_q2d(AVRational a){
    return a.num / (double) a.den;
}複製程式碼

視訊

對於 視訊的frame 而言屬性 pts 就是當前這一幀的位置,假如一個視訊的幀率是25的話,那麼 tb 就是 AVRational{1, 25},所以根據上面的計算方式,可以得出每個視訊幀是以0.04s 遞增的。

那每一幀的 pts 是怎麼來的,從程式碼中可以看出來,每讀一個 AVPacket 的時候都要從 AVIOContext 解析 chunks 那 pts 就是從中得到的,然後在解碼後賦值給 frame。

static int read_packet(AVFormatContext *s, AVPacket *pkt)
{
    WtvContext *wtv = s->priv_data;
    AVIOContext *pb = wtv->pb;
    int stream_index, len, ret;
​
    // 解析chunks
    stream_index = parse_chunks(s, SEEK_TO_DATA, 0, &len);
    if (stream_index < 0)
        return stream_index;
​
    ret = av_get_packet(pb, pkt, len - 32);
    if (ret < 0)
        return ret;
    pkt->stream_index = stream_index;
    //從解析中得到的pts 賦值給 avpacket 的 pts
    pkt->pts          = wtv->pts;
    avio_skip(pb, WTV_PAD8(len) - len);
    return 0;
}複製程式碼

在H.264 的編碼過程中,每一幀都會有一個pts的寫入,再編碼成 AVPacket。這個可以從 ffmpeg 的編碼 sample 中看到,在doc/example/decoding_encoding.c 檔案中。

音訊

音訊和視訊有點不一樣,本身音訊是沒有pts 這個概念的,但是為了適應和視訊的同步的計算,還是得有一個播放時間。假如說音訊的取樣率是44.1K,表示的意思是一秒有44.1K的取樣。在解碼後的 AVFrame 中可以得到一個引數叫 nb_samples 表示當前音訊幀幾個取樣,再累加起來,那麼就可以知道當前這一個AVFrame 的播放時間。

當然這只是我的理解,如果有有誤,請提示。

小結

所以音視訊同步時間的計算,就是視訊時間對音訊時間在一定的區間內的追趕、延遲或者跳幀。


相關文章