Coverage Report

Created: 2026-10-28 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/vvenc/source/Lib/EncoderLib/BinEncoder.cpp
Line
Count
Source
1
/* -----------------------------------------------------------------------------
2
The copyright in this software is being made available under the Clear BSD
3
License, included below. No patent rights, trademark rights and/or 
4
other Intellectual Property Rights other than the copyrights concerning 
5
the Software are granted under this license.
6
7
The Clear BSD License
8
9
Copyright (c) 2019-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVenC Authors.
10
All rights reserved.
11
12
Redistribution and use in source and binary forms, with or without modification,
13
are permitted (subject to the limitations in the disclaimer below) provided that
14
the following conditions are met:
15
16
     * Redistributions of source code must retain the above copyright notice,
17
     this list of conditions and the following disclaimer.
18
19
     * Redistributions in binary form must reproduce the above copyright
20
     notice, this list of conditions and the following disclaimer in the
21
     documentation and/or other materials provided with the distribution.
22
23
     * Neither the name of the copyright holder nor the names of its
24
     contributors may be used to endorse or promote products derived from this
25
     software without specific prior written permission.
26
27
NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY
28
THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
29
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
31
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
32
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
36
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38
POSSIBILITY OF SUCH DAMAGE.
39
40
41
------------------------------------------------------------------------------------------- */
42
43
44
45
#include "BinEncoder.h"
46
#include "CommonLib/Rom.h"
47
#include "CommonLib/dtrace_next.h"
48
49
//! \ingroup EncoderLib
50
//! \{
51
52
namespace vvenc {
53
54
BinCounter::BinCounter()
55
5.97k
  : m_CtxBinsCodedBuffer( Ctx::NumberOfContexts )
56
5.97k
  , m_NumBinsCtx        ( m_CtxBinsCodedBuffer.data() )
57
5.97k
  , m_NumBinsEP         ( 0 )
58
5.97k
  , m_NumBinsTrm        ( 0 )
59
5.97k
{}
60
61
62
void BinCounter::reset()
63
1.49k
{
64
552k
  for( std::size_t k = 0; k < m_CtxBinsCodedBuffer.size(); k++ )
65
550k
  {
66
550k
    m_NumBinsCtx[k] = 0;
67
550k
  }
68
1.49k
  m_NumBinsEP       = 0;
69
1.49k
  m_NumBinsTrm      = 0;
70
1.49k
}
71
72
73
uint32_t BinCounter::getAll() const
74
1.49k
{
75
1.49k
  uint32_t  count = m_NumBinsEP + m_NumBinsTrm;
76
552k
  for( std::size_t k = 0; k < m_CtxBinsCodedBuffer.size(); k++ )
77
550k
  {
78
550k
    count += m_NumBinsCtx[k];
79
550k
  }
80
1.49k
  return count;
81
1.49k
}
82
83
84
85
BinEncoderBase::BinEncoderBase( const BinProbModel* dummy )
86
5.97k
  : BinEncIf          ( dummy )
87
5.97k
  , m_Bitstream       ( 0 )
88
5.97k
  , m_Low             ( 0 )
89
5.97k
  , m_Range           ( 0 )
90
5.97k
  , m_bufferedByte    ( 0 )
91
5.97k
  , m_numBufferedBytes( 0 )
92
5.97k
  , m_bitsLeft        ( 0 )
93
5.97k
{}
94
95
void BinEncoderBase::init( OutputBitstream* bitstream )
96
4.97k
{
97
4.97k
  m_Bitstream = bitstream;
98
4.97k
}
99
100
void BinEncoderBase::uninit()
101
0
{
102
0
  m_Bitstream = 0;
103
0
}
104
105
void BinEncoderBase::start()
106
1.49k
{
107
1.49k
  m_Low               = 0;
108
1.49k
  m_Range             = 510;
109
1.49k
  m_bufferedByte      = 0xff;
110
1.49k
  m_numBufferedBytes  = 0;
111
1.49k
  m_bitsLeft          = 23;
112
1.49k
  BinCounter::reset();
113
1.49k
  m_BinStore. reset();
114
1.49k
}
115
116
void BinEncoderBase::finish()
117
1.49k
{
118
1.49k
  if( m_Low >> ( 32 - m_bitsLeft ) )
119
9
  {
120
9
    m_Bitstream->write( m_bufferedByte + 1, 8 );
121
10
    while( m_numBufferedBytes > 1 )
122
1
    {
123
1
      m_Bitstream->write( 0x00, 8 );
124
1
      m_numBufferedBytes--;
125
1
    }
126
9
    m_Low -= 1 << ( 32 - m_bitsLeft );
127
9
  }
128
1.48k
  else
129
1.48k
  {
130
1.48k
    if( m_numBufferedBytes > 0 )
131
1.48k
    {
132
1.48k
      m_Bitstream->write( m_bufferedByte, 8 );
133
1.48k
    }
134
1.49k
    while( m_numBufferedBytes > 1 )
135
11
    {
136
11
      m_Bitstream->write( 0xff, 8 );
137
11
      m_numBufferedBytes--;
138
11
    }
139
1.48k
  }
140
1.49k
  m_Bitstream->write( m_Low >> 8, 24 - m_bitsLeft );
141
1.49k
}
142
143
void BinEncoderBase::restart()
144
0
{
145
0
  m_Low               = 0;
146
0
  m_Range             = 510;
147
0
  m_bufferedByte      = 0xff;
148
0
  m_numBufferedBytes  = 0;
149
0
  m_bitsLeft          = 23;
150
0
}
151
152
void BinEncoderBase::reset( int qp, int initId )
153
1.49k
{
154
1.49k
  Ctx::init( qp, initId );
155
1.49k
  start();
156
1.49k
}
157
158
void BinEncoderBase::resetBits()
159
0
{
160
0
  m_Low               = 0;
161
0
  m_bufferedByte      = 0xff;
162
0
  m_numBufferedBytes  = 0;
163
0
  m_bitsLeft          = 23;
164
0
  BinCounter::reset();
165
0
}
166
167
void BinEncoderBase::encodeBinEP( unsigned bin )
168
485
{
169
485
  DTRACE( g_trace_ctx, D_CABAC, "%d" "  " "%d" "  EP=%d \n", DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), m_Range, bin );
170
171
485
  BinCounter::addEP();
172
485
  m_Low <<= 1;
173
485
  if( bin )
174
21
  {
175
21
    m_Low += m_Range;
176
21
  }
177
485
  m_bitsLeft--;
178
485
  if( m_bitsLeft < 12 )
179
18
  {
180
18
    writeOut();
181
18
  }
182
485
}
183
184
void BinEncoderBase::encodeBinsEP( unsigned bins, unsigned numBins )
185
20.3k
{
186
104k
  for(int i = 0; i < numBins; i++)
187
83.7k
  {
188
83.7k
    DTRACE( g_trace_ctx, D_CABAC, "%d" "  " "%d" "  EP=%d \n", DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), m_Range, ( bins >> ( numBins - 1 - i ) ) & 1 );
189
83.7k
  }
190
191
20.3k
  BinCounter::addEP( numBins );
192
20.3k
  if( m_Range == 256 )
193
2.38k
  {
194
2.38k
    encodeAlignedBinsEP( bins, numBins );
195
2.38k
    return;
196
2.38k
  }
197
20.8k
  while( numBins > 8 )
198
2.83k
  {
199
2.83k
    numBins          -= 8;
200
2.83k
    unsigned pattern  = bins >> numBins;
201
2.83k
    m_Low           <<= 8;
202
2.83k
    m_Low            += m_Range * pattern;
203
2.83k
    bins             -= pattern << numBins;
204
2.83k
    m_bitsLeft       -= 8;
205
2.83k
    if( m_bitsLeft < 12 )
206
2.83k
    {
207
2.83k
      writeOut();
208
2.83k
    }
209
2.83k
  }
210
18.0k
  m_Low     <<= numBins;
211
18.0k
  m_Low      += m_Range * bins;
212
18.0k
  m_bitsLeft -= numBins;
213
18.0k
  if( m_bitsLeft < 12 )
214
5.59k
  {
215
5.59k
    writeOut();
216
5.59k
  }
217
18.0k
}
218
219
void BinEncoderBase::encodeRemAbsEP(unsigned bins, unsigned goRicePar, unsigned cutoff, int maxLog2TrDynamicRange)
220
2.98k
{
221
2.98k
  const unsigned threshold = cutoff << goRicePar;
222
2.98k
  if (bins < threshold)
223
0
  {
224
0
    const unsigned bitMask = (1 << goRicePar) - 1;
225
0
    const unsigned length = (bins >> goRicePar) + 1;
226
0
    encodeBinsEP((1 << length) - 2, length);
227
0
    encodeBinsEP(bins & bitMask, goRicePar);
228
0
  }
229
2.98k
  else 
230
2.98k
  {
231
2.98k
    const unsigned  maxPrefixLength = 32 - cutoff - maxLog2TrDynamicRange;
232
2.98k
    unsigned        prefixLength = 0;
233
2.98k
    unsigned        codeValue = (bins >> goRicePar) - cutoff;
234
2.98k
    unsigned        suffixLength;
235
2.98k
    if (codeValue >= ((1 << maxPrefixLength) - 1))
236
82
    {
237
82
      prefixLength = maxPrefixLength;
238
82
      suffixLength = maxLog2TrDynamicRange;
239
82
    }
240
2.90k
    else
241
2.90k
    {
242
21.9k
      while (codeValue > ((2 << prefixLength) - 2))
243
19.0k
      {
244
19.0k
        prefixLength++;
245
19.0k
      }
246
2.90k
      suffixLength = prefixLength + goRicePar + 1; //+1 for the separator bit
247
2.90k
    }
248
2.98k
    const unsigned totalPrefixLength = prefixLength + cutoff;
249
2.98k
    const unsigned bitMask = (1 << goRicePar) - 1;
250
2.98k
    const unsigned prefix = (1 << totalPrefixLength) - 1;
251
2.98k
    const unsigned suffix = ((codeValue - ((1 << prefixLength) - 1)) << goRicePar) | (bins & bitMask);
252
2.98k
    encodeBinsEP(prefix, totalPrefixLength); //prefix
253
2.98k
    encodeBinsEP(suffix, suffixLength); //separator, suffix, and rParam bits
254
2.98k
  }
255
2.98k
}
256
257
void BinEncoderBase::encodeBinTrm( unsigned bin )
258
1.49k
{
259
1.49k
  BinCounter::addTrm();
260
1.49k
  m_Range -= 2;
261
1.49k
  if( bin )
262
1.49k
  {
263
1.49k
    m_Low      += m_Range;
264
1.49k
    m_Low     <<= 7;
265
1.49k
    m_Range     = 2 << 7;
266
1.49k
    m_bitsLeft -= 7;
267
1.49k
  }
268
0
  else if( m_Range >= 256 )
269
0
  {
270
0
    return;
271
0
  }
272
0
  else
273
0
  {
274
0
    m_Low     <<= 1;
275
0
    m_Range   <<= 1;
276
0
    m_bitsLeft--;
277
0
  }
278
1.49k
  if( m_bitsLeft < 12 )
279
1.27k
  {
280
1.27k
    writeOut();
281
1.27k
  }
282
1.49k
}
283
284
285
void BinEncoderBase::align()
286
0
{
287
0
  m_Range = 256;
288
0
}
289
290
291
void BinEncoderBase::encodeAlignedBinsEP( unsigned bins, unsigned numBins )
292
2.38k
{
293
2.38k
  unsigned remBins = numBins;
294
5.96k
  while( remBins > 0 )
295
3.57k
  {
296
    //The process of encoding an EP bin is the same as that of coding a normal
297
    //bin where the symbol ranges for 1 and 0 are both half the range:
298
    //
299
    //  low = (low + range/2) << 1       (to encode a 1)
300
    //  low =  low            << 1       (to encode a 0)
301
    //
302
    //  i.e.
303
    //  low = (low + (bin * range/2)) << 1
304
    //
305
    //  which is equivalent to:
306
    //
307
    //  low = (low << 1) + (bin * range)
308
    //
309
    //  this can be generalised for multiple bins, producing the following expression:
310
    //
311
3.57k
    unsigned binsToCode = std::min<unsigned>( remBins, 8); //code bytes if able to take advantage of the system's byte-write function
312
3.57k
    unsigned binMask    = ( 1 << binsToCode ) - 1;
313
3.57k
    unsigned newBins    = ( bins >> ( remBins - binsToCode ) ) & binMask;
314
3.57k
    m_Low               = ( m_Low << binsToCode ) + ( newBins << 8 ); //range is known to be 256
315
3.57k
    remBins            -= binsToCode;
316
3.57k
    m_bitsLeft         -= binsToCode;
317
3.57k
    if( m_bitsLeft < 12 )
318
2.24k
    {
319
2.24k
      writeOut();
320
2.24k
    }
321
3.57k
  }
322
2.38k
}
323
324
void BinEncoderBase::writeOut()
325
36.5k
{
326
36.5k
  unsigned leadByte = m_Low >> ( 24 - m_bitsLeft );
327
36.5k
  m_bitsLeft       += 8;
328
36.5k
  m_Low            &= 0xffffffffu >> m_bitsLeft;
329
36.5k
  if( leadByte == 0xff )
330
2.22k
  {
331
2.22k
    m_numBufferedBytes++;
332
2.22k
  }
333
34.2k
  else
334
34.2k
  {
335
34.2k
    if( m_numBufferedBytes > 0 )
336
32.8k
    {
337
32.8k
      unsigned carry  = leadByte >> 8;
338
32.8k
      unsigned byte   = m_bufferedByte + carry;
339
32.8k
      m_bufferedByte  = leadByte & 0xff;
340
32.8k
      m_Bitstream->write( byte, 8 );
341
32.8k
      byte            = ( 0xff + carry ) & 0xff;
342
35.0k
      while( m_numBufferedBytes > 1 )
343
2.20k
      {
344
2.20k
        m_Bitstream->write( byte, 8 );
345
2.20k
        m_numBufferedBytes--;
346
2.20k
      }
347
32.8k
    }
348
1.49k
    else
349
1.49k
    {
350
1.49k
      m_numBufferedBytes  = 1;
351
1.49k
      m_bufferedByte      = leadByte;
352
1.49k
    }
353
34.2k
  }
354
36.5k
}
355
356
357
358
BinEncoder::BinEncoder()
359
5.97k
  : BinEncoderBase( static_cast<const BinProbModel*>    ( nullptr ) )
360
5.97k
  , m_Ctx         ( static_cast<CtxStore&>( *this   ) )
361
5.97k
{}
362
363
void BinEncoder::encodeBin( unsigned bin, unsigned ctxId )
364
406k
{
365
406k
  BinCounter::addCtx( ctxId );
366
406k
  BinProbModel& rcProbModel = m_Ctx[ctxId];
367
406k
  uint32_t      LPS         = rcProbModel.getLPS( m_Range );
368
369
//  DTRACE( g_trace_ctx, D_CABAC, "%d" " %d " "%d" "  " "[%d:%d]" "  " "%2d(MPS=%d)"  "  " "  -  " "%d" "\n", DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), ctxId, m_Range, m_Range - LPS, LPS, ( unsigned int ) ( rcProbModel.state() ), bin == rcProbModel.mps(), bin );
370
406k
  DTRACE( g_trace_ctx, D_CABAC, " %d " "%d" "  " "[%d:%d]" "  " "%2d(MPS=%d)"  "  " "  -  " "%d" "\n", DTRACE_GET_COUNTER( g_trace_ctx, D_CABAC ), m_Range, m_Range - LPS, LPS, (unsigned int)( rcProbModel.state() ), bin == rcProbModel.mps(), bin );
371
372
406k
  m_Range   -=  LPS;
373
406k
  if( bin != rcProbModel.mps() )
374
51.7k
  {
375
51.7k
    int numBits   = rcProbModel.getRenormBitsLPS( LPS );
376
51.7k
    m_bitsLeft   -= numBits;
377
51.7k
    m_Low        += m_Range;
378
51.7k
    m_Low         = m_Low << numBits;
379
51.7k
    m_Range       = LPS   << numBits;
380
51.7k
    if( m_bitsLeft < 12 )
381
11.7k
    {
382
11.7k
      writeOut();
383
11.7k
    }
384
51.7k
  }
385
354k
  else
386
354k
  {
387
354k
    if( m_Range < 256 )
388
109k
    {
389
      //int numBits   = rcProbModel.getRenormBitsRange();
390
109k
      int numBits   = 1;
391
109k
      m_bitsLeft   -= numBits;
392
109k
      m_Low       <<= numBits;
393
109k
      m_Range     <<= numBits;
394
109k
      if( m_bitsLeft < 12 )
395
12.7k
      {
396
12.7k
        writeOut();
397
12.7k
      }
398
109k
    }
399
354k
  }
400
406k
  rcProbModel.update( bin );
401
406k
  BinEncoderBase::m_BinStore.addBin( bin, ctxId );
402
406k
}
403
404
BinEncIf* BinEncoder::getTestBinEncoder() const
405
0
{
406
0
  BinEncIf* testBinEncoder = 0;
407
0
  if( m_BinStore.inUse() )
408
0
  {
409
0
    testBinEncoder = new BinEncoder();
410
0
  }
411
0
  return testBinEncoder;
412
0
}
413
414
415
416
417
418
BitEstimatorBase::BitEstimatorBase( const BinProbModel* dummy )
419
38.2k
  : BinEncIf      ( dummy )
420
38.2k
{
421
38.2k
  m_EstFracBits = 0;
422
38.2k
}
423
424
void BitEstimatorBase::encodeRemAbsEP(unsigned bins, unsigned goRicePar, unsigned cutoff, int maxLog2TrDynamicRange)
425
681k
{
426
681k
  m_EstFracBits += BinProbModelBase::estFracBitsEP( numRemAbsEPBins( bins, goRicePar, cutoff, maxLog2TrDynamicRange ) );
427
681k
}
428
429
unsigned BitEstimatorBase::numRemAbsEPBins( unsigned bins, unsigned goRicePar, unsigned cutoff, int maxLog2TrDynamicRange )
430
6.56M
{
431
6.56M
  const unsigned threshold = cutoff << goRicePar;
432
6.56M
  if (bins < threshold)
433
3.47M
  {
434
3.47M
    return (bins >> goRicePar) + 1 + goRicePar;
435
3.47M
  }
436
3.08M
  else 
437
3.08M
  {
438
3.08M
    const unsigned  maxPrefixLength = 32 - cutoff - maxLog2TrDynamicRange;
439
3.08M
    unsigned        prefixLength = 0;
440
3.08M
    unsigned        codeValue = (bins >> goRicePar) - cutoff;
441
3.08M
    unsigned        suffixLength;
442
3.08M
    if (codeValue >= ((1 << maxPrefixLength) - 1))
443
492
    {
444
492
      prefixLength = maxPrefixLength;
445
492
      suffixLength = maxLog2TrDynamicRange;
446
492
    }
447
3.08M
    else
448
3.08M
    {
449
11.8M
      while (codeValue > ((2 << prefixLength) - 2))
450
8.72M
      {
451
8.72M
        prefixLength++;
452
8.72M
      }
453
3.08M
      suffixLength = prefixLength + goRicePar + 1; //+1 for the separator bit
454
3.08M
    }
455
3.08M
    return cutoff + prefixLength + suffixLength;
456
3.08M
  }
457
6.56M
}
458
459
void BitEstimatorBase::align()
460
0
{
461
0
  static const uint64_t add   = BinProbModelBase::estFracBitsEP() - 1;
462
0
  static const uint64_t mask  = ~add;
463
0
  m_EstFracBits += add;
464
0
  m_EstFracBits &= mask;
465
0
}
466
467
468
BitEstimator::BitEstimator()
469
38.2k
  : BitEstimatorBase  ( static_cast<const BinProbModel*>    ( nullptr) )
470
38.2k
  , m_Ctx             ( static_cast<CtxStore&>              ( *this  ) )
471
38.2k
{}
472
473
} // namespace vvenc
474
475
//! \}
476