美文网首页
音视频解码器

音视频解码器

作者: 贝克街的猫大哥呀 | 来源:发表于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