Newer
Older

Karsten Suehring
committed
/* The copyright in this software is being made available under the BSD
* License, included below. This software may be subject to other third party
* and contributor rights, including patent rights, and no such rights are
* granted under this license.
*
* Copyright (c) 2010-2025, ITU/ISO/IEC

Karsten Suehring
committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the ITU/ISO/IEC nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
/** \file CABACWriter.cpp
* \brief Writer for low level syntax
*/
#include "CommonLib/Contexts.h"
#include "CABACWriter.h"
#include "EncLib.h"
#include "CommonLib/UnitTools.h"
#include "CommonLib/dtrace_buffer.h"
#include <map>
#include <algorithm>
#include <limits>
//! \ingroup EncoderLib
//! \{
void CABACWriter::initCtxModels( const Slice& slice )
{
int qp = slice.getSliceQp();
SliceType sliceType = slice.getSliceType();
SliceType encCABACTableIdx = slice.getEncCABACTableIdx();
if( !slice.isIntra() && (encCABACTableIdx==B_SLICE || encCABACTableIdx==P_SLICE) && slice.getPPS()->getCabacInitPresentFlag() )
{
sliceType = encCABACTableIdx;
}
m_binEncoder.reset(qp, (int) sliceType);
m_binEncoder.setBaseLevel(slice.getRiceBaseLevel());
m_binEncoder.riceStatReset(slice.getSPS()->getBitDepth(ChannelType::LUMA),
slice.getSPS()->getSpsRangeExtension().getPersistentRiceAdaptationEnabledFlag());

Karsten Suehring
committed
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
}
template <class BinProbModel>
SliceType xGetCtxInitId( const Slice& slice, const BinEncIf& binEncoder, Ctx& ctxTest )
{
const CtxStore<BinProbModel>& ctxStoreTest = static_cast<const CtxStore<BinProbModel>&>( ctxTest );
const CtxStore<BinProbModel>& ctxStoreRef = static_cast<const CtxStore<BinProbModel>&>( binEncoder.getCtx() );
int qp = slice.getSliceQp();
if( !slice.isIntra() )
{
SliceType aSliceTypeChoices[] = { B_SLICE, P_SLICE };
uint64_t bestCost = std::numeric_limits<uint64_t>::max();
SliceType bestSliceType = aSliceTypeChoices[0];
for (uint32_t idx=0; idx<2; idx++)
{
uint64_t curCost = 0;
SliceType curSliceType = aSliceTypeChoices[idx];
ctxTest.init( qp, (int)curSliceType );
for( int k = 0; k < Ctx::NumberOfContexts; k++ )
{
if( binEncoder.getNumBins(k) > 0 )
{
curCost += uint64_t( binEncoder.getNumBins(k) ) * ctxStoreRef[k].estFracExcessBits( ctxStoreTest[k] );
}
}
if (curCost < bestCost)
{
bestSliceType = curSliceType;
bestCost = curCost;
}
}
return bestSliceType;
}
else
{
return I_SLICE;
}
}
SliceType CABACWriter::getCtxInitId( const Slice& slice )
{

Karsten Suehring
committed
{
case BpmType::STD: return xGetCtxInitId<BinProbModel_Std>(slice, m_binEncoder, m_testCtx);

Karsten Suehring
committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
default: return NUMBER_OF_SLICE_TYPES;
}
}
unsigned estBits( BinEncIf& binEnc, const std::vector<bool>& bins, const Ctx& ctx, const int ctxId, const uint8_t winSize )
{
binEnc.initCtxAndWinSize( ctxId, ctx, winSize );
binEnc.start();
const std::size_t numBins = bins.size();
unsigned startBits = binEnc.getNumWrittenBits();
for( std::size_t binId = 0; binId < numBins; binId++ )
{
unsigned bin = ( bins[binId] ? 1 : 0 );
binEnc.encodeBin( bin, ctxId );
}
unsigned endBits = binEnc.getNumWrittenBits();
unsigned codedBits = endBits - startBits;
return codedBits;
}
//================================================================================
// clause 7.3.8.1
//--------------------------------------------------------------------------------
// void end_of_slice()
//================================================================================
void CABACWriter::end_of_slice()
{
m_binEncoder.encodeBinTrm(1);
m_binEncoder.finish();

Karsten Suehring
committed
}
//================================================================================
// clause 7.3.8.2
//--------------------------------------------------------------------------------
// bool coding_tree_unit( cs, area, qp, ctuRsAddr, skipSao, skipAlf )

Karsten Suehring
committed
//================================================================================
void CABACWriter::coding_tree_unit(CodingStructure &cs, const UnitArea &area, EnumArray<int, ChannelType> &qps,
unsigned ctuRsAddr, bool skipSao /* = false */, bool skipAlf /* = false */)

Karsten Suehring
committed
{

Karsten Suehring
committed
partitioner.initCtu(area, ChannelType::LUMA, *cs.slice);

Karsten Suehring
committed
if( !skipSao )
{
sao( *cs.slice, ctuRsAddr );
}

Karsten Suehring
committed
{
for (int compIdx = 0; compIdx < MAX_NUM_COMPONENT; compIdx++)
codeAlfCtuEnableFlag(cs, ctuRsAddr, compIdx, nullptr);
if (isLuma(ComponentID(compIdx)))
{
codeAlfCtuFilterIndex(cs, ctuRsAddr, cs.slice->getAlfEnabledFlag(COMPONENT_Y));
if (isChroma(ComponentID(compIdx)))
{
AlfMode *alfModes =
cs.slice->getAlfEnabledFlag((ComponentID) compIdx) ? cs.slice->getPic()->getAlfModes(compIdx) : nullptr;
if (alfModes != nullptr && alfModes[ctuRsAddr] != AlfMode::OFF)
{
codeAlfCtuAlternative( cs, ctuRsAddr, compIdx );
}
}

Karsten Suehring
committed
}
if ( !skipAlf )
{
for ( int compIdx = 1; compIdx < getNumberValidComponents( cs.pcv->chrFormat ); compIdx++ )
{
if (cs.slice->m_ccAlfFilterParam.ccAlfFilterEnabled[compIdx - 1])
{
const int filterCount = cs.slice->m_ccAlfFilterParam.ccAlfFilterCount[compIdx - 1];
const int ry = ctuRsAddr / cs.pcv->widthInCtus;
const int rx = ctuRsAddr % cs.pcv->widthInCtus;
const Position lumaPos(rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight);
codeCcAlfFilterControlIdc(cs.slice->m_ccAlfFilterControl[compIdx - 1][ctuRsAddr], cs, ComponentID(compIdx),
ctuRsAddr, cs.slice->m_ccAlfFilterControl[compIdx - 1], lumaPos, filterCount);
}
}
}
if (CS::isDualITree(cs) && isChromaEnabled(cs.pcv->chrFormat) && cs.pcv->maxCUWidth > 64)

Karsten Suehring
committed
{
CUCtx chromaCuCtx(qps[ChannelType::CHROMA]);
chromaPartitioner.initCtu(area, ChannelType::CHROMA, *cs.slice);
coding_tree(cs, partitioner, cuCtx, &chromaPartitioner, &chromaCuCtx);
qps[ChannelType::LUMA] = cuCtx.qp;
qps[ChannelType::CHROMA] = chromaCuCtx.qp;

Karsten Suehring
committed
}
else
{
if (CS::isDualITree(cs) && isChromaEnabled(cs.pcv->chrFormat))

Christian Helmrich
committed
{
CUCtx cuCtxChroma(qps[ChannelType::CHROMA]);
partitioner.initCtu(area, ChannelType::CHROMA, *cs.slice);
coding_tree(cs, partitioner, cuCtxChroma);

Christian Helmrich
committed
}

Karsten Suehring
committed
}
//================================================================================
// clause 7.3.8.3
//--------------------------------------------------------------------------------
// void sao ( slice, ctuRsAddr )
// void sao_block_params ( saoPars, bitDepths, sliceEnabled, leftMergeAvail, aboveMergeAvail, onlyEstMergeInfo )
// void sao_offset_params ( ctbPars, compID, sliceEnabled, bitDepth )

Karsten Suehring
committed
//================================================================================
void CABACWriter::sao( const Slice& slice, unsigned ctuRsAddr )
{
const SPS& sps = *slice.getSPS();

Karsten Suehring
committed
{
return;
}
CodingStructure &cs = *slice.getPic()->cs;
const PreCalcValues &pcv = *cs.pcv;
const SAOBlkParam &saoCtuParams = cs.picture->getSAO()[ctuRsAddr];
const bool sliceSaoLumaFlag = slice.getSaoEnabledFlag(ChannelType::LUMA);
slice.getSaoEnabledFlag(ChannelType::CHROMA) && isChromaEnabled(sps.getChromaFormatIdc());
if (!sliceSaoLumaFlag && !sliceSaoChromaFlag)

Karsten Suehring
committed
{
return;
}
const bool sliceEnabled[3] = { sliceSaoLumaFlag, sliceSaoChromaFlag, sliceSaoChromaFlag };
const int frameWidthInCtus = pcv.widthInCtus;
const int ry = ctuRsAddr / frameWidthInCtus;
const int rx = ctuRsAddr - ry * frameWidthInCtus;
const Position pos(rx * cs.pcv->maxCUWidth, ry * cs.pcv->maxCUHeight);
const unsigned curSliceIdx = slice.getIndependentSliceIdx();
const TileIdx curTileIdx = cs.pps->getTileIdx(pos);
cs.getCURestricted(pos.offset(-(int) pcv.maxCUWidth, 0), pos, curSliceIdx, curTileIdx, ChannelType::LUMA)
!= nullptr;
cs.getCURestricted(pos.offset(0, -(int) pcv.maxCUHeight), pos, curSliceIdx, curTileIdx, ChannelType::LUMA)
!= nullptr;
sao_block_params(saoCtuParams, sps.getBitDepths(), sliceEnabled, leftMergeAvail, aboveMergeAvail, false);

Karsten Suehring
committed
}
void CABACWriter::sao_block_params(const SAOBlkParam &saoPars, const BitDepths &bitDepths, const bool *sliceEnabled,
bool leftMergeAvail, bool aboveMergeAvail, bool onlyEstMergeInfo)

Karsten Suehring
committed
{
bool isLeftMerge = false;
bool isAboveMerge = false;
if( leftMergeAvail )
{
// sao_merge_left_flag
isLeftMerge = (saoPars[COMPONENT_Y].modeIdc == SAOMode::MERGE
&& saoPars[COMPONENT_Y].typeIdc.mergeType == SAOModeMergeTypes::LEFT);
m_binEncoder.encodeBin((isLeftMerge), Ctx::SaoMergeFlag());

Karsten Suehring
committed
}
if( aboveMergeAvail && !isLeftMerge )
{
// sao_merge_above_flag
isAboveMerge = (saoPars[COMPONENT_Y].modeIdc == SAOMode::MERGE
&& saoPars[COMPONENT_Y].typeIdc.mergeType == SAOModeMergeTypes::ABOVE);
m_binEncoder.encodeBin((isAboveMerge), Ctx::SaoMergeFlag());

Karsten Suehring
committed
}
if( onlyEstMergeInfo )
{
return; //only for RDO
}
if( !isLeftMerge && !isAboveMerge )
{
// explicit parameters
for( int compIdx=0; compIdx < MAX_NUM_COMPONENT; compIdx++ )
{
sao_offset_params(saoPars[compIdx], ComponentID(compIdx), sliceEnabled[compIdx],
bitDepths[toChannelType(ComponentID(compIdx))]);

Karsten Suehring
committed
}
}
}
void CABACWriter::sao_offset_params(const SAOOffset &ctbPars, ComponentID compID, bool sliceEnabled, int bitDepth)

Karsten Suehring
committed
{
if( !sliceEnabled )
{
CHECK(ctbPars.modeIdc != SAOMode::OFF, "Sao must be off, if it is disabled on slice level");

Karsten Suehring
committed
return;
}
const bool isFirstCompOfChType = ( getFirstComponentOfChannel( toChannelType(compID) ) == compID );
if( isFirstCompOfChType )
{
// sao_type_idx_luma / sao_type_idx_chroma
if (ctbPars.modeIdc == SAOMode::OFF)

Karsten Suehring
committed
{

Karsten Suehring
committed
}
else if (ctbPars.typeIdc.newType == SAOModeNewTypes::BO)

Karsten Suehring
committed
{
m_binEncoder.encodeBin(1, Ctx::SaoTypeIdx());
m_binEncoder.encodeBinEP(0);

Karsten Suehring
committed
}
else
{
CHECK(!(ctbPars.typeIdc.newType < SAOModeNewTypes::START_BO), "Unspecified error");
m_binEncoder.encodeBin(1, Ctx::SaoTypeIdx());
m_binEncoder.encodeBinEP(1);

Karsten Suehring
committed
}
}
if (ctbPars.modeIdc == SAOMode::NEW)

Karsten Suehring
committed
{
const int maxOffsetQVal = SampleAdaptiveOffset::getMaxOffsetQVal( bitDepth );
int numClasses = (ctbPars.typeIdc.newType == SAOModeNewTypes::BO ? 4 : NUM_SAO_EO_CLASSES);

Karsten Suehring
committed
int k = 0;
int offset[4];
for( int i = 0; i < numClasses; i++ )
{
if (ctbPars.typeIdc.newType != SAOModeNewTypes::BO && i == SAO_CLASS_EO_PLAIN)

Karsten Suehring
committed
{
continue;
}
int classIdx =
(ctbPars.typeIdc.newType == SAOModeNewTypes::BO ? (ctbPars.typeAuxInfo + i) % NUM_SAO_BO_CLASSES : i);

Karsten Suehring
committed
offset[k++] = ctbPars.offset[classIdx];
}
// sao_offset_abs
for( int i = 0; i < 4; i++ )
{
unsigned absOffset = ( offset[i] < 0 ? -offset[i] : offset[i] );
unary_max_eqprob( absOffset, maxOffsetQVal );
}
// band offset mode
if (ctbPars.typeIdc.newType == SAOModeNewTypes::BO)

Karsten Suehring
committed
{
// sao_offset_sign
for( int i = 0; i < 4; i++ )
{
if( offset[i] )
{

Karsten Suehring
committed
}
}
// sao_band_position
m_binEncoder.encodeBinsEP(ctbPars.typeAuxInfo, NUM_SAO_BO_CLASSES_LOG2);

Karsten Suehring
committed
}
// edge offset mode
else
{
if( isFirstCompOfChType )
{
// sao_eo_class_luma / sao_eo_class_chroma
CHECK(ctbPars.typeIdc.newType < SAOModeNewTypes::START_EO, "sao edge offset class is outside valid range");
m_binEncoder.encodeBinsEP(to_underlying(ctbPars.typeIdc.newType) - to_underlying(SAOModeNewTypes::START_EO),
NUM_SAO_EO_TYPES_LOG2);

Karsten Suehring
committed
}
}
}
}
//================================================================================
// clause 7.3.8.4
//--------------------------------------------------------------------------------
// void coding_tree ( cs, partitioner, cuCtx )
// void split_cu_flag ( split, cs, partitioner )
// void split_cu_mode_mt ( split, cs, partitioner )
//================================================================================
void CABACWriter::coding_tree(const CodingStructure& cs, Partitioner& partitioner, CUCtx& cuCtx, Partitioner* pPartitionerChroma, CUCtx* pCuCtxChroma)
{
const PPS &pps = *cs.pps;
const UnitArea &currArea = partitioner.currArea();
const CodingUnit &cu = *cs.getCU(currArea.block(partitioner.chType), partitioner.chType);

Karsten Suehring
committed
// Reset delta QP coding flag and ChromaQPAdjustemt coding flag
//Note: do not reset qg at chroma CU
if( pps.getUseDQP() && partitioner.currQgEnable() && !isChroma( partitioner.chType ) )
{
cuCtx.qgStart = true;
cuCtx.isDQPCoded = false;
}
if( cs.slice->getUseChromaQpAdj() && partitioner.currQgChromaEnable() )

Karsten Suehring
committed
{
cuCtx.isChromaQpAdjCoded = false;
}
// Reset delta QP coding flag and ChromaQPAdjustemt coding flag
if (CS::isDualITree(cs) && pPartitionerChroma != nullptr)
{
if (pps.getUseDQP() && pPartitionerChroma->currQgEnable())
{
pCuCtxChroma->qgStart = true;
pCuCtxChroma->isDQPCoded = false;
}
if (cs.slice->getUseChromaQpAdj() && pPartitionerChroma->currQgChromaEnable())

Karsten Suehring
committed
{
pCuCtxChroma->isChromaQpAdjCoded = false;
}
}
const PartSplit splitMode = CU::getSplitAtDepth( cu, partitioner.currDepth );
split_cu_mode( splitMode, cs, partitioner );
CHECK( !partitioner.canSplit( splitMode, cs ), "The chosen split mode is invalid!" );
if( splitMode != CU_DONT_SPLIT )
{
if (CS::isDualITree(cs) && pPartitionerChroma != nullptr
&& (partitioner.currArea().lwidth() >= 64 || partitioner.currArea().lheight() >= 64))
{
partitioner.splitCurrArea(CU_QUAD_SPLIT, cs);
pPartitionerChroma->splitCurrArea(CU_QUAD_SPLIT, cs);
bool beContinue = true;
bool lumaContinue = true;
bool chromaContinue = true;

Karsten Suehring
committed
while (beContinue)
{
if (partitioner.currArea().lwidth() > 64 || partitioner.currArea().lheight() > 64)

Karsten Suehring
committed
{
if (cs.picture->block(partitioner.chType).contains(partitioner.currArea().block(partitioner.chType).pos()))

Karsten Suehring
committed
{
coding_tree(cs, partitioner, cuCtx, pPartitionerChroma, pCuCtxChroma);

Karsten Suehring
committed
}
lumaContinue = partitioner.nextPart(cs);
chromaContinue = pPartitionerChroma->nextPart(cs);
CHECK(lumaContinue != chromaContinue, "luma chroma partition should be matched");
beContinue = lumaContinue;
}
else
{
// dual tree coding under 64x64 block
if (cs.picture->block(partitioner.chType).contains(partitioner.currArea().block(partitioner.chType).pos()))

Karsten Suehring
committed
{
coding_tree(cs, partitioner, cuCtx);
}
lumaContinue = partitioner.nextPart(cs);
if (cs.picture->block(pPartitionerChroma->chType)
.contains(pPartitionerChroma->currArea().block(pPartitionerChroma->chType).pos()))
{
coding_tree(cs, *pPartitionerChroma, *pCuCtxChroma);

Karsten Suehring
committed
}
chromaContinue = pPartitionerChroma->nextPart(cs);
CHECK(lumaContinue != chromaContinue, "luma chroma partition should be matched");
beContinue = lumaContinue;

Karsten Suehring
committed
}
}
partitioner.exitCurrSplit();
pPartitionerChroma->exitCurrSplit();
}
else
{
const ModeType modeTypeParent = partitioner.modeType;
const ModeType modeTypeChild = CU::getModeTypeAtDepth(cu, partitioner.currDepth);
mode_constraint(splitMode, cs, partitioner, modeTypeChild);
partitioner.modeType = modeTypeChild;
bool chromaNotSplit = modeTypeParent == MODE_TYPE_ALL && modeTypeChild == MODE_TYPE_INTRA ? true : false;
CHECK(chromaNotSplit && partitioner.chType != ChannelType::LUMA, "chType must be luma");
if (partitioner.treeType == TREE_D)
{
partitioner.treeType = chromaNotSplit ? TREE_L : TREE_D;
}

Karsten Suehring
committed
do
{
if (cs.picture->block(partitioner.chType).contains(partitioner.currArea().block(partitioner.chType).pos()))

Karsten Suehring
committed
{
coding_tree( cs, partitioner, cuCtx );
}
} while( partitioner.nextPart( cs ) );
partitioner.exitCurrSplit();
if( chromaNotSplit )
{
if (isChromaEnabled(cs.pcv->chrFormat))
{
CHECK(partitioner.chType != ChannelType::LUMA, "must be luma status");
partitioner.chType = ChannelType::CHROMA;
if (cs.picture->block(partitioner.chType).contains(partitioner.currArea().block(partitioner.chType).pos()))
{
coding_tree(cs, partitioner, cuCtx);
}
partitioner.treeType = TREE_D;
}
partitioner.modeType = modeTypeParent;

Karsten Suehring
committed
}
// Predict QP on start of quantization group
if( cuCtx.qgStart )
{
cuCtx.qgStart = false;

Karsten Suehring
committed
cuCtx.qp = CU::predictQP( cu, cuCtx.qp );
}
CHECK( cu.treeType != partitioner.treeType, "treeType mismatch" );

Karsten Suehring
committed
// coding unit
coding_unit( cu, partitioner, cuCtx );
{
DTRACE_COND( (isEncoding()), g_trace_ctx, D_QP, "[chroma CU]x=%d, y=%d, w=%d, h=%d, qp=%d\n", cu.Cb().x, cu.Cb().y, cu.Cb().width, cu.Cb().height, cu.qp );
}
else
{
DTRACE_COND((isEncoding()), g_trace_ctx, D_QP, "x=%d, y=%d, w=%d, h=%d, qp=%d\n", cu.Y().x, cu.Y().y, cu.Y().width,
cu.Y().height, cu.qp);

Karsten Suehring
committed
DTRACE_BLOCK_REC_COND( ( !isEncoding() ), cs.picture->getRecoBuf( cu ), cu, cu.predMode );
}
void CABACWriter::mode_constraint( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner, const ModeType modeType )
{
CHECK( split == CU_DONT_SPLIT, "splitMode shall not be no split" );
int val = cs.signalModeCons( split, partitioner, partitioner.modeType );
if( val == LDT_MODE_TYPE_SIGNAL )
{
CHECK( modeType == MODE_TYPE_ALL, "shall not be no constraint case" );
bool flag = modeType == MODE_TYPE_INTRA;
int ctxIdx = DeriveCtx::CtxModeConsFlag( cs, partitioner );
m_binEncoder.encodeBin(flag, Ctx::ModeConsFlag(ctxIdx));
DTRACE( g_trace_ctx, D_SYNTAX, "mode_cons_flag() flag=%d\n", flag );
}
else if( val == LDT_MODE_TYPE_INFER )
{
assert( modeType == MODE_TYPE_INTRA );
}
else
{
assert( modeType == partitioner.modeType );
}
}
void CABACWriter::split_cu_mode( const PartSplit split, const CodingStructure& cs, Partitioner& partitioner )
{
bool canNo, canQt, canBh, canBv, canTh, canTv;
partitioner.canSplit( cs, canNo, canQt, canBh, canBv, canTh, canTv );
bool canSpl[6] = { canNo, canQt, canBh, canBv, canTh, canTv };
unsigned ctxSplit = 0, ctxQtSplit = 0, ctxBttHV = 0, ctxBttH12 = 0, ctxBttV12;
DeriveCtx::CtxSplit( cs, partitioner, ctxSplit, ctxQtSplit, ctxBttHV, ctxBttH12, ctxBttV12, canSpl );
const bool canSplit = canBh || canBv || canTh || canTv || canQt;
const bool isNo = split == CU_DONT_SPLIT;
if( canNo && canSplit )
{
m_binEncoder.encodeBin(!isNo, Ctx::SplitFlag(ctxSplit));
}
DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctx=%d split=%d\n", ctxSplit, !isNo );
if( isNo )
{
return;
}
const bool canBtt = canBh || canBv || canTh || canTv;
const bool isQt = split == CU_QUAD_SPLIT;
if( canQt && canBtt )
{
m_binEncoder.encodeBin(isQt, Ctx::SplitQtFlag(ctxQtSplit));
}
DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctx=%d qt=%d\n", ctxQtSplit, isQt );
if( isQt )
{
return;
}
const bool canHor = canBh || canTh;
const bool canVer = canBv || canTv;
const bool isVer = split == CU_VERT_SPLIT || split == CU_TRIV_SPLIT;
if( canVer && canHor )
{
m_binEncoder.encodeBin(isVer, Ctx::SplitHvFlag(ctxBttHV));
}
const bool can14 = isVer ? canTv : canTh;
const bool can12 = isVer ? canBv : canBh;
const bool is12 = isVer ? ( split == CU_VERT_SPLIT ) : ( split == CU_HORZ_SPLIT );
if( can12 && can14 )
{
m_binEncoder.encodeBin(is12, Ctx::Split12Flag(isVer ? ctxBttV12 : ctxBttH12));
}
DTRACE( g_trace_ctx, D_SYNTAX, "split_cu_mode() ctxHv=%d ctx12=%d mode=%d\n", ctxBttHV, isVer ? ctxBttV12 : ctxBttH12, split );
}

Karsten Suehring
committed
//================================================================================
// clause 7.3.8.5
//--------------------------------------------------------------------------------
// void coding_unit ( cu, partitioner, cuCtx )
// void cu_skip_flag ( cu )
// void pred_mode ( cu )
// void part_mode ( cu )
// void cu_pred_data ( pus )
// void cu_lic_flag ( cu )
// void intra_luma_pred_modes ( pus )
// void intra_chroma_pred_mode ( pu )
// void cu_residual ( cu, partitioner, cuCtx )
// void rqt_root_cbf ( cu )
// void end_of_ctu ( cu, cuCtx )
//================================================================================
void CABACWriter::coding_unit( const CodingUnit& cu, Partitioner& partitioner, CUCtx& cuCtx )
{
DTRACE( g_trace_ctx, D_SYNTAX, "coding_unit() treeType=%d modeType=%d\n", cu.treeType, cu.modeType );

Karsten Suehring
committed
CodingStructure& cs = *cu.cs;
// skip flag
if ((!cs.slice->isIntra() || cs.slice->getSPS()->getIBCFlag()) && cu.Y().valid())

Karsten Suehring
committed
{
cu_skip_flag( cu );
}
// skip data
if( cu.skip )
{
CHECK( !cu.firstPU->mergeFlag, "Merge flag has to be on!" );
CHECK(cu.colorTransform, "ACT should not be enabled for skip mode");

Karsten Suehring
committed
PredictionUnit& pu = *cu.firstPU;
prediction_unit ( pu );
end_of_ctu ( cu, cuCtx );
return;
}
// prediction mode and partitioning data
pred_mode ( cu );
if (CU::isIntra(cu))
{
adaptive_color_transform(cu);
}
Yung-Hsuan Chao (Jessie)
committed
if (CU::isPLT(cu))
{
CHECK(cu.colorTransform, "ACT should not be enabled for PLT mode");
if (cu.isSepTree())
{
if (isLuma(partitioner.chType))
{
cu_palette_info(cu, COMPONENT_Y, 1, cuCtx);
}
if (isChromaEnabled(cu.chromaFormat) && partitioner.chType == ChannelType::CHROMA)
{
cu_palette_info(cu, COMPONENT_Cb, 2, cuCtx);
}
}
else
{
cu_palette_info(cu, COMPONENT_Y, getNumberValidComponents(cu.chromaFormat), cuCtx);
}
end_of_ctu(cu, cuCtx);
return;
Yung-Hsuan Chao (Jessie)
committed
}

Karsten Suehring
committed
// prediction data ( intra prediction modes / reference indexes + motion vectors )
cu_pred_data( cu );
// residual data ( coded block flags + transform coefficient levels )
cu_residual( cu, partitioner, cuCtx );
// end of cu
end_of_ctu( cu, cuCtx );
}
void CABACWriter::cu_skip_flag( const CodingUnit& cu )
{
unsigned ctxId = DeriveCtx::CtxSkipFlag( cu );
if ((cu.slice->isIntra() || cu.isConsIntra()) && cu.cs->slice->getSPS()->getIBCFlag())
if (CU::canUseIbc(cu)) // disable IBC mode larger than 64x64
m_binEncoder.encodeBin((cu.skip), Ctx::SkipFlag(ctxId));
DTRACE(g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0);
if ( !cu.cs->slice->getSPS()->getIBCFlag() && cu.lwidth() == 4 && cu.lheight() == 4 )
{
return;
}
if( !cu.cs->slice->getSPS()->getIBCFlag() && cu.isConsIntra() )
{
return;
}
m_binEncoder.encodeBin((cu.skip), Ctx::SkipFlag(ctxId));

Karsten Suehring
committed
DTRACE( g_trace_ctx, D_SYNTAX, "cu_skip_flag() ctx=%d skip=%d\n", ctxId, cu.skip ? 1 : 0 );
if (cu.skip && cu.cs->slice->getSPS()->getIBCFlag())
// disable IBC mode larger than 64x64 and disable IBC when only allowing inter mode
if ( cu.lwidth() == 4 && cu.lheight() == 4 )
{
return;
}
m_binEncoder.encodeBin(CU::isIBC(cu) ? 1 : 0, Ctx::IBCFlag(ctxidx));
DTRACE(g_trace_ctx, D_SYNTAX, "ibc() ctx=%d cu.predMode=%d\n", ctxidx, cu.predMode);

Karsten Suehring
committed
}
void CABACWriter::pred_mode( const CodingUnit& cu )
{
if (cu.cs->slice->getSPS()->getIBCFlag() && cu.chType != ChannelType::CHROMA)
if( cu.isConsInter() )
{
assert( CU::isInter( cu ) );
return;
}
if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || cu.isConsIntra() )
m_binEncoder.encodeBin(CU::isIBC(cu), Ctx::IBCFlag(ctxidx));
if (!CU::isIBC(cu) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64 && (cu.lumaSize().width * cu.lumaSize().height > 16) )
m_binEncoder.encodeBin(CU::isPLT(cu), Ctx::PLTFlag(0));
if( cu.isConsInter() )
{
return;
}
m_binEncoder.encodeBin((CU::isIntra(cu) || CU::isPLT(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
if (CU::isIntra(cu) || CU::isPLT(cu))
{
if (cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64 && (cu.lumaSize().width * cu.lumaSize().height > 16) )
m_binEncoder.encodeBin(CU::isPLT(cu), Ctx::PLTFlag(0));
if (CU::canUseIbc(cu)) // disable IBC mode larger than 64x64
m_binEncoder.encodeBin(CU::isIBC(cu), Ctx::IBCFlag(ctxidx));
if( cu.isConsInter() )
assert( CU::isInter( cu ) );
if ( cu.cs->slice->isIntra() || ( cu.lwidth() == 4 && cu.lheight() == 4 ) || cu.isConsIntra() )
if (cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64 && ( ( (!isLuma(cu.chType)) && (cu.chromaSize().width * cu.chromaSize().height > 16) ) || ((isLuma(cu.chType)) && ((cu.lumaSize().width * cu.lumaSize().height) > 16 ) ) ) && (!cu.isLocalSepTree() || isLuma(cu.chType) ) )
m_binEncoder.encodeBin((CU::isPLT(cu)), Ctx::PLTFlag(0));
m_binEncoder.encodeBin((CU::isIntra(cu) || CU::isPLT(cu)), Ctx::PredMode(DeriveCtx::CtxPredModeFlag(cu)));
if ((CU::isIntra(cu) || CU::isPLT(cu)) && cu.cs->slice->getSPS()->getPLTMode() && cu.lwidth() <= 64 && cu.lheight() <= 64 && ( ( (!isLuma(cu.chType)) && (cu.chromaSize().width * cu.chromaSize().height > 16) ) || ((isLuma(cu.chType)) && ((cu.lumaSize().width * cu.lumaSize().height) > 16 ) ) ) && (!cu.isLocalSepTree() || isLuma(cu.chType) ) )
m_binEncoder.encodeBin((CU::isPLT(cu)), Ctx::PLTFlag(0));

Karsten Suehring
committed
}
}
void CABACWriter::bdpcm_mode( const CodingUnit& cu, const ComponentID compID )
{
if (!cu.cs->sps->getBDPCMEnabledFlag())
{
return;
}
if (!CU::bdpcmAllowed(cu, compID))
{
return;
}
const BdpcmMode bdpcmMode = cu.getBdpcmMode(compID);
unsigned ctxId = isLuma(compID) ? 0 : 2;
m_binEncoder.encodeBin(bdpcmMode != BdpcmMode::NONE ? 1 : 0, Ctx::BDPCMMode(ctxId));
m_binEncoder.encodeBin(bdpcmMode != BdpcmMode::HOR ? 1 : 0, Ctx::BDPCMMode(ctxId + 1));
DTRACE(g_trace_ctx, D_SYNTAX, "bdpcm_mode(%d) x=%d, y=%d, w=%d, h=%d, bdpcm=%d\n", ChannelType::LUMA,
cu.lumaPos().x, cu.lumaPos().y, cu.lwidth(), cu.lheight(), cu.bdpcmMode);
DTRACE(g_trace_ctx, D_SYNTAX, "bdpcm_mode(%d) x=%d, y=%d, w=%d, h=%d, bdpcm=%d\n", ChannelType::CHROMA,
cu.chromaPos().x, cu.chromaPos().y, cu.chromaSize().width, cu.chromaSize().height, cu.bdpcmModeChroma);

Karsten Suehring
committed
void CABACWriter::cu_pred_data( const CodingUnit& cu )
{
if( CU::isIntra( cu ) )
{
if( cu.Y().valid() )
{
bdpcm_mode( cu, COMPONENT_Y );
}

Karsten Suehring
committed
intra_luma_pred_modes ( cu );
if( ( !cu.Y().valid() || ( !cu.isSepTree() && cu.Y().valid() ) ) && isChromaEnabled(cu.chromaFormat) )
bdpcm_mode(cu, ComponentID(ChannelType::CHROMA));

Karsten Suehring
committed
intra_chroma_pred_modes( cu );
return;
}
if (!cu.Y().valid()) // dual tree chroma CU
{
return;
}

Karsten Suehring
committed
for( auto &pu : CU::traversePUs( cu ) )
{
prediction_unit( pu );
}
imv_mode ( cu );
affine_amvr_mode( cu );
cu_bcw_flag( cu );

Karsten Suehring
committed
}
void CABACWriter::cu_bcw_flag(const CodingUnit& cu)
if(!CU::isBcwIdxCoded(cu))
CHECK(!(BCW_NUM > 1 && (BCW_NUM == 2 || (BCW_NUM & 0x01) == 1)), " !( BCW_NUM > 1 && ( BCW_NUM == 2 || ( BCW_NUM & 0x01 ) == 1 ) ) ");
const uint8_t bcwCodingIdx = (uint8_t)g_BcwCodingOrder[CU::getValidBcwIdx(cu)];
const int32_t numBcw = (cu.slice->getCheckLDC()) ? 5 : 3;
m_binEncoder.encodeBin((bcwCodingIdx == 0 ? 0 : 1), Ctx::bcwIdx(0));
if(numBcw > 2 && bcwCodingIdx != 0)
const uint32_t prefixNumBits = numBcw - 2;
uint8_t idx = 1;
for(int ui = 0; ui < prefixNumBits; ++ui)
{
if (bcwCodingIdx == idx)

Karsten Suehring
committed
DTRACE(g_trace_ctx, D_SYNTAX, "cu_bcw_flag() bcw_idx=%d\n", cu.bcwIdx ? 1 : 0);

Karsten Suehring
committed
void CABACWriter::xWriteTruncBinCode(const uint32_t symbol, const uint32_t numSymbols)
CHECKD(symbol >= numSymbols, "symbol must be less than numSymbols");
const int thresh = floorLog2(numSymbols);
const int val = 1 << thresh;
const int b = numSymbols - val;
m_binEncoder.encodeBinsEP(symbol + val - b, thresh + 1);
void CABACWriter::extend_ref_line(const PredictionUnit& pu)
{
if (!cu.Y().valid() || !CU::isIntra(cu) || !isLuma(cu.chType) || cu.bdpcmMode != BdpcmMode::NONE)
if( !cu.cs->sps->getUseMRL() )
{
return;
}
bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0);
if (isFirstLineOfCtu)
{
return;
}
int multiRefIdx = pu.multiRefIdx;
if (MRL_NUM_REF_LINES > 1)
{
m_binEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[0], Ctx::MultiRefLineIdx(0));
if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0])
{
m_binEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[1], Ctx::MultiRefLineIdx(1));
}
}
}
void CABACWriter::extend_ref_line(const CodingUnit& cu)
{
if (!cu.Y().valid() || !CU::isIntra(cu) || !isLuma(cu.chType) || cu.bdpcmMode != BdpcmMode::NONE)
if( !cu.cs->sps->getUseMRL() )
{
return;
}
const int numBlocks = CU::getNumPUs(cu);
const PredictionUnit* pu = cu.firstPU;
for (int k = 0; k < numBlocks; k++)
{
bool isFirstLineOfCtu = (((cu.block(COMPONENT_Y).y)&((cu.cs->sps)->getMaxCUWidth() - 1)) == 0);
if (isFirstLineOfCtu)
{
return;
}
int multiRefIdx = pu->multiRefIdx;
if (MRL_NUM_REF_LINES > 1)
{
m_binEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[0], Ctx::MultiRefLineIdx(0));
if (MRL_NUM_REF_LINES > 2 && multiRefIdx != MULTI_REF_LINE_IDX[0])
{
m_binEncoder.encodeBin(multiRefIdx != MULTI_REF_LINE_IDX[1], Ctx::MultiRefLineIdx(1));