最近测试提出了一个bug,ijk获取到的aac文件的duration不准,发来一看,确实不准,在AE或者系统mediaplayer中得到的都是3m48s(准确时间是MMParserExtractor: ADTS: duration = 228010580us,如下图),ijk得到的是2m54s,在播放的时候,在2m54s的时候流就结束了,放到编译的ffmpeg中, Duration:居然是00:03:13.07,但是VLC是3m53s,这个文件也是奇葩了!其他播放器暂时不去讨论,现在只希望做到MMParserExtractor与IJKPlayer获得的时长一直即可! 
1、分析问题
下面开始分析这个问题,命令行看下这个文件,ffmpeg中获取到的确实是3m13s

仔细看下红色箭头所指,这个意思是获取到的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, "-->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, "-->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,"-->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,"-->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);

本文详细解析了AAC音频文件的格式特点,针对ffmpeg中AAC文件duration获取不准的问题,通过分析ADTS帧头信息和计算帧数来准确获取音频文件的总时长。
最低0.47元/天 解锁文章
3287





