Files
mesa/src/gallium/drivers/d3d12/d3d12_video_encoder_bitstream.cpp
T
2023-06-27 23:16:37 +00:00

360 lines
9.3 KiB
C++
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <climits>
#include "d3d12_video_encoder_bitstream.h"
d3d12_video_encoder_bitstream::d3d12_video_encoder_bitstream()
{
m_pBitsBuffer = nullptr;
m_uiBitsBufferSize = 0;
m_uiOffset = 0;
m_iBitsToGo = 32;
m_uintEncBuffer = 0;
m_bExternalBuffer = false;
m_bBufferOverflow = false;
m_bPreventStartCode = false;
m_bAllowReallocate = false;
}
d3d12_video_encoder_bitstream::~d3d12_video_encoder_bitstream()
{
if (!m_bExternalBuffer) {
if (m_pBitsBuffer) {
delete[] (m_pBitsBuffer);
(m_pBitsBuffer) = NULL;
}
}
}
int32_t
d3d12_video_encoder_bitstream::get_exp_golomb0_code_len(uint32_t uiVal)
{
int32_t iLen = 0;
uiVal++;
if (uiVal >= 0x10000) {
uiVal >>= 16;
iLen += 16;
}
if (uiVal >= 0x100) {
uiVal >>= 8;
iLen += 8;
}
assert(uiVal < 256);
return iLen + m_iLog_2_N[uiVal];
}
void
d3d12_video_encoder_bitstream::exp_Golomb_ue(uint32_t uiVal)
{
if (uiVal != UINT32_MAX) {
int32_t iLen = get_exp_golomb0_code_len(uiVal);
put_bits((iLen << 1) + 1, uiVal + 1);
} else {
put_bits(32, 0);
put_bits(1, 1);
put_bits(32, 1);
}
}
void
d3d12_video_encoder_bitstream::exp_Golomb_se(int32_t iVal)
{
if (iVal > 0) {
exp_Golomb_ue((iVal << 1) - 1);
} else {
exp_Golomb_ue(((-iVal) << 1) - (iVal == INT_MIN));
}
}
void
d3d12_video_encoder_bitstream::setup_bitstream(uint32_t uiInitBufferSize, uint8_t *pBuffer, size_t initial_byte_offset)
{
m_pBitsBuffer = pBuffer;
m_uiBitsBufferSize = uiInitBufferSize;
m_uiOffset = initial_byte_offset;
memset(m_pBitsBuffer + initial_byte_offset, 0, m_uiBitsBufferSize - initial_byte_offset);
m_bExternalBuffer = true;
m_bAllowReallocate = false;
}
bool
d3d12_video_encoder_bitstream::create_bitstream(uint32_t uiInitBufferSize)
{
assert((uiInitBufferSize) >= 4 && !(uiInitBufferSize & 3));
m_pBitsBuffer = (uint8_t *) new uint8_t[uiInitBufferSize];
if (nullptr == m_pBitsBuffer) {
return false;
}
m_uiBitsBufferSize = uiInitBufferSize;
m_uiOffset = 0;
memset(m_pBitsBuffer, 0, m_uiBitsBufferSize);
m_bExternalBuffer = false;
return true;
}
bool
d3d12_video_encoder_bitstream::reallocate_buffer()
{
uint32_t uiBufferSize = m_uiBitsBufferSize * 3 / 2;
uint8_t *pNewBuffer = (uint8_t *) new uint8_t[uiBufferSize];
if (nullptr == pNewBuffer) {
return false;
}
memcpy(pNewBuffer, m_pBitsBuffer, m_uiOffset * sizeof(uint8_t));
if (m_pBitsBuffer) {
delete[] (m_pBitsBuffer);
(m_pBitsBuffer) = NULL;
}
m_pBitsBuffer = pNewBuffer;
m_uiBitsBufferSize = uiBufferSize;
return true;
}
bool
d3d12_video_encoder_bitstream::verify_buffer(uint32_t uiBytesToWrite)
{
if (!m_bBufferOverflow) {
if (m_uiOffset + uiBytesToWrite > m_uiBitsBufferSize) {
if (!m_bAllowReallocate || !reallocate_buffer()) {
m_bBufferOverflow = true;
return false;
}
}
return true;
}
return false;
}
void
d3d12_video_encoder_bitstream::inc_current_offset(int32_t dwOffset)
{
assert(32 == m_iBitsToGo && m_uiOffset < m_uiBitsBufferSize);
m_uiOffset += dwOffset;
}
void
d3d12_video_encoder_bitstream::get_current_buffer_position_and_size(uint8_t **ppCurrBufPos, int32_t *pdwLeftBufSize)
{
assert(32 == m_iBitsToGo && m_uiOffset < m_uiBitsBufferSize);
*ppCurrBufPos = m_pBitsBuffer + m_uiOffset;
*pdwLeftBufSize = m_uiBitsBufferSize - m_uiOffset;
}
void
d3d12_video_encoder_bitstream::attach(uint8_t *pBitsBuffer, uint32_t uiBufferSize)
{
m_pBitsBuffer = pBitsBuffer;
m_uiBitsBufferSize = uiBufferSize;
m_bExternalBuffer = true;
m_bBufferOverflow = false;
m_bAllowReallocate = false;
clear();
}
void
d3d12_video_encoder_bitstream::write_byte_start_code_prevention(uint8_t u8Val)
{
int32_t iOffset = m_uiOffset;
uint8_t *pBuffer = m_pBitsBuffer + iOffset;
if (m_bPreventStartCode && iOffset > 1) {
if (((u8Val & 0xfc) | pBuffer[-2] | pBuffer[-1]) == 0) {
*pBuffer++ = 3;
iOffset++;
}
}
*pBuffer = u8Val;
iOffset++;
m_uiOffset = iOffset;
}
#define WRITE_BYTE(byte) write_byte_start_code_prevention(byte)
void
d3d12_video_encoder_bitstream::put_bits(int32_t uiBitsCount, uint32_t iBitsVal)
{
assert(uiBitsCount > 0);
assert(uiBitsCount <= 32);
if (uiBitsCount < m_iBitsToGo) {
m_uintEncBuffer |= (iBitsVal << (m_iBitsToGo - uiBitsCount));
m_iBitsToGo -= uiBitsCount;
} else if (verify_buffer(4)) {
int32_t iLeftOverBits = uiBitsCount - m_iBitsToGo;
m_uintEncBuffer |= (iBitsVal >> iLeftOverBits);
uint8_t *temp = (uint8_t *) (&m_uintEncBuffer);
WRITE_BYTE(*(temp + 3));
WRITE_BYTE(*(temp + 2));
WRITE_BYTE(*(temp + 1));
WRITE_BYTE(*temp);
m_uintEncBuffer = 0;
m_iBitsToGo = 32 - iLeftOverBits;
if (iLeftOverBits > 0) {
m_uintEncBuffer = (iBitsVal << (32 - iLeftOverBits));
}
}
}
void
d3d12_video_encoder_bitstream::flush()
{
ASSERTED bool isAligned = is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
assert(isAligned);
uint32_t temp = (uint32_t) (32 - m_iBitsToGo);
if (!verify_buffer(temp >> 3)) {
return;
}
while (temp > 0) {
WRITE_BYTE((uint8_t) (m_uintEncBuffer >> 24));
m_uintEncBuffer <<= 8;
temp -= 8;
}
m_iBitsToGo = 32;
m_uintEncBuffer = 0;
}
void
d3d12_video_encoder_bitstream::append_byte_stream(d3d12_video_encoder_bitstream *pStream)
{
ASSERTED bool isStreamAligned =
pStream->is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
assert(isStreamAligned);
ASSERTED bool isThisAligned = is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
assert(isThisAligned);
assert(m_iBitsToGo == 32);
uint8_t *pDst = m_pBitsBuffer + m_uiOffset;
uint8_t *pSrc = pStream->get_bitstream_buffer();
uint32_t uiLen = (uint32_t) pStream->get_byte_count();
if (!verify_buffer(uiLen)) {
return;
}
memcpy(pDst, pSrc, uiLen);
m_uiOffset += uiLen;
}
void
d3d12_video_encoder_bitstream::put_aligning_bits()
{
int32_t iLeft = get_num_bits_for_byte_align();
if (iLeft)
put_bits(iLeft, 0); // trailing_zero_bit
ASSERTED bool isAligned = is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
assert(isAligned);
}
void
d3d12_video_encoder_bitstream::put_trailing_bits()
{
// trailing_one_bit shall be equal to 1.
// When the syntax element trailing_one_bit is read, it is a requirement that nbBits is greater than zero.
put_bits(1, 1); // trailing_one_bit
int32_t nbBits = get_num_bits_for_byte_align();
while (nbBits > 0) {
put_bits(1, 0); // trailing_zero_bit
nbBits--;
}
ASSERTED bool isAligned = is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
assert(isAligned);
}
void
d3d12_video_encoder_bitstream::put_su_bits(uint16_t uiBitsCount, int32_t iBitsVal)
{
put_bits(uiBitsCount, calculate_su_bits(uiBitsCount, iBitsVal));
}
void
d3d12_video_encoder_bitstream::put_ns_bits(uint16_t uiBitsCount, uint32_t iBitsVal)
{
if (uiBitsCount > 1) {
uint32_t width = 0;
uint32_t tmp = uiBitsCount;
while (tmp) {
tmp = (tmp >> 1);
width++;
}
uint32_t m = (1 << width) - uiBitsCount;
if (iBitsVal < m)
put_bits(width - 1, iBitsVal);
else
put_bits(width, iBitsVal + m);
}
}
uint16_t
d3d12_video_encoder_bitstream::calculate_su_bits(uint16_t uiBitsCount, int32_t iBitsVal)
{
int16_t mask_sign = 1 << (uiBitsCount - 1);
if (iBitsVal & mask_sign)
iBitsVal = iBitsVal - 2 * mask_sign;
return iBitsVal;
}
void
d3d12_video_encoder_bitstream::put_le_bytes(size_t uiBytesCount, uint32_t iBitsVal)
{
assert(uiBytesCount <= sizeof(iBitsVal));
for (size_t i = 0; i < uiBytesCount; i++) {
put_bits(8, static_cast<uint8_t>(iBitsVal & 0xFF));
iBitsVal >>= 8;
}
}
void
d3d12_video_encoder_bitstream::put_leb128_bytes(uint64_t iBitsVal)
{
do {
uint8_t cur_byte = (iBitsVal & 0x7F);
iBitsVal >>= 7;
if (iBitsVal != 0)
cur_byte |= 0x80;
put_bits(8, cur_byte);
} while (iBitsVal != 0);
}