ffmpeg源码分析与应用示例(一)——H.264解码与QP提取

来源:互联网 发布:大连网络推广 编辑:程序博客网 时间:2024/05/16 01:24
本文包含以下内容
1、H.264解码流程详述与对应ffmpeg源码解析
2、针对一个应用实例介绍通过修改ffmpeg源码解决问题的方案

具有较强的综合性。

先介绍一下在第二部分中将要解决的实际问题:自ffmpeg 1.2版本之后,用于描述解码后的视音频原始数据相关信息的AVFrame结构体被移出了avcodec库,转而加入了avutil库之中,这样的改变本来是合理的,但是也带来了一些问题。例如,以前在AVFrame中可以直接提取解码得到的QP table(int8_t *qscale_table)和QP stride(int qstride),但是因为这两个变量需要利用avcodec库进行解码后才能获得,于是在AVFrame独立之后,这两个变量(以及包括mbskip_table在内的很多其他变量)也被标注为弃用的(attribute_deprecated),无法再进行提取。在进行诸如码流分析或质量评价之类的工作时,QP table是经常要用到的,于是这篇文章里就介绍一下如何通过分析ffmpeg源码并进行修改来重新获得QP table和QP stride。

简单介绍一下ffmpeg源码调试与修改的基本方法:

首先是基本的conifigure和make,configure命令不用太复杂,像下面这个这么简单的就可以,需要注意的是不要--enable-shared,否则调试时不能step into。如果是windows的话,需要mingw。

[plain] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. # ./configure --enable-gpl --enable-debug --disable-optimizations --disable-asm --enable-ffplay  
然后打开eclipse+cdt,选File->new->Makefile Project with Existing Code,接下来的对话框中的Toolchain for Indexer Settings中选Linux GCC,完成项目的新建之后右键点击ffmpeg_g选debug即可开始调试。如果进行修改的话,在每次修改了源码之后重新进行make即可。

H.264解码流程详述与对应ffmpeg源码解析

这里的分析基于20150630的ffmpeg版本。
ffmpeg中通过av_register_all注册了诸多的编解码器、封装格式、协议等,由此,在进行针对相应内容进行操作时会调用对应的函数。如下,在ffmpeg的API函数avcodec_decode_video2中,通过调用AVCodec的decode函数完成解码操作的关键部分
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,  
  2.                                               int *got_picture_ptr,  
  3.                                               const AVPacket *avpkt)  
  4. {  
  5.     AVCodecInternal *avci = avctx->internal;  
  6.     int ret;  
  7.     // copy to ensure we do not change avpkt  
  8.     AVPacket tmp = *avpkt;  
  9.   
  10.     if (!avctx->codec)  
  11.         return AVERROR(EINVAL);  
  12.     if (avctx->codec->type != AVMEDIA_TYPE_VIDEO) {  
  13.         av_log(avctx, AV_LOG_ERROR, "Invalid media type for video\n");  
  14.         return AVERROR(EINVAL);  
  15.     }  
  16.   
  17.     *got_picture_ptr = 0;  
  18.     if ((avctx->coded_width || avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx))  
  19.         return AVERROR(EINVAL);  
  20.   
  21.     av_frame_unref(picture);  
  22.   
  23.     if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {  
  24.         int did_split = av_packet_split_side_data(&tmp);  
  25.         ret = apply_param_change(avctx, &tmp);  
  26.         if (ret < 0) {  
  27.             av_log(avctx, AV_LOG_ERROR, "Error applying parameter changes.\n");  
  28.             if (avctx->err_recognition & AV_EF_EXPLODE)  
  29.                 goto fail;  
  30.         }  
  31.   
  32.         avctx->internal->pkt = &tmp;  
  33.         if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)  
  34.             ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr,  
  35.                                          &tmp);  
  36.         else {  
  37.             ret = avctx->codec->decode(avctx, picture, got_picture_ptr,  
  38.                                        &tmp);//解码功能的核心部分  
  39.             picture->pkt_dts = avpkt->dts;  
  40.   
  41.             if(!avctx->has_b_frames){  
  42.                 av_frame_set_pkt_pos(picture, avpkt->pos);  
  43.             }  
  44.             //FIXME these should be under if(!avctx->has_b_frames)  
  45.             /* get_buffer is supposed to set frame parameters */  
  46.             if (!(avctx->codec->capabilities & CODEC_CAP_DR1)) {  
  47.                 if (!picture->sample_aspect_ratio.num)    picture->sample_aspect_ratio = avctx->sample_aspect_ratio;  
  48.                 if (!picture->width)                      picture->width               = avctx->width;  
  49.                 if (!picture->height)                     picture->height              = avctx->height;  
  50.                 if (picture->format == AV_PIX_FMT_NONE)   picture->format              = avctx->pix_fmt;  
  51.             }  
  52.         }  
  53.         add_metadata_from_side_data(avctx, picture);  
  54.   
  55. fail:  
  56.         emms_c(); //needed to avoid an emms_c() call before every return;  
  57.   
  58.         avctx->internal->pkt = NULL;  
  59.         if (did_split) {  
  60.             av_packet_free_side_data(&tmp);  
  61.             if(ret == tmp.size)  
  62.                 ret = avpkt->size;  
  63.         }  
  64.   
  65.         if (*got_picture_ptr) {  
  66.             if (!avctx->refcounted_frames) {  
  67.                 int err = unrefcount_frame(avci, picture);  
  68.                 if (err < 0)  
  69.                     return err;  
  70.             }  
  71.   
  72.             avctx->frame_number++;  
  73.             av_frame_set_best_effort_timestamp(picture,  
  74.                                                guess_correct_pts(avctx,  
  75.                                                                  picture->pkt_pts,  
  76.                                                                  picture->pkt_dts));  
  77.         } else  
  78.             av_frame_unref(picture);  
  79.     } else  
  80.         ret = 0;  
  81.   
  82.     /* many decoders assign whole AVFrames, thus overwriting extended_data; 
  83.      * make sure it's set correctly */  
  84.     av_assert0(!picture->extended_data || picture->extended_data == picture->data);  
  85.   
  86. #if FF_API_AVCTX_TIMEBASE  
  87.     if (avctx->framerate.num > 0 && avctx->framerate.den > 0)  
  88.         avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));  
  89. #endif  
  90.   
  91.     return ret;  
  92. }  

而注册的H.264具体解码功能包含在结构体ff_h264_decoder中,如下
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. AVCodec ff_h264_decoder = {  
  2.     .name                  = "h264",  
  3.     .long_name             = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"),  
  4.     .type                  = AVMEDIA_TYPE_VIDEO,  
  5.     .id                    = AV_CODEC_ID_H264,  
  6.     .priv_data_size        = sizeof(H264Context),  
  7.     .init                  = ff_h264_decode_init,  
  8.     .close                 = h264_decode_end,  
  9.     .decode                = h264_decode_frame,  
  10.     .capabilities          = /*CODEC_CAP_DRAW_HORIZ_BAND |*/ CODEC_CAP_DR1 |  
  11.                              CODEC_CAP_DELAY | CODEC_CAP_SLICE_THREADS |  
  12.                              CODEC_CAP_FRAME_THREADS,  
  13.     .flush                 = flush_dpb,  
  14.     .init_thread_copy      = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),  
  15.     .update_thread_context = ONLY_IF_THREADS_ENABLED(ff_h264_update_thread_context),  
  16.     .profiles              = NULL_IF_CONFIG_SMALL(profiles),  
  17.     .priv_class            = &h264_class,  
  18. };  
可以看到它就是一个AVCodec结构体,里面包含了H264解码的初始化、实际解码、关闭等操作。因此,要分析ffmpeg源码中的H264解码部分,就要重点看h264_decode_frame
先给出一个标准的H.264解码流程图,如下

解码器从NAL中接收压缩的比特流,经过对码流进行熵解码获得量化系数等参数,量化参数X经过反量化和反变换后得到参数数据D‘,解码器使用从码流中解码得到的头信息创建一个预测块P,P与D'求和得到图像块数据uF',最后每个uF’通过去块效应滤波器得到重建图像的解码块F。
下面结合此流程图的各部分进行分析

首先是从NAL中接收压缩的比特流并进行解码,见ff_h264_decode_frame中的decode_nal_units
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static int h264_decode_frame(AVCodecContext *avctx, void *data,  
  2.                              int *got_frame, AVPacket *avpkt)  
  3. {  
  4.     ……  
  5.     if (h->is_avc && av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, NULL)) {  
  6.         int side_size;  
  7.         uint8_t *side = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);  
  8.         if (is_extra(side, side_size))  
  9.             ff_h264_decode_extradata(h, side, side_size);  
  10.     }  
  11.     if(h->is_avc && buf_size >= 9 && buf[0]==1 && buf[2]==0 && (buf[4]&0xFC)==0xFC && (buf[5]&0x1F) && buf[8]==0x67){  
  12.         if (is_extra(buf, buf_size))  
  13.             return ff_h264_decode_extradata(h, buf, buf_size);  
  14.     }  
  15.   
  16.     buf_index = decode_nal_units(h, buf, buf_size, 0);  
  17.     if (buf_index < 0)  
  18.         return AVERROR_INVALIDDATA;  
  19.   
  20.     if (!h->cur_pic_ptr && h->nal_unit_type == NAL_END_SEQUENCE) {  
  21.         av_assert0(buf_index <= buf_size);  
  22.         goto out;  
  23.     }  
  24.   
  25.    ……  
  26.   
  27.     av_assert0(pict->buf[0] || !*got_frame);  
  28.   
  29.     ff_h264_unref_picture(h, &h->last_pic_for_ec);  
  30.   
  31.     return get_consumed_bytes(buf_index, buf_size);  
  32. }  
进一步深入decode_nal_units,可见其首先调用了ff_h264_decode_nal对NAL单元进行解析,然后根据NAL单元类型的不同调用不同的处理函数,例如,对于SPS,调用ff_h264_decode_seq_parameter_set对SPS进行解析。在经过解析之后,会调用ff_h264_execute_decode_slices进行真正的解码slice的操作
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size,  
  2.                             int parse_extradata)  
  3. {  
  4.     AVCodecContext *const avctx = h->avctx;  
  5.     H264Context *hx; ///< thread context  
  6.     ……  
  7.         for (;;) {  
  8.             ……  
  9.             ptr = ff_h264_decode_nal(hx, buf + buf_index, &dst_length,  
  10.                                      &consumed, next_avc - buf_index);  
  11.             if (!ptr || dst_length < 0) {  
  12.                 ret = -1;  
  13.                 goto end;  
  14.             }  
  15.   
  16.             ……  
  17.   
  18.             switch (hx->nal_unit_type) {  
  19.             case NAL_IDR_SLICE:  
  20.                 if ((ptr[0] & 0xFC) == 0x98) {  
  21.                     av_log(h->avctx, AV_LOG_ERROR, "Invalid inter IDR frame\n");  
  22.                     h->next_outputed_poc = INT_MIN;  
  23.                     ret = -1;  
  24.                     goto end;  
  25.                 }  
  26.                 if (h->nal_unit_type != NAL_IDR_SLICE) {  
  27.                     av_log(h->avctx, AV_LOG_ERROR,  
  28.                            "Invalid mix of idr and non-idr slices\n");  
  29.                     ret = -1;  
  30.                     goto end;  
  31.                 }  
  32.                 if(!idr_cleared)  
  33.                     idr(h); // FIXME ensure we don't lose some frames if there is reordering  
  34.                 idr_cleared = 1;  
  35.                 h->has_recovery_point = 1;  
  36.             case NAL_SLICE:  
  37.                 init_get_bits(&hx->gb, ptr, bit_length);  
  38.                 hx->intra_gb_ptr      =  
  39.                 hx->inter_gb_ptr      = &hx->gb;  
  40.   
  41.                 if ((err = ff_h264_decode_slice_header(hx, h)))  
  42.                     break;  
  43.   
  44.                 if (h->sei_recovery_frame_cnt >= 0) {  
  45.                     if (h->frame_num != h->sei_recovery_frame_cnt || hx->slice_type_nos != AV_PICTURE_TYPE_I)  
  46.                         h->valid_recovery_point = 1;  
  47.   
  48.                     if (   h->recovery_frame < 0  
  49.                         || ((h->recovery_frame - h->frame_num) & ((1 << h->sps.log2_max_frame_num)-1)) > h->sei_recovery_frame_cnt) {  
  50.                         h->recovery_frame = (h->frame_num + h->sei_recovery_frame_cnt) &  
  51.                                             ((1 << h->sps.log2_max_frame_num) - 1);  
  52.   
  53.                         if (!h->valid_recovery_point)  
  54.                             h->recovery_frame = h->frame_num;  
  55.                     }  
  56.                 }  
  57.   
  58.                 h->cur_pic_ptr->f.key_frame |=  
  59.                     (hx->nal_unit_type == NAL_IDR_SLICE);  
  60.   
  61.                 if (hx->nal_unit_type == NAL_IDR_SLICE ||  
  62.                     h->recovery_frame == h->frame_num) {  
  63.                     h->recovery_frame         = -1;  
  64.                     h->cur_pic_ptr->recovered = 1;  
  65.                 }  
  66.                 // If we have an IDR, all frames after it in decoded order are  
  67.                 // "recovered".  
  68.                 if (hx->nal_unit_type == NAL_IDR_SLICE)  
  69.                     h->frame_recovered |= FRAME_RECOVERED_IDR;  
  70.                 h->frame_recovered |= 3*!!(avctx->flags2 & CODEC_FLAG2_SHOW_ALL);  
  71.                 h->frame_recovered |= 3*!!(avctx->flags & CODEC_FLAG_OUTPUT_CORRUPT);  
  72. #if 1  
  73.                 h->cur_pic_ptr->recovered |= h->frame_recovered;  
  74. #else  
  75.                 h->cur_pic_ptr->recovered |= !!(h->frame_recovered & FRAME_RECOVERED_IDR);  
  76. #endif  
  77.   
  78.                 if (h->current_slice == 1) {  
  79.                     if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS))  
  80.                         decode_postinit(h, nal_index >= nals_needed);  
  81.   
  82.                     if (h->avctx->hwaccel &&  
  83.                         (ret = h->avctx->hwaccel->start_frame(h->avctx, NULL, 0)) < 0)  
  84.                         return ret;  
  85.                     if (CONFIG_H264_VDPAU_DECODER &&  
  86.                         h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)  
  87.                         ff_vdpau_h264_picture_start(h);  
  88.                 }  
  89.   
  90.                 if (hx->redundant_pic_count == 0) {  
  91.                     if (avctx->hwaccel) {  
  92.                         ret = avctx->hwaccel->decode_slice(avctx,  
  93.                                                            &buf[buf_index - consumed],  
  94.                                                            consumed);  
  95.                         if (ret < 0)  
  96.                             return ret;  
  97.                     } else if (CONFIG_H264_VDPAU_DECODER &&  
  98.                                h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU) {  
  99.                         ff_vdpau_add_data_chunk(h->cur_pic_ptr->f.data[0],  
  100.                                                 start_code,  
  101.                                                 sizeof(start_code));  
  102.                         ff_vdpau_add_data_chunk(h->cur_pic_ptr->f.data[0],  
  103.                                                 &buf[buf_index - consumed],  
  104.                                                 consumed);  
  105.                     } else  
  106.                         context_count++;  
  107.                 }  
  108.                 break;  
  109.             case NAL_DPA:  
  110.             case NAL_DPB:  
  111.             case NAL_DPC:  
  112.                 avpriv_request_sample(avctx, "data partitioning");  
  113.                 ret = AVERROR(ENOSYS);  
  114.                 goto end;  
  115.                 break;  
  116.             case NAL_SEI:  
  117.                 init_get_bits(&h->gb, ptr, bit_length);  
  118.                 ret = ff_h264_decode_sei(h);  
  119.                 if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))  
  120.                     goto end;  
  121.                 break;  
  122.             case NAL_SPS:  
  123.                 init_get_bits(&h->gb, ptr, bit_length);  
  124.                 if (ff_h264_decode_seq_parameter_set(h) < 0 && (h->is_avc ? nalsize : 1)) {  
  125.                     av_log(h->avctx, AV_LOG_DEBUG,  
  126.                            "SPS decoding failure, trying again with the complete NAL\n");  
  127.                     if (h->is_avc)  
  128.                         av_assert0(next_avc - buf_index + consumed == nalsize);  
  129.                     if ((next_avc - buf_index + consumed - 1) >= INT_MAX/8)  
  130.                         break;  
  131.                     init_get_bits(&h->gb, &buf[buf_index + 1 - consumed],  
  132.                                   8*(next_avc - buf_index + consumed - 1));  
  133.                     ff_h264_decode_seq_parameter_set(h);  
  134.                 }  
  135.   
  136.                 break;  
  137.             case NAL_PPS:  
  138.                 init_get_bits(&h->gb, ptr, bit_length);  
  139.                 ret = ff_h264_decode_picture_parameter_set(h, bit_length);  
  140.                 if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))  
  141.                     goto end;  
  142.                 break;  
  143.             case NAL_AUD:  
  144.             case NAL_END_SEQUENCE:  
  145.             case NAL_END_STREAM:  
  146.             case NAL_FILLER_DATA:  
  147.             case NAL_SPS_EXT:  
  148.             case NAL_AUXILIARY_SLICE:  
  149.                 break;  
  150.             case NAL_FF_IGNORE:  
  151.                 break;  
  152.             default:  
  153.                 av_log(avctx, AV_LOG_DEBUG, "Unknown NAL code: %d (%d bits)\n",  
  154.                        hx->nal_unit_type, bit_length);  
  155.             }  
  156.   
  157.             if (context_count == h->max_contexts) {  
  158.                 ret = ff_h264_execute_decode_slices(h, context_count);  
  159.                 if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))  
  160.                     goto end;  
  161.                 context_count = 0;  
  162.             }  
  163.   
  164.             if (err < 0 || err == SLICE_SKIPED) {  
  165.                 if (err < 0)  
  166.                     av_log(h->avctx, AV_LOG_ERROR, "decode_slice_header error\n");  
  167.                 h->ref_count[0] = h->ref_count[1] = h->list_count = 0;  
  168.             } else if (err == SLICE_SINGLETHREAD) {  
  169.                 /* Slice could not be decoded in parallel mode, copy down 
  170.                  * NAL unit stuff to context 0 and restart. Note that 
  171.                  * rbsp_buffer is not transferred, but since we no longer 
  172.                  * run in parallel mode this should not be an issue. */  
  173.                 h->nal_unit_type = hx->nal_unit_type;  
  174.                 h->nal_ref_idc   = hx->nal_ref_idc;  
  175.                 hx               = h;  
  176.                 goto again;  
  177.             }  
  178.         }  
  179.     }  
  180.     if (context_count) {  
  181.         ret = ff_h264_execute_decode_slices(h, context_count);  
  182.         if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE))  
  183.             goto end;  
  184.     }  
  185.   
  186.     ret = 0;  
  187. end:  
  188.     /* clean up */  
  189.     if (h->cur_pic_ptr && !h->droppable) {  
  190.         ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX,  
  191.                                   h->picture_structure == PICT_BOTTOM_FIELD);  
  192.     }  
  193.   
  194.     return (ret < 0) ? ret : buf_index;  
  195. }  
再深入去看ff_h264_execute_decode_slices,会发现它直接调用了decode_slice来进行slice的解码。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * Call decode_slice() for each context. 
  3.  * 
  4.  * @param h h264 master context 
  5.  * @param context_count number of contexts to execute 
  6.  */  
  7. int ff_h264_execute_decode_slices(H264Context *h, unsigned context_count)  
  8. {  
  9.     AVCodecContext *const avctx = h->avctx;  
  10.     H264Context *hx;  
  11.     int i;  
  12.   
  13.     av_assert0(h->mb_y < h->mb_height);  
  14.   
  15.     if (h->avctx->hwaccel ||  
  16.         h->avctx->codec->capabilities & CODEC_CAP_HWACCEL_VDPAU)  
  17.         return 0;  
  18.     if (context_count == 1) {  
  19.         return decode_slice(avctx, &h);  
  20.     } else {  
  21.         av_assert0(context_count > 0);  
  22.         for (i = 1; i < context_count; i++) {  
  23.             hx                 = h->thread_context[i];  
  24.             if (CONFIG_ERROR_RESILIENCE) {  
  25.                 hx->er.error_count = 0;  
  26.             }  
  27.             hx->x264_build     = h->x264_build;  
  28.         }  
  29.   
  30.         avctx->execute(avctx, decode_slice, h->thread_context,  
  31.                        NULL, context_count, sizeof(void *));  
  32.   
  33.         /* pull back stuff from slices to master context */  
  34.         hx                   = h->thread_context[context_count - 1];  
  35.         h->mb_x              = hx->mb_x;  
  36.         h->mb_y              = hx->mb_y;  
  37.         h->droppable         = hx->droppable;  
  38.         h->picture_structure = hx->picture_structure;  
  39.         if (CONFIG_ERROR_RESILIENCE) {  
  40.             for (i = 1; i < context_count; i++)  
  41.                 h->er.error_count += h->thread_context[i]->er.error_count;  
  42.         }  
  43.     }  
  44.   
  45.     return 0;  
  46. }  
那就再来看看decode_slice
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static int decode_slice(struct AVCodecContext *avctx, void *arg)  
  2. {  
  3.     H264Context *h = *(void **)arg;  
  4.     ……  
  5.   
  6.     if (h->pps.cabac) {  
  7.         /* realign */  
  8.         align_get_bits(&h->gb);  
  9.   
  10.         /* init cabac */  
  11.         ff_init_cabac_decoder(&h->cabac,  
  12.                               h->gb.buffer + get_bits_count(&h->gb) / 8,  
  13.                               (get_bits_left(&h->gb) + 7) / 8);  
  14.   
  15.         ff_h264_init_cabac_states(h);  
  16.   
  17.         for (;;) {  
  18.             // START_TIMER  
  19.             int ret = ff_h264_decode_mb_cabac(h);  
  20.             int eos;  
  21.             // STOP_TIMER("decode_mb_cabac")  
  22.   
  23.             if (ret >= 0)  
  24.                 ff_h264_hl_decode_mb(h);  
  25.   
  26.             // FIXME optimal? or let mb_decode decode 16x32 ?  
  27.             if (ret >= 0 && FRAME_MBAFF(h)) {  
  28.                 h->mb_y++;  
  29.   
  30.                 ret = ff_h264_decode_mb_cabac(h);  
  31.   
  32.                 if (ret >= 0)  
  33.                     ff_h264_hl_decode_mb(h);  
  34.                 h->mb_y--;  
  35.             }  
  36.             eos = get_cabac_terminate(&h->cabac);  
  37.   
  38.             if ((h->workaround_bugs & FF_BUG_TRUNCATED) &&  
  39.                 h->cabac.bytestream > h->cabac.bytestream_end + 2) {  
  40.                 er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x - 1,  
  41.                              h->mb_y, ER_MB_END);  
  42.                 if (h->mb_x >= lf_x_start)  
  43.                     loop_filter(h, lf_x_start, h->mb_x + 1);  
  44.                 return 0;  
  45.             }  
  46.             if (h->cabac.bytestream > h->cabac.bytestream_end + 2 )  
  47.                 av_log(h->avctx, AV_LOG_DEBUG, "bytestream overread %"PTRDIFF_SPECIFIER"\n", h->cabac.bytestream_end - h->cabac.bytestream);  
  48.             if (ret < 0 || h->cabac.bytestream > h->cabac.bytestream_end + 4) {  
  49.                 av_log(h->avctx, AV_LOG_ERROR,  
  50.                        "error while decoding MB %d %d, bytestream %"PTRDIFF_SPECIFIER"\n",  
  51.                        h->mb_x, h->mb_y,  
  52.                        h->cabac.bytestream_end - h->cabac.bytestream);  
  53.                 er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x,  
  54.                              h->mb_y, ER_MB_ERROR);  
  55.                 return AVERROR_INVALIDDATA;  
  56.             }  
  57.   
  58.             if (++h->mb_x >= h->mb_width) {  
  59.                 loop_filter(h, lf_x_start, h->mb_x);  
  60.                 h->mb_x = lf_x_start = 0;  
  61.                 decode_finish_row(h);  
  62.                 ++h->mb_y;  
  63.                 if (FIELD_OR_MBAFF_PICTURE(h)) {  
  64.                     ++h->mb_y;  
  65.                     if (FRAME_MBAFF(h) && h->mb_y < h->mb_height)  
  66.                         predict_field_decoding_flag(h);  
  67.                 }  
  68.             }  
  69.   
  70.             if (eos || h->mb_y >= h->mb_height) {  
  71.                 tprintf(h->avctx, "slice end %d %d\n",  
  72.                         get_bits_count(&h->gb), h->gb.size_in_bits);  
  73.                 er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x - 1,  
  74.                              h->mb_y, ER_MB_END);  
  75.                 if (h->mb_x > lf_x_start)  
  76.                     loop_filter(h, lf_x_start, h->mb_x);  
  77.                 return 0;  
  78.             }  
  79.         }  
  80.     } else {  
  81.         for (;;) {  
  82.             int ret = ff_h264_decode_mb_cavlc(h);  
  83.   
  84.             if (ret >= 0)  
  85.                 ff_h264_hl_decode_mb(h);  
  86.   
  87.             // FIXME optimal? or let mb_decode decode 16x32 ?  
  88.             if (ret >= 0 && FRAME_MBAFF(h)) {  
  89.                 h->mb_y++;  
  90.                 ret = ff_h264_decode_mb_cavlc(h);  
  91.   
  92.                 if (ret >= 0)  
  93.                     ff_h264_hl_decode_mb(h);  
  94.                 h->mb_y--;  
  95.             }  
  96.   
  97.             if (ret < 0) {  
  98.                 av_log(h->avctx, AV_LOG_ERROR,  
  99.                        "error while decoding MB %d %d\n", h->mb_x, h->mb_y);  
  100.                 er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x,  
  101.                              h->mb_y, ER_MB_ERROR);  
  102.                 return ret;  
  103.             }  
  104.   
  105.             if (++h->mb_x >= h->mb_width) {  
  106.                 loop_filter(h, lf_x_start, h->mb_x);  
  107.                 h->mb_x = lf_x_start = 0;  
  108.                 decode_finish_row(h);  
  109.                 ++h->mb_y;  
  110.                 if (FIELD_OR_MBAFF_PICTURE(h)) {  
  111.                     ++h->mb_y;  
  112.                     if (FRAME_MBAFF(h) && h->mb_y < h->mb_height)  
  113.                         predict_field_decoding_flag(h);  
  114.                 }  
  115.                 if (h->mb_y >= h->mb_height) {  
  116.                     tprintf(h->avctx, "slice end %d %d\n",  
  117.                             get_bits_count(&h->gb), h->gb.size_in_bits);  
  118.   
  119.                     if (   get_bits_left(&h->gb) == 0  
  120.                         || get_bits_left(&h->gb) > 0 && !(h->avctx->err_recognition & AV_EF_AGGRESSIVE)) {  
  121.                         er_add_slice(h, h->resync_mb_x, h->resync_mb_y,  
  122.                                      h->mb_x - 1, h->mb_y, ER_MB_END);  
  123.   
  124.                         return 0;  
  125.                     } else {  
  126.                         er_add_slice(h, h->resync_mb_x, h->resync_mb_y,  
  127.                                      h->mb_x, h->mb_y, ER_MB_END);  
  128.   
  129.                         return AVERROR_INVALIDDATA;  
  130.                     }  
  131.                 }  
  132.             }  
  133.   
  134.             if (get_bits_left(&h->gb) <= 0 && h->mb_skip_run <= 0) {  
  135.                 tprintf(h->avctx, "slice end %d %d\n",  
  136.                         get_bits_count(&h->gb), h->gb.size_in_bits);  
  137.   
  138.                 if (get_bits_left(&h->gb) == 0) {  
  139.                     er_add_slice(h, h->resync_mb_x, h->resync_mb_y,  
  140.                                  h->mb_x - 1, h->mb_y, ER_MB_END);  
  141.                     if (h->mb_x > lf_x_start)  
  142.                         loop_filter(h, lf_x_start, h->mb_x);  
  143.   
  144.                     return 0;  
  145.                 } else {  
  146.                     er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x,  
  147.                                  h->mb_y, ER_MB_ERROR);  
  148.   
  149.                     return AVERROR_INVALIDDATA;  
  150.                 }  
  151.             }  
  152.         }  
  153.     }  
  154. }  
至此就已经很清晰了,首先通过PPS判断是CABAC熵编码还是CAVLC熵编码,然后针对每一个宏块调用对应的熵解码函数进行解码,即ff_h264_decode_mb_cabac和ff_h264_decode_mb_cavlc,然后再进行宏块的解码,使用的是ff_h264_hl_decode_mb,帧内预测和帧间预测的内容也包含在其中,最后使用loop_filter进行去块效应滤波,这里还多了一个错误隐藏功能,使用的是er_add_slice。

对于本文的需求,分析到这一步就够了。再往里面深入的话,就需要各位静下心来,对照标准一点一点看了,网上也有很多相关的文章供参考。

ffmpeg源码修改与QP提取

通过前面对ffmpeg中H.264解码部分的源码分析,现在我们可以解决在文章最开始提到的实际问题了。

每一个宏块都有自己的QP值,将一帧中所有宏块的QP值集合到一起即得到QP table。直接定位到与帧解码对应的函数h264_decode_frame(libavcodec/h264.c),当成功解码得到一帧数据的时候,会将got_frame赋值为1,此时即可将解码得到的QP table赋值给作为输出的AVFrame。于是,修改后的代码如下,非常简单。需要注意的是,在flush buffer阶段也需要进行对应的QP table赋值操作。

[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static int h264_decode_frame(AVCodecContext *avctx, void *data,  
  2.                              int *got_frame, AVPacket *avpkt)  
  3. {  
  4.     const uint8_t *buf = avpkt->data;  
  5.     int buf_size       = avpkt->size;  
  6.     H264Context *h     = avctx->priv_data;  
  7.     AVFrame *pict      = data;  
  8.     int buf_index      = 0;  
  9.     H264Picture *out;  
  10.     int i, out_idx;  
  11.     int ret;  
  12.   
  13.     h->flags = avctx->flags;  
  14.   
  15.     ff_h264_unref_picture(h, &h->last_pic_for_ec);  
  16.   
  17.     /* end of stream, output what is still in the buffers */  
  18.     if (buf_size == 0) {  
  19.  out:  
  20.   
  21.         h->cur_pic_ptr = NULL;  
  22.         h->first_field = 0;  
  23.   
  24.         // FIXME factorize this with the output code below  
  25.         out     = h->delayed_pic[0];  
  26.         out_idx = 0;  
  27.         for (i = 1;  
  28.              h->delayed_pic[i] &&  
  29.              !h->delayed_pic[i]->f.key_frame &&  
  30.              !h->delayed_pic[i]->mmco_reset;  
  31.              i++)  
  32.             if (h->delayed_pic[i]->poc < out->poc) {  
  33.                 out     = h->delayed_pic[i];  
  34.                 out_idx = i;  
  35.             }  
  36.   
  37.         for (i = out_idx; h->delayed_pic[i]; i++)  
  38.             h->delayed_pic[i] = h->delayed_pic[i + 1];  
  39.   
  40.         if (out) {  
  41.             out->reference &= ~DELAYED_PIC_REF;  
  42.             ret = output_frame(h, pict, out);  
  43.             if (ret < 0)  
  44.                 return ret;  
  45.   
  46.             //get the qscale table, modified by zhanghui  
  47.             if(out->qscale_table)  
  48.             {  
  49.                 pict->qscale_table=out->qscale_table;  
  50.                 pict->qstride=h->mb_stride;  
  51.                 pict->qscale_type=FF_QSCALE_TYPE_H264;  
  52.             }  
  53.   
  54.             *got_frame = 1;  
  55.         }  
  56.   
  57.         return buf_index;  
  58.     }  
  59.     if (h->is_avc && av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, NULL)) {  
  60.         int side_size;  
  61.         uint8_t *side = av_packet_get_side_data(avpkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);  
  62.         if (is_extra(side, side_size))  
  63.             ff_h264_decode_extradata(h, side, side_size);  
  64.     }  
  65.     if(h->is_avc && buf_size >= 9 && buf[0]==1 && buf[2]==0 && (buf[4]&0xFC)==0xFC && (buf[5]&0x1F) && buf[8]==0x67){  
  66.         if (is_extra(buf, buf_size))  
  67.             return ff_h264_decode_extradata(h, buf, buf_size);  
  68.     }  
  69.   
  70.     buf_index = decode_nal_units(h, buf, buf_size, 0);  
  71.     if (buf_index < 0)  
  72.         return AVERROR_INVALIDDATA;  
  73.   
  74.     if (!h->cur_pic_ptr && h->nal_unit_type == NAL_END_SEQUENCE) {  
  75.         av_assert0(buf_index <= buf_size);  
  76.         goto out;  
  77.     }  
  78.   
  79.     if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS) && !h->cur_pic_ptr) {  
  80.         if (avctx->skip_frame >= AVDISCARD_NONREF ||  
  81.             buf_size >= 4 && !memcmp("Q264", buf, 4))  
  82.             return buf_size;  
  83.         av_log(avctx, AV_LOG_ERROR, "no frame!\n");  
  84.         return AVERROR_INVALIDDATA;  
  85.     }  
  86.   
  87.     if (!(avctx->flags2 & CODEC_FLAG2_CHUNKS) ||  
  88.         (h->mb_y >= h->mb_height && h->mb_height)) {  
  89.         if (avctx->flags2 & CODEC_FLAG2_CHUNKS)  
  90.             decode_postinit(h, 1);  
  91.   
  92.         ff_h264_field_end(h, 0);  
  93.   
  94.         /* Wait for second field. */  
  95.         *got_frame = 0;  
  96.         if (h->next_output_pic && (  
  97.                                    h->next_output_pic->recovered)) {  
  98.             if (!h->next_output_pic->recovered)  
  99.                 h->next_output_pic->f.flags |= AV_FRAME_FLAG_CORRUPT;  
  100.   
  101.             if (!h->avctx->hwaccel &&  
  102.                  (h->next_output_pic->field_poc[0] == INT_MAX ||  
  103.                   h->next_output_pic->field_poc[1] == INT_MAX)  
  104.             ) {  
  105.                 int p;  
  106.                 AVFrame *f = &h->next_output_pic->f;  
  107.                 int field = h->next_output_pic->field_poc[0] == INT_MAX;  
  108.                 uint8_t *dst_data[4];  
  109.                 int linesizes[4];  
  110.                 const uint8_t *src_data[4];  
  111.   
  112.                 av_log(h->avctx, AV_LOG_DEBUG, "Duplicating field %d to fill missing\n", field);  
  113.   
  114.                 for (p = 0; p<4; p++) {  
  115.                     dst_data[p] = f->data[p] + (field^1)*f->linesize[p];  
  116.                     src_data[p] = f->data[p] +  field   *f->linesize[p];  
  117.                     linesizes[p] = 2*f->linesize[p];  
  118.                 }  
  119.   
  120.                 av_image_copy(dst_data, linesizes, src_data, linesizes,  
  121.                               f->format, f->width, f->height>>1);  
  122.             }  
  123.   
  124.             ret = output_frame(h, pict, h->next_output_pic);  
  125.             if (ret < 0)  
  126.                 return ret;  
  127.   
  128.             //get the qscale table, modified by zhanghui  
  129.             if(h->next_output_pic->qscale_table)  
  130.             {  
  131.                 pict->qscale_table=h->next_output_pic->qscale_table;  
  132.                 pict->qstride=h->mb_stride;  
  133.                 pict->qscale_type=FF_QSCALE_TYPE_H264;  
  134.             }  
  135.   
  136.             *got_frame = 1;  
  137.   
  138.             if (CONFIG_MPEGVIDEO) {  
  139.                 ff_print_debug_info2(h->avctx, pict, h->er.mbskip_table,  
  140.                                     h->next_output_pic->mb_type,  
  141.                                     h->next_output_pic->qscale_table,  
  142.                                     h->next_output_pic->motion_val,  
  143.                                     &h->low_delay,  
  144.                                     h->mb_width, h->mb_height, h->mb_stride, 1);  
  145.             }  
  146.         }  
  147.     }  
  148.   
  149.     av_assert0(pict->buf[0] || !*got_frame);  
  150.   
  151.     ff_h264_unref_picture(h, &h->last_pic_for_ec);  
  152.   
  153.     return get_consumed_bytes(buf_index, buf_size);  
  154. }  
保存修改,重新make即可。也可以利用diff和patch工具把对源码的修改做成一个补丁,这样以后再下载了新的ffmpeg源码也可以直接通过patch将我们曾经的修改应用到新的源码中去,非常方便。

上面的应用实例非常简单,进行其他的修改也可以使用类似的思路,我这里算是抛砖引玉,以后还会讲述如何从ffmpeg中抽取代码等其他的ffmpeg源码应用实例。

本文的示例也存在一个小问题,经观察,在AVFrame中新增了AVBufferRef *qp_table_buf变量,应该也是用于存储QP table的,但是AVBufferRef这个结构体我还不太了解它是干什么用的、怎么用的,按理说如果能将QP table存到这个里面应该是更好的,但是我的尝试都失败了,希望有经验的朋友多多指教,谢谢!

0 0