// 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(A) << 24) | (static_cast(B) << 16) | (static_cast(C) << 8) | static_cast(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 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 DataBuffer; }; class FMP4AtomReader { public: UE_API FMP4AtomReader(const TConstArrayView& 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 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 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>& OutBoxInfos, const TSharedPtr& InDataReader, const TArray& InFirstBoxes, const TArray& InStopAfterBoxes, const TArray& InReadDataOfBoxes, IBaseDataReader::FCancellationCheckDelegate InCheckCancellationDelegate); FString GetLastError() const { return LastError; } private: FString LastError; int64 CurrentOffset = 0; }; class FMP4BoxTreeParser { public: UE_API bool ParseBoxTree(const TSharedPtr& InRootBox); TSharedPtr GetBoxTree() const { return BoxTree; } private: UE_API bool ParseBoxTreeInternal(const TWeakPtr& InParent, const FMP4BoxInfo& InBox); TSharedPtr BoxTree; }; } // namespace UtilitiesMP4 class IFileDataReader : public IBaseDataReader { public: static ELECTRABASE_API TSharedPtr Create(); virtual ~IFileDataReader() = default; virtual bool Open(const FString& InFilename) = 0; }; } // namespace Electra #undef UE_API