Coverage Report

Created: 2026-04-01 07:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/vvenc/source/Lib/CommonLib/BitStream.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
/** \file     BitStream.cpp
45
    \brief    class for handling bitstream
46
*/
47
48
#include "BitStream.h"
49
#include "dtrace_next.h"
50
51
#include <stdint.h>
52
#include <vector>
53
#include <string.h>
54
#include <memory.h>
55
56
//! \ingroup CommonLib
57
//! \{
58
59
namespace vvenc {
60
61
// ====================================================================================================================
62
// Constructor / destructor / create / destroy
63
// ====================================================================================================================
64
65
OutputBitstream::OutputBitstream()
66
0
{
67
0
  clear();
68
0
}
69
70
OutputBitstream::~OutputBitstream()
71
0
{
72
0
}
73
74
75
InputBitstream::InputBitstream()
76
0
: m_fifo()
77
0
, m_emulationPreventionByteLocation()
78
0
, m_fifo_idx(0)
79
0
, m_num_held_bits(0)
80
0
, m_held_bits(0)
81
0
, m_numBitsRead(0)
82
0
{ }
83
84
InputBitstream::InputBitstream(const InputBitstream &src)
85
0
: m_fifo(src.m_fifo)
86
0
, m_emulationPreventionByteLocation(src.m_emulationPreventionByteLocation)
87
0
, m_fifo_idx(src.m_fifo_idx)
88
0
, m_num_held_bits(src.m_num_held_bits)
89
0
, m_held_bits(src.m_held_bits)
90
0
, m_numBitsRead(src.m_numBitsRead)
91
0
{ }
92
93
// ====================================================================================================================
94
// Public member functions
95
// ====================================================================================================================
96
97
void InputBitstream::resetToStart()
98
0
{
99
0
  m_fifo_idx=0;
100
0
  m_num_held_bits=0;
101
0
  m_held_bits=0;
102
0
  m_numBitsRead=0;
103
0
}
104
105
uint8_t* OutputBitstream::getByteStream() const
106
0
{
107
0
  return (uint8_t*) &m_fifo.front();
108
0
}
109
110
uint32_t OutputBitstream::getByteStreamLength()
111
0
{
112
0
  return uint32_t(m_fifo.size());
113
0
}
114
115
void OutputBitstream::clear()
116
0
{
117
0
  m_fifo.clear();
118
0
  m_held_bits = 0;
119
0
  m_num_held_bits = 0;
120
0
}
121
122
void OutputBitstream::write   ( uint32_t uiBits, uint32_t uiNumberOfBits )
123
0
{
124
0
  CHECK( uiNumberOfBits > 32, "Number of bits is exceeds '32'" );
125
0
  CHECK( uiNumberOfBits != 32 && (uiBits & (~0u << uiNumberOfBits)) != 0, "Unsupported parameters" );
126
127
  /* any modulo 8 remainder of num_total_bits cannot be written this time,
128
   * and will be held until next time. */
129
0
  uint32_t num_total_bits = uiNumberOfBits + m_num_held_bits;
130
0
  uint32_t next_num_held_bits = num_total_bits % 8;
131
132
  /* form a byte aligned word (write_bits), by concatenating any held bits
133
   * with the new bits, discarding the bits that will form the next_held_bits.
134
   * eg: H = held bits, V = n new bits        /---- next_held_bits
135
   * len(H)=7, len(V)=1: ... ---- HHHH HHHV . 0000 0000, next_num_held_bits=0
136
   * len(H)=7, len(V)=2: ... ---- HHHH HHHV . V000 0000, next_num_held_bits=1
137
   * if total_bits < 8, the value of v_ is not used */
138
0
  uint8_t next_held_bits = uiBits << (8 - next_num_held_bits);
139
140
0
  if (!(num_total_bits >> 3))
141
0
  {
142
    /* insufficient bits accumulated to write out, append new_held_bits to
143
     * current held_bits */
144
    /* NB, this requires that v only contains 0 in bit positions {31..n} */
145
0
    m_held_bits |= next_held_bits;
146
0
    m_num_held_bits = next_num_held_bits;
147
0
    return;
148
0
  }
149
150
  /* topword serves to justify held_bits to align with the msb of uiBits */
151
0
  uint32_t topword = (uiNumberOfBits - next_num_held_bits) & ~((1 << 3) -1);
152
0
  uint32_t write_bits = (uint32_t)(((uint64_t)m_held_bits << topword) | (uiBits >> next_num_held_bits));
153
0
  switch (num_total_bits >> 3)
154
0
  {
155
0
  case 4: m_fifo.push_back(write_bits >> 24);
156
0
  case 3: m_fifo.push_back(write_bits >> 16);
157
0
  case 2: m_fifo.push_back(write_bits >> 8);
158
0
  case 1: m_fifo.push_back(write_bits);
159
0
  }
160
161
0
  DTRACE( g_trace_ctx, D_BITSTREAM, " %5d: %0X\n", (int)(m_fifo.size() - 1), m_fifo.back() );
162
0
  m_held_bits = next_held_bits;
163
0
  m_num_held_bits = next_num_held_bits;
164
0
}
165
166
void OutputBitstream::writeAlignOne()
167
0
{
168
0
  uint32_t num_bits = getNumBitsUntilByteAligned();
169
0
  write((1 << num_bits) - 1, num_bits);
170
0
  return;
171
0
}
172
173
void OutputBitstream::writeAlignZero()
174
0
{
175
0
  if (0 == m_num_held_bits)
176
0
  {
177
0
    return;
178
0
  }
179
0
  m_fifo.push_back(m_held_bits);
180
0
  m_held_bits = 0;
181
0
  m_num_held_bits = 0;
182
0
}
183
184
/**
185
 - add substream to the end of the current bitstream
186
 .
187
 \param  pcSubstream  substream to be added
188
 */
189
void OutputBitstream::addSubstream( const OutputBitstream* pcSubstream )
190
0
{
191
0
  uint32_t uiNumBits = pcSubstream->getNumberOfWrittenBits();
192
193
0
  const std::vector<uint8_t>& rbsp = pcSubstream->getFIFO();
194
0
  for (std::vector<uint8_t>::const_iterator it = rbsp.begin(); it != rbsp.end();)
195
0
  {
196
0
    write(*it++, 8);
197
0
  }
198
0
  if (uiNumBits&0x7)
199
0
  {
200
0
    write(pcSubstream->getHeldBits()>>(8-(uiNumBits&0x7)), uiNumBits&0x7);
201
0
  }
202
0
}
203
204
void OutputBitstream::writeByteAlignment()
205
0
{
206
0
  write( 1, 1);
207
0
  writeAlignZero();
208
0
}
209
210
int OutputBitstream::countStartCodeEmulations()
211
0
{
212
0
  uint32_t cnt = 0;
213
0
  std::vector<uint8_t>& rbsp   = getFIFO();
214
0
  for (std::vector<uint8_t>::iterator it = rbsp.begin(); it != rbsp.end();)
215
0
  {
216
0
    std::vector<uint8_t>::iterator found = it;
217
0
    do
218
0
    {
219
      // find the next emulated 00 00 {00,01,02,03}
220
      // NB, end()-1, prevents finding a trailing two byte sequence
221
0
      found = search_n(found, rbsp.end()-1, 2, 0);
222
0
      found++;
223
      // if not found, found == end, otherwise found = second zero byte
224
0
      if (found == rbsp.end())
225
0
      {
226
0
        break;
227
0
      }
228
0
      if (*(++found) <= 3)
229
0
      {
230
0
        break;
231
0
      }
232
0
    } while (true);
233
0
    it = found;
234
0
    if (found != rbsp.end())
235
0
    {
236
0
      cnt++;
237
0
    }
238
0
  }
239
0
  return cnt;
240
0
}
241
242
/**
243
 * read uiNumberOfBits from bitstream without updating the bitstream
244
 * state, storing the result in ruiBits.
245
 *
246
 * If reading uiNumberOfBits would overrun the bitstream buffer,
247
 * the bitstream is effectively padded with sufficient zero-bits to
248
 * avoid the overrun.
249
 */
250
void InputBitstream::pseudoRead ( uint32_t uiNumberOfBits, uint32_t& ruiBits )
251
0
{
252
0
  uint32_t saved_num_held_bits = m_num_held_bits;
253
0
  uint8_t saved_held_bits = m_held_bits;
254
0
  uint32_t saved_fifo_idx = m_fifo_idx;
255
256
0
  uint32_t num_bits_to_read = std::min(uiNumberOfBits, getNumBitsLeft());
257
0
  read(num_bits_to_read, ruiBits);
258
0
  ruiBits <<= (uiNumberOfBits - num_bits_to_read);
259
260
0
  m_fifo_idx = saved_fifo_idx;
261
0
  m_held_bits = saved_held_bits;
262
0
  m_num_held_bits = saved_num_held_bits;
263
0
}
264
265
266
void InputBitstream::read (uint32_t uiNumberOfBits, uint32_t& ruiBits)
267
0
{
268
0
  CHECK( uiNumberOfBits > 32, "Too many bits read" );
269
270
0
  m_numBitsRead += uiNumberOfBits;
271
272
  /* NB, bits are extracted from the MSB of each byte. */
273
0
  uint32_t retval = 0;
274
0
  if (uiNumberOfBits <= m_num_held_bits)
275
0
  {
276
    /* n=1, len(H)=7:   -VHH HHHH, shift_down=6, mask=0xfe
277
     * n=3, len(H)=7:   -VVV HHHH, shift_down=4, mask=0xf8
278
     */
279
0
    retval = m_held_bits >> (m_num_held_bits - uiNumberOfBits);
280
0
    retval &= ~(0xff << uiNumberOfBits);
281
0
    m_num_held_bits -= uiNumberOfBits;
282
0
    ruiBits = retval;
283
0
    return;
284
0
  }
285
286
  /* all num_held_bits will go into retval
287
   *   => need to mask leftover bits from previous extractions
288
   *   => align retval with top of extracted word */
289
  /* n=5, len(H)=3: ---- -VVV, mask=0x07, shift_up=5-3=2,
290
   * n=9, len(H)=3: ---- -VVV, mask=0x07, shift_up=9-3=6 */
291
0
  uiNumberOfBits -= m_num_held_bits;
292
0
  retval = m_held_bits & ~(0xff << m_num_held_bits);
293
0
  retval <<= uiNumberOfBits;
294
295
  /* number of whole bytes that need to be loaded to form retval */
296
  /* n=32, len(H)=0, load 4bytes, shift_down=0
297
   * n=32, len(H)=1, load 4bytes, shift_down=1
298
   * n=31, len(H)=1, load 4bytes, shift_down=1+1
299
   * n=8,  len(H)=0, load 1byte,  shift_down=0
300
   * n=8,  len(H)=3, load 1byte,  shift_down=3
301
   * n=5,  len(H)=1, load 1byte,  shift_down=1+3
302
   */
303
0
  uint32_t aligned_word = 0;
304
0
  uint32_t num_bytes_to_load = (uiNumberOfBits - 1) >> 3;
305
0
  CHECK(m_fifo_idx + num_bytes_to_load >= m_fifo.size(), "Exceeded FIFO size");
306
307
0
  switch (num_bytes_to_load)
308
0
  {
309
0
  case 3: aligned_word  = m_fifo[m_fifo_idx++] << 24;
310
0
  case 2: aligned_word |= m_fifo[m_fifo_idx++] << 16;
311
0
  case 1: aligned_word |= m_fifo[m_fifo_idx++] <<  8;
312
0
  case 0: aligned_word |= m_fifo[m_fifo_idx++];
313
0
  }
314
315
  /* resolve remainder bits */
316
0
  uint32_t next_num_held_bits = (32 - uiNumberOfBits) % 8;
317
318
  /* copy required part of aligned_word into retval */
319
0
  retval |= aligned_word >> next_num_held_bits;
320
321
  /* store held bits */
322
0
  m_num_held_bits = next_num_held_bits;
323
0
  m_held_bits = aligned_word;
324
325
0
  ruiBits = retval;
326
0
}
327
328
/**
329
 * insert the contents of the bytealigned (and flushed) bitstream src
330
 * into this at byte position pos.
331
 */
332
void OutputBitstream::insertAt(const OutputBitstream& src, uint32_t pos)
333
0
{
334
0
  CHECK(0 != src.getNumberOfWrittenBits() % 8, "Number of written bits is not a multiple of 8");
335
336
0
  std::vector<uint8_t>::iterator at = m_fifo.begin() + pos;
337
0
  m_fifo.insert(at, src.m_fifo.begin(), src.m_fifo.end());
338
0
}
339
340
uint32_t InputBitstream::readOutTrailingBits ()
341
0
{
342
0
  uint32_t count=0;
343
0
  uint32_t uiBits = 0;
344
345
0
  while ( ( getNumBitsLeft() > 0 ) && (getNumBitsUntilByteAligned()!=0) )
346
0
  {
347
0
    count++;
348
0
    read ( 1, uiBits );
349
0
  }
350
0
  return count;
351
0
}
352
353
/**
354
 Extract substream from the current bitstream.
355
356
 \param  uiNumBits    number of bits to transfer
357
 */
358
InputBitstream *InputBitstream::extractSubstream( uint32_t uiNumBits )
359
0
{
360
0
  uint32_t uiNumBytes = uiNumBits/8;
361
0
  InputBitstream *pResult = new InputBitstream;
362
363
0
  std::vector<uint8_t> &buf = pResult->getFifo();
364
0
  buf.reserve((uiNumBits+7)>>3);
365
366
0
  if (m_num_held_bits == 0)
367
0
  {
368
0
    std::size_t currentOutputBufferSize=buf.size();
369
0
    const uint32_t uiNumBytesToReadFromFifo = std::min<uint32_t>(uiNumBytes, (uint32_t)m_fifo.size() - m_fifo_idx);
370
0
    buf.resize(currentOutputBufferSize+uiNumBytes);
371
0
    memcpy(&(buf[currentOutputBufferSize]), &(m_fifo[m_fifo_idx]), uiNumBytesToReadFromFifo); m_fifo_idx+=uiNumBytesToReadFromFifo;
372
0
    if (uiNumBytesToReadFromFifo != uiNumBytes)
373
0
    {
374
0
      memset(&(buf[currentOutputBufferSize+uiNumBytesToReadFromFifo]), 0, uiNumBytes - uiNumBytesToReadFromFifo);
375
0
    }
376
0
  }
377
0
  else
378
0
  {
379
0
    for (uint32_t ui = 0; ui < uiNumBytes; ui++)
380
0
    {
381
0
      uint32_t uiByte;
382
0
      read(8, uiByte);
383
0
      buf.push_back(uiByte);
384
0
    }
385
0
  }
386
0
  if (uiNumBits&0x7)
387
0
  {
388
0
    uint32_t uiByte = 0;
389
0
    read(uiNumBits&0x7, uiByte);
390
0
    uiByte <<= 8-(uiNumBits&0x7);
391
0
    buf.push_back(uiByte);
392
0
  }
393
0
  return pResult;
394
0
}
395
396
uint32_t InputBitstream::readByteAlignment()
397
0
{
398
0
  uint32_t code = 0;
399
0
  read( 1, code );
400
0
  CHECK(code != 1, "Code is not '1'");
401
402
0
  uint32_t numBits = getNumBitsUntilByteAligned();
403
0
  if(numBits)
404
0
  {
405
0
    CHECK(numBits > getNumBitsLeft(), "More bits available than left");
406
0
    read( numBits, code );
407
0
    CHECK(code != 0, "Code not '0'");
408
0
  }
409
0
  return numBits+1;
410
0
}
411
412
} // namespace vvenc
413
414
//! \}
415