/*
-Copyright (c) 2005-2006, John Hurst
+Copyright (c) 2005-2018, John Hurst
All rights reserved.
Redistribution and use in source and binary forms, with or without
#define _MXF_H_
#include "MXFTypes.h"
+#include <algorithm>
namespace ASDCP
{
{
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;
-
- Pair() : BodySID(0), ByteOffset(0) {}
- Pair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {}
-
- ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); }
+ class PartitionPair : public Kumu::IArchive
+ {
+ public:
+ ui32_t BodySID;
+ ui64_t ByteOffset;
- inline const char* ToString(char* str_buf) const {
- char intbuf[IntBufferLen];
- snprintf(str_buf, IdentBufferLen, "%-6lu: %s", BodySID, ui64sz(ByteOffset, intbuf));
- return str_buf;
- }
+ PartitionPair() : BodySID(0), ByteOffset(0) {}
+ PartitionPair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {}
+ virtual ~PartitionPair() {}
- inline Result_t Unarchive(ASDCP::MemIOReader& Reader) {
- Result_t result = Reader.ReadUi32BE(&BodySID);
+ ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); }
- if ( ASDCP_SUCCESS(result) )
- result = Reader.ReadUi64BE(&ByteOffset);
+ 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;
+ }
- return result;
- }
+ inline bool HasValue() const { return true; }
+ inline ui32_t ArchiveLength() const { return sizeof(ui32_t) + sizeof(ui64_t); }
- inline Result_t Archive(ASDCP::MemIOWriter& Writer) {
- Result_t result = Writer.WriteUi32BE(BodySID);
+ 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;
+ }
+ };
- if ( ASDCP_SUCCESS(result) )
- result = Writer.WriteUi64BE(ByteOffset);
+ const Dictionary*& m_Dict;
- return result;
- }
- };
+ typedef SimpleArray<PartitionPair>::iterator pair_iterator;
+ typedef SimpleArray<PartitionPair>::const_iterator const_pair_iterator;
- Array<Pair> PairArray;
+ SimpleArray<PartitionPair> 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 bool GetPairBySID(ui32_t, PartitionPair&) const;
virtual void Dump(FILE* = 0);
};
//
class Partition : public ASDCP::KLVFilePacket
- {
+ {
ASDCP_NO_COPY_CONSTRUCT(Partition);
+ Partition();
protected:
- class h__PacketList;
- mem_ptr<h__PacketList> m_PacketList;
+ class PacketList
+ {
+ public:
+ std::list<InterchangeObject*> m_List;
+ std::map<UUID, InterchangeObject*> 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<InterchangeObject*>& ObjectList);
+ };
+
+ mem_ptr<PacketList> m_PacketList;
public:
+ const Dictionary*& m_Dict;
+
ui16_t MajorVersion;
ui16_t MinorVersion;
ui32_t KAGSize;
UL OperationalPattern;
Batch<UL> EssenceContainers;
- Partition();
+ Partition(const Dictionary*&);
virtual ~Partition();
- virtual void AddChildObject(InterchangeObject*);
- virtual Result_t InitFromFile(const ASDCP::FileReader& Reader);
- virtual Result_t WriteToFile(ASDCP::FileWriter& Writer, UL& PartitionLabel);
+ 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);
};
mem_ptr<h__PrimerLookup> 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) {}
+
+ bool operator<(const LocalTagEntry& rhs) const {
+ if ( Tag.a < rhs.Tag.a )
+ {
+ return true;
+ }
+
+ if ( Tag.a == rhs.Tag.a && Tag.b < rhs.Tag.b )
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ 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 - (ui32_t)strlen(str_buf));
return str_buf;
}
- inline Result_t Unarchive(ASDCP::MemIOReader& Reader) {
- Result_t result = Reader.ReadUi8(&Tag.a);
- if ( ASDCP_SUCCESS(result) ) result = Reader.ReadUi8(&Tag.b);
- if ( ASDCP_SUCCESS(result) ) result = UL.Unarchive(Reader);
- return result;
+ inline bool HasValue() const { return UL.HasValue(); }
+ inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); }
+
+ 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 Archive(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.Archive(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<LocalTagEntry> LocalTagEntryBatch;
+ const Dictionary*& m_Dict;
- Primer();
+ Primer(const Dictionary*&);
virtual ~Primer();
virtual void ClearTagList();
virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
- virtual Result_t WriteToFile(ASDCP::FileWriter& Writer);
+ virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
virtual void Dump(FILE* = 0);
};
+ // wrapper object manages optional properties
+ template <class PropertyType>
+ 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(true) {}
+ const optional_property<PropertyType>& 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<PropertyType>& 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; }
+ };
+
+ // wrapper object manages optional properties
+ template <class PropertyType>
+ class optional_container_property
+ {
+ PropertyType m_property;
+
+ public:
+ optional_container_property() {}
+ optional_container_property(const PropertyType& value) : m_property(value) {}
+ const optional_container_property<PropertyType>& operator=(const PropertyType& rhs) {
+ this->Copy(rhs.m_property);
+ return *this;
+ }
+
+ bool operator==(const PropertyType& rhs) const { return this->m_property == rhs; }
+ bool operator==(const optional_property<PropertyType>& rhs) const { return this->m_property == rhs.m_property; }
+ operator PropertyType&() { return this->m_property; }
+ void set(const PropertyType& rhs) { this->m_property = rhs; }
+ void reset(const PropertyType& rhs) { this->clear(); }
+ bool empty() const { return ! this->m_property.HasValue(); }
+ PropertyType& get() { return m_property; }
+ const PropertyType& const_get() const { return m_property; }
+ };
+ // base class of all metadata objects
//
class InterchangeObject : public ASDCP::KLVPacket
{
- protected:
- const MDDEntry* m_Typeinfo;
+ InterchangeObject();
public:
+ const Dictionary*& m_Dict;
IPrimerLookup* m_Lookup;
UUID InstanceUID;
- UUID GenerationUID;
+ optional_property<UUID> GenerationUID;
- InterchangeObject() : m_Typeinfo(0), 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);
};
//
- InterchangeObject* CreateObject(const byte_t* label);
+ typedef std::list<InterchangeObject*> 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;
- UUID PrimaryPackage;
- Batch<UUID> Identifications;
+ optional_property<ui32_t> ObjectModelVersion;
+ optional_property<UUID> PrimaryPackage;
+ Array<UUID> Identifications;
UUID ContentStorage;
UL OperationalPattern;
Batch<UL> EssenceContainers;
Batch<UL> DMSchemes;
+ optional_property<Batch<UL> > ApplicationSchemes;
+ optional_property<Batch<UL> > ConformsToSpecifications;
- Preface() : Version(258), ObjectModelVersion(0) {}
+ Preface(const Dictionary*& d);
virtual ~Preface() {}
+
+ 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);
//
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;
- DeltaEntry() : PosTableIndex(-1), Slice(0), ElementData(0) {}
- Result_t Unarchive(ASDCP::MemIOReader& Reader);
- Result_t Archive(ASDCP::MemIOWriter& Writer);
- 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;
+
+ // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
+ // to a more suitable value
// std::list<ui32_t> SliceOffset;
// Array<Rational> PosTable;
- Result_t Unarchive(ASDCP::MemIOReader& Reader);
- Result_t Archive(ASDCP::MemIOWriter& Writer);
- const char* ToString(char* str_buf) const;
+ IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0x80), 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;
ui32_t BodySID;
ui8_t SliceCount;
ui8_t PosTableCount;
- Batch<DeltaEntry> DeltaEntryArray;
- Batch<IndexEntry> IndexEntryArray;
+ Array<DeltaEntry> DeltaEntryArray;
+ Array<IndexEntry> 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 WriteToTLVSet(TLVWriter& TLVSet);
//---------------------------------------------------------------------------------
//
- class h__PacketList; // See MXF.cpp
class Identification;
class SourcePackage;
//
- class OPAtomHeader : public Partition
+ class OP1aHeader : public Partition
{
- ASDCP_NO_COPY_CONSTRUCT(OPAtomHeader);
+ Kumu::ByteString m_HeaderData;
+ ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
+ OP1aHeader();
public:
- ASDCP::MXF::RIP m_RIP;
+ const Dictionary*& m_Dict;
ASDCP::MXF::Primer m_Primer;
Preface* 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);
+ 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<InterchangeObject*>& 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
{
+ Kumu::ByteString m_FooterData;
IndexTableSegment* m_CurrentSegment;
- ASDCP::FrameBuffer m_Buffer;
ui32_t m_BytesPerEditUnit;
Rational m_EditRate;
ui32_t m_BodySID;
+ IndexTableSegment::DeltaEntry m_DefaultDeltaEntry;
+
ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
+ OPAtomIndexFooter();
public:
- fpos_t m_ECOffset;
+ 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, ui64_t duration);
+ 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<InterchangeObject*>& 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, fpos_t offset);
+ 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<const std::string, const label_traits, ci_comp> 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