FFmpeg的H 264解码器源代码简单分析 熵解码(Entropy Decoding)部分

分享一下我老师大神的人工智能教程。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

               

=====================================================

H.264源代码分析文章列表:

【编码 - x264

x264源代码简单分析:概述

x264源代码简单分析:x264命令行工具(x264.exe)

x264源代码简单分析:编码器主干部分-1

x264源代码简单分析:编码器主干部分-2

x264源代码简单分析:x264_slice_write()

x264源代码简单分析:滤波(Filter)部分

x264源代码简单分析:宏块分析(Analysis)部分-帧内宏块(Intra)

x264源代码简单分析:宏块分析(Analysis)部分-帧间宏块(Inter)

x264源代码简单分析:宏块编码(Encode)部分

x264源代码简单分析:熵编码(Entropy Encoding)部分

FFmpeg与libx264接口源代码简单分析

【解码 - libavcodec H.264 解码器

FFmpeg的H.264解码器源代码简单分析:概述

FFmpeg的H.264解码器源代码简单分析:解析器(Parser)部分

FFmpeg的H.264解码器源代码简单分析:解码器主干部分

FFmpeg的H.264解码器源代码简单分析:熵解码(EntropyDecoding)部分

FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧内宏块(Intra)

FFmpeg的H.264解码器源代码简单分析:宏块解码(Decode)部分-帧间宏块(Inter)

FFmpeg的H.264解码器源代码简单分析:环路滤波(Loop Filter)部分

=====================================================


本文分析FFmpeg的H.264解码器的熵解码(Entropy Decoding)部分的源代码。FFmpeg的H.264解码器调用decode_slice()函数完成了解码工作。这些解码工作可以大体上分为3个步骤:熵解码,宏块解码以及环路滤波。本文分析这3个步骤中的第1个步骤。

函数调用关系图

熵解码(Entropy Decoding)部分的源代码在整个H.264解码器中的位置如下图所示。

熵解码(Entropy Decoding)部分的源代码的调用关系如下图所示。

 从图中可以看出,FFmpeg的熵解码方面的函数有两个:ff_h264_decode_mb_cabac()和ff_h264_decode_mb_cavlc()。ff_h264_decode_mb_cabac()用于解码CABAC编码方式的H.264数据,ff_h264_decode_mb_cavlc()用于解码CAVLC编码方式的H.264数据。本文挑选了ff_h264_decode_mb_cavlc()函数进行分析。
 ff_h264_decode_mb_cavlc()调用了很多的读取指数哥伦布编码数据的函数,例如get_ue_golomb_long(),get_ue_golomb(),get_se_golomb(),get_ue_golomb_31()等。此外在解码残差数据的时候,调用了decode_residual()函数,而decode_residual()会调用get_vlc2()函数读取CAVLC编码数据。
 总而言之,“熵解码”部分的作用就是按照H.264语法和语义的规定,读取数据(宏块类型、运动矢量、参考帧、残差等)并且赋值到FFmpeg H.264解码器中相应的变量上。需要注意的是,“熵解码”部分并不使用这些变量还原视频数据。还原视频数据的功能在下一步“宏块解码”步骤中完成。
 在开始看ff_h264_decode_mb_cavlc()之前先回顾一下decode_slice()函数。


decode_slice()

decode_slice()用于解码H.264的Slice。该函数完成了“熵解码”、“宏块解码”、“环路滤波”的功能。它的定义位于libavcodec\h264_slice.c,如下所示。
//解码slice//三个主要步骤://1.熵解码(CAVLC/CABAC)//2.宏块解码//3.环路滤波//此外还包含了错误隐藏代码static int decode_slice(struct AVCodecContext *avctx, void *arg){    H264Context *h = *(void **)arg;    int lf_x_start = h->mb_x;    h->mb_skip_run = -1;    av_assert0(h->block_offset[15] == (4 * ((scan8[15] - scan8[0]) & 7) << h->pixel_shift) + 4 * h->linesize * ((scan8[15] - scan8[0]) >> 3));    h->is_complex = FRAME_MBAFF(h) || h->picture_structure != PICT_FRAME ||                    avctx->codec_id != AV_CODEC_ID_H264 ||                    (CONFIG_GRAY && (h->flags & CODEC_FLAG_GRAY));    if (!(h->avctx->active_thread_type & FF_THREAD_SLICE) && h->picture_structure == PICT_FRAME && h->er.error_status_table) {        const int start_i  = av_clip(h->resync_mb_x + h->resync_mb_y * h->mb_width, 0, h->mb_num - 1);        if (start_i) {            int prev_status = h->er.error_status_table[h->er.mb_index2xy[start_i - 1]];            prev_status &= ~ VP_START;            if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END))                h->er.error_occurred = 1;        }    }    //CABAC情况    if (h->pps.cabac) {        /* realign */        align_get_bits(&h->gb);        /* init cabac */        //初始化CABAC解码器        ff_init_cabac_decoder(&h->cabac,                              h->gb.buffer + get_bits_count(&h->gb) / 8,                              (get_bits_left(&h->gb) + 7) / 8);        ff_h264_init_cabac_states(h);        //循环处理每个宏块        for (;;) {            // START_TIMER         //解码CABAC数据            int ret = ff_h264_decode_mb_cabac(h);            int eos;            // STOP_TIMER("decode_mb_cabac")            //解码宏块            if (ret >= 0)                ff_h264_hl_decode_mb(h);            // FIXME optimal? or let mb_decode decode 16x32 ?            //宏块级帧场自适应。很少接触            if (ret >= 0 && FRAME_MBAFF(h)) {                h->mb_y++;                ret = ff_h264_decode_mb_cabac(h);                //解码宏块                if (ret >= 0)                    ff_h264_hl_decode_mb(h);                h->mb_y--;            }            eos = get_cabac_terminate(&h->cabac);            if ((h->workaround_bugs & FF_BUG_TRUNCATED) &&                h->cabac.bytestream > h->cabac.bytestream_end + 2) {             //错误隐藏                er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x - 1,                             h->mb_y, ER_MB_END);                if (h->mb_x >= lf_x_start)                    loop_filter(h, lf_x_start, h->mb_x + 1);                return 0;            }            if (h->cabac.bytestream > h->cabac.bytestream_end + 2 )                av_log(h->avctx, AV_LOG_DEBUG, "bytestream overread %"PTRDIFF_SPECIFIER"\n", h->cabac.bytestream_end - h->cabac.bytestream);            if (ret < 0 || h->cabac.bytestream > h->cabac.bytestream_end + 4) {                av_log(h->avctx, AV_LOG_ERROR,                       "error while decoding MB %d %d, bytestream %"PTRDIFF_SPECIFIER"\n",                       h->mb_x, h->mb_y,                       h->cabac.bytestream_end - h->cabac.bytestream);                er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x,                             h->mb_y, ER_MB_ERROR);                return AVERROR_INVALIDDATA;            }            //mb_x自增            //如果自增后超过了一行的mb个数            if (++h->mb_x >= h->mb_width) {             //环路滤波                loop_filter(h, lf_x_start, h->mb_x);                h->mb_x = lf_x_start = 0;                decode_finish_row(h);                //mb_y自增(处理下一行)                ++h->mb_y;                //宏块级帧场自适应,暂不考虑                if (FIELD_OR_MBAFF_PICTURE(h)) {                    ++h->mb_y;                    if (FRAME_MBAFF(h) && h->mb_y < h->mb_height)                        predict_field_decoding_flag(h);                }            }            //如果mb_y超过了mb的行数            if (eos || h->mb_y >= h->mb_height) {                tprintf(h->avctx, "slice end %d %d\n",                        get_bits_count(&h->gb), h->gb.size_in_bits);                er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x - 1,                             h->mb_y, ER_MB_END);                if (h->mb_x > lf_x_start)                    loop_filter(h, lf_x_start, h->mb_x);                return 0;            }        }    } else {     //CAVLC情况     //循环处理每个宏块        for (;;) {         //解码宏块的CAVLC            int ret = ff_h264_decode_mb_cavlc(h);            //解码宏块            if (ret >= 0)                ff_h264_hl_decode_mb(h);            // FIXME optimal? or let mb_decode decode 16x32 ?            if (ret >= 0 && FRAME_MBAFF(h)) {                h->mb_y++;                ret = ff_h264_decode_mb_cavlc(h);                if (ret >= 0)                    ff_h264_hl_decode_mb(h);                h->mb_y--;            }            if (ret < 0) {                av_log(h->avctx, AV_LOG_ERROR,                       "error while decoding MB %d %d\n", h->mb_x, h->mb_y);                er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x,                             h->mb_y, ER_MB_ERROR);                return ret;            }            if (++h->mb_x >= h->mb_width) {             //环路滤波                loop_filter(h, lf_x_start, h->mb_x);                h->mb_x = lf_x_start = 0;                decode_finish_row(h);                ++h->mb_y;                if (FIELD_OR_MBAFF_PICTURE(h)) {                    ++h->mb_y;                    if (FRAME_MBAFF(h) && h->mb_y < h->mb_height)                        predict_field_decoding_flag(h);                }                if (h->mb_y >= h->mb_height) {                    tprintf(h->avctx, "slice end %d %d\n",                            get_bits_count(&h->gb), h->gb.size_in_bits);                    if (   get_bits_left(&h->gb) == 0                        || get_bits_left(&h->gb) > 0 && !(h->avctx->err_recognition & AV_EF_AGGRESSIVE)) {                     //错误隐藏                        er_add_slice(h, h->resync_mb_x, h->resync_mb_y,                                     h->mb_x - 1, h->mb_y, ER_MB_END);                        return 0;                    } else {                        er_add_slice(h, h->resync_mb_x, h->resync_mb_y,                                     h->mb_x, h->mb_y, ER_MB_END);                        return AVERROR_INVALIDDATA;                    }                }            }            if (get_bits_left(&h->gb) <= 0 && h->mb_skip_run <= 0) {                tprintf(h->avctx, "slice end %d %d\n",                        get_bits_count(&h->gb), h->gb.size_in_bits);                if (get_bits_left(&h->gb) == 0) {                    er_add_slice(h, h->resync_mb_x, h->resync_mb_y,                                 h->mb_x - 1, h->mb_y, ER_MB_END);                    if (h->mb_x > lf_x_start)                        loop_filter(h, lf_x_start, h->mb_x);                    return 0;                } else {                    er_add_slice(h, h->resync_mb_x, h->resync_mb_y, h->mb_x,                                 h->mb_y, ER_MB_ERROR);                    return AVERROR_INVALIDDATA;                }            }        }    }}

可以看出decode_slice()的的流程如下:

(1)判断H.264码流是CABAC编码还是CAVLC编码,进入不同的处理循环。

(2)如果是CABAC编码,首先调用ff_init_cabac_decoder()初始化CABAC解码器。然后进入一个循环,依次对每个宏块进行以下处理:

a)调用ff_h264_decode_mb_cabac()进行CABAC熵解码

b)调用ff_h264_hl_decode_mb()进行宏块解码

c)解码一行宏块之后调用loop_filter()进行环路滤波

d)此外还有可能调用er_add_slice()进行错误隐藏处理

(3)如果是CABAC编码,直接进入一个循环,依次对每个宏块进行以下处理:

a)调用ff_h264_decode_mb_cavlc()进行CAVLC熵解码

b)调用ff_h264_hl_decode_mb()进行宏块解码

c)解码一行宏块之后调用loop_filter()进行环路滤波

d)此外还有可能调用er_add_slice()进行错误隐藏处理

可以看出,出了熵解码以外,宏块解码和环路滤波的函数是一样的。下面详细看一下CAVLC熵解码函数ff_h264_decode_mb_cavlc()。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值