这个问题是这样产生的,一同事反应会随机出现ijk获取到的aac文件的duration不准,发来一看,确实不准,在AE或者系统mediaplayer中得到的都是8.4秒(准确时间是MtkAACExtractor: ADTS: duration = 8448000 us),ijk得到的是9.3秒,在播放的时候,在8秒的时候流就结束了,放到编译的ffmpeg中,一看也是9.3秒。
1.分析问题
下面开始分析这个问题,命令行看下这个文件,ffmpeg中获取到的确实是9.3秒
仔细看下红色箭头所指,这个意思是获取到的duration是根据比特率计算的,可能不准确。这种获取音视频info有问题的我们一般可以从avformat_find_stream_info函数开始分析。
这里直接从log开始看,waring出现出现在utils.c/libavformat下
static void estimate_timings_from_bit_rate(AVFormatContext *ic)
{
int64_t filesize, duration;
int i, show_warning = 0;
AVStream *st;
av_log(ic, AV_LOG_WARNING,
"hxk-->ic->bit_rate:%lld\n",ic->bit_rate);
//这里从log可以看到,bitrate也没获取到,bitrate = 0
/* if bit_rate is already set, we believe it */
if (ic->bit_rate <= 0) {
int64_t bit_rate = 0;
for (i = 0; i < ic->nb_streams; i++) {
st = ic->streams[i];
if (st->codecpar->bit_rate <= 0 && st->internal->avctx->bit_rate > 0)
st->codecpar->bit_rate = st->internal->avctx->bit_rate;
if (st->codecpar->bit_rate > 0) {
if (INT64_MAX - st->codecpar->bit_rate < bit_rate) {
bit_rate = 0;
break;
}
bit_rate += st->codecpar->bit_rate;
} else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->codec_info_nb_frames > 1) {
// If we have a videostream with packets but without a bitrate
// then consider the sum not known
bit_rate = 0;
break;
}
}
//这里算出来一个bitrate
ic->bit_rate = bit_rate;
av_log(ic, AV_LOG_WARNING,
"hxk-->ic->bit_rate:%lld\n",ic->bit_rate);
}
//从log中可以看到,这里的duration也是0
/* if duration is already set, we believe it */
av_log(ic, AV_LOG_WARNING,
"hxk-->ic->duration:%lld\n",ic->duration);
if (ic->duration == AV_NOPTS_VALUE &&
ic->bit_rate != 0) {
filesize = ic->pb ? avio_size(ic->pb) : 0;
av_log(ic, AV_LOG_WARNING,
"hxk-->ic->filesize:%lld\n",filesize);
if (filesize > ic->internal->data_offset) {
filesize -= ic->internal->data_offset;
for (i = 0; i < ic->nb_streams; i++) {
st = ic->streams[i];
if ( st->time_base.num <= INT64_MAX / ic->bit_rate
&& st->duration == AV_NOPTS_VALUE) {
//这里根据文件字节*8 /比特率来计算duration,这里cbr这样计算可以计算,但是如果vbr(码率动态)的话就有问题了
duration = av_rescale(8 * filesize, st->time_base.den,
ic->bit_rate *
(int64_t) st->time_base.num);
//获取到的duration就不准确了
st->duration = duration;
show_warning = 1;
}
}
}
}
if (show_warning)
av_log(ic, AV_LOG_WARNING,
"Estimating duration from bitrate, this may be inaccurate\n");
}
调用上面这个函数的地方是utils.c/libavofrmat:
static void estimate_timings(AVFormatContext *ic, int64_t old_offset)
{
int64_t file_size;
/* get the file size, if possible */
if (ic->iformat->flags &am