2 Copyright (c) 2005-2013, 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(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 Array<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
306 ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
310 class DeltaEntry : public Kumu::IArchive
317 DeltaEntry() : PosTableIndex(-1), Slice(0), ElementData(0) {}
318 DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
319 inline bool HasValue() const { return true; }
320 ui32_t ArchiveLength() const { return sizeof(ui32_t) + 2; }
321 bool Unarchive(Kumu::MemIOReader* Reader);
322 bool Archive(Kumu::MemIOWriter* Writer) const;
323 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
327 class IndexEntry : public Kumu::IArchive
335 // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
336 // to a more suitable value
337 // std::list<ui32_t> SliceOffset;
338 // Array<Rational> PosTable;
340 IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
341 IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
342 TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
343 inline bool HasValue() const { return true; }
344 ui32_t ArchiveLength() const { return sizeof(ui64_t) + 3; };
345 bool Unarchive(Kumu::MemIOReader* Reader);
346 bool Archive(Kumu::MemIOWriter* Writer) const;
347 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
350 const Dictionary*& m_Dict;
351 ui64_t RtFileOffset; // not part of the MXF structure: used to manage runtime index access
352 ui64_t RtEntryOffset;
354 Rational IndexEditRate;
355 ui64_t IndexStartPosition;
356 ui64_t IndexDuration;
357 ui32_t EditUnitByteCount;
362 Batch<DeltaEntry> DeltaEntryArray;
363 Batch<IndexEntry> IndexEntryArray;
365 IndexTableSegment(const Dictionary*&);
366 virtual ~IndexTableSegment();
368 virtual void Copy(const IndexTableSegment& rhs);
369 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
370 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
371 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
372 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
373 virtual void Dump(FILE* = 0);
376 //---------------------------------------------------------------------------------
378 class Identification;
382 class OP1aHeader : public Partition
384 Kumu::ByteString m_HeaderData;
385 ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
389 const Dictionary*& m_Dict;
390 ASDCP::MXF::Primer m_Primer;
393 OP1aHeader(const Dictionary*&);
394 virtual ~OP1aHeader();
395 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
396 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
397 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
398 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
399 virtual void Dump(FILE* = 0);
400 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
401 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
402 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
403 Identification* GetIdentification();
404 SourcePackage* GetSourcePackage();
408 class OPAtomIndexFooter : public Partition
410 Kumu::ByteString m_FooterData;
411 IndexTableSegment* m_CurrentSegment;
412 ui32_t m_BytesPerEditUnit;
416 ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
420 const Dictionary*& m_Dict;
421 Kumu::fpos_t m_ECOffset;
422 IPrimerLookup* m_Lookup;
424 OPAtomIndexFooter(const Dictionary*&);
425 virtual ~OPAtomIndexFooter();
426 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
427 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
428 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
429 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration);
430 virtual void Dump(FILE* = 0);
432 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
433 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
434 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
436 virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const;
437 virtual void PushIndexEntry(const IndexTableSegment::IndexEntry&);
438 virtual void SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate);
439 virtual void SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset);
442 //---------------------------------------------------------------------------------
446 inline std::string to_lower(std::string str) {
447 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
451 // ignore case when searching for audio labels
454 inline bool operator()(const std::string& a, const std::string& b) const {
455 return to_lower(a) < to_lower(b);
459 typedef std::map<const std::string, const UL, ci_comp> mca_label_map_t;
460 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&);
463 class ASDCP_MCAConfigParser : public InterchangeObject_list_t
465 KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser);
466 ASDCP_MCAConfigParser();
469 mca_label_map_t m_LabelMap;
470 ui32_t m_ChannelCount;
471 const Dictionary*& m_Dict;
475 ASDCP_MCAConfigParser(const Dictionary*&);
476 bool DecodeString(const std::string& s, const std::string& language = "en");
478 // Valid only after a successful call to DecodeString
479 ui32_t ChannelCount() const;
483 class AS02_MCAConfigParser : public ASDCP_MCAConfigParser
485 KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser);
486 AS02_MCAConfigParser();
489 AS02_MCAConfigParser(const Dictionary*&);