-
Frank Bossen authoredFrank Bossen authored
BinDecoder.cpp 10.80 KiB
/* 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-2019, ITU/ISO/IEC
* 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 BinDecoder.cpp
* \brief Low level binary symbol writer
*/
#include "BinDecoder.h"
#include "CommonLib/Rom.h"
#if RExt__DECODER_DEBUG_BIT_STATISTICS
#include "CommonLib/CodingStatistics.h"
#endif
#include "CommonLib/dtrace_next.h"
#define CNT_OFFSET 0
template <class BinProbModel>
BinDecoderBase::BinDecoderBase( const BinProbModel* dummy )
: Ctx ( dummy )
, m_Bitstream ( 0 )
, m_Range ( 0 )
, m_Value ( 0 )
, m_bitsNeeded( 0 )
{}
void BinDecoderBase::init( InputBitstream* bitstream )
{
m_Bitstream = bitstream;
}
void BinDecoderBase::uninit()
{
m_Bitstream = 0;
}
void BinDecoderBase::start()
{
CHECK( m_Bitstream->getNumBitsUntilByteAligned(), "Bitstream is not byte aligned." );
#if RExt__DECODER_DEBUG_BIT_STATISTICS
CodingStatistics::UpdateCABACStat(STATS__CABAC_INITIALISATION, 512, 510, 0);
#endif
m_Range = 510;
m_Value = ( m_Bitstream->readByte() << 8 ) + m_Bitstream->readByte();
m_bitsNeeded = -8;
}
void BinDecoderBase::finish()
{
unsigned lastByte;
m_Bitstream->peekPreviousByte( lastByte );
CHECK( ( ( lastByte << ( 8 + m_bitsNeeded ) ) & 0xff ) != 0x80,
"No proper stop/alignment pattern at end of CABAC stream." );
}
void BinDecoderBase::reset( int qp, int initId )
{
Ctx::init( qp, initId );
start();
}
unsigned BinDecoderBase::decodeBinEP()
{
m_Value += m_Value;
if( ++m_bitsNeeded >= 0 )
{
m_Value += m_Bitstream->readByte();
m_bitsNeeded = -8;
}
unsigned bin = 0;
unsigned SR = m_Range << 7;
if( m_Value >= SR )
{
m_Value -= SR;
bin = 1;
}
#if RExt__DECODER_DEBUG_BIT_STATISTICS
CodingStatistics::IncrementStatisticEP( *ptype, 1, int(bin) );
#endif
DTRACE( g_trace_ctx, D_CABAC, "%d" " " "%d" " EP=%d \n", DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), m_Range, bin );
return bin;
}
unsigned BinDecoderBase::decodeBinsEP( unsigned numBins )
{
#if ENABLE_TRACING
int numBinsOrig = numBins;
#endif
if( m_Range == 256 )
{
return decodeAlignedBinsEP( numBins );
}
unsigned remBins = numBins;
unsigned bins = 0;
while( remBins > 8 )
{
m_Value = ( m_Value << 8 ) + ( m_Bitstream->readByte() << ( 8 + m_bitsNeeded ) );
unsigned SR = m_Range << 15;
for( int i = 0; i < 8; i++ )
{
bins += bins;
SR >>= 1;
if( m_Value >= SR )
{
bins ++;
m_Value -= SR;
}
}
remBins -= 8;
}
m_bitsNeeded += remBins;
m_Value <<= remBins;
if( m_bitsNeeded >= 0 )
{
m_Value += m_Bitstream->readByte() << m_bitsNeeded;
m_bitsNeeded -= 8;
}
unsigned SR = m_Range << ( remBins + 7 );
for ( int i = 0; i < remBins; i++ )
{
bins += bins;
SR >>= 1;
if( m_Value >= SR )
{
bins ++;
m_Value -= SR;
}
}
#if RExt__DECODER_DEBUG_BIT_STATISTICS
CodingStatistics::IncrementStatisticEP( *ptype, numBins, int(bins) );
#endif
#if ENABLE_TRACING
for( int i = 0; i < numBinsOrig; i++ )
{
DTRACE( g_trace_ctx, D_CABAC, "%d" " " "%d" " EP=%d \n", DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), m_Range, ( bins >> ( numBinsOrig - 1 - i ) ) & 1 );
}
#endif
return bins;
}
unsigned BinDecoderBase::decodeRemAbsEP( unsigned goRicePar, bool useLimitedPrefixLength, int maxLog2TrDynamicRange )
{
unsigned cutoff = COEF_REMAIN_BIN_REDUCTION;
unsigned prefix = 0;
useLimitedPrefixLength = true;
if( useLimitedPrefixLength )
{
const unsigned maxPrefix = 32 - maxLog2TrDynamicRange;
unsigned codeWord = 0;
do
{
prefix++;
codeWord = decodeBinEP();
}
while( codeWord && prefix < maxPrefix );
prefix -= 1 - codeWord;
}
else
{
while( decodeBinEP() )
{
prefix++;
}
}
unsigned length = goRicePar, offset;
if( prefix < cutoff )
{
offset = prefix << goRicePar;
}
else
{
offset = ( ( ( 1 << ( prefix - cutoff ) ) + cutoff - 1 ) << goRicePar );
if( useLimitedPrefixLength )
{
length += ( prefix == ( 32 - maxLog2TrDynamicRange ) ? maxLog2TrDynamicRange - goRicePar : prefix - COEF_REMAIN_BIN_REDUCTION );
}
else
{
length += ( prefix - cutoff );
}
}
return offset + decodeBinsEP( length );
}
unsigned BinDecoderBase::decodeBinTrm()
{
m_Range -= 2;
unsigned SR = m_Range << 7;
if( m_Value >= SR )
{
#if RExt__DECODER_DEBUG_BIT_STATISTICS
CodingStatistics::UpdateCABACStat ( STATS__CABAC_TRM_BITS, m_Range+2, 2, 1 );
CodingStatistics::IncrementStatisticEP( STATS__BYTE_ALIGNMENT_BITS, -m_bitsNeeded, 0 );
#endif
return 1;
}
else
{
#if RExt__DECODER_DEBUG_BIT_STATISTICS
CodingStatistics::UpdateCABACStat ( STATS__CABAC_TRM_BITS, m_Range+2, m_Range, 0 );
#endif
if( m_Range < 256 )
{
m_Range += m_Range;
m_Value += m_Value;
if( ++m_bitsNeeded == 0 )
{
m_Value += m_Bitstream->readByte();
m_bitsNeeded = -8;
}
}
return 0;
}
}
void BinDecoderBase::align()
{
#if RExt__DECODER_DEBUG_BIT_STATISTICS
CodingStatistics::UpdateCABACStat( STATS__CABAC_EP_BIT_ALIGNMENT, m_Range, 256, 0 );
#endif
m_Range = 256;
}
unsigned BinDecoderBase::decodeAlignedBinsEP( unsigned numBins )
{
#if ENABLE_TRACING
int numBinsOrig = numBins;
#endif
unsigned remBins = numBins;
unsigned bins = 0;
while( remBins > 0 )
{
// The MSB of m_Value is known to be 0 because range is 256. Therefore:
// > The comparison against the symbol range of 128 is simply a test on the next-most-significant bit
// > "Subtracting" the symbol range if the decoded bin is 1 simply involves clearing that bit.
// As a result, the required bins are simply the <binsToRead> next-most-significant bits of m_Value
// (m_Value is stored MSB-aligned in a 16-bit buffer - hence the shift of 15)
//
// m_Value = |0|V|V|V|V|V|V|V|V|B|B|B|B|B|B|B| (V = usable bit, B = potential buffered bit (buffer refills when m_bitsNeeded >= 0))
//
unsigned binsToRead = std::min<unsigned>( remBins, 8 ); //read bytes if able to take advantage of the system's byte-read function
unsigned binMask = ( 1 << binsToRead ) - 1;
unsigned newBins = ( m_Value >> (15 - binsToRead) ) & binMask;
bins = ( bins << binsToRead) | newBins;
m_Value = ( m_Value << binsToRead) & 0x7FFF;
remBins -= binsToRead;
m_bitsNeeded += binsToRead;
if( m_bitsNeeded >= 0 )
{
m_Value |= m_Bitstream->readByte() << m_bitsNeeded;
m_bitsNeeded -= 8;
}
}
#if RExt__DECODER_DEBUG_BIT_STATISTICS
CodingStatistics::IncrementStatisticEP( *ptype, numBins, int(bins) );
#endif
#if ENABLE_TRACING
for( int i = 0; i < numBinsOrig; i++ )
{
DTRACE( g_trace_ctx, D_CABAC, "%d" " " "%d" " " "EP=%d \n", DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), m_Range, ( bins >> ( numBinsOrig - 1 - i ) ) & 1 );
}
#endif
return bins;
}
template <class BinProbModel>
TBinDecoder<BinProbModel>::TBinDecoder()
: BinDecoderBase( static_cast<const BinProbModel*> ( nullptr ) )
, m_Ctx ( static_cast<CtxStore<BinProbModel>&>( *this ) )
{}
template <class BinProbModel>
unsigned TBinDecoder<BinProbModel>::decodeBin( unsigned ctxId )
{
BinProbModel& rcProbModel = m_Ctx[ctxId];
unsigned bin = rcProbModel.mps();
uint32_t LPS = rcProbModel.getLPS( m_Range );
DTRACE( g_trace_ctx, D_CABAC, "%d" " %d " "%d" " " "[%d:%d]" " " "%2d(MPS=%d)" " " , DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), ctxId, m_Range, m_Range-LPS, LPS, ( unsigned int )( rcProbModel.state() ), m_Value < ( ( m_Range - LPS ) << 7 ) );
//DTRACE( g_trace_ctx, D_CABAC, " %d " "%d" " " "[%d:%d]" " " "%2d(MPS=%d)" " ", DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), m_Range, m_Range - LPS, LPS, (unsigned int)( rcProbModel.state() ), m_Value < ( ( m_Range - LPS ) << 7 ) );
m_Range -= LPS;
uint32_t SR = m_Range << 7;
if( m_Value < SR )
{
#if RExt__DECODER_DEBUG_BIT_STATISTICS
CodingStatistics::UpdateCABACStat( *ptype, m_Range+LPS, m_Range, int( bin ) );
#endif
// MPS path
if( m_Range < 256 )
{
int numBits = rcProbModel.getRenormBitsRange( m_Range );
m_Range <<= numBits;
m_Value <<= numBits;
m_bitsNeeded += numBits;
if( m_bitsNeeded >= 0 )
{
m_Value += m_Bitstream->readByte() << m_bitsNeeded;
m_bitsNeeded -= 8;
}
}
}
else
{
bin = 1 - bin;
#if RExt__DECODER_DEBUG_BIT_STATISTICS
CodingStatistics::UpdateCABACStat( *ptype, m_Range+LPS, LPS, int( bin ) );
#endif
// LPS path
int numBits = rcProbModel.getRenormBitsLPS( LPS );
m_Value -= SR;
m_Value = m_Value << numBits;
m_Range = LPS << numBits;
m_bitsNeeded += numBits;
if( m_bitsNeeded >= 0 )
{
m_Value += m_Bitstream->readByte() << m_bitsNeeded;
m_bitsNeeded -= 8;
}
}
rcProbModel.update( bin );
//DTRACE_DECR_COUNTER( g_trace_ctx, D_CABAC );
DTRACE_WITHOUT_COUNT( g_trace_ctx, D_CABAC, " - " "%d" "\n", bin );
return bin;
}
template class TBinDecoder<BinProbModel_Std>;