Files
UnrealEngine/Engine/Plugins/Media/ElectraCodecs/Source/ElectraDecoders/Public/Utils/ElectraBitstreamReader.h
2025-05-18 13:04:45 +08:00

359 lines
6.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include <CoreMinimal.h>
#if defined(_MSC_VER)
#include <intrin.h>
#endif
namespace ElectraDecodersUtil
{
class FElectraBitstreamReader
{
public:
FElectraBitstreamReader() = default;
FElectraBitstreamReader(const void* InData, uint64 InDataSize, uint64 StartBytePosition = 0, uint32 StartBitPosition = 0)
{
SetData(InData, InDataSize, StartBytePosition, StartBitPosition);
}
FElectraBitstreamReader(const FElectraBitstreamReader& rhs)
{
Data = rhs.Data;
DataSize = rhs.DataSize;
BytePosition = rhs.BytePosition;
BitPosition = rhs.BitPosition;
}
FElectraBitstreamReader& operator = (const FElectraBitstreamReader& rhs)
{
Data = rhs.Data;
DataSize = rhs.DataSize;
BytePosition = rhs.BytePosition;
BitPosition = rhs.BitPosition;
return *this;
}
void SetData(const void* InData, uint64 InDataSize, uint64 StartBytePosition = 0, uint32 StartBitPosition = 0)
{
check(InData && InDataSize);
Data = (const uint8*)InData;
DataSize = InDataSize;
BytePosition = StartBytePosition;
BitPosition = StartBitPosition;
}
bool IsByteAligned() const
{
return (BitPosition & 7) == 0;
}
const void* GetRemainingData() const
{
return Data + BytePosition;
}
uint64 GetRemainingByteLength() const
{
return DataSize - BytePosition;
}
uint32 GetBytePosition() const
{
return BytePosition;
}
uint32 GetBitPosition() const
{
return BitPosition;
}
uint64 GetRemainingBits() const
{
return GetRemainingByteLength() * 8 - BitPosition;
}
bool GetAlignedBytes(uint8* To, uint64 nBytes)
{
check(IsByteAligned());
if (IsByteAligned() && GetRemainingByteLength() >= nBytes)
{
FMemory::Memcpy(To, GetRemainingData(), nBytes);
BytePosition += nBytes;
return true;
}
return false;
}
void SkipBytes(uint64 nBytes)
{
BytePosition += nBytes;
if (BytePosition > DataSize)
{
BytePosition = DataSize;
}
}
void SkipBits(uint64 nBits)
{
SkipBytes(nBits >> 3);
GetBits(nBits & 7);
}
uint32 GetBits(uint64 nBits)
{
if (nBits == 0)
{
return 0;
}
else if (nBits > GetRemainingBits())
{
BytePosition = DataSize;
BitPosition = 0;
return 0;
}
else
{
uint32 rv = PeekBits(nBits);
uint32 bp = BitPosition + nBits;
BytePosition += bp >> 3;
BitPosition = bp & 7;
return rv;
}
}
uint32 PeekBits(uint64 nBits)
{
checkf(nBits <= 32, TEXT("This function can return at most 32 bits!"));
if (nBits == 0)
{
return 0;
}
else if (nBits > GetRemainingBits())
{
return 0;
}
else
{
uint32 bytePos = BytePosition + (BitPosition >> 3);
uint32 bitPos = BitPosition & 7;
uint32 w;
uint64 rl = GetRemainingByteLength();
if (rl >= 4)
{
#if defined(_MSC_VER)
w = _byteswap_ulong(*(const uint32*)(Data + bytePos));
#else
w = __builtin_bswap32(*(const uint32*)(Data + bytePos));
#endif
}
else
{
if (rl == 3)
{
w = ((uint32)Data[bytePos + 0] << 24) | ((uint32)Data[bytePos + 1] << 16) | ((uint32)Data[bytePos + 2] << 8);
}
else if (rl == 2)
{
w = ((uint32)Data[bytePos + 0] << 24) | ((uint32)Data[bytePos + 1] << 16);
}
else if (rl == 1)
{
w = ((uint32)Data[bytePos + 0] << 24);
}
else
{
w = 0;
}
}
if (bitPos == 0)
{
w = w >> (32 - nBits);
return w;
}
else
{
uint32 w0 = w;
uint8 w1;
if (rl > 4)
{
w1 = *(const uint8*)(Data + bytePos + 4);
}
else
{
w1 = 0;
}
w = (w0 << bitPos) | uint32(w1 >> (8 - bitPos));
w = w >> (32 - nBits);
return w;
}
}
}
uint64 GetBits64(uint64 nBits)
{
if (nBits <= 32)
{
return GetBits(nBits);
}
else
{
uint32 upper = GetBits(nBits - 32);
uint32 lower = GetBits(32);
return (uint64(upper) << 32ULL) | uint64(lower);
}
}
private:
const uint8* Data = nullptr;
uint64 DataSize = 0;
uint64 BytePosition = 0;
uint32 BitPosition = 0;
};
struct FElectraByteReader
{
FElectraByteReader(const void* InData, int64 DataSize)
: Data((const uint8*)InData)
, NumBytesToGo(DataSize)
{ }
bool ReadByte(uint8& To)
{
if (NumBytesToGo)
{
To = *Data++;
--NumBytesToGo;
return true;
}
return false;
}
bool ReadByte(uint16& To)
{
if (NumBytesToGo >= sizeof(uint16))
{
uint16 hi = *Data++;
uint16 lo = *Data++;
NumBytesToGo -= sizeof(uint16);
To = (hi << 8) | lo;
return true;
}
return false;
}
bool ReadBytes(uint8* To, int64 num)
{
if (NumBytesToGo >= num)
{
FMemory::Memcpy(To, Data, num);
Data += num;
NumBytesToGo -= num;
return true;
}
return false;
}
int64 BytesRemaining() const
{
return NumBytesToGo;
}
private:
const uint8* Data = nullptr;
int64 NumBytesToGo = 0;
};
class FElectraBitstreamWriter
{
public:
FElectraBitstreamWriter()
{
Buffer.SetNumZeroed(256);
}
void PutBits(uint32 InValue, uint32 InNumBits)
{
check(InNumBits != 0);
check(InNumBits <= 32);
uint32 Mask = 1U << (InNumBits-1);
while(Mask)
{
PutBit((InValue & Mask) != 0 ? 1 : 0);
Mask >>= 1;
}
}
void PutBits64(uint64 InValue, uint32 InNumBits)
{
uint32 Upper = static_cast<uint32>(InValue >> 32U);
uint32 Lower = static_cast<uint32>(InValue);
if (InNumBits > 32)
{
const uint32 nb = InNumBits - 32;
PutBits(Upper, nb);
InNumBits -= nb;
}
PutBits(Lower, InNumBits);
}
void AlignToBytes(uint32 InFillBitsWith)
{
if (BitPosition)
{
do
{
PutBit(InFillBitsWith);
} while(BitPosition);
}
}
uint32 GetNumBits() const
{
return BytePosition * 8 + BitPosition;
}
uint32 GetNumBytesUsed() const
{
return (GetNumBits() + 7) / 8;
}
bool IsByteAligned() const
{
return BitPosition == 0;
}
void GetArray(TArray<uint8>& OutArray)
{
Buffer.SetNum(GetNumBytesUsed());
OutArray = MoveTemp(Buffer);
BytePosition = 0;
BitPosition = 0;
}
private:
void PutBit(uint32 InBit)
{
InBit <<= (7 - BitPosition);
check(Buffer.Num());
Buffer[BytePosition] |= (uint8)InBit;
if (++BitPosition == 8)
{
BitPosition = 0;
if (++BytePosition > (uint32)Buffer.Num())
{
Buffer.SetNumZeroed(Buffer.Num() + 256);
}
}
}
TArray<uint8> Buffer;
uint32 BytePosition = 0;
uint32 BitPosition = 0;
};
} // namespace ElectraDecodersUtil