Add call to parent constructor.
[asdcplib-cth.git] / src / MXF.h
1 /*
2 Copyright (c) 2005-2015, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
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.
15
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.
26 */
27 /*! \file    MXF.h
28     \version $Id: MXF.h,v 1.57 2015/10/10 20:26:29 jhurst Exp $
29     \brief   MXF objects
30 */
31
32 #ifndef _MXF_H_
33 #define _MXF_H_
34
35 #include "MXFTypes.h"
36 #include <algorithm>
37
38 namespace ASDCP
39 {
40   namespace MXF
41     {
42       class InterchangeObject;
43
44       const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
45
46       //
47       typedef ASDCP::MXF::InterchangeObject* (*MXFObjectFactory_t)(const Dictionary*&);
48
49       //
50       void SetObjectFactory(const UL& label, MXFObjectFactory_t factory);
51
52       //
53       InterchangeObject* CreateObject(const Dictionary*& Dict, const UL& label);
54
55
56       // seek an open file handle to the start of the RIP KLV packet
57       Result_t SeekToRIP(const Kumu::FileReader&);
58       
59       //
60       class RIP : public ASDCP::KLVFilePacket
61         {
62           ASDCP_NO_COPY_CONSTRUCT(RIP);
63           RIP();
64
65         public:
66           //
67           class PartitionPair : public Kumu::IArchive
68             {
69             public:
70               ui32_t BodySID;
71               ui64_t ByteOffset;
72
73               PartitionPair() : BodySID(0), ByteOffset(0) {}
74               PartitionPair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {}
75               virtual ~PartitionPair() {}
76
77               ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); }
78
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());
82                 return str_buf;
83               }
84
85               inline bool HasValue() const { return true; }
86               inline ui32_t ArchiveLength() const { return sizeof(ui32_t) + sizeof(ui64_t); }
87
88               inline bool Unarchive(Kumu::MemIOReader* Reader) {
89                 if ( ! Reader->ReadUi32BE(&BodySID) ) return false;
90                 if ( ! Reader->ReadUi64BE(&ByteOffset) ) return false;
91                 return true;
92               }
93               
94               inline bool Archive(Kumu::MemIOWriter* Writer) const {
95                 if ( ! Writer->WriteUi32BE(BodySID) ) return false;
96                 if ( ! Writer->WriteUi64BE(ByteOffset) ) return false;
97                 return true;
98               }
99             };
100
101           const Dictionary*& m_Dict;
102
103           typedef SimpleArray<PartitionPair>::iterator pair_iterator;
104           typedef SimpleArray<PartitionPair>::const_iterator const_pair_iterator;
105
106           SimpleArray<PartitionPair> PairArray;
107
108         RIP(const Dictionary*& d) : m_Dict(d) {}
109           virtual ~RIP() {}
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);
114         };
115
116
117       //
118       class Partition : public ASDCP::KLVFilePacket
119         {
120           ASDCP_NO_COPY_CONSTRUCT(Partition);
121           Partition();
122
123         protected:
124           class PacketList
125           {
126           public:
127             std::list<InterchangeObject*> m_List;
128             std::map<UUID, InterchangeObject*> m_Map;
129
130             ~PacketList();
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);
135           };
136
137           mem_ptr<PacketList> m_PacketList;
138
139         public:
140           const Dictionary*& m_Dict;
141
142           ui16_t    MajorVersion;
143           ui16_t    MinorVersion;
144           ui32_t    KAGSize;
145           ui64_t    ThisPartition;
146           ui64_t    PreviousPartition;
147           ui64_t    FooterPartition;
148           ui64_t    HeaderByteCount;
149           ui64_t    IndexByteCount;
150           ui32_t    IndexSID;
151           ui64_t    BodyOffset;
152           ui32_t    BodySID;
153           UL        OperationalPattern;
154           Batch<UL> EssenceContainers;
155
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);
164         };
165
166
167       //
168       class Primer : public ASDCP::KLVFilePacket, public ASDCP::IPrimerLookup
169         {
170           class h__PrimerLookup;
171           mem_ptr<h__PrimerLookup> m_Lookup;
172           ui8_t   m_LocalTag;
173           ASDCP_NO_COPY_CONSTRUCT(Primer);
174           Primer();
175
176         public:
177           //
178         class LocalTagEntry : Kumu::IArchive
179             {
180             public:
181               TagValue    Tag;
182               ASDCP::UL   UL;
183
184               LocalTagEntry() { Tag.a = Tag.b = 0; }
185             LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {}
186
187               bool operator<(const LocalTagEntry& rhs) const {
188                 return ( ( Tag.a < rhs.Tag.a ) || ( Tag.b < rhs.Tag.b ) );
189               }
190
191               inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
192                 snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b);
193                 UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf));
194                 return str_buf;
195               }
196
197               inline bool HasValue() const { return UL.HasValue(); }
198               inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); }
199
200               inline bool Unarchive(Kumu::MemIOReader* Reader) {
201                 if ( ! Reader->ReadUi8(&Tag.a) ) return false;
202                 if ( ! Reader->ReadUi8(&Tag.b) ) return false;
203                 return UL.Unarchive(Reader);
204               }
205
206               inline bool Archive(Kumu::MemIOWriter* Writer) const {
207                 if ( ! Writer->WriteUi8(Tag.a) ) return false;
208                 if ( ! Writer->WriteUi8(Tag.b) ) return false;
209                 return UL.Archive(Writer);
210               }
211             };
212
213           Batch<LocalTagEntry> LocalTagEntryBatch;
214           const Dictionary*& m_Dict;
215
216           Primer(const Dictionary*&);
217           virtual ~Primer();
218
219           virtual void     ClearTagList();
220           virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag);
221           virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag);
222
223           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
224           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
225           virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
226           virtual void     Dump(FILE* = 0);
227         };
228
229       // wrapper object manages optional properties
230       template <class PropertyType>
231         class optional_property
232         {
233           PropertyType m_property;
234           bool m_has_value;
235
236         public:
237         optional_property() : m_has_value(false) {}
238         optional_property(const PropertyType& value) : m_property(value), m_has_value(true) {}
239           const optional_property<PropertyType>& operator=(const PropertyType& rhs) {
240             this->m_property = rhs;
241             this->m_has_value = true;
242             return *this;
243           }
244           bool operator==(const PropertyType& rhs) const { return this->m_property == rhs; }
245           bool operator==(const optional_property<PropertyType>& rhs) const { return this->m_property == rhs.m_property; }
246           operator PropertyType&() { return this->m_property; }
247           void set(const PropertyType& rhs) { this->m_property = rhs; this->m_has_value = true; }
248           void set_has_value(bool has_value = true) { this->m_has_value = has_value; }
249           void reset(const PropertyType& rhs) { this->m_has_value = false; }
250           bool empty() const { return ! m_has_value; }
251           PropertyType& get() { return m_property; }
252           const PropertyType& const_get() const { return m_property; }
253         };
254
255       // wrapper object manages optional properties
256       template <class PropertyType>
257         class optional_container_property
258         {
259           PropertyType m_property;
260
261         public:
262           optional_container_property() {}
263         optional_container_property(const PropertyType& value) : m_property(value) {}
264           const optional_container_property<PropertyType>& operator=(const PropertyType& rhs) {
265             this->Copy(rhs.m_property);
266             return *this;
267           }
268
269           bool operator==(const PropertyType& rhs) const { return this->m_property == rhs; }
270           bool operator==(const optional_property<PropertyType>& rhs) const { return this->m_property == rhs.m_property; }
271           operator PropertyType&() { return this->m_property; }
272           void set(const PropertyType& rhs) { this->m_property = rhs; }
273           void reset(const PropertyType& rhs) { this->clear(); }
274           bool empty() const { return ! this->m_property.HasValue(); }
275           PropertyType& get() { return m_property; }
276           const PropertyType& const_get() const { return m_property; }
277         };
278
279       // base class of all metadata objects
280       //
281       class InterchangeObject : public ASDCP::KLVPacket
282         {
283           InterchangeObject();
284
285         public:
286           const Dictionary*& m_Dict;
287           IPrimerLookup* m_Lookup;
288           UUID           InstanceUID;
289           optional_property<UUID>  GenerationUID;
290
291         InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
292           virtual ~InterchangeObject() {}
293
294           virtual void Copy(const InterchangeObject& rhs);
295           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
296           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
297           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
298           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
299           virtual bool     IsA(const byte_t* label);
300           virtual const char* ObjectName() { return "InterchangeObject"; }
301           virtual void     Dump(FILE* stream = 0);
302         };
303
304       //
305       typedef std::list<InterchangeObject*> InterchangeObject_list_t;
306
307       //
308       class Preface : public InterchangeObject
309         {
310           ASDCP_NO_COPY_CONSTRUCT(Preface);
311           Preface();
312
313         public:
314           const Dictionary*& m_Dict;
315           Kumu::Timestamp    LastModifiedDate;
316           ui16_t       Version;
317           optional_property<ui32_t> ObjectModelVersion;
318           optional_property<UUID> PrimaryPackage;
319           Array<UUID>  Identifications;
320           UUID         ContentStorage;
321           UL           OperationalPattern;
322           Batch<UL>    EssenceContainers;
323           Batch<UL>    DMSchemes;
324           optional_property<Batch<UL> > ApplicationSchemes;
325
326           Preface(const Dictionary*& d);
327           virtual ~Preface() {}
328
329           virtual void Copy(const Preface& rhs);
330           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
331           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
332           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
333           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
334           virtual void     Dump(FILE* = 0);
335         };
336
337       const ui32_t MaxIndexSegmentSize = 65536;
338
339       //
340       class IndexTableSegment : public InterchangeObject
341         {
342           IndexTableSegment();
343           ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
344
345         public:
346           //
347         class DeltaEntry : public Kumu::IArchive
348             {
349             public:
350               i8_t    PosTableIndex;
351               ui8_t   Slice;
352               ui32_t  ElementData;
353
354               DeltaEntry() : PosTableIndex(0), Slice(0), ElementData(0) {}
355               DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
356               inline bool HasValue() const { return true; }
357               ui32_t      ArchiveLength() const { return sizeof(ui32_t) + 2; }
358               bool        Unarchive(Kumu::MemIOReader* Reader);
359               bool        Archive(Kumu::MemIOWriter* Writer) const;
360               const char* EncodeString(char* str_buf, ui32_t buf_len) const;
361             };
362
363           //
364           class IndexEntry : public Kumu::IArchive
365             {
366             public:
367               i8_t               TemporalOffset;
368               i8_t               KeyFrameOffset;
369               ui8_t              Flags;
370               ui64_t             StreamOffset;
371
372               // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
373               // to a more suitable value
374               //              std::list<ui32_t>  SliceOffset;
375               //              Array<Rational>    PosTable;
376
377               IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
378               IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
379                     TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
380               inline bool HasValue() const { return true; }
381               ui32_t      ArchiveLength() const { return sizeof(ui64_t) + 3; };
382               bool        Unarchive(Kumu::MemIOReader* Reader);
383               bool        Archive(Kumu::MemIOWriter* Writer) const;
384               const char* EncodeString(char* str_buf, ui32_t buf_len) const;
385             };
386
387           const Dictionary*& m_Dict;
388           ui64_t  RtFileOffset; // not part of the MXF structure: used to manage runtime index access 
389           ui64_t  RtEntryOffset;
390
391           Rational    IndexEditRate;
392           ui64_t      IndexStartPosition;
393           ui64_t      IndexDuration;
394           ui32_t      EditUnitByteCount;
395           ui32_t      IndexSID;
396           ui32_t      BodySID;
397           ui8_t       SliceCount;
398           ui8_t       PosTableCount;
399           Array<DeltaEntry> DeltaEntryArray;
400           Array<IndexEntry> IndexEntryArray;
401
402           IndexTableSegment(const Dictionary*&);
403           virtual ~IndexTableSegment();
404
405           virtual void Copy(const IndexTableSegment& rhs);
406           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
407           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
408           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
409           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
410           virtual void     Dump(FILE* = 0);
411         };
412
413       //---------------------------------------------------------------------------------
414       //
415       class Identification;
416       class SourcePackage;
417
418       //
419       class OP1aHeader : public Partition
420         {
421           Kumu::ByteString m_HeaderData;
422           ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
423           OP1aHeader();
424
425         public:
426           const Dictionary*&  m_Dict;
427           ASDCP::MXF::Primer  m_Primer;
428           Preface*            m_Preface;
429
430           OP1aHeader(const Dictionary*&);
431           virtual ~OP1aHeader();
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, ui32_t HeaderLength = 16384);
436           virtual void     Dump(FILE* = 0);
437           virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
438           virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
439           virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
440           Identification*  GetIdentification();
441           SourcePackage*   GetSourcePackage();
442         };
443
444       // Searches the header object and returns the edit rate based on the contents of the
445       // File Package items.  Logs an error message and returns false if anthing goes wrong.
446       bool GetEditRateFromFP(ASDCP::MXF::OP1aHeader& header, ASDCP::Rational& edit_rate);
447
448       //
449       class OPAtomIndexFooter : public Partition
450         {
451           Kumu::ByteString    m_FooterData;
452           IndexTableSegment*  m_CurrentSegment;
453           ui32_t              m_BytesPerEditUnit;
454           Rational            m_EditRate;
455           ui32_t              m_BodySID;
456           IndexTableSegment::DeltaEntry m_DefaultDeltaEntry;
457
458           ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
459           OPAtomIndexFooter();
460
461         public:
462           const Dictionary*&   m_Dict;
463           Kumu::fpos_t        m_ECOffset;
464           IPrimerLookup*      m_Lookup;
465          
466           OPAtomIndexFooter(const Dictionary*&);
467           virtual ~OPAtomIndexFooter();
468           virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
469           virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
470           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
471           virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration);
472           virtual void     Dump(FILE* = 0);
473
474           virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
475           virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
476           virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
477
478           virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const;
479           virtual void     PushIndexEntry(const IndexTableSegment::IndexEntry&);
480           virtual void     SetDeltaParams(const IndexTableSegment::DeltaEntry&);
481           virtual void     SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate);
482           virtual void     SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset);
483         };
484
485       //---------------------------------------------------------------------------------
486       //
487
488       //
489       inline std::string to_lower(std::string str) {
490         std::transform(str.begin(), str.end(), str.begin(), ::tolower);
491         return str;
492       }
493
494       // ignore case when searching for audio labels
495       struct ci_comp
496       {
497         inline bool operator()(const std::string& a, const std::string& b) const {
498           return to_lower(a) < to_lower(b);
499         }
500       };
501
502       struct label_traits
503       {
504         const std::string tag_name;
505         const bool requires_prefix;
506         const UL ul;
507
508       label_traits(const std::string& tag_name, const bool requires_prefix, const UL ul) : 
509         tag_name(tag_name), requires_prefix(requires_prefix), ul(ul) { }
510       };
511
512       typedef std::map<const std::string, const label_traits, ci_comp> mca_label_map_t;
513
514       bool decode_mca_string(const std::string& s, const mca_label_map_t& labels,
515                              const Dictionary*& dict, const std::string& language, InterchangeObject_list_t&, ui32_t&);
516
517       //
518       class ASDCP_MCAConfigParser : public InterchangeObject_list_t
519         {
520           KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser);
521           ASDCP_MCAConfigParser();
522
523         protected:
524           mca_label_map_t m_LabelMap;
525           ui32_t m_ChannelCount;
526           const Dictionary*& m_Dict;
527
528           
529         public:
530           ASDCP_MCAConfigParser(const Dictionary*&);
531           bool DecodeString(const std::string& s, const std::string& language = "en-US");
532
533           // Valid only after a successful call to DecodeString
534           ui32_t ChannelCount() const;
535         };
536
537       //
538       class AS02_MCAConfigParser : public ASDCP_MCAConfigParser
539         {
540           KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser);
541           AS02_MCAConfigParser();
542           
543         public:
544           AS02_MCAConfigParser(const Dictionary*&);
545         };
546
547     } // namespace MXF
548 } // namespace ASDCP
549
550
551 #endif // _MXF_H_
552
553 //
554 // end MXF.h
555 //