一:解码器初始化步骤
AVCodec *codec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);
AVCodecContext *vc = avcodec_alloc_context3(codec)
avcodec_parameters_to_context(vc,ic->streams[videoStream]->codecpar)
vc->thread_count=1;
re=avcodec_open2(vc, 0, 0);
avcodec_find_decoder获取解码器方法,avcodec_alloc_context3获取视频解码器上下文,thread_count设置解码器线程数,
avcodec_open2打开解码器。
同样音频解码器初始化方式一样:
AVCodec *acodec = avcodec_find_decoder(ic->streams[audioStream]->codecpar->codec_id);
AVCodecContext *ac = avcodec_alloc_context3(acodec);
avcodec_parameters_to_context(ac,ic->streams[audioStream]->codecpar);
ac->thread_count=1;
re=avcodec_open2(ac, 0, 0);
注意avcodec_find_decoder中所传参数。
二:解码
解码部分主要涉及两个重要步骤,上传和获取。上传是将原始数据上传解码器进行解码,获取是接受解码好的帧数据。
主要方法:avcodec_send_packet(cc,pkt); avcodec_receive_frame(cc,frame); 第一个参数都是AVCodecContext 解码上下文。
AVPacket和AVFrame声明
AVPacket *pkt=av_packet_alloc();
AVFrame *frame=av_frame_alloc();
具体代码:
AVPacket *pkt=av_packet_alloc();
AVFrame *frame=av_frame_alloc();
long long start=getNowMs();
int frameCount=0;
for(;;)
{
if(getNowMs()-start>=3000)
{
LOGW("now decode fps is %d",frameCount/3);
start=getNowMs();
frameCount=0;
}
int re = av_read_frame(ic,pkt);
if(re != 0)
{
LOGW("读取到结尾处!");
int pos = 20 * r2d(ic->streams[videoStream]->time_base);
av_seek_frame(ic,videoStream,pos,AVSEEK_FLAG_BACKWARD|AVSEEK_FLAG_FRAME );
continue;
}
AVCodecContext *cc = vc;
if(pkt->stream_index == audioStream)
cc=ac;
//发送到线程中解码
re = avcodec_send_packet(cc,pkt);
//清理
int p = pkt->pts;
av_packet_unref(pkt);
if(re != 0)
{
LOGW("avcodec_send_packet failed!");
continue;
}
for(;;)
{
re = avcodec_receive_frame(cc,frame);
if(re !=0)
{
//LOGW("avcodec_receive_frame failed!");
break;
}
LOGW("avcodec_receive_frame %lld",frame->pts);
if (cc == vc) {
frameCount++;
}
}
}
}else{
LOGW("avformat_open_input %s error", av_err2str(re));
}
这块要判断是音频流还是视频流,上下文参数不一样。
frameCount是用于记录帧数。上面使用的线程数是1,三秒钟打印一次帧数:
日志中看到的fps为100左右 ,这个是在开启neon下线程数为1的速度。如果测试不支持neon可以替换之前编译的未开启neon库。
此时的Cpu占用情况:
把解码器的thread_count 修改为8再测试:
此时fps为300左右,解码速度明显提升了很多。
再看下Cpu情况:
Cpu的使用率上升到70-80。
三:硬解码测试
将codec初始化为硬解码,调用java的mediacodec(反射),需要手动配置虚拟机环境
注意引用的so库要是支持硬解码的,相关的编译参数配置正确,不然会报错。
看到Cpu的使用率下降到8
再看下fps:
关于软硬解码的区别网上有很多详细的文章,软解码使用Cpu进行所以对于处理器来说占用率很大,硬解码使用非cpu解码如Gpu等。软解码Cpu负载率重性能比硬解码低,低码率下质量不如硬解码。
项目连接:编译好的So库