/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 | | |