美文网首页
音视频解码器

音视频解码器

作者: 贝克街的猫大哥呀 | 来源:发表于2018-07-05 16:01 被阅读0次

    解码器分为音频与视频。视频又分为硬解与软解。

    以下是初始化视频解码器:

    //视频解码器 软解码器

    AVCodec *codec = avcodec_find_decoder(ic->streams[videoStream]->codecpar->codec_id);

    //采用视频硬解码器

    //codec=avcodec_find_decoder_by_name("h264_mediacodec");

    if (!codec) {//判断解码器是否初始化成功

        LOGW("avcodec video find failed");

    return env->NewStringUTF(hello.c_str());;

    }

    //获得视频解码器上下文  这里的上下文参数只有一个解码器,然后并无流信息

    AVCodecContext *vc = avcodec_alloc_context3(codec);

    //将视频流的信息注入到上下文吧,下面的操作跟codec解码器本身已经没什么关系了,主要是用AVCodecContext上下文去处理

    avcodec_parameters_to_context(vc, ic->streams[videoStream]->codecpar);

    //设置视频解码的线程数 越高越快,但肯定对CPU的消耗就越大

    //若采用硬解码,则这里的定义没什么意义

    vc->thread_count =8;

    //打开解码器

    re = avcodec_open2(vc,0,0);

    if (re !=0) {

    LOGW("avcodec_open2  video failed!");

    return env->NewStringUTF(hello.c_str());;

    音频解码器跟视频解码器类似:

    //音频解码器

    AVCodec *acodec = avcodec_find_decoder(ic->streams[audioStream]->codecpar->codec_id);

    if (!acodec) {//判断解码器是否初始化成功

        LOGW("acodec audio find failed");

    return env->NewStringUTF(hello.c_str());;

    }

    //音频解码器初始化

    AVCodecContext *ac = avcodec_alloc_context3(acodec);

    //将音频流的信息注入到上下文吧,下面的操作跟codec解码器本身已经没什么关系了,主要是用AVCodecContext上下文去处理

    avcodec_parameters_to_context(ac, ic->streams[audioStream]->codecpar);

    //设置音频解码的线程数 越高越快,但肯定对CPU的消耗就越大

    ac->thread_count =8;

    //打开解码器

    re = avcodec_open2(ac,0,0);

    if (re !=0) {

    LOGW("avcodec_open2  audio failed!");

    return env->NewStringUTF(hello.c_str());;

    }

    下面将解码器和AVPacket 联系起来:

    //AVPacket 相当于保存了帧信息,可以是保存某一帧,也能是一个数组,保存一个帧集合 所以这里注意清理数据

    AVPacket *apt = av_packet_alloc();

    //AVFrame其实就是每一帧!

    AVFrame *frame=av_frame_alloc();

    当 re = av_read_frame(ic, apt);   这个方法执行后,就会将frame注入到apt中。

    此时解码关键就是:re=avcodec_send_packet(cc,apt);  cc是解码器上下文,对应上面的ac或者vc,此方法是将apt发送到解码线程,进行解码。 这里要注意,如果apt是最后一帧的话,要传一个NULL进去,不然取帧的时候,最后几帧会掉下。

    //将其发送到解码线程中 这里传送的是一个AVPacket

    re=avcodec_send_packet(cc,apt);

    //清理

    int p = apt->pts;

    //已经将apt发送到了接收线程,所以这里直接清理就可以了。因为接收线程已经又有了一份,

    av_packet_unref(apt);

    if(re !=0){

    LOGW("avcodec_send_packet failed! errorinfo=%s" ,av_err2str(re));

    return env->NewStringUTF(hello.c_str());

    }

    现在将解码出的帧取出来,关键代码为:re =avcodec_receive_frame(cc,frame);   这里的frame不用回收。跟apt还不太一样。

    为什么要开一个循环来取呢,因为在解码是avcodec_send_packet这个方法,他可能并不是解一致,就会回调avcodec_receive_frame,可能是解几帧才回调一次,因此这里就采用无限循环avcodec_receive_frame来取内已经解码好的帧。

    这里直接取出传送过来的所有帧,由于很可能不止一帧,因此我们开启一个循环来取

    for(;;){

    re =avcodec_receive_frame(cc,frame);

    if(re !=0){

    //表示已经取完

            break;

    }

    if(cc=vc){

    //表示是视频帧

    }

    }

    当采用硬解码时,需要加上这个方法:

    相应的,要引入头文件:

    extern "C" {

    #include <libavcodec/jni.h>

    }

    extern "C"

    JNIEXPORT

    jint JNI_OnLoad(JavaVM *vm,void *res)

    {

        av_jni_set_java_vm(vm,0);

        return JNI_VERSION_1_4;

    }

    ffmepg调用硬解码,其实并不是在C层调,而是要调用JAVA层的代码。

    相关文章

      网友评论

          本文标题:音视频解码器

          本文链接:https://www.haomeiwen.com/subject/vwspuftx.html