HEVC学习笔记5-x265中cuGeom

Pre

HEVC学习笔记系列目录
从compressCTU里面,根据rd值划分了不同的编码帧内CU的方法,rd设置为5或6才符合HEVC标准,则接下来进行函数compressInterCU_rd5_6的解析。

void Analysis::compressInterCU_rd5_6(const CUData& parentCTU, const CUGeom& cuGeom, uint32_t &zOrder, int32_t qp)

compressInterCU_rd5_6函数大体

两个if作为主要部分:

  • if (mightNotSplit)
  • if (mightSplit && (!md.bestMode || !md.bestMode->cu.isSkipped(0)))

很明显,字面意义:看当前CTU是否仍需要划分,这里的划分是说四叉树划分。四叉树划分最多三层,也就是说标准中,CU最小是8×8,最大64×64。
而这两个flag的定义主要与cuGeom有关。

bool mightSplit = !(cuGeom.flags & CUGeom::LEAF);
bool mightNotSplit = !(cuGeom.flags & CUGeom::SPLIT_MANDATORY);

cuGeom


Eclipse中F3跳转到cuGem的定义,cuGeom是一个结构体:

struct CUGeom
{
    enum {
        INTRA           = 1<<0, // CU is intra predicted
        PRESENT         = 1<<1, // CU is not completely outside the frame
        SPLIT_MANDATORY = 1<<2, // CU split is mandatory if CU is inside frame and can be split
        LEAF            = 1<<3, // CU is a leaf node of the CTU
        SPLIT           = 1<<4, // CU is currently split in four child CUs.
    };

    // (1 + 4 + 16 + 64) = 85.
    enum { MAX_GEOMS = 85 };

    uint32_t log2CUSize;    // Log of the CU size.
    uint32_t childOffset;   // offset of the first child CU from current CU
    uint32_t absPartIdx;    // Part index of this CU in terms of 4x4 blocks.
    uint32_t numPartitions; // Number of 4x4 blocks in the CU
    uint32_t flags;         // CU flags.
    uint32_t depth;         // depth of this CU relative from CTU
};

注释很清楚,(x265中注释不多,但是很多地方注释得很必要),MAX_GEONS=85,其中,这里的(1 + 4 + 16 + 64) = 85.因为最多可以划分3层,如果地一层不划分,有1块64×64的大CU,划分则就有四个32×32的CU,则再下一层有16个16×16的CU,最底下有64个8×8的CU。
depth则是当前CU在zorder上与CTU的距离,64×64的大CU则就是0。
而flags,在eclipse中Ctrl+shift+G,搜索项目中对选中变量/函数的使用的地方。
则会发现在/source/common/cudata.cpp里面有CU_SET_FLAG的字眼,跳过去:

void CUData::calcCTUGeoms(uint32_t ctuWidth, uint32_t ctuHeight, uint32_t maxCUSize, uint32_t minCUSize, CUGeom cuDataArray[CUGeom::MAX_GEOMS])

不贴详细代码了,三重循环:

    for (uint32_t log2CUSize = g_log2Size[maxCUSize], rangeCUIdx = 0; log2CUSize >= g_log2Size[minCUSize]; log2CUSize--)
        for (uint32_t sbY = 0; sbY < sbWidth; sbY++)
            for (uint32_t sbX = 0; sbX < sbWidth; sbX++)

g_log2Size,是对Size的log2取值:

const uint8_t g_log2Size[MAX_CU_SIZE + 1] =
{
    0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3,
    4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
    6
};

在循环里面是对cuGeom实例的各种变量赋值,明显是进行四叉树结构的一些initialization.至于划分flag,我没有细究#define CU_SET_FLAG(bitfield, flag, value) (bitfield) = ((bitfield) & (~(flag))) | ((~((value) - 1)) & (flag)),这个宏定义函数,根据HEVC标准,所有的分支都要走,每个CTU都要划分三层,然后根据划分过程中,结果的优劣来判定到底划分与否,把信息写入到编码块中。

文章版权归 FindHao 所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明作者 FindHao 和本文原始地址:
https://www.findhao.net/easycoding/1456

你可能喜欢:(相似内容推荐和广告都使用了谷歌的推荐系统,需要对本站取消广告屏蔽才能显示。感谢点击↓广告支持博主~)

Find

新浪微博(FindSpace博客)QQ群:不安分的Coder(375670127) 不安分的Coder

6 条回复

  1. sabre说道:

    bool mightSplit = !(cuGeom.flags & CUGeom::LEAF);bool mightNotSplit = !(cuGeom.flags & CUGeom::SPLIT_MANDATORY);请问博主,这两个得出来的到底是什么啊

  2. 老千说道:

    把博主的hevc文章全部看了,非常感谢你的经验分享。
    不过有一个概念错误多次出现,简单说一说。标准是从解码器的角度定义hevc,而一般的教材通常从编码器的角度来讲解,但其实标准根本不关心编码器的设计。一个编码器即使把所有CTU不加区分地划为64×64,2Nx2N预测,它依然是标准的——因为它编出来的码流能被标准解码器解码。所以博主很多时候认为x265不标准的地方,其实没有问题。

    • Find说道:

      感谢你的意见。其实我认为HM是标准的实现,所有不符合HM设计的都是不标准的。解码器不关心编码的划分模式,所以以解码器能否解码作为标准我觉得不太合适。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*