從上一篇文章 ijkplayer音視訊同步流程分析 中對Ijkplayer的音視訊同步有所瞭解之後,那麼 這個音視訊的時間是怎麼計算的呢?
首先得理解ipb 幀的概念,可以閱讀這篇文章 An ffmpeg and SDL Tutorial
其次就是 AVRational 這個結構體了, ijkplayer 原始碼中的很多結構體中都有這個成員,比如 AVStream、AVPacket 等等。
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 的播放時間。
當然這只是我的理解,如果有有誤,請提示。
小結
所以音視訊同步時間的計算,就是視訊時間對音訊時間在一定的區間內的追趕、延遲或者跳幀。