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);
223 class InterchangeObject : public ASDCP::KLVPacket
228 const Dictionary*& m_Dict;
229 IPrimerLookup* m_Lookup;
233 InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
234 virtual ~InterchangeObject() {}
236 virtual void Copy(const InterchangeObject& rhs);
237 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
238 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
239 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
240 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
241 virtual bool IsA(const byte_t* label);
242 virtual const char* ObjectName() { return "InterchangeObject"; }
243 virtual void Dump(FILE* stream = 0);
247 typedef std::list<InterchangeObject*> InterchangeObject_list_t;
250 class Preface : public InterchangeObject
252 ASDCP_NO_COPY_CONSTRUCT(Preface);
256 const Dictionary*& m_Dict;
257 Kumu::Timestamp LastModifiedDate;
259 ui32_t ObjectModelVersion;
261 Batch<UUID> Identifications;
263 UL OperationalPattern;
264 Batch<UL> EssenceContainers;
267 Preface(const Dictionary*& d);
268 virtual ~Preface() {}
270 virtual void Copy(const Preface& rhs);
271 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
272 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
273 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
274 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
275 virtual void Dump(FILE* = 0);
278 const ui32_t MaxIndexSegmentSize = 65536;
281 class IndexTableSegment : public InterchangeObject
283 ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
287 class DeltaEntry : public Kumu::IArchive
294 DeltaEntry() : PosTableIndex(-1), Slice(0), ElementData(0) {}
295 DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
296 inline bool HasValue() const { return true; }
297 ui32_t ArchiveLength() const { return sizeof(ui32_t) + 2; }
298 bool Unarchive(Kumu::MemIOReader* Reader);
299 bool Archive(Kumu::MemIOWriter* Writer) const;
300 const char* EncodeString(char* str_buf, ui32_t buf_len) const;
304 class IndexEntry : public Kumu::IArchive
312 // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
313 // to a more suitable value
314 // std::list<ui32_t> SliceOffset;
315 // Array<Rational> PosTable;
317 IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
318 IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
319 TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
320 inline bool HasValue() const { return true; }
321 ui32_t ArchiveLength() const { return sizeof(ui64_t) + 3; };
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;
327 const Dictionary*& m_Dict;
328 ui64_t RtFileOffset; // not part of the MXF structure: used to manage runtime index access
329 ui64_t RtEntryOffset;
331 Rational IndexEditRate;
332 ui64_t IndexStartPosition;
333 ui64_t IndexDuration;
334 ui32_t EditUnitByteCount;
339 Batch<DeltaEntry> DeltaEntryArray;
340 Batch<IndexEntry> IndexEntryArray;
342 IndexTableSegment(const Dictionary*&);
343 virtual ~IndexTableSegment();
345 virtual void Copy(const IndexTableSegment& rhs);
346 virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
347 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
348 virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
349 virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
350 virtual void Dump(FILE* = 0);
353 //---------------------------------------------------------------------------------
355 class Identification;
359 class OP1aHeader : public Partition
361 Kumu::ByteString m_HeaderData;
362 ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
366 const Dictionary*& m_Dict;
367 ASDCP::MXF::Primer m_Primer;
370 OP1aHeader(const Dictionary*&);
371 virtual ~OP1aHeader();
372 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
373 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
374 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
375 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
376 virtual void Dump(FILE* = 0);
377 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
378 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
379 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
380 Identification* GetIdentification();
381 SourcePackage* GetSourcePackage();
385 class OPAtomIndexFooter : public Partition
387 Kumu::ByteString m_FooterData;
388 IndexTableSegment* m_CurrentSegment;
389 ui32_t m_BytesPerEditUnit;
393 ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
397 const Dictionary*& m_Dict;
398 Kumu::fpos_t m_ECOffset;
399 IPrimerLookup* m_Lookup;
401 OPAtomIndexFooter(const Dictionary*&);
402 virtual ~OPAtomIndexFooter();
403 virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
404 virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
405 virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
406 virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration);
407 virtual void Dump(FILE* = 0);
409 virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
410 virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
411 virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
413 virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const;
414 virtual void PushIndexEntry(const IndexTableSegment::IndexEntry&);
415 virtual void SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate);
416 virtual void SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset);
419 //---------------------------------------------------------------------------------
423 inline std::string to_lower(std::string str) {
424 std::transform(str.begin(), str.end(), str.begin(), ::tolower);
428 // ignore case when searching for audio labels
431 inline bool operator()(const std::string& a, const std::string& b) const {
432 return to_lower(a) < to_lower(b);
436 typedef std::map<const std::string, const UL, ci_comp> mca_label_map_t;
437 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&);
440 class ASDCP_MCAConfigParser : public InterchangeObject_list_t
442 KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser);
443 ASDCP_MCAConfigParser();
446 mca_label_map_t m_LabelMap;
447 ui32_t m_ChannelCount;
448 const Dictionary*& m_Dict;
452 ASDCP_MCAConfigParser(const Dictionary*&);
453 bool DecodeString(const std::string& s, const std::string& language = "en");
455 // Valid only after a successful call to DecodeString
456 ui32_t ChannelCount() const;
460 class AS02_MCAConfigParser : public ASDCP_MCAConfigParser
462 KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser);
463 AS02_MCAConfigParser();
466 AS02_MCAConfigParser(const Dictionary*&);