ffmpeg 解码流程

定义三个函数处理解码h264

1.编码前初始化, 返回视频宽高
int* decode_init(char * in_filename)
{

    avcodec_register_all();
    av_register_all();
    decode_frame = av_frame_alloc();
    AVPacket pkt;
     //获取各种上下文    
    if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
        retu = -1;
        goto end;
    }
    if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
        retu = -2;
        goto end;
    }
    //例遍流,找到流所对应得下标
    for (i = 0; i < ifmt_ctx->nb_streams; i++) {
        //Create output AVStream according to input AVStream
        AVFormatContext *ofmt_ctx;
        AVStream *in_stream = ifmt_ctx->streams[i];
        AVStream *out_stream = NULL;

        if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoindex = i;

        }
    }
    //open decoder
    video_dec_ctx = ifmt_ctx->streams[videoindex]->codec;
    video_dec = avcodec_find_decoder(video_dec_ctx->codec_id);
    if(avcodec_open2(video_dec_ctx,video_dec,NULL)<0)
    {
        retu = -3;
        goto end;
    }
    double g_height = ifmt_ctx->streams[videoindex]->codec->height;
    double g_width = ifmt_ctx->streams[videoindex]->codec->width;

    int* wh = malloc(sizeof(int)*2);
    wh[0] = g_width;
    wh[1] = g_height;
end: 
    if(retu != 0)
        return NULL;
    else
        return wh;
}


2.解码一帧,返回该帧不用释放,该变量作用域是文件,所以想要支持多线程并发解码,需要将其所用参数封装为结构体存储。

AVFrame* decode_next()
{
    if(decode_frame!=NULL)
        av_frame_unref(decode_frame);

    int ret = 0;
    int got_frame = 0;
    int error_time = 0;
    while(1)
    {
        //Get an AVPacket
        if (av_read_frame(ifmt_ctx, &pkt) < 0)
        {
            av_free_packet(&pkt);
            goto decode_free;
        }
        if (pkt.stream_index == videoindex) 
        { 

            ret = avcodec_decode_video2(video_dec_ctx,decode_frame, &got_frame, &pkt);
            if(got_frame)
                goto decode_success;
            else
            {
                if(failed_times ++<30)
                    continue;
                else
                goto decode_free;
            }
        }
        av_free_packet(&pkt);

    }
decode_free:
    av_free_packet(&pkt);
    return NULL;

decode_success:

    return decode_frame;
}

如果是某些特殊编码(比如h264、h265),在读取packet失败之后就停止解码会丢掉末尾的帧。具体原因分析点击这里。
所以要在读取packet失败之后接着调用解码,获取剩余的帧。使用一个变量failed_times 记录编码器中存在的帧数。在读取结束之后接着调用failed_times  次avcodec_decode_video2
修改如下:
int failed_times  = 0;
int read_packet_failed = 0;
AVFrame* decode_next()
{
    if(decode_frame!=NULL)
        av_frame_unref(decode_frame);

    int ret = 0;
    int got_frame = 0;
    int error_time = 0;
    while(1)
    {
        //Get an AVPacket
        if (av_read_frame(ifmt_ctx, &pkt) < 0)
        {
            read_packet_failed  = 1;
            av_free_packet(&pkt);
            if(failed_times > 0)
            {
                failed_times--;
                goto decode;
            }
            else
                goto decode_free;
        }
        if (pkt.stream_index == videoindex) 
        { 
decode:
            ret = avcodec_decode_video2(video_dec_ctx,decode_frame, &got_frame, &pkt);
            if(got_frame)
                goto decode_success;
            else
            {
                if(read_packet_failed)
                     goto decode_free;
                else
                {
                    failed_times ++;
                    continue;
                }
                else
                goto decode_free;
            }
        }
        av_free_packet(&pkt);

    }
decode_free:
    av_free_packet(&pkt);
    return NULL;

decode_success:

    return decode_frame;
}

3.解码完成之后释放。
int decode_release()
{

     avcodec_close(video_dec_ctx);
   // av_free(video_dec_ctx);
    avformat_close_input(&ifmt_ctx);
    if(decode_frame!=NULL)
    {
        av_frame_free(&decode_frame);
        decode_frame = NULL;
    }

}




你可能感兴趣的:(视频处理,ffmpeg)