FFmpeg音视频解码及单多线程测试

一:解码器初始化步骤

  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再测试:
![](https://img-blog.csdnimg.cn/20201217192645542.png
此时fps为300左右,解码速度明显提升了很多。
再看下Cpu情况:

Cpu的使用率上升到70-80。
三:硬解码测试


将codec初始化为硬解码,调用java的mediacodec(反射),需要手动配置虚拟机环境

注意引用的so库要是支持硬解码的,相关的编译参数配置正确,不然会报错。

看到Cpu的使用率下降到8
再看下fps:

关于软硬解码的区别网上有很多详细的文章,软解码使用Cpu进行所以对于处理器来说占用率很大,硬解码使用非cpu解码如Gpu等。软解码Cpu负载率重性能比硬解码低,低码率下质量不如硬解码。
项目连接:编译好的So库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值