ffmpeg 解码流程

来源:互联网 发布:典型网络暴力事件盘点 编辑:程序博客网 时间:2024/06/06 17:27
定义三个函数处理解码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;    }}




0 0
原创粉丝点击