X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FMXF.h;h=6041772a08c7abbd5e6ddbc20d7f6c61b18e3ad7;hb=665b2e2e5dcf2266e636d29bcf4ef281da65117f;hp=74c64dbb6e7b8317819c9232e1881c1c28d13d37;hpb=6e23666cb6184999efc74577cfb1b524181ba5df;p=asdcplib.git diff --git a/src/MXF.h b/src/MXF.h index 74c64db..6041772 100755 --- a/src/MXF.h +++ b/src/MXF.h @@ -1,5 +1,5 @@ /* -Copyright (c) 2005-2006, John Hurst +Copyright (c) 2005-2014, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -33,69 +33,108 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _MXF_H_ #include "MXFTypes.h" +#include namespace ASDCP { namespace MXF { + class InterchangeObject; + + const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH; + + // + typedef ASDCP::MXF::InterchangeObject* (*MXFObjectFactory_t)(const Dictionary*&); + + // + void SetObjectFactory(const UL& label, MXFObjectFactory_t factory); + + // + InterchangeObject* CreateObject(const Dictionary*& Dict, const UL& label); + + // seek an open file handle to the start of the RIP KLV packet - Result_t SeekToRIP(const FileReader&); + Result_t SeekToRIP(const Kumu::FileReader&); // class RIP : public ASDCP::KLVFilePacket { ASDCP_NO_COPY_CONSTRUCT(RIP); + RIP(); public: // - class Pair { - public: - ui32_t BodySID; - ui64_t ByteOffset; - - ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); } - - inline const char* ToString(char* str_buf) const { - char intbuf[IntBufferLen]; - snprintf(str_buf, IdentBufferLen, "%-6lu: %s", BodySID, ui64sz(ByteOffset, intbuf)); - return str_buf; - } - - inline Result_t ReadFrom(ASDCP::MemIOReader& Reader) { - Result_t result = Reader.ReadUi32BE(&BodySID); + class Pair : public Kumu::IArchive + { + public: + ui32_t BodySID; + ui64_t ByteOffset; - if ( ASDCP_SUCCESS(result) ) - result = Reader.ReadUi64BE(&ByteOffset); + Pair() : BodySID(0), ByteOffset(0) {} + Pair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {} + virtual ~Pair() {} - return result; - } + ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); } - inline Result_t WriteTo(ASDCP::MemIOWriter& Writer) { - Result_t result = Writer.WriteUi32BE(BodySID); + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + Kumu::ui64Printer offset_str(ByteOffset); + snprintf(str_buf, buf_len, "%-6u: %s", BodySID, offset_str.c_str()); + return str_buf; + } - if ( ASDCP_SUCCESS(result) ) - result = Writer.WriteUi64BE(ByteOffset); + inline bool HasValue() const { return true; } + inline ui32_t ArchiveLength() const { return sizeof(ui32_t) + sizeof(ui64_t); } - return result; - } - }; + inline bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi32BE(&BodySID) ) return false; + if ( ! Reader->ReadUi64BE(&ByteOffset) ) return false; + return true; + } + + inline bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi32BE(BodySID) ) return false; + if ( ! Writer->WriteUi64BE(ByteOffset) ) return false; + return true; + } + }; + const Dictionary*& m_Dict; Array PairArray; - RIP() {} + RIP(const Dictionary*& d) : m_Dict(d) {} virtual ~RIP() {} - virtual Result_t InitFromFile(const ASDCP::FileReader& Reader); - virtual Result_t WriteToFile(ASDCP::FileWriter& Writer); + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer); + virtual Result_t GetPairBySID(ui32_t, Pair&) const; virtual void Dump(FILE* = 0); }; // class Partition : public ASDCP::KLVFilePacket - { + { ASDCP_NO_COPY_CONSTRUCT(Partition); + Partition(); + + protected: + class PacketList + { + public: + std::list m_List; + std::map m_Map; + + ~PacketList(); + void AddPacket(InterchangeObject* ThePacket); // takes ownership + Result_t GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object); + Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object); + Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list& ObjectList); + }; + + mem_ptr m_PacketList; public: + const Dictionary*& m_Dict; + ui16_t MajorVersion; ui16_t MinorVersion; ui32_t KAGSize; @@ -110,154 +149,209 @@ namespace ASDCP UL OperationalPattern; Batch
    EssenceContainers; - Partition() {} - virtual ~Partition() {} - virtual Result_t InitFromFile(const ASDCP::FileReader& Reader); - virtual Result_t WriteToFile(ASDCP::FileWriter& Writer); + Partition(const Dictionary*&); + virtual ~Partition(); + virtual void AddChildObject(InterchangeObject*); // takes ownership + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel); + virtual ui32_t ArchiveSize(); // returns the size of the archived structure virtual void Dump(FILE* = 0); }; // - class Primer : public ASDCP::KLVPacket, public ASDCP::IPrimerLookup + class Primer : public ASDCP::KLVFilePacket, public ASDCP::IPrimerLookup { class h__PrimerLookup; mem_ptr m_Lookup; + ui8_t m_LocalTag; ASDCP_NO_COPY_CONSTRUCT(Primer); + Primer(); public: // - class LocalTagEntry + class LocalTagEntry : Kumu::IArchive { public: TagValue Tag; ASDCP::UL UL; - inline const char* ToString(char* str_buf) const { - snprintf(str_buf, IdentBufferLen, "%02x %02x: ", Tag.a, Tag.b); - UL.ToString(str_buf + strlen(str_buf)); + LocalTagEntry() { Tag.a = Tag.b = 0; } + LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {} + + inline const char* EncodeString(char* str_buf, ui32_t buf_len) const { + snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b); + UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf)); return str_buf; } - inline Result_t ReadFrom(ASDCP::MemIOReader& Reader) { - Result_t result = Reader.ReadUi8(&Tag.a); - - if ( ASDCP_SUCCESS(result) ) - result = Reader.ReadUi8(&Tag.b); + inline bool HasValue() const { return UL.HasValue(); } + inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); } - if ( ASDCP_SUCCESS(result) ) - result = UL.ReadFrom(Reader); - - return result; + inline bool Unarchive(Kumu::MemIOReader* Reader) { + if ( ! Reader->ReadUi8(&Tag.a) ) return false; + if ( ! Reader->ReadUi8(&Tag.b) ) return false; + return UL.Unarchive(Reader); } - inline Result_t WriteTo(ASDCP::MemIOWriter& Writer) { - Result_t result = Writer.WriteUi8(Tag.a); - - if ( ASDCP_SUCCESS(result) ) - result = Writer.WriteUi8(Tag.b); - - if ( ASDCP_SUCCESS(result) ) - result = UL.WriteTo(Writer); - - return result; + inline bool Archive(Kumu::MemIOWriter* Writer) const { + if ( ! Writer->WriteUi8(Tag.a) ) return false; + if ( ! Writer->WriteUi8(Tag.b) ) return false; + return UL.Archive(Writer); } }; Batch LocalTagEntryBatch; + const Dictionary*& m_Dict; - Primer(); + Primer(const Dictionary*&); virtual ~Primer(); virtual void ClearTagList(); - virtual Result_t InsertTag(const ASDCP::UL& Key, ASDCP::TagValue& Tag); + virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag); virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag); virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer); virtual void Dump(FILE* = 0); }; + // wrapper object manages optional properties + template + class optional_property + { + PropertyType m_property; + bool m_has_value; + + public: + optional_property() : m_has_value(false) {} + optional_property(const PropertyType& value) : m_property(value), m_has_value(false) {} + const optional_property& operator=(const PropertyType& rhs) { this->m_property = rhs; this->m_has_value = true; return *this; } + bool operator==(const PropertyType& rhs) const { return this->m_property == rhs; } + bool operator==(const optional_property& rhs) const { return this->m_property == rhs.m_property; } + operator PropertyType&() { return this->m_property; } + void set(const PropertyType& rhs) { this->m_property = rhs; this->m_has_value = true; } + void set_has_value(bool has_value = true) { this->m_has_value = has_value; } + void reset(const PropertyType& rhs) { this->m_has_value = false; } + bool empty() const { return ! m_has_value; } + PropertyType& get() { return m_property; } + const PropertyType& const_get() const { return m_property; } + }; + // base class of all metadata objects // class InterchangeObject : public ASDCP::KLVPacket { + InterchangeObject(); + public: + const Dictionary*& m_Dict; IPrimerLookup* m_Lookup; - UID InstanceUID; - UUID GenerationUID; + UUID InstanceUID; + optional_property GenerationUID; - InterchangeObject() : m_Lookup(0) {} + InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {} virtual ~InterchangeObject() {} + + virtual void Copy(const InterchangeObject& rhs); virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); virtual bool IsA(const byte_t* label); + virtual const char* ObjectName() { return "InterchangeObject"; } virtual void Dump(FILE* stream = 0); }; // - InterchangeObject* CreateObject(const byte_t* label); - + typedef std::list InterchangeObject_list_t; // class Preface : public InterchangeObject { ASDCP_NO_COPY_CONSTRUCT(Preface); + Preface(); public: - UUID GenerationUID; - Timestamp LastModifiedDate; + const Dictionary*& m_Dict; + Kumu::Timestamp LastModifiedDate; ui16_t Version; - ui32_t ObjectModelVersion; - UID PrimaryPackage; - Batch Identifications; - UID ContentStorage; + optional_property ObjectModelVersion; + optional_property PrimaryPackage; + Batch Identifications; + UUID ContentStorage; UL OperationalPattern; Batch
      EssenceContainers; Batch
        DMSchemes; + optional_property > ApplicationSchemes; - Preface() {} + Preface(const Dictionary*& d); virtual ~Preface() {} - virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); - virtual Result_t WriteToBuffer(ASDCP::FrameBuffer& Buffer); + + virtual void Copy(const Preface& rhs); + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); virtual void Dump(FILE* = 0); }; + const ui32_t MaxIndexSegmentSize = 65536; + // class IndexTableSegment : public InterchangeObject { + IndexTableSegment(); ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment); public: // - class DeltaEntry + class DeltaEntry : public Kumu::IArchive { public: i8_t PosTableIndex; ui8_t Slice; ui32_t ElementData; - Result_t ReadFrom(ASDCP::MemIOReader& Reader); - Result_t WriteTo(ASDCP::MemIOWriter& Writer); - inline const char* ToString(char* str_buf) const; + DeltaEntry() : PosTableIndex(0), Slice(0), ElementData(0) {} + DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {} + inline bool HasValue() const { return true; } + ui32_t ArchiveLength() const { return sizeof(ui32_t) + 2; } + bool Unarchive(Kumu::MemIOReader* Reader); + bool Archive(Kumu::MemIOWriter* Writer) const; + const char* EncodeString(char* str_buf, ui32_t buf_len) const; }; // - class IndexEntry + class IndexEntry : public Kumu::IArchive { public: i8_t TemporalOffset; i8_t KeyFrameOffset; ui8_t Flags; ui64_t StreamOffset; - std::list SliceOffset; - Array PosTable; - Result_t ReadFrom(ASDCP::MemIOReader& Reader); - Result_t WriteTo(ASDCP::MemIOWriter& Writer); - inline const char* ToString(char* str_buf) const; + // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp + // to a more suitable value + // std::list SliceOffset; + // Array PosTable; + + IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {} + IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) : + TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {} + inline bool HasValue() const { return true; } + ui32_t ArchiveLength() const { return sizeof(ui64_t) + 3; }; + bool Unarchive(Kumu::MemIOReader* Reader); + bool Archive(Kumu::MemIOWriter* Writer) const; + const char* EncodeString(char* str_buf, ui32_t buf_len) const; }; + const Dictionary*& m_Dict; + ui64_t RtFileOffset; // not part of the MXF structure: used to manage runtime index access + ui64_t RtEntryOffset; + Rational IndexEditRate; ui64_t IndexStartPosition; ui64_t IndexDuration; @@ -269,59 +363,149 @@ namespace ASDCP Batch DeltaEntryArray; Batch IndexEntryArray; - IndexTableSegment(); + IndexTableSegment(const Dictionary*&); virtual ~IndexTableSegment(); + + virtual void Copy(const IndexTableSegment& rhs); + virtual Result_t InitFromTLVSet(TLVReader& TLVSet); virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); - virtual Result_t WriteToBuffer(ASDCP::FrameBuffer& Buffer); + virtual Result_t WriteToTLVSet(TLVWriter& TLVSet); + virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&); virtual void Dump(FILE* = 0); }; //--------------------------------------------------------------------------------- // - class h__PacketList; // See MXF.cpp class Identification; class SourcePackage; // - class OPAtomHeader : public Partition + class OP1aHeader : public Partition { - mem_ptr m_PacketList; - ASDCP_NO_COPY_CONSTRUCT(OPAtomHeader); + Kumu::ByteString m_HeaderData; + ASDCP_NO_COPY_CONSTRUCT(OP1aHeader); + OP1aHeader(); public: - ASDCP::MXF::RIP m_RIP; - ASDCP::MXF::Primer m_Primer; - InterchangeObject* m_Preface; - ASDCP::FrameBuffer m_Buffer; - bool m_HasRIP; - - OPAtomHeader(); - virtual ~OPAtomHeader(); - virtual Result_t InitFromFile(const ASDCP::FileReader& Reader); - virtual Result_t WriteToFile(ASDCP::FileWriter& Writer, ui32_t HeaderLength = 16384); + const Dictionary*& m_Dict; + ASDCP::MXF::Primer m_Primer; + Preface* m_Preface; + + OP1aHeader(const Dictionary*&); + virtual ~OP1aHeader(); + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384); virtual void Dump(FILE* = 0); + virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0); virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0); + virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list& ObjectList); Identification* GetIdentification(); SourcePackage* GetSourcePackage(); }; + // Searches the header object and returns the edit rate based on the contents of the + // File Package items. Logs an error message and returns false if anthing goes wrong. + bool GetEditRateFromFP(ASDCP::MXF::OP1aHeader& header, ASDCP::Rational& edit_rate); + // class OPAtomIndexFooter : public Partition { - mem_ptr m_PacketList; - ASDCP::FrameBuffer m_Buffer; + Kumu::ByteString m_FooterData; + IndexTableSegment* m_CurrentSegment; + ui32_t m_BytesPerEditUnit; + Rational m_EditRate; + ui32_t m_BodySID; + IndexTableSegment::DeltaEntry m_DefaultDeltaEntry; + ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter); + OPAtomIndexFooter(); public: - IPrimerLookup* m_Lookup; + const Dictionary*& m_Dict; + Kumu::fpos_t m_ECOffset; + IPrimerLookup* m_Lookup; - OPAtomIndexFooter(); + OPAtomIndexFooter(const Dictionary*&); virtual ~OPAtomIndexFooter(); - virtual Result_t InitFromFile(const ASDCP::FileReader& Reader); - virtual Result_t WriteToFile(ASDCP::FileWriter& Writer); + virtual Result_t InitFromFile(const Kumu::FileReader& Reader); + virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l); + virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l); + virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration); virtual void Dump(FILE* = 0); - virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&); + virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0); + virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0); + virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list& ObjectList); + + virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const; + virtual void PushIndexEntry(const IndexTableSegment::IndexEntry&); + virtual void SetDeltaParams(const IndexTableSegment::DeltaEntry&); + virtual void SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate); + virtual void SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset); + }; + + //--------------------------------------------------------------------------------- + // + + // + inline std::string to_lower(std::string str) { + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return str; + } + + // ignore case when searching for audio labels + struct ci_comp + { + inline bool operator()(const std::string& a, const std::string& b) const { + return to_lower(a) < to_lower(b); + } + }; + + struct label_traits + { + const std::string tag_name; + const bool requires_prefix; + const UL ul; + + label_traits(const std::string& tag_name, const bool requires_prefix, const UL ul) : + tag_name(tag_name), requires_prefix(requires_prefix), ul(ul) { } + }; + + typedef std::map mca_label_map_t; + + bool decode_mca_string(const std::string& s, const mca_label_map_t& labels, + const Dictionary*& dict, const std::string& language, InterchangeObject_list_t&, ui32_t&); + + // + class ASDCP_MCAConfigParser : public InterchangeObject_list_t + { + KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser); + ASDCP_MCAConfigParser(); + + protected: + mca_label_map_t m_LabelMap; + ui32_t m_ChannelCount; + const Dictionary*& m_Dict; + + + public: + ASDCP_MCAConfigParser(const Dictionary*&); + bool DecodeString(const std::string& s, const std::string& language = "en-US"); + + // Valid only after a successful call to DecodeString + ui32_t ChannelCount() const; + }; + + // + class AS02_MCAConfigParser : public ASDCP_MCAConfigParser + { + KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser); + AS02_MCAConfigParser(); + + public: + AS02_MCAConfigParser(const Dictionary*&); }; } // namespace MXF