diff --git a/CMakeLists.txt b/CMakeLists.txt index 76e7f16..5de62dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,8 @@ set(SRC_FILES adts/adtsframe.cpp adts/adtsstream.cpp aspectratio.cpp + av1/av1configuration.h + av1/av1configuration.cpp avc/avcconfiguration.cpp avc/avcinfo.cpp avi/bitmapinfoheader.cpp diff --git a/av1/av1configuration.cpp b/av1/av1configuration.cpp new file mode 100644 index 0000000..0a92a92 --- /dev/null +++ b/av1/av1configuration.cpp @@ -0,0 +1,32 @@ +#include "./av1configuration.h" + +#include "../diagnostics.h" +#include "../exceptions.h" + +#include + +using namespace std; +using namespace IoUtilities; + +namespace TagParser { + +/*! + * \class Av1Configuration + * \brief The Av1Configuration struct provides a parser for AV1 configuration found in ISOBMFF files. + */ + +/*! + * \brief Parses the AV1 configuration using the specified \a reader. + * \throws Throws TruncatedDataException() when the config size exceeds the specified \a maxSize. + * \remarks Logging/reporting parsing errors is not implemented yet. + * \todo Provide implementation + */ +void Av1Configuration::parse(BinaryReader &reader, uint64 maxSize, Diagnostics &diag) +{ + VAR_UNUSED(reader) + VAR_UNUSED(maxSize) + VAR_UNUSED(diag) + throw NotImplementedException(); +} + +} // namespace TagParser diff --git a/av1/av1configuration.h b/av1/av1configuration.h new file mode 100644 index 0000000..c79a62b --- /dev/null +++ b/av1/av1configuration.h @@ -0,0 +1,50 @@ +#ifndef TAG_PARSER_AV1CONFIGURATION_H +#define TAG_PARSER_AV1CONFIGURATION_H + +#include "../global.h" + +#include + +namespace IoUtilities { +class BinaryReader; +} + +namespace TagParser { + +class MediaFormat; +class Diagnostics; + +struct TAG_PARSER_EXPORT Av1Configuration { + Av1Configuration(); + uint64 markerAndVersion; + uint64 profileAndLevel; + byte tier; + byte highBitdepth; + byte twelveBit; + byte monochrome; + byte chromaSubsamplingX; + byte chromaSubsamplingY; + uint16 chromaSamplePosition; + + void parse(IoUtilities::BinaryReader &reader, uint64 maxSize, Diagnostics &diag); +}; + +/*! + * \brief Constructs an empty AVC configuration. + */ +inline Av1Configuration::Av1Configuration() + : markerAndVersion(0) + , profileAndLevel(0) + , tier(0) + , highBitdepth(0) + , twelveBit(0) + , monochrome(0) + , chromaSubsamplingX(0) + , chromaSubsamplingY(0) + , chromaSamplePosition(0) +{ +} + +} // namespace TagParser + +#endif // TAG_PARSER_AV1CONFIGURATION_H diff --git a/mp4/mp4ids.cpp b/mp4/mp4ids.cpp index d23e9bb..2765fee 100644 --- a/mp4/mp4ids.cpp +++ b/mp4/mp4ids.cpp @@ -69,7 +69,8 @@ MediaFormat fourccToMediaFormat(uint32 fourccId) case H264Decoder5: case H264Decoder6: return GeneralMediaFormat::Avc; - case Av1: + case Av1_IVF: + case Av1_ISOBMFF: return GeneralMediaFormat::Av1; case Divx4Decoder1: case Divx4Decoder2: diff --git a/mp4/mp4ids.h b/mp4/mp4ids.h index 6b61772..af14134 100644 --- a/mp4/mp4ids.h +++ b/mp4/mp4ids.h @@ -11,6 +11,7 @@ class MediaFormat; namespace Mp4AtomIds { enum KnownValue : uint32 { + Av1Configuration = 0x61763143, AvcConfiguration = 0x61766343, BitrateBox = 0x62747274, CleanAperature = 0x636c6170, @@ -217,7 +218,8 @@ enum KnownValue : uint32 { Avc2 = 0x61766332, /**< H.264/MPEG-4 AVC video */ Avc3 = 0x61766333, /**< H.264/MPEG-4 AVC video */ Avc4 = 0x61766334, /**< H.264/MPEG-4 AVC video */ - Av1 = 0x41563031, /**< AV1 video */ + Av1_IVF = 0x41563031, /**< AV1 video (found in IVF) */ + Av1_ISOBMFF = 0x61763031, /**< AV1 video (found in ISOBMFF) */ Blur = 0x626C7572, Bps8 = 0x38627073, BrightnessAndContrast = 0x6272636F, diff --git a/mp4/mp4track.cpp b/mp4/mp4track.cpp index d5760e7..efe71f7 100644 --- a/mp4/mp4track.cpp +++ b/mp4/mp4track.cpp @@ -4,6 +4,8 @@ #include "./mp4ids.h" #include "./mpeg4descriptor.h" +#include "../av1/av1configuration.h" + #include "../avc/avcconfiguration.h" #include "../mpegaudio/mpegaudioframe.h" @@ -1044,6 +1046,17 @@ void Mp4Track::addInfo(const AvcConfiguration &avcConfig, AbstractTrack &track) } } +/*! + * \brief Adds the information from the specified \a av1Config to the specified \a track. + * \todo Provide implementation + */ +void Mp4Track::addInfo(const Av1Configuration &av1Config, AbstractTrack &track) +{ + VAR_UNUSED(av1Config) + VAR_UNUSED(track) + throw NotImplementedException(); +} + /*! * \brief Buffers all atoms required by the makeTrack() method. * @@ -1665,6 +1678,8 @@ void Mp4Track::internalParseHeader(Diagnostics &diag) case FourccIds::Drmi: case FourccIds::Hevc1: case FourccIds::Hevc2: + case FourccIds::Av1_IVF: + case FourccIds::Av1_ISOBMFF: m_istream->seekg(6 + 2 + 16, ios_base::cur); // skip reserved bytes, data reference index, and reserved bytes (again) m_pixelSize.setWidth(reader.readUInt16BE()); m_pixelSize.setHeight(reader.readUInt16BE()); @@ -1715,6 +1730,22 @@ void Mp4Track::internalParseHeader(Diagnostics &diag) } } + // parse AV1 configuration + if (auto *const av1ConfigAtom = esDescParentAtom->childById(Mp4AtomIds::Av1Configuration, diag)) { + m_istream->seekg(av1ConfigAtom->dataOffset()); + m_av1Config = make_unique(); + try { + m_av1Config->parse(reader, av1ConfigAtom->dataSize(), diag); + addInfo(*m_av1Config, *this); + } catch (const NotImplementedException &) { + diag.emplace_back(DiagLevel::Critical, "Parsing AV1 configuration is not supported yet.", context); + } catch (const TruncatedDataException &) { + diag.emplace_back(DiagLevel::Critical, "AV1 configuration is truncated.", context); + } catch (const Failure &) { + diag.emplace_back(DiagLevel::Critical, "AV1 configuration is invalid.", context); + } + } + // parse MPEG-4 elementary stream descriptor Mp4Atom *esDescAtom = esDescParentAtom->childById(Mp4FormatExtensionIds::Mpeg4ElementaryStreamDescriptor, diag); if (!esDescAtom) { diff --git a/mp4/mp4track.h b/mp4/mp4track.h index 22a673e..f47f006 100644 --- a/mp4/mp4track.h +++ b/mp4/mp4track.h @@ -11,6 +11,7 @@ namespace TagParser { class Mp4Atom; class Mpeg4Descriptor; struct AvcConfiguration; +struct Av1Configuration; struct TrackHeaderInfo; class TAG_PARSER_EXPORT Mpeg4AudioSpecificConfig { @@ -128,6 +129,7 @@ public: uint32 sampleToChunkEntryCount() const; const Mpeg4ElementaryStreamInfo *mpeg4ElementaryStreamInfo() const; const AvcConfiguration *avcConfiguration() const; + const Av1Configuration *av1Configuration() const; // methods to parse configuration details from the track header static std::unique_ptr parseMpeg4ElementaryStreamInfo( @@ -157,6 +159,7 @@ public: void updateChunkOffset(uint32 chunkIndex, uint64 offset); static void addInfo(const AvcConfiguration &avcConfig, AbstractTrack &track); + static void addInfo(const Av1Configuration &av1Config, AbstractTrack &track); protected: void internalParseHeader(Diagnostics &diag) override; @@ -185,6 +188,7 @@ private: uint32 m_sampleToChunkEntryCount; std::unique_ptr m_esInfo; std::unique_ptr m_avcConfig; + std::unique_ptr m_av1Config; }; /*! @@ -256,6 +260,17 @@ inline const AvcConfiguration *Mp4Track::avcConfiguration() const return m_avcConfig.get(); } +/*! + * \brief Returns the AV1 configuration. + * \remarks + * - The track must be parsed before this information becomes available. + * - The track keeps ownership over the returned object. + */ +inline const Av1Configuration *Mp4Track::av1Configuration() const +{ + return m_av1Config.get(); +} + } // namespace TagParser #endif // TAG_PARSER_MP4TRACK_H