Files
UnrealEngine/Engine/Plugins/Media/ElectraUtil/Source/ElectraBase/Public/Utilities/UtilitiesMP4.h
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

195 lines
6.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreTypes.h"
#include "Containers/Array.h"
#include "Containers/UnrealString.h"
#include "Templates/SharedPointer.h"
#include "Templates/PimplPtr.h"
#include "Math/NumericLimits.h"
#include "IElectraBaseDataReader.h"
#define UE_API ELECTRABASE_API
namespace Electra
{
#if !PLATFORM_LITTLE_ENDIAN
static constexpr uint8 GetFromBigEndian(uint8 value) { return value; }
static constexpr int8 GetFromBigEndian(int8 value) { return value; }
static constexpr uint16 GetFromBigEndian(uint16 value) { return value; }
static constexpr int16 GetFromBigEndian(int16 value) { return value; }
static constexpr int32 GetFromBigEndian(int32 value) { return value; }
static constexpr uint32 GetFromBigEndian(uint32 value) { return value; }
static constexpr int64 GetFromBigEndian(int64 value) { return value; }
static constexpr uint64 GetFromBigEndian(uint64 value) { return value; }
#else
static constexpr uint16 EndianSwap(uint16 value) { return (value >> 8) | (value << 8); }
static constexpr int16 EndianSwap(int16 value) { return int16(EndianSwap(uint16(value))); }
static constexpr uint32 EndianSwap(uint32 value) { return (value << 24) | ((value & 0xff00) << 8) | ((value >> 8) & 0xff00) | (value >> 24); }
static constexpr int32 EndianSwap(int32 value) { return int32(EndianSwap(uint32(value))); }
static constexpr uint64 EndianSwap(uint64 value) { return (uint64(EndianSwap(uint32(value & 0xffffffffU))) << 32) | uint64(EndianSwap(uint32(value >> 32))); }
static constexpr int64 EndianSwap(int64 value) { return int64(EndianSwap(uint64(value)));}
static constexpr uint8 GetFromBigEndian(uint8 value) { return value; }
static constexpr int8 GetFromBigEndian(int8 value) { return value; }
static constexpr uint16 GetFromBigEndian(uint16 value) { return EndianSwap(value); }
static constexpr int16 GetFromBigEndian(int16 value) { return EndianSwap(value); }
static constexpr int32 GetFromBigEndian(int32 value) { return EndianSwap(value); }
static constexpr uint32 GetFromBigEndian(uint32 value) { return EndianSwap(value); }
static constexpr int64 GetFromBigEndian(int64 value) { return EndianSwap(value); }
static constexpr uint64 GetFromBigEndian(uint64 value) { return EndianSwap(value); }
#endif
namespace UtilitiesMP4
{
class FMP4BoxBase;
static constexpr uint32 MakeBoxAtom(const uint8 A, const uint8 B, const uint8 C, const uint8 D)
{
return (static_cast<uint32>(A) << 24) | (static_cast<uint32>(B) << 16) | (static_cast<uint32>(C) << 8) | static_cast<uint32>(D);
}
static FString GetPrintableBoxAtom(uint32 InAtom)
{
TCHAR tc[4];
tc[0] = (TCHAR) ((InAtom >> 24) & 255);
tc[1] = (TCHAR) ((InAtom >> 16) & 255);
tc[2] = (TCHAR) ((InAtom >> 8) & 255);
tc[3] = (TCHAR) ((InAtom >> 0) & 255);
for(int32 i=0;i<4; ++i)
{
tc[i] = tc[i] >= 32 && tc[i] <= 127 ? tc[i] : TCHAR(' ');
}
return FString::ConstructFromPtrSize(tc, 4);
}
static FString Printable4CC(const uint32 In4CC)
{
FString Out;
// Not so much just printable as alphanumeric.
for(uint32 i=0, Atom=In4CC; i<4; ++i, Atom<<=8)
{
int32 v = Atom >> 24;
if ((v >= 'A' && v <= 'Z') || (v >= 'a' && v <= 'z') || (v >= '0' && v <= '9') || v == '_' || v == '.')
{
Out.AppendChar(v);
}
else
{
// Not alphanumeric, return it as a hex string.
return FString::Printf(TEXT("%08x"), In4CC);
}
}
return Out;
}
struct FMP4BoxInfo
{
TConstArrayView<uint8> Data;
uint8 UUID[16] {};
int64 Size = 0;
int64 Offset = 0;
uint32 Type = 0;
uint32 DataOffset = 0;
#if !UE_BUILD_SHIPPING
char Name[5]{0};
#endif
};
struct FMP4BoxData : public FMP4BoxInfo
{
TArray<uint8> DataBuffer;
};
class FMP4AtomReader
{
public:
UE_API FMP4AtomReader(const TConstArrayView<uint8>& InData);
UE_API bool ParseIntoBoxInfo(FMP4BoxInfo& OutBoxInfo, int64 InAtFileOffset);
UE_API int64 GetCurrentOffset() const;
UE_API int64 GetNumBytesRemaining() const;
UE_API const uint8* GetCurrentDataPointer() const;
UE_API void SetCurrentOffset(int64 InNewOffset);
template <typename T>
bool Read(T& OutValue)
{
T Temp = 0;
int64 NumRead = ReadData(&Temp, sizeof(T));
if (NumRead == sizeof(T))
{
OutValue = ValueFromBigEndian(Temp);
return true;
}
return false;
}
UE_API bool ReadVersionAndFlags(uint8& OutVersion, uint32& OutFlags);
UE_API bool ReadString(FString& OutString, uint16 InNumBytes);
UE_API bool ReadStringUTF8(FString& OutString, int32 InNumBytes);
UE_API bool ReadStringUTF16(FString& OutString, int32 InNumBytes);
UE_API bool ReadBytes(void* OutBuffer, int32 InNumBytes);
UE_API bool ReadAsNumber(int64& OutValue, int32 InNumBytes);
UE_API bool ReadAsNumber(uint64& OutValue, int32 InNumBytes);
UE_API bool ReadAsNumber(float& OutValue);
UE_API bool ReadAsNumber(double& OutValue);
bool SkipBytes(int32 InNumBytes)
{
return ReadData(nullptr, InNumBytes) == InNumBytes;
}
private:
template <typename T>
T ValueFromBigEndian(const T value)
{ return GetFromBigEndian(value); }
UE_API int32 ReadData(void* IntoBuffer, int32 NumBytesToRead);
const uint8* DataPtr = nullptr;
int64 DataSize = 0;
int64 CurrentOffset = 0;
};
class FMP4BoxLocatorReader
{
public:
FMP4BoxLocatorReader() = default;
UE_API ~FMP4BoxLocatorReader();
UE_API bool LocateAndReadRootBoxes(TArray<TSharedPtr<FMP4BoxData, ESPMode::ThreadSafe>>& OutBoxInfos, const TSharedPtr<IBaseDataReader, ESPMode::ThreadSafe>& InDataReader, const TArray<uint32>& InFirstBoxes, const TArray<uint32>& InStopAfterBoxes, const TArray<uint32>& InReadDataOfBoxes, IBaseDataReader::FCancellationCheckDelegate InCheckCancellationDelegate);
FString GetLastError() const
{ return LastError; }
private:
FString LastError;
int64 CurrentOffset = 0;
};
class FMP4BoxTreeParser
{
public:
UE_API bool ParseBoxTree(const TSharedPtr<FMP4BoxInfo, ESPMode::ThreadSafe>& InRootBox);
TSharedPtr<FMP4BoxBase> GetBoxTree() const
{ return BoxTree; }
private:
UE_API bool ParseBoxTreeInternal(const TWeakPtr<FMP4BoxBase>& InParent, const FMP4BoxInfo& InBox);
TSharedPtr<FMP4BoxBase> BoxTree;
};
} // namespace UtilitiesMP4
class IFileDataReader : public IBaseDataReader
{
public:
static ELECTRABASE_API TSharedPtr<IFileDataReader, ESPMode::ThreadSafe> Create();
virtual ~IFileDataReader() = default;
virtual bool Open(const FString& InFilename) = 0;
};
} // namespace Electra
#undef UE_API