一、引言
本文讲解FFmpeg源码对WAV音频文件进行解复用(解封装)时,其AVStream的time_base是怎样被计算出来的。
二、FFmpeg源码中计算WAV音频文件AVStream的time_base的实现
从《音视频入门基础:WAV专题(5)——FFmpeg源码中解码WAV Header的实现》中可以知道,FFmpeg对WAV音频文件进行解复用(解封装)时,其源码内部会调用wav_read_header函数解码WAV音频文件的WAV Header。而该函数内部会调用wav_parse_fmt_tag函数解析“Format chunk”子区块:
for (;;) {
//...
switch (tag) {
case MKTAG('f', 'm', 't', ' '):
/* only parse the first 'fmt ' tag found */
if (!got_xma2 && !got_fmt && (ret = wav_parse_fmt_tag(s, size, st)) < 0) {
return ret;
} else if (got_fmt)
av_log(s, AV_LOG_WARNING, "found more than one 'fmt ' tag\n");
got_fmt = 1;
break;
}
}
}
wav_parse_fmt_tag函数内部会调用avpriv_set_pts_info函数设置AVStream的time_base。关于avpriv_set_pts_info函数的用法可以参考:《FFmpeg源码:avpriv_set_pts_info函数分析》。可以看到,调用avpriv_set_pts_info函数后,st->time_base.num会被设置为1,st->time_base.den会被设置为st->codecpar->sample_rate。也就是说WAV音频文件AVStream的time_base为音频采样频率的倒数:
static int wav_parse_fmt_tag(AVFormatContext *s, int64_t size, AVStream *st)
{
AVIOContext *pb = s->pb;
WAVDemuxContext *wav = s->priv_data;
int ret;
/* parse fmt header */
ret = ff_get_wav_header(s, pb, st->codecpar, size, wav->rifx);
if (ret < 0)
return ret;
handle_stream_probing(st);
ffstream(st)->need_parsing = AVSTREAM_PARSE_FULL_RAW;
avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
return 0;
}
三、总结
WAV音频文件AVStream的time_base为音频采样频率的倒数。比如音频采样频率为44100Hz,其AVStream的time_base为1/44100(44100分之一)。