xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/d3d12/d3d12_video_encoder_bitstream.cpp (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1 /*
2  * Copyright © Microsoft Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include <climits>
25 #include "d3d12_video_encoder_bitstream.h"
26 
d3d12_video_encoder_bitstream()27 d3d12_video_encoder_bitstream::d3d12_video_encoder_bitstream()
28 {
29    m_pBitsBuffer = nullptr;
30    m_uiBitsBufferSize = 0;
31    m_uiOffset = 0;
32    m_iBitsToGo = 32;
33    m_uintEncBuffer = 0;
34    m_bExternalBuffer = false;
35    m_bBufferOverflow = false;
36    m_bPreventStartCode = false;
37    m_bAllowReallocate = false;
38 }
39 
~d3d12_video_encoder_bitstream()40 d3d12_video_encoder_bitstream::~d3d12_video_encoder_bitstream()
41 {
42    if (!m_bExternalBuffer) {
43       if (m_pBitsBuffer) {
44          delete[] (m_pBitsBuffer);
45          (m_pBitsBuffer) = NULL;
46       }
47    }
48 }
49 
50 int32_t
get_exp_golomb0_code_len(uint32_t uiVal)51 d3d12_video_encoder_bitstream::get_exp_golomb0_code_len(uint32_t uiVal)
52 {
53    int32_t iLen = 0;
54    uiVal++;
55 
56    if (uiVal >= 0x10000) {
57       uiVal >>= 16;
58       iLen += 16;
59    }
60    if (uiVal >= 0x100) {
61       uiVal >>= 8;
62       iLen += 8;
63    }
64 
65    assert(uiVal < 256);
66 
67    return iLen + m_iLog_2_N[uiVal];
68 }
69 
70 void
exp_Golomb_ue(uint32_t uiVal)71 d3d12_video_encoder_bitstream::exp_Golomb_ue(uint32_t uiVal)
72 {
73    if (uiVal != UINT32_MAX) {
74       int32_t iLen = get_exp_golomb0_code_len(uiVal);
75       put_bits((iLen << 1) + 1, uiVal + 1);
76    } else {
77       put_bits(32, 0);
78       put_bits(1, 1);
79       put_bits(32, 1);
80    }
81 }
82 
83 void
exp_Golomb_se(int32_t iVal)84 d3d12_video_encoder_bitstream::exp_Golomb_se(int32_t iVal)
85 {
86    if (iVal > 0) {
87       exp_Golomb_ue((iVal << 1) - 1);
88    } else {
89       exp_Golomb_ue(((-iVal) << 1) - (iVal == INT_MIN));
90    }
91 }
92 
93 void
setup_bitstream(uint32_t uiInitBufferSize,uint8_t * pBuffer,size_t initial_byte_offset)94 d3d12_video_encoder_bitstream::setup_bitstream(uint32_t uiInitBufferSize, uint8_t *pBuffer, size_t initial_byte_offset)
95 {
96    m_pBitsBuffer = pBuffer;
97    m_uiBitsBufferSize = uiInitBufferSize;
98    m_uiOffset = initial_byte_offset;
99    memset(m_pBitsBuffer + initial_byte_offset, 0, m_uiBitsBufferSize - initial_byte_offset);
100    m_bExternalBuffer = true;
101    m_bAllowReallocate = false;
102 }
103 
104 bool
create_bitstream(uint32_t uiInitBufferSize)105 d3d12_video_encoder_bitstream::create_bitstream(uint32_t uiInitBufferSize)
106 {
107    assert((uiInitBufferSize) >= 4 && !(uiInitBufferSize & 3));
108 
109    m_pBitsBuffer = (uint8_t *) new uint8_t[uiInitBufferSize];
110 
111    if (nullptr == m_pBitsBuffer) {
112       return false;
113    }
114 
115    m_uiBitsBufferSize = uiInitBufferSize;
116    m_uiOffset = 0;
117    memset(m_pBitsBuffer, 0, m_uiBitsBufferSize);
118    m_bExternalBuffer = false;
119 
120    return true;
121 }
122 
123 bool
reallocate_buffer()124 d3d12_video_encoder_bitstream::reallocate_buffer()
125 {
126    uint32_t uiBufferSize = m_uiBitsBufferSize * 3 / 2;
127    uint8_t *pNewBuffer = (uint8_t *) new uint8_t[uiBufferSize];
128 
129    if (nullptr == pNewBuffer) {
130       return false;
131    }
132 
133    memcpy(pNewBuffer, m_pBitsBuffer, m_uiOffset * sizeof(uint8_t));
134    if (m_pBitsBuffer) {
135       delete[] (m_pBitsBuffer);
136       (m_pBitsBuffer) = NULL;
137    }
138    m_pBitsBuffer = pNewBuffer;
139    m_uiBitsBufferSize = uiBufferSize;
140    return true;
141 }
142 
143 bool
verify_buffer(uint32_t uiBytesToWrite)144 d3d12_video_encoder_bitstream::verify_buffer(uint32_t uiBytesToWrite)
145 {
146    if (!m_bBufferOverflow) {
147       if (m_uiOffset + uiBytesToWrite > m_uiBitsBufferSize) {
148          if (!m_bAllowReallocate || !reallocate_buffer()) {
149             m_bBufferOverflow = true;
150             return false;
151          }
152       }
153 
154       return true;
155    }
156 
157    return false;
158 }
159 
160 void
inc_current_offset(int32_t dwOffset)161 d3d12_video_encoder_bitstream::inc_current_offset(int32_t dwOffset)
162 {
163    assert(32 == m_iBitsToGo && m_uiOffset < m_uiBitsBufferSize);
164    m_uiOffset += dwOffset;
165 }
166 
167 void
get_current_buffer_position_and_size(uint8_t ** ppCurrBufPos,int32_t * pdwLeftBufSize)168 d3d12_video_encoder_bitstream::get_current_buffer_position_and_size(uint8_t **ppCurrBufPos, int32_t *pdwLeftBufSize)
169 {
170    assert(32 == m_iBitsToGo && m_uiOffset < m_uiBitsBufferSize);
171    *ppCurrBufPos = m_pBitsBuffer + m_uiOffset;
172    *pdwLeftBufSize = m_uiBitsBufferSize - m_uiOffset;
173 }
174 
175 void
attach(uint8_t * pBitsBuffer,uint32_t uiBufferSize)176 d3d12_video_encoder_bitstream::attach(uint8_t *pBitsBuffer, uint32_t uiBufferSize)
177 {
178    m_pBitsBuffer = pBitsBuffer;
179    m_uiBitsBufferSize = uiBufferSize;
180    m_bExternalBuffer = true;
181    m_bBufferOverflow = false;
182    m_bAllowReallocate = false;
183 
184    clear();
185 }
186 
187 void
write_byte_start_code_prevention(uint8_t u8Val)188 d3d12_video_encoder_bitstream::write_byte_start_code_prevention(uint8_t u8Val)
189 {
190    int32_t iOffset = m_uiOffset;
191    uint8_t *pBuffer = m_pBitsBuffer + iOffset;
192 
193    if (m_bPreventStartCode && iOffset > 1) {
194       if (((u8Val & 0xfc) | pBuffer[-2] | pBuffer[-1]) == 0) {
195          *pBuffer++ = 3;
196          iOffset++;
197       }
198    }
199 
200    *pBuffer = u8Val;
201    iOffset++;
202 
203    m_uiOffset = iOffset;
204 }
205 
206 #define WRITE_BYTE(byte) write_byte_start_code_prevention(byte)
207 
208 void
put_bits(int32_t uiBitsCount,uint32_t iBitsVal)209 d3d12_video_encoder_bitstream::put_bits(int32_t uiBitsCount, uint32_t iBitsVal)
210 {
211    assert(uiBitsCount > 0);
212    assert(uiBitsCount <= 32);
213 
214    if (uiBitsCount < m_iBitsToGo) {
215       m_uintEncBuffer |= (iBitsVal << (m_iBitsToGo - uiBitsCount));
216       m_iBitsToGo -= uiBitsCount;
217    } else if (verify_buffer(4)) {
218       int32_t iLeftOverBits = uiBitsCount - m_iBitsToGo;
219       m_uintEncBuffer |= (iBitsVal >> iLeftOverBits);
220 
221       uint8_t *temp = (uint8_t *) (&m_uintEncBuffer);
222       WRITE_BYTE(*(temp + 3));
223       WRITE_BYTE(*(temp + 2));
224       WRITE_BYTE(*(temp + 1));
225       WRITE_BYTE(*temp);
226 
227       m_uintEncBuffer = 0;
228       m_iBitsToGo = 32 - iLeftOverBits;
229 
230       if (iLeftOverBits > 0) {
231          m_uintEncBuffer = (iBitsVal << (32 - iLeftOverBits));
232       }
233    }
234 }
235 
236 void
flush()237 d3d12_video_encoder_bitstream::flush()
238 {
239    ASSERTED bool isAligned = is_byte_aligned();   // causes side-effects in object state, don't put inside assert()
240    assert(isAligned);
241 
242    uint32_t temp = (uint32_t) (32 - m_iBitsToGo);
243 
244    if (!verify_buffer(temp >> 3)) {
245       return;
246    }
247 
248    while (temp > 0) {
249       WRITE_BYTE((uint8_t) (m_uintEncBuffer >> 24));
250       m_uintEncBuffer <<= 8;
251       temp -= 8;
252    }
253 
254    m_iBitsToGo = 32;
255    m_uintEncBuffer = 0;
256 }
257 
258 void
append_byte_stream(d3d12_video_encoder_bitstream * pStream)259 d3d12_video_encoder_bitstream::append_byte_stream(d3d12_video_encoder_bitstream *pStream)
260 {
261    ASSERTED bool isStreamAligned =
262       pStream->is_byte_aligned();   // causes side-effects in object state, don't put inside assert()
263    assert(isStreamAligned);
264    ASSERTED bool isThisAligned = is_byte_aligned();   // causes side-effects in object state, don't put inside assert()
265    assert(isThisAligned);
266    assert(m_iBitsToGo == 32);
267 
268    uint8_t *pDst = m_pBitsBuffer + m_uiOffset;
269    uint8_t *pSrc = pStream->get_bitstream_buffer();
270    uint32_t uiLen = (uint32_t) pStream->get_byte_count();
271 
272    if (!verify_buffer(uiLen)) {
273       return;
274    }
275 
276    memcpy(pDst, pSrc, uiLen);
277    m_uiOffset += uiLen;
278 }
279 
280 void
put_aligning_bits()281 d3d12_video_encoder_bitstream::put_aligning_bits()
282 {
283    int32_t iLeft = get_num_bits_for_byte_align();
284    if (iLeft)
285       put_bits(iLeft, 0);   // trailing_zero_bit
286 
287    ASSERTED bool isAligned = is_byte_aligned();   // causes side-effects in object state, don't put inside assert()
288    assert(isAligned);
289 }
290 
291 void
put_trailing_bits()292 d3d12_video_encoder_bitstream::put_trailing_bits()
293 {
294    // trailing_one_bit shall be equal to 1.
295    // When the syntax element trailing_one_bit is read, it is a requirement that nbBits is greater than zero.
296    put_bits(1, 1);   // trailing_one_bit
297    int32_t nbBits = get_num_bits_for_byte_align();
298    while (nbBits > 0) {
299       put_bits(1, 0);   // trailing_zero_bit
300       nbBits--;
301    }
302    ASSERTED bool isAligned = is_byte_aligned();   // causes side-effects in object state, don't put inside assert()
303    assert(isAligned);
304 }
305 
306 void
put_su_bits(uint16_t uiBitsCount,int32_t iBitsVal)307 d3d12_video_encoder_bitstream::put_su_bits(uint16_t uiBitsCount, int32_t iBitsVal)
308 {
309    put_bits(uiBitsCount, calculate_su_bits(uiBitsCount, iBitsVal));
310 }
311 
312 void
put_ns_bits(uint16_t uiBitsCount,uint32_t iBitsVal)313 d3d12_video_encoder_bitstream::put_ns_bits(uint16_t uiBitsCount, uint32_t iBitsVal)
314 {
315    if (uiBitsCount > 1) {
316       uint32_t width = 0;
317       uint32_t tmp = uiBitsCount;
318       while (tmp) {
319          tmp = (tmp >> 1);
320          width++;
321       }
322       uint32_t m = (1 << width) - uiBitsCount;
323       if (iBitsVal < m)
324          put_bits(width - 1, iBitsVal);
325       else
326          put_bits(width, iBitsVal + m);
327    }
328 }
329 
330 uint16_t
calculate_su_bits(uint16_t uiBitsCount,int32_t iBitsVal)331 d3d12_video_encoder_bitstream::calculate_su_bits(uint16_t uiBitsCount, int32_t iBitsVal)
332 {
333    int16_t mask_sign = 1 << (uiBitsCount - 1);
334    if (iBitsVal & mask_sign)
335       iBitsVal = iBitsVal - 2 * mask_sign;
336    return iBitsVal;
337 }
338 
339 void
put_le_bytes(size_t uiBytesCount,uint32_t iBitsVal)340 d3d12_video_encoder_bitstream::put_le_bytes(size_t uiBytesCount, uint32_t iBitsVal)
341 {
342    assert(uiBytesCount <= sizeof(iBitsVal));
343    for (size_t i = 0; i < uiBytesCount; i++) {
344       put_bits(8, static_cast<uint8_t>(iBitsVal & 0xFF));
345       iBitsVal >>= 8;
346    }
347 }
348 
349 void
put_leb128_bytes(uint64_t iBitsVal)350 d3d12_video_encoder_bitstream::put_leb128_bytes(uint64_t iBitsVal)
351 {
352    do {
353       uint8_t cur_byte = (iBitsVal & 0x7F);
354       iBitsVal >>= 7;
355       if (iBitsVal != 0)
356          cur_byte |= 0x80;
357       put_bits(8, cur_byte);
358    } while (iBitsVal != 0);
359 }
360