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.
41 class InterchangeObject;
43 const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
46 typedef ASDCP::MXF::InterchangeObject* (*MXFObjectFactory_t)(const Dictionary*&);
49 void SetObjectFactory(UL label, MXFObjectFactory_t factory);
52 InterchangeObject* CreateObject(const Dictionary*& Dict, const UL& label);
55 // seek an open file handle to the start of the RIP KLV packet
56 Result_t SeekToRIP(const Kumu::FileReader&);
59 class RIP : public ASDCP::KLVFilePacket
61 ASDCP_NO_COPY_CONSTRUCT(RIP);
66 class Pair : public Kumu::IArchive
72 Pair() : BodySID(0), ByteOffset(0) {}
73 Pair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {}
76 ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); }
78 inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
79 Kumu::ui64Printer offset_str(ByteOffset);
80 snprintf(str_buf, buf_len, "%-6u: %s", BodySID, offset_str.c_str());
84 inline bool HasValue() const { return true; }
85 inline ui32_t ArchiveLength() const { return sizeof(ui32_t) + sizeof(ui64_t); }
87 inline bool Unarchive(Kumu::MemIOReader* Reader) {
88 if ( ! Reader->ReadUi32BE(&BodySID) ) return false;
89 if ( ! Reader->ReadUi64BE(&ByteOffset) ) return false;
93 inline bool Archive(Kumu::MemIOWriter* Writer) const {
94 if ( ! Writer->WriteUi32BE(BodySID) ) return false;
95 if ( ! Writer->WriteUi64BE(ByteOffset) ) return false;
100 const Dictionary*& m_Dict;
101 Array<Pair> PairArray;
103 RIP(const Dictionary*& d) : m_Dict(d) {}
105 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
106 virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
107 virtual Result_t GetPairBySID(ui32_t, Pair&) const;
108 virtual void Dump(FILE* = 0);
113 class Partition : public ASDCP::KLVFilePacket
115 ASDCP_NO_COPY_CONSTRUCT(Partition);
122 std::list<InterchangeObject*> m_List;
123 std::map<UUID, InterchangeObject*> m_Map;
126 void AddPacket(InterchangeObject* ThePacket); // takes ownership
127 Result_t GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object);
128 Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object);
129 Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
132 mem_ptr<PacketList> m_PacketList;
135 const Dictionary*& m_Dict;
140 ui64_t ThisPartition;
141 ui64_t PreviousPartition;
142 ui64_t FooterPartition;
143 ui64_t HeaderByteCount;
144 ui64_t IndexByteCount;
148 UL OperationalPattern;
149 Batch<UL> EssenceContainers;
151 Partition(const Dictionary*&);
152 virtual ~Partition();
153 virtual void AddChildObject(InterchangeObject*); // takes ownership
154 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
155 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
156 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel);
157 virtual ui32_t ArchiveSize(); // returns the size of the archived structure
158 virtual void Dump(FILE* = 0);
163 class Primer : public ASDCP::KLVFilePacket, public ASDCP::IPrimerLookup
165 class h__PrimerLookup;
166 mem_ptr<h__PrimerLookup> m_Lookup;
168 ASDCP_NO_COPY_CONSTRUCT(Primer);
173 class LocalTagEntry : Kumu::IArchive
179 LocalTagEntry() { Tag.a = Tag.b = 0; }
180 LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {}
182 inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
183 snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b);
184 UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf));
188 inline bool HasValue() const { return UL.HasValue(); }
189 inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); }
191 inline bool Unarchive(Kumu::MemIOReader* Reader) {
192 if ( ! Reader->ReadUi8(&Tag.a) ) return false;
193 if ( ! Reader->ReadUi8(&Tag.b) ) return false;
194 return UL.Unarchive(Reader);
197 inline bool Archive(Kumu::MemIOWriter* Writer) const {
198 if ( ! Writer->WriteUi8(Tag.a) ) return false;
199 if ( ! Writer->WriteUi8(Tag.b) ) return false;
200 return UL.Archive(Writer);
204 Batch<LocalTagEntry> LocalTagEntryBatch;
205 const Dictionary*& m_Dict;
207 Primer(const Dictionary*&);
210 virtual void ClearTagList();
211 virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag);
212 virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag);
214 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
215 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
216 virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
217 virtual void Dump(FILE* = 0);
222 class InterchangeObject : public ASDCP::KLVPacket
227 const Dictionary*& m_Dict;
228 IPrimerLookup* m_Lookup;
232 InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
233 virtual ~InterchangeObject() {}
235 virtual void Copy(const InterchangeObject& rhs);
236 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
237 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
238 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
239 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
240 virtual bool IsA(const byte_t* label);
241 virtual const char* ObjectName() { return "InterchangeObject"; }
242 virtual void Dump(FILE* stream = 0);
246 typedef std::list<InterchangeObject*> InterchangeObject_list_t;
249 class Preface : public InterchangeObject
251 ASDCP_NO_COPY_CONSTRUCT(Preface);
255 const Dictionary*& m_Dict;
256 Kumu::Timestamp LastModifiedDate;
258 ui32_t ObjectModelVersion;
260 Batch<UUID> Identifications;
262 UL OperationalPattern;
263 Batch<UL> EssenceContainers;
266 Preface(const Dictionary*& d);
267 virtual ~Preface() {}
269 virtual void Copy(const Preface& rhs);
270 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
271 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
272 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
273 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
274 virtual void Dump(FILE* = 0);
277 const ui32_t MaxIndexSegmentSize = 65536;
280 class IndexTableSegment : public InterchangeObject
282 ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
286 class DeltaEntry : public Kumu::IArchive
293 DeltaEntry() : PosTableIndex(-1), Slice(0), ElementData(0) {}
294 DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
295 inline bool HasValue() const { return true; }
296 ui32_t ArchiveLength() const { return sizeof(ui32_t) + 2; }
297 bool Unarchive(Kumu::MemIOReader* Reader);
298 bool Archive(Kumu::MemIOWriter* Writer) const;
299 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
303 class IndexEntry : public Kumu::IArchive
311 // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
312 // to a more suitable value
313 // std::list<ui32_t> SliceOffset;
314 // Array<Rational> PosTable;
316 IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
317 IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
318 TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
319 inline bool HasValue() const { return true; }
320 ui32_t ArchiveLength() const { return sizeof(ui64_t) + 3; };
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;
326 const Dictionary*& m_Dict;
327 ui64_t RtFileOffset; // not part of the MXF structure: used to manage runtime index access
328 ui64_t RtEntryOffset;
330 Rational IndexEditRate;
331 ui64_t IndexStartPosition;
332 ui64_t IndexDuration;
333 ui32_t EditUnitByteCount;
338 Batch<DeltaEntry> DeltaEntryArray;
339 Batch<IndexEntry> IndexEntryArray;
341 IndexTableSegment(const Dictionary*&);
342 virtual ~IndexTableSegment();
344 virtual void Copy(const IndexTableSegment& rhs);
345 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
346 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
347 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
348 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
349 virtual void Dump(FILE* = 0);
352 //---------------------------------------------------------------------------------
354 class Identification;
358 class OP1aHeader : public Partition
360 Kumu::ByteString m_HeaderData;
361 ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
365 const Dictionary*& m_Dict;
366 ASDCP::MXF::Primer m_Primer;
369 OP1aHeader(const Dictionary*&);
370 virtual ~OP1aHeader();
371 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
372 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
373 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
374 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
375 virtual void Dump(FILE* = 0);
376 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
377 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
378 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
379 Identification* GetIdentification();
380 SourcePackage* GetSourcePackage();
384 class OPAtomIndexFooter : public Partition
386 Kumu::ByteString m_FooterData;
387 IndexTableSegment* m_CurrentSegment;
388 ui32_t m_BytesPerEditUnit;
392 ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
396 const Dictionary*& m_Dict;
397 Kumu::fpos_t m_ECOffset;
398 IPrimerLookup* m_Lookup;
400 OPAtomIndexFooter(const Dictionary*&);
401 virtual ~OPAtomIndexFooter();
402 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
403 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
404 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
405 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration);
406 virtual void Dump(FILE* = 0);
408 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
409 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
410 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
412 virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const;
413 virtual void PushIndexEntry(const IndexTableSegment::IndexEntry&);
414 virtual void SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate);
415 virtual void SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset);
418 //---------------------------------------------------------------------------------
422 inline std::string to_lower(std::string str) {
423 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
427 // ignore case when searching for audio labels
430 inline bool operator()(const std::string& a, const std::string& b) const {
431 return to_lower(a) < to_lower(b);
436 class MCAConfigParser : public InterchangeObject_list_t
438 typedef std::map<const std::string, const UL, ci_comp> label_map_t;
439 label_map_t label_map;
440 ui32_t m_ChannelCount;
442 const Dictionary*& m_Dict;
444 KM_NO_COPY_CONSTRUCT(MCAConfigParser);
448 MCAConfigParser(const Dictionary*&);
449 bool DecodeString(const std::string& s, const std::string& language = "en");
451 // Valid only after a successful call to DecodeString
452 ui32_t ChannelCount() const;