/src/vvdec/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) 2018-2026, Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V. & The VVdeC 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 | | /** \file BitStream.cpp |
44 | | \brief class for handling bitstream |
45 | | */ |
46 | | |
47 | | #include "BitStream.h" |
48 | | |
49 | | #include <stdint.h> |
50 | | #include <vector> |
51 | | #include <string.h> |
52 | | #include <memory.h> |
53 | | |
54 | | |
55 | | namespace vvdec |
56 | | { |
57 | | |
58 | | void InputBitstream::resetToStart() |
59 | 0 | { |
60 | 0 | m_fifo_idx = 0; |
61 | 0 | m_num_held_bits = 0; |
62 | 0 | m_held_bits = 0; |
63 | | #if ENABLE_TRACING |
64 | | m_numBitsRead = 0; |
65 | | #endif |
66 | 0 | } |
67 | | |
68 | | /** |
69 | | * read uiNumberOfBits from bitstream without updating the bitstream |
70 | | * state, storing the result in ruiBits. |
71 | | * |
72 | | * If reading uiNumberOfBits would overrun the bitstream buffer, |
73 | | * the bitstream is effectively padded with sufficient zero-bits to |
74 | | * avoid the overrun. |
75 | | */ |
76 | | uint32_t InputBitstream::peekBits( uint32_t uiNumberOfBits ) |
77 | 0 | { |
78 | 0 | auto saved_fifo_idx = m_fifo_idx; |
79 | 0 | auto saved_num_held_bits = m_num_held_bits; |
80 | 0 | auto saved_held_bits = m_held_bits; |
81 | | #if ENABLE_TRACING |
82 | | auto saved_numBitsRead = m_numBitsRead; |
83 | | #endif |
84 | |
|
85 | 0 | uint32_t num_bits_to_read = std::min(uiNumberOfBits, getNumBitsLeft()); |
86 | 0 | uint32_t uiBits = read( num_bits_to_read ); |
87 | 0 | uiBits <<= (uiNumberOfBits - num_bits_to_read); |
88 | |
|
89 | 0 | m_fifo_idx = saved_fifo_idx; |
90 | 0 | m_num_held_bits = saved_num_held_bits; |
91 | 0 | m_held_bits = saved_held_bits; |
92 | | #if ENABLE_TRACING |
93 | | m_numBitsRead = saved_numBitsRead; |
94 | | #endif |
95 | 0 | return uiBits; |
96 | 0 | } |
97 | | |
98 | | |
99 | | uint32_t InputBitstream::read (uint32_t uiNumberOfBits) |
100 | 0 | { |
101 | | #if ENABLE_TRACING |
102 | | m_numBitsRead += uiNumberOfBits; |
103 | | #endif |
104 | |
|
105 | 0 | constexpr static uint64_t ONES = ~static_cast<uint64_t>( 0 ); // need to ensure 64 bits for the mask, because shift by 32 is UB for uin32_t |
106 | | |
107 | | /* NB, bits are extracted from the MSB of each byte. */ |
108 | 0 | uint32_t retval = 0; |
109 | 0 | if (uiNumberOfBits <= m_num_held_bits) |
110 | 0 | { |
111 | | /* n=1, len(H)=7: -VHH HHHH, shift_down=6, mask=0xfe |
112 | | * n=3, len(H)=7: -VVV HHHH, shift_down=4, mask=0xf8 |
113 | | */ |
114 | 0 | retval = static_cast<uint32_t>( m_held_bits >> ( m_num_held_bits - uiNumberOfBits ) ); |
115 | 0 | retval &= ~( ONES << uiNumberOfBits ); |
116 | 0 | m_num_held_bits -= uiNumberOfBits; |
117 | |
|
118 | 0 | return retval; |
119 | 0 | } |
120 | | |
121 | 0 | CHECK( uiNumberOfBits > 32, "Too many bits read" ); |
122 | |
|
123 | 0 | if( m_num_held_bits ) |
124 | 0 | { |
125 | | /* all num_held_bits will go into retval |
126 | | * => need to mask leftover bits from previous extractions |
127 | | * => align retval with top of extracted word */ |
128 | | /* n=5, len(H)=3: ---- -VVV, mask=0x07, shift_up=5-3=2, |
129 | | * n=9, len(H)=3: ---- -VVV, mask=0x07, shift_up=9-3=6 */ |
130 | 0 | uiNumberOfBits -= m_num_held_bits; |
131 | 0 | retval = static_cast<uint32_t>( m_held_bits ) & ~( ONES << m_num_held_bits ); // we can cast to 32 bits, because the held bits are the rightmost bits |
132 | 0 | retval <<= uiNumberOfBits; |
133 | 0 | } |
134 | | |
135 | | /* number of whole bytes that need to be loaded to form retval */ |
136 | | /* n=32, len(H)=0, load 4bytes, shift_down=0 |
137 | | * n=32, len(H)=1, load 4bytes, shift_down=1 |
138 | | * n=31, len(H)=1, load 4bytes, shift_down=1+1 |
139 | | * n=8, len(H)=0, load 1byte, shift_down=0 |
140 | | * n=8, len(H)=3, load 1byte, shift_down=3 |
141 | | * n=5, len(H)=1, load 1byte, shift_down=1+3 |
142 | | */ |
143 | 0 | load_next_bits( uiNumberOfBits ); |
144 | | |
145 | | /* resolve remainder bits */ |
146 | 0 | m_num_held_bits -= uiNumberOfBits; |
147 | | |
148 | | /* copy required part of m_held_bits into retval */ |
149 | 0 | retval |= static_cast<uint32_t>( m_held_bits >> m_num_held_bits ); |
150 | |
|
151 | 0 | return retval; |
152 | 0 | } |
153 | | |
154 | | uint32_t InputBitstream::readOutTrailingBits () |
155 | 0 | { |
156 | 0 | uint32_t count = 0; |
157 | 0 | while( ( getNumBitsLeft() > 0 ) && ( getNumBitsUntilByteAligned() != 0 ) ) |
158 | 0 | { |
159 | 0 | count++; |
160 | 0 | read( 1 ); |
161 | 0 | } |
162 | 0 | return count; |
163 | 0 | } |
164 | | |
165 | | /** |
166 | | Extract substream from the current bitstream. |
167 | | |
168 | | \param uiNumBits number of bits to transfer |
169 | | */ |
170 | | std::unique_ptr<InputBitstream> InputBitstream::extractSubstream( uint32_t uiNumBits ) |
171 | 0 | { |
172 | 0 | std::unique_ptr<InputBitstream> substream( new InputBitstream ); |
173 | |
|
174 | 0 | AlignedByteVec& buf = substream->getFifo(); |
175 | 0 | buf.reserve( ( uiNumBits + 7 ) / 8 + 1 ); // +1 because a zero byte might be added later |
176 | |
|
177 | 0 | const uint32_t uiNumBytes = uiNumBits / 8; // don't round up here, because the remaing bits will be copied later |
178 | 0 | if( m_num_held_bits == 0 ) |
179 | 0 | { |
180 | 0 | CHECK( m_fifo_idx + uiNumBytes > m_fifo.size(), "Exceeded FIFO size" ); |
181 | |
|
182 | 0 | std::size_t currentOutputBufferSize = buf.size(); |
183 | 0 | buf.resize( currentOutputBufferSize + uiNumBytes ); |
184 | |
|
185 | 0 | const uint32_t uiNumBytesToReadFromFifo = std::min<uint32_t>( uiNumBytes, (uint32_t) m_fifo.size() - m_fifo_idx ); |
186 | 0 | memcpy( &( buf[currentOutputBufferSize] ), &( m_fifo[m_fifo_idx] ), uiNumBytesToReadFromFifo ); |
187 | 0 | m_fifo_idx += uiNumBytesToReadFromFifo; |
188 | |
|
189 | 0 | if( uiNumBytesToReadFromFifo != uiNumBytes ) |
190 | 0 | { |
191 | 0 | memset( &( buf[currentOutputBufferSize + uiNumBytesToReadFromFifo] ), 0, uiNumBytes - uiNumBytesToReadFromFifo ); |
192 | 0 | } |
193 | 0 | } |
194 | 0 | else |
195 | 0 | { |
196 | 0 | for( uint32_t ui = 0; ui < uiNumBytes; ui++ ) |
197 | 0 | { |
198 | 0 | uint32_t uiByte = read( 8 ); |
199 | 0 | buf.push_back( uiByte ); |
200 | 0 | } |
201 | 0 | } |
202 | | |
203 | 0 | if( uiNumBits & 0x7 ) |
204 | 0 | { |
205 | 0 | uint32_t uiByte = read( uiNumBits & 0x7 ); |
206 | 0 | uiByte <<= 8 - ( uiNumBits & 0x7 ); |
207 | 0 | buf.push_back( uiByte ); |
208 | 0 | } |
209 | 0 | return substream; |
210 | 0 | } |
211 | | |
212 | | uint32_t InputBitstream::readByteAlignment() |
213 | 0 | { |
214 | 0 | uint32_t code = read( 1 ); |
215 | 0 | CHECK( code != 1, "Code is not '1'" ); |
216 | |
|
217 | 0 | uint32_t numBits = getNumBitsUntilByteAligned(); |
218 | 0 | if(numBits) |
219 | 0 | { |
220 | 0 | CHECK( numBits > getNumBitsLeft(), "More bits available than left" ); |
221 | 0 | code = read( numBits ); |
222 | 0 | CHECK( code != 0, "Code not '0'" ); |
223 | 0 | } |
224 | 0 | return numBits+1; |
225 | 0 | } |
226 | | |
227 | | } |