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 Pair : public Kumu::IArchive
73 Pair() : BodySID(0), ByteOffset(0) {}
74 Pair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {}
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;
102 HeadlessArray<Pair> PairArray;
104 RIP(const Dictionary*& d) : m_Dict(d) {}
106 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
107 virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
108 virtual Result_t GetPairBySID(ui32_t, Pair&) const;
109 virtual void Dump(FILE* = 0);
114 class Partition : public ASDCP::KLVFilePacket
116 ASDCP_NO_COPY_CONSTRUCT(Partition);
123 std::list<InterchangeObject*> m_List;
124 std::map<UUID, InterchangeObject*> m_Map;
127 void AddPacket(InterchangeObject* ThePacket); // takes ownership
128 Result_t GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object);
129 Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object);
130 Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
133 mem_ptr<PacketList> m_PacketList;
136 const Dictionary*& m_Dict;
141 ui64_t ThisPartition;
142 ui64_t PreviousPartition;
143 ui64_t FooterPartition;
144 ui64_t HeaderByteCount;
145 ui64_t IndexByteCount;
149 UL OperationalPattern;
150 Batch<UL> EssenceContainers;
152 Partition(const Dictionary*&);
153 virtual ~Partition();
154 virtual void AddChildObject(InterchangeObject*); // takes ownership
155 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
156 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
157 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel);
158 virtual ui32_t ArchiveSize(); // returns the size of the archived structure
159 virtual void Dump(FILE* = 0);
164 class Primer : public ASDCP::KLVFilePacket, public ASDCP::IPrimerLookup
166 class h__PrimerLookup;
167 mem_ptr<h__PrimerLookup> m_Lookup;
169 ASDCP_NO_COPY_CONSTRUCT(Primer);
174 class LocalTagEntry : Kumu::IArchive
180 LocalTagEntry() { Tag.a = Tag.b = 0; }
181 LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {}
183 inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
184 snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b);
185 UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf));
189 inline bool HasValue() const { return UL.HasValue(); }
190 inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); }
192 inline bool Unarchive(Kumu::MemIOReader* Reader) {
193 if ( ! Reader->ReadUi8(&Tag.a) ) return false;
194 if ( ! Reader->ReadUi8(&Tag.b) ) return false;
195 return UL.Unarchive(Reader);
198 inline bool Archive(Kumu::MemIOWriter* Writer) const {
199 if ( ! Writer->WriteUi8(Tag.a) ) return false;
200 if ( ! Writer->WriteUi8(Tag.b) ) return false;
201 return UL.Archive(Writer);
205 Batch<LocalTagEntry> LocalTagEntryBatch;
206 const Dictionary*& m_Dict;
208 Primer(const Dictionary*&);
211 virtual void ClearTagList();
212 virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag);
213 virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag);
215 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
216 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
217 virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
218 virtual void Dump(FILE* = 0);
221 // wrapper object manages optional properties
222 template <class PropertyType>
223 class optional_property
225 PropertyType m_property;
229 optional_property() : m_has_value(false) {}
230 optional_property(const PropertyType& value) : m_property(value), m_has_value(false) {}
231 const optional_property<PropertyType>& operator=(const PropertyType& rhs) { this->m_property = rhs; this->m_has_value = true; return *this; }
232 bool operator==(const PropertyType& rhs) const { return this->m_property == rhs; }
233 bool operator==(const optional_property<PropertyType>& rhs) const { return this->m_property == rhs.m_property; }
234 operator PropertyType&() { return this->m_property; }
235 void set(const PropertyType& rhs) { this->m_property = rhs; this->m_has_value = true; }
236 void set_has_value(bool has_value = true) { this->m_has_value = has_value; }
237 void reset(const PropertyType& rhs) { this->m_has_value = false; }
238 bool empty() const { return ! m_has_value; }
239 PropertyType& get() { return m_property; }
240 const PropertyType& const_get() const { return m_property; }
243 // base class of all metadata objects
245 class InterchangeObject : public ASDCP::KLVPacket
250 const Dictionary*& m_Dict;
251 IPrimerLookup* m_Lookup;
253 optional_property<UUID> GenerationUID;
255 InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
256 virtual ~InterchangeObject() {}
258 virtual void Copy(const InterchangeObject& rhs);
259 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
260 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
261 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
262 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
263 virtual bool IsA(const byte_t* label);
264 virtual const char* ObjectName() { return "InterchangeObject"; }
265 virtual void Dump(FILE* stream = 0);
269 typedef std::list<InterchangeObject*> InterchangeObject_list_t;
272 class Preface : public InterchangeObject
274 ASDCP_NO_COPY_CONSTRUCT(Preface);
278 const Dictionary*& m_Dict;
279 Kumu::Timestamp LastModifiedDate;
281 optional_property<ui32_t> ObjectModelVersion;
282 optional_property<UUID> PrimaryPackage;
283 Batch<UUID> Identifications;
285 UL OperationalPattern;
286 Batch<UL> EssenceContainers;
288 optional_property<Batch<UL> > ApplicationSchemes;
290 Preface(const Dictionary*& d);
291 virtual ~Preface() {}
293 virtual void Copy(const Preface& rhs);
294 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
295 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
296 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
297 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
298 virtual void Dump(FILE* = 0);
301 const ui32_t MaxIndexSegmentSize = 65536;
304 class IndexTableSegment : public InterchangeObject
307 ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
311 class DeltaEntry : public Kumu::IArchive
318 DeltaEntry() : PosTableIndex(0), Slice(0), ElementData(0) {}
319 DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
320 inline bool HasValue() const { return true; }
321 ui32_t ArchiveLength() const { return sizeof(ui32_t) + 2; }
322 bool Unarchive(Kumu::MemIOReader* Reader);
323 bool Archive(Kumu::MemIOWriter* Writer) const;
324 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
328 class IndexEntry : public Kumu::IArchive
336 // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
337 // to a more suitable value
338 // std::list<ui32_t> SliceOffset;
339 // Array<Rational> PosTable;
341 IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
342 IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
343 TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
344 inline bool HasValue() const { return true; }
345 ui32_t ArchiveLength() const { return sizeof(ui64_t) + 3; };
346 bool Unarchive(Kumu::MemIOReader* Reader);
347 bool Archive(Kumu::MemIOWriter* Writer) const;
348 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
351 const Dictionary*& m_Dict;
352 ui64_t RtFileOffset; // not part of the MXF structure: used to manage runtime index access
353 ui64_t RtEntryOffset;
355 Rational IndexEditRate;
356 ui64_t IndexStartPosition;
357 ui64_t IndexDuration;
358 ui32_t EditUnitByteCount;
363 Batch<DeltaEntry> DeltaEntryArray;
364 Batch<IndexEntry> IndexEntryArray;
366 IndexTableSegment(const Dictionary*&);
367 virtual ~IndexTableSegment();
369 virtual void Copy(const IndexTableSegment& rhs);
370 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
371 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
372 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
373 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
374 virtual void Dump(FILE* = 0);
377 //---------------------------------------------------------------------------------
379 class Identification;
383 class OP1aHeader : public Partition
385 Kumu::ByteString m_HeaderData;
386 ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
390 const Dictionary*& m_Dict;
391 ASDCP::MXF::Primer m_Primer;
394 OP1aHeader(const Dictionary*&);
395 virtual ~OP1aHeader();
396 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
397 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
398 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
399 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
400 virtual void Dump(FILE* = 0);
401 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
402 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
403 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
404 Identification* GetIdentification();
405 SourcePackage* GetSourcePackage();
408 // Searches the header object and returns the edit rate based on the contents of the
409 // File Package items. Logs an error message and returns false if anthing goes wrong.
410 bool GetEditRateFromFP(ASDCP::MXF::OP1aHeader& header, ASDCP::Rational& edit_rate);
413 class OPAtomIndexFooter : public Partition
415 Kumu::ByteString m_FooterData;
416 IndexTableSegment* m_CurrentSegment;
417 ui32_t m_BytesPerEditUnit;
420 IndexTableSegment::DeltaEntry m_DefaultDeltaEntry;
422 ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
426 const Dictionary*& m_Dict;
427 Kumu::fpos_t m_ECOffset;
428 IPrimerLookup* m_Lookup;
430 OPAtomIndexFooter(const Dictionary*&);
431 virtual ~OPAtomIndexFooter();
432 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
433 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
434 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
435 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration);
436 virtual void Dump(FILE* = 0);
438 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
439 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
440 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
442 virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const;
443 virtual void PushIndexEntry(const IndexTableSegment::IndexEntry&);
444 virtual void SetDeltaParams(const IndexTableSegment::DeltaEntry&);
445 virtual void SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate);
446 virtual void SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset);
449 //---------------------------------------------------------------------------------
453 inline std::string to_lower(std::string str) {
454 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
458 // ignore case when searching for audio labels
461 inline bool operator()(const std::string& a, const std::string& b) const {
462 return to_lower(a) < to_lower(b);
468 const std::string tag_name;
469 const bool requires_prefix;
472 label_traits(const std::string& tag_name, const bool requires_prefix, const UL ul) :
473 tag_name(tag_name), requires_prefix(requires_prefix), ul(ul) { }
476 typedef std::map<const std::string, const label_traits, ci_comp> mca_label_map_t;
478 bool decode_mca_string(const std::string& s, const mca_label_map_t& labels,
479 const Dictionary*& dict, const std::string& language, InterchangeObject_list_t&, ui32_t&);
482 class ASDCP_MCAConfigParser : public InterchangeObject_list_t
484 KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser);
485 ASDCP_MCAConfigParser();
488 mca_label_map_t m_LabelMap;
489 ui32_t m_ChannelCount;
490 const Dictionary*& m_Dict;
494 ASDCP_MCAConfigParser(const Dictionary*&);
495 bool DecodeString(const std::string& s, const std::string& language = "en-US");
497 // Valid only after a successful call to DecodeString
498 ui32_t ChannelCount() const;
502 class AS02_MCAConfigParser : public ASDCP_MCAConfigParser
504 KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser);
505 AS02_MCAConfigParser();
508 AS02_MCAConfigParser(const Dictionary*&);