FFMPeg代码分析:avcodec_decode_video2函数

转自:http://blog.csdn.net/shaqoneal/article/details/16967789

该函数的作用是实现压缩视频的解码。在avcodec.h中的声明方式如下:

  1. int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt);  
待解码的数据保存在avpkt->data中,大小为avpkt->size;解码完成后,picture用于保存输出图像数据。

该方法的各个参数:

AVCodecContext *avctx:编解码上下文环境,定义了编解码操作的一些细节;

AVFrame *picture:输出参数;传递到该方法的对象本身必须在外部由av_frame_alloc()分配空间,而实际解码过后的数据储存区将由AVCodecContext.get_buffer2()分配;AVCodecContext.refcounted_frames表示该frame的引用计数,当这个值为1时,表示有另外一帧将该帧用作参考帧,而且参考帧返回给调用者;当参考完成时,调用者需要调用av_frame_unref()方法解除对该帧的参考;av_frame_is_writable()可以通过返回值是否为1来验证该帧是否可写。

int *got_picture_ptr:该值为0表明没有图像可以解码,否则表明有图像可以解码;

const AVPacket *avpkt:输入参数,包含待解码数据。

  1. int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr,  
  2.  const AVPacket *avpkt)  
  3. {  
  4.     AVCodecInternal *avci = avctx->internal;  
  5.     int ret;  
  6.     // copy to ensure we do not change avpkt  
  7.     AVPacket tmp = *avpkt;  
  8.   
  9.     if (!avctx->codec)  
  10.         return AVERROR(EINVAL);  
  11.     if (avctx->codec->type != AVMEDIA_TYPE_VIDEO) {  
  12.         av_log(avctx, AV_LOG_ERROR, "Invalid media type for video\n");  
  13.         return AVERROR(EINVAL);  
  14.     }  
  15.   
  16.     *got_picture_ptr = 0;  
  17.     if ((avctx->coded_width || avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx))  
  18.         return AVERROR(EINVAL);  
  19.   
  20.     avcodec_get_frame_defaults(picture);  
  21.   
  22.     if (!avctx->refcounted_frames)  
  23.         av_frame_unref(&avci->to_free);  
  24.   
  25.     if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {  
  26.         int did_split = av_packet_split_side_data(&tmp);  
  27.         apply_param_change(avctx, &tmp);  
  28.         avctx->pkt = &tmp;  
  29.         if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)  
  30.             ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr,  
  31.                                          &tmp);  
  32.         else {  
  33.             ret = avctx->codec->decode(avctx, picture, got_picture_ptr,  
  34.                                        &tmp);  
  35.             picture->pkt_dts = avpkt->dts;  
  36.   
  37.             if(!avctx->has_b_frames){  
  38.                 av_frame_set_pkt_pos(picture, avpkt->pos);  
  39.             }  
  40.             //FIXME these should be under if(!avctx->has_b_frames)  
  41.             /* get_buffer is supposed to set frame parameters */  
  42.             if (!(avctx->codec->capabilities & CODEC_CAP_DR1)) {  
  43.                 if (!picture->sample_aspect_ratio.num)    picture->sample_aspect_ratio = avctx->sample_aspect_ratio;  
  44.                 if (!picture->width)                      picture->width               = avctx->width;  
  45.                 if (!picture->height)                     picture->height              = avctx->height;  
  46.                 if (picture->format == AV_PIX_FMT_NONE)   picture->format              = avctx->pix_fmt;  
  47.             }  
  48.         }  
  49.         add_metadata_from_side_data(avctx, picture);  
  50.   
  51.         emms_c(); //needed to avoid an emms_c() call before every return;  
  52.   
  53.         avctx->pkt = NULL;  
  54.         if (did_split) {  
  55.             av_packet_free_side_data(&tmp);  
  56.             if(ret == tmp.size)  
  57.                 ret = avpkt->size;  
  58.         }  
  59.   
  60.         if (ret < 0 && picture->data[0])  
  61.             av_frame_unref(picture);  
  62.   
  63.         if (*got_picture_ptr) {  
  64.             if (!avctx->refcounted_frames) {  
  65.                 avci->to_free = *picture;  
  66.                 avci->to_free.extended_data = avci->to_free.data;  
  67.                 memset(picture->buf, 0, sizeof(picture->buf));  
  68.             }  
  69.   
  70.             avctx->frame_number++;  
  71.             av_frame_set_best_effort_timestamp(picture, guess_correct_pts(avctx, picture->pkt_pts, picture->pkt_dts));  
  72.         }  
  73.     } else  
  74.         ret = 0;  
  75.   
  76.     /* many decoders assign whole AVFrames, thus overwriting extended_data; 
  77.      * make sure it's set correctly */  
  78.     picture->extended_data = picture->data;  
  79.   
  80.     return ret;  
  81. }  
在该函数中,调用了ret = avctx->codec->decode(avctx, picture, got_picture_ptr, &tmp);实现解码功能。在当前demo中,codec类型为ff_hevc_decoder,decode指针指向的函数为hevc_decode_frame。ff_hevc_decoder的定义如下:
  1. AVCodec ff_hevc_decoder = {  
  2.     .name                  = "hevc",  
  3.     .long_name             = NULL_IF_CONFIG_SMALL("HEVC (High Efficiency Video Coding)"),  
  4.     .type                  = AVMEDIA_TYPE_VIDEO,  
  5.     .id                    = AV_CODEC_ID_HEVC,  
  6.     .priv_data_size        = sizeof(HEVCContext),  
  7.     .priv_class            = &hevc_decoder_class,  
  8.     .init                  = hevc_decode_init,  
  9.     .close                 = hevc_decode_free,  
  10.     .decode                = hevc_decode_frame,  
  11.     .flush                 = hevc_decode_flush,  
  12.     .update_thread_context = hevc_update_thread_context,  
  13.     .init_thread_copy      = hevc_init_thread_copy,  
  14.     .capabilities   = CODEC_CAP_DR1 | CODEC_CAP_DELAY | CODEC_CAP_SLICE_THREADS | CODEC_CAP_FRAME_THREADS,  
  15. };  
解码函数:
  1. static int hevc_decode_frame(AVCodecContext *avctx, void *data, int *got_output,  
  2.                              AVPacket *avpkt)  
  3. {  
  4.     int ret;  
  5.     HEVCContext *s = avctx->priv_data;  
  6.   
  7.     if (!avpkt->size) {  
  8.         ret = ff_hevc_output_frame(s, data, 1);  
  9.         if (ret < 0)  
  10.             return ret;  
  11.   
  12.         *got_output = ret;  
  13.         return 0;  
  14.     }  
  15.   
  16.     s->ref = NULL;  
  17.     ret = decode_nal_units(s, avpkt->data, avpkt->size);  
  18.     if (ret < 0)  
  19.         return ret;  
  20.   
  21.     /* verify the SEI checksum */  
  22.     if (avctx->err_recognition & AV_EF_CRCCHECK && s->is_decoded &&  
  23.         avctx->err_recognition & AV_EF_EXPLODE &&  
  24.         s->is_md5) {  
  25.         ret = verify_md5(s, s->ref->frame);  
  26.         if (ret < 0) {  
  27.             ff_hevc_unref_frame(s, s->ref, ~0);  
  28.             return ret;  
  29.         }  
  30.     }  
  31.     s->is_md5 = 0;  
  32.   
  33.     if (s->is_decoded) {  
  34.         av_log(avctx, AV_LOG_DEBUG, "Decoded frame with POC %d.\n", s->poc);  
  35.         s->is_decoded = 0;  
  36.     }  
  37.   
  38.     if (s->output_frame->buf[0]) {  
  39.         av_frame_move_ref(data, s->output_frame);  
  40.         *got_output = 1;  
  41.     }  
  42.   
  43.     return avpkt->size;  
  44. }  
熟悉编解码标准的同学都知道,H.264和HEVC都定义了网络抽象层NAL来执行传输层的任务,每一个NAL单元都按照规定保存了某些语法元素。函数decode_nal_units执行了对这些NAL单元进行解析并对NAL的下一层视频编码层VCL进行解码的任务。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值