2 Copyright (c) 2005-2015, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 class InterchangeObject;
44 const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
47 typedef ASDCP::MXF::InterchangeObject* (*MXFObjectFactory_t)(const Dictionary*&);
50 void SetObjectFactory(const UL& label, MXFObjectFactory_t factory);
53 InterchangeObject* CreateObject(const Dictionary*& Dict, const UL& label);
56 // seek an open file handle to the start of the RIP KLV packet
57 Result_t SeekToRIP(const Kumu::FileReader&);
60 class RIP : public ASDCP::KLVFilePacket
62 ASDCP_NO_COPY_CONSTRUCT(RIP);
67 class PartitionPair : public Kumu::IArchive
73 PartitionPair() : BodySID(0), ByteOffset(0) {}
74 PartitionPair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {}
75 virtual ~PartitionPair() {}
77 ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); }
79 inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
80 Kumu::ui64Printer offset_str(ByteOffset);
81 snprintf(str_buf, buf_len, "%-6u: %s", BodySID, offset_str.c_str());
85 inline bool HasValue() const { return true; }
86 inline ui32_t ArchiveLength() const { return sizeof(ui32_t) + sizeof(ui64_t); }
88 inline bool Unarchive(Kumu::MemIOReader* Reader) {
89 if ( ! Reader->ReadUi32BE(&BodySID) ) return false;
90 if ( ! Reader->ReadUi64BE(&ByteOffset) ) return false;
94 inline bool Archive(Kumu::MemIOWriter* Writer) const {
95 if ( ! Writer->WriteUi32BE(BodySID) ) return false;
96 if ( ! Writer->WriteUi64BE(ByteOffset) ) return false;
101 const Dictionary*& m_Dict;
103 typedef SimpleArray<PartitionPair>::iterator pair_iterator;
104 typedef SimpleArray<PartitionPair>::const_iterator const_pair_iterator;
106 SimpleArray<PartitionPair> PairArray;
108 RIP(const Dictionary*& d) : m_Dict(d) {}
110 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
111 virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
112 virtual bool GetPairBySID(ui32_t, PartitionPair&) const;
113 virtual void Dump(FILE* = 0);
118 class Partition : public ASDCP::KLVFilePacket
120 ASDCP_NO_COPY_CONSTRUCT(Partition);
127 std::list<InterchangeObject*> m_List;
128 std::map<UUID, InterchangeObject*> m_Map;
131 void AddPacket(InterchangeObject* ThePacket); // takes ownership
132 Result_t GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object);
133 Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object);
134 Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
137 mem_ptr<PacketList> m_PacketList;
140 const Dictionary*& m_Dict;
145 ui64_t ThisPartition;
146 ui64_t PreviousPartition;
147 ui64_t FooterPartition;
148 ui64_t HeaderByteCount;
149 ui64_t IndexByteCount;
153 UL OperationalPattern;
154 Batch<UL> EssenceContainers;
156 Partition(const Dictionary*&);
157 virtual ~Partition();
158 virtual void AddChildObject(InterchangeObject*); // takes ownership
159 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
160 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
161 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel);
162 virtual ui32_t ArchiveSize(); // returns the size of the archived structure
163 virtual void Dump(FILE* = 0);
168 class Primer : public ASDCP::KLVFilePacket, public ASDCP::IPrimerLookup
170 class h__PrimerLookup;
171 mem_ptr<h__PrimerLookup> m_Lookup;
173 ASDCP_NO_COPY_CONSTRUCT(Primer);
178 class LocalTagEntry : Kumu::IArchive
184 LocalTagEntry() { Tag.a = Tag.b = 0; }
185 LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {}
187 bool operator<(const LocalTagEntry& rhs) const {
188 if ( Tag.a < rhs.Tag.a )
193 if ( Tag.a == rhs.Tag.a && Tag.b < rhs.Tag.b )
201 inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
202 snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b);
203 UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf));
207 inline bool HasValue() const { return UL.HasValue(); }
208 inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); }
210 inline bool Unarchive(Kumu::MemIOReader* Reader) {
211 if ( ! Reader->ReadUi8(&Tag.a) ) return false;
212 if ( ! Reader->ReadUi8(&Tag.b) ) return false;
213 return UL.Unarchive(Reader);
216 inline bool Archive(Kumu::MemIOWriter* Writer) const {
217 if ( ! Writer->WriteUi8(Tag.a) ) return false;
218 if ( ! Writer->WriteUi8(Tag.b) ) return false;
219 return UL.Archive(Writer);
223 Batch<LocalTagEntry> LocalTagEntryBatch;
224 const Dictionary*& m_Dict;
226 Primer(const Dictionary*&);
229 virtual void ClearTagList();
230 virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag);
231 virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag);
233 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
234 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
235 virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
236 virtual void Dump(FILE* = 0);
239 // wrapper object manages optional properties
240 template <class PropertyType>
241 class optional_property
243 PropertyType m_property;
247 optional_property() : m_has_value(false) {}
248 optional_property(const PropertyType& value) : m_property(value), m_has_value(true) {}
249 const optional_property<PropertyType>& operator=(const PropertyType& rhs) {
250 this->m_property = rhs;
251 this->m_has_value = true;
254 bool operator==(const PropertyType& rhs) const { return this->m_property == rhs; }
255 bool operator==(const optional_property<PropertyType>& rhs) const { return this->m_property == rhs.m_property; }
256 operator PropertyType&() { return this->m_property; }
257 void set(const PropertyType& rhs) { this->m_property = rhs; this->m_has_value = true; }
258 void set_has_value(bool has_value = true) { this->m_has_value = has_value; }
259 void reset(const PropertyType& rhs) { this->m_has_value = false; }
260 bool empty() const { return ! m_has_value; }
261 PropertyType& get() { return m_property; }
262 const PropertyType& const_get() const { return m_property; }
265 // wrapper object manages optional properties
266 template <class PropertyType>
267 class optional_container_property
269 PropertyType m_property;
272 optional_container_property() {}
273 optional_container_property(const PropertyType& value) : m_property(value) {}
274 const optional_container_property<PropertyType>& operator=(const PropertyType& rhs) {
275 this->Copy(rhs.m_property);
279 bool operator==(const PropertyType& rhs) const { return this->m_property == rhs; }
280 bool operator==(const optional_property<PropertyType>& rhs) const { return this->m_property == rhs.m_property; }
281 operator PropertyType&() { return this->m_property; }
282 void set(const PropertyType& rhs) { this->m_property = rhs; }
283 void reset(const PropertyType& rhs) { this->clear(); }
284 bool empty() const { return ! this->m_property.HasValue(); }
285 PropertyType& get() { return m_property; }
286 const PropertyType& const_get() const { return m_property; }
289 // base class of all metadata objects
291 class InterchangeObject : public ASDCP::KLVPacket
296 const Dictionary*& m_Dict;
297 IPrimerLookup* m_Lookup;
299 optional_property<UUID> GenerationUID;
301 InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
302 virtual ~InterchangeObject() {}
304 virtual void Copy(const InterchangeObject& rhs);
305 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
306 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
307 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
308 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
309 virtual bool IsA(const byte_t* label);
310 virtual const char* ObjectName() { return "InterchangeObject"; }
311 virtual void Dump(FILE* stream = 0);
315 typedef std::list<InterchangeObject*> InterchangeObject_list_t;
318 class Preface : public InterchangeObject
320 ASDCP_NO_COPY_CONSTRUCT(Preface);
324 const Dictionary*& m_Dict;
325 Kumu::Timestamp LastModifiedDate;
327 optional_property<ui32_t> ObjectModelVersion;
328 optional_property<UUID> PrimaryPackage;
329 Array<UUID> Identifications;
331 UL OperationalPattern;
332 Batch<UL> EssenceContainers;
334 optional_property<Batch<UL> > ApplicationSchemes;
336 Preface(const Dictionary*& d);
337 virtual ~Preface() {}
339 virtual void Copy(const Preface& rhs);
340 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
341 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
342 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
343 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
344 virtual void Dump(FILE* = 0);
347 const ui32_t MaxIndexSegmentSize = 65536;
350 class IndexTableSegment : public InterchangeObject
353 ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
357 class DeltaEntry : public Kumu::IArchive
364 DeltaEntry() : PosTableIndex(0), Slice(0), ElementData(0) {}
365 DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
366 inline bool HasValue() const { return true; }
367 ui32_t ArchiveLength() const { return sizeof(ui32_t) + 2; }
368 bool Unarchive(Kumu::MemIOReader* Reader);
369 bool Archive(Kumu::MemIOWriter* Writer) const;
370 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
374 class IndexEntry : public Kumu::IArchive
382 // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
383 // to a more suitable value
384 // std::list<ui32_t> SliceOffset;
385 // Array<Rational> PosTable;
387 IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
388 IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
389 TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
390 inline bool HasValue() const { return true; }
391 ui32_t ArchiveLength() const { return sizeof(ui64_t) + 3; };
392 bool Unarchive(Kumu::MemIOReader* Reader);
393 bool Archive(Kumu::MemIOWriter* Writer) const;
394 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
397 const Dictionary*& m_Dict;
398 ui64_t RtFileOffset; // not part of the MXF structure: used to manage runtime index access
399 ui64_t RtEntryOffset;
401 Rational IndexEditRate;
402 ui64_t IndexStartPosition;
403 ui64_t IndexDuration;
404 ui32_t EditUnitByteCount;
409 Array<DeltaEntry> DeltaEntryArray;
410 Array<IndexEntry> IndexEntryArray;
412 IndexTableSegment(const Dictionary*&);
413 virtual ~IndexTableSegment();
415 virtual void Copy(const IndexTableSegment& rhs);
416 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
417 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
418 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
419 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
420 virtual void Dump(FILE* = 0);
423 //---------------------------------------------------------------------------------
425 class Identification;
429 class OP1aHeader : public Partition
431 Kumu::ByteString m_HeaderData;
432 ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
436 const Dictionary*& m_Dict;
437 ASDCP::MXF::Primer m_Primer;
440 OP1aHeader(const Dictionary*&);
441 virtual ~OP1aHeader();
442 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
443 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
444 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
445 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
446 virtual void Dump(FILE* = 0);
447 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
448 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
449 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
450 Identification* GetIdentification();
451 SourcePackage* GetSourcePackage();
454 // Searches the header object and returns the edit rate based on the contents of the
455 // File Package items. Logs an error message and returns false if anthing goes wrong.
456 bool GetEditRateFromFP(ASDCP::MXF::OP1aHeader& header, ASDCP::Rational& edit_rate);
459 class OPAtomIndexFooter : public Partition
461 Kumu::ByteString m_FooterData;
462 IndexTableSegment* m_CurrentSegment;
463 ui32_t m_BytesPerEditUnit;
466 IndexTableSegment::DeltaEntry m_DefaultDeltaEntry;
468 ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
472 const Dictionary*& m_Dict;
473 Kumu::fpos_t m_ECOffset;
474 IPrimerLookup* m_Lookup;
476 OPAtomIndexFooter(const Dictionary*&);
477 virtual ~OPAtomIndexFooter();
478 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
479 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
480 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
481 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration);
482 virtual void Dump(FILE* = 0);
484 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
485 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
486 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
488 virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const;
489 virtual void PushIndexEntry(const IndexTableSegment::IndexEntry&);
490 virtual void SetDeltaParams(const IndexTableSegment::DeltaEntry&);
491 virtual void SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate);
492 virtual void SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset);
495 //---------------------------------------------------------------------------------
499 inline std::string to_lower(std::string str) {
500 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
504 // ignore case when searching for audio labels
507 inline bool operator()(const std::string& a, const std::string& b) const {
508 return to_lower(a) < to_lower(b);
514 const std::string tag_name;
515 const bool requires_prefix;
518 label_traits(const std::string& tag_name, const bool requires_prefix, const UL ul) :
519 tag_name(tag_name), requires_prefix(requires_prefix), ul(ul) { }
522 typedef std::map<const std::string, const label_traits, ci_comp> mca_label_map_t;
524 bool decode_mca_string(const std::string& s, const mca_label_map_t& labels,
525 const Dictionary*& dict, const std::string& language, InterchangeObject_list_t&, ui32_t&);
528 class ASDCP_MCAConfigParser : public InterchangeObject_list_t
530 KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser);
531 ASDCP_MCAConfigParser();
534 mca_label_map_t m_LabelMap;
535 ui32_t m_ChannelCount;
536 const Dictionary*& m_Dict;
540 ASDCP_MCAConfigParser(const Dictionary*&);
541 bool DecodeString(const std::string& s, const std::string& language = "en-US");
543 // Valid only after a successful call to DecodeString
544 ui32_t ChannelCount() const;
548 class AS02_MCAConfigParser : public ASDCP_MCAConfigParser
550 KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser);
551 AS02_MCAConfigParser();
554 AS02_MCAConfigParser(const Dictionary*&);