从上一篇文章 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 的播放时间。
当然这只是我的理解,如果有有误,请提示。
小结
所以音视频同步时间的计算,就是视频时间对音频时间在一定的区间内的追赶、延迟或者跳帧。