最新用ffmpeg+x264编码视频,之前使用老版本的ffmpeg编码视频文件没有问题,但是换了最新的版本之后(ffmpeg版本号2.8.2),出现了编码出来的视频帧率特别大的问题。

找了很久,终于解决了,在这里记录一下探索过程。

首先,我设置的视频的帧率是25帧/s,但是编码出来的视频帧率则是几千,如下图所示

ffmpeg android CPU 占用 ffmpeg占用cpu过高_ffmpeg

可以看到上图的帧率和码率都是非法的值,这个是为什么呢?

下面是解决过程。

首先,先知道这个帧率是存在AVStream里的,也就是AVStream的time_base字段。但是我明明设置的这个字段是25帧每秒,为什么最后编码出来的视频是这个样子呢。

没办法,只好去参看ffmpeg文档,在AVStream的time_base的介绍中有这么一句话。

ffmpeg android CPU 占用 ffmpeg占用cpu过高_字段_02

简单的翻译一下,这句话的意思是在avformat_write_header中,这个混合器(不知道怎么翻译好,简单来说就是把视频流和音频流混合在一起的东西)会重新覆盖这个值,这个覆盖的值和你设置的值是无关的,它依赖这个存储的格式。

恩 这算是给了我一个指示,马上去看avformat_write_header。不幸的事,文档中只有简单的该函数的介绍,并没有说明这个值怎么变化。

没办法了 只有使用最原始的办法了,打开source insight ,查看ffmpeg的源码吧。

可以看见avformat_write_header还是比较简单的,只调用了几个接口,下面的问题就是找到是哪个接口更改了这个值。

ffmpeg android CPU 占用 ffmpeg占用cpu过高_帧率_03

这个简单 可以是用最原始的方法 打日志解决。通过打日志可以找到是在write_header中更改了这个值。

这个write_header是你设置的Outputforamt的write_header方法,这里我设置的是mp4,所以muxer就是ff_mp4_muxer,全局搜索这个字段就行了。

可以找到这个muxer的write_header方法是mov_write_header

ffmpeg android CPU 占用 ffmpeg占用cpu过高_ffmpeg_04

好了 终于找到根源了,让我们来看一下这个mov_write_header方法吧,

这个函数比较长,我就不全截取下来了,如果你不愿意去看代码的话,找根源还可以使用万能方法(我不会告诉你)

这里直接截取根源的代码

ffmpeg android CPU 占用 ffmpeg占用cpu过高_字段_05

注意看画红框的代码,这里的track->timescale会在下面重新计算AVStream的time_base,也就是这里更改了我设置的值。上面的if判断如果设置了video_track_timescale这个值的话,则他就采用这个值,要是没有设置这个值的话,就采用我们AVStream的time_base的分母,等等,你下面的while循环是什么鬼,如果我设置的分母小于10000.你就一直乘以2,直到它大于10000,怪不得我编码出来的视频都这么奇葩呢。原来是你在搞鬼。


好吧 终于找到根源了。下面就是解决办法了。通过看源码可以知道 如果我们设置了video_track_timescale,他就会采用这个值。恩好,既然这样。那我们在avformat_write_header之前设置上这个值吧‘

AVDictionary* opt = NULL;
     av_dict_set_int(&opt, "video_track_timescale", 25, 0);
     avformat_write_header(m_pFormatCtx, &opt);

恩 重新编码一下试试。结果果然如我所料,这回帧率正常了,码率也正常了。

ffmpeg android CPU 占用 ffmpeg占用cpu过高_帧率_06

ps:这个地方之前版本的ffmpeg没有下面的while循环,当然老版本的代码和新版本的代码变化也很大,不知道这个while循环的意义是什么。


小弟也是初学ffmpeg和音视频编码,对很多的基础名词都不知道什么意思(比如上面的video_track_timescale)