included CMakelists.txt into dist
[asdcplib.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$
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                 if ( Tag.a < rhs.Tag.a )
189                   {
190                     return true;
191                   }
192                 
193                 if ( Tag.a == rhs.Tag.a && Tag.b < rhs.Tag.b )
194                   {
195                     return true;
196                   }
197
198                 return false;
199               }
200
201               inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
202                 snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b);
203                 UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf));
204                 return str_buf;
205               }
206
207               inline bool HasValue() const { return UL.HasValue(); }
208               inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); }
209
210               inline bool Unarchive(Kumu::MemIOReader* Reader) {
211                 if ( ! Reader->ReadUi8(&Tag.a) ) return false;
212                 if ( ! Reader->ReadUi8(&Tag.b) ) return false;
213                 return UL.Unarchive(Reader);
214               }
215
216               inline bool Archive(Kumu::MemIOWriter* Writer) const {
217                 if ( ! Writer->WriteUi8(Tag.a) ) return false;
218                 if ( ! Writer->WriteUi8(Tag.b) ) return false;
219                 return UL.Archive(Writer);
220               }
221             };
222
223           Batch<LocalTagEntry> LocalTagEntryBatch;
224           const Dictionary*& m_Dict;
225
226           Primer(const Dictionary*&);
227           virtual ~Primer();
228
229           virtual void     ClearTagList();
230           virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag);
231           virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag);
232
233           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
234           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
235           virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
236           virtual void     Dump(FILE* = 0);
237         };
238
239       // wrapper object manages optional properties
240       template <class PropertyType>
241         class optional_property
242         {
243           PropertyType m_property;
244           bool m_has_value;
245
246         public:
247         optional_property() : m_has_value(false) {}
248         optional_property(const PropertyType& value) : m_property(value), m_has_value(true) {}
249           const optional_property<PropertyType>& operator=(const PropertyType& rhs) {
250             this->m_property = rhs;
251             this->m_has_value = true;
252             return *this;
253           }
254           bool operator==(const PropertyType& rhs) const { return this->m_property == rhs; }
255           bool operator==(const optional_property<PropertyType>& rhs) const { return this->m_property == rhs.m_property; }
256           operator PropertyType&() { return this->m_property; }
257           void set(const PropertyType& rhs) { this->m_property = rhs; this->m_has_value = true; }
258           void set_has_value(bool has_value = true) { this->m_has_value = has_value; }
259           void reset(const PropertyType& rhs) { this->m_has_value = false; }
260           bool empty() const { return ! m_has_value; }
261           PropertyType& get() { return m_property; }
262           const PropertyType& const_get() const { return m_property; }
263         };
264
265       // wrapper object manages optional properties
266       template <class PropertyType>
267         class optional_container_property
268         {
269           PropertyType m_property;
270
271         public:
272           optional_container_property() {}
273         optional_container_property(const PropertyType& value) : m_property(value) {}
274           const optional_container_property<PropertyType>& operator=(const PropertyType& rhs) {
275             this->Copy(rhs.m_property);
276             return *this;
277           }
278
279           bool operator==(const PropertyType& rhs) const { return this->m_property == rhs; }
280           bool operator==(const optional_property<PropertyType>& rhs) const { return this->m_property == rhs.m_property; }
281           operator PropertyType&() { return this->m_property; }
282           void set(const PropertyType& rhs) { this->m_property = rhs; }
283           void reset(const PropertyType& rhs) { this->clear(); }
284           bool empty() const { return ! this->m_property.HasValue(); }
285           PropertyType& get() { return m_property; }
286           const PropertyType& const_get() const { return m_property; }
287         };
288
289       // base class of all metadata objects
290       //
291       class InterchangeObject : public ASDCP::KLVPacket
292         {
293           InterchangeObject();
294
295         public:
296           const Dictionary*& m_Dict;
297           IPrimerLookup* m_Lookup;
298           UUID           InstanceUID;
299           optional_property<UUID>  GenerationUID;
300
301         InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
302           virtual ~InterchangeObject() {}
303
304           virtual void Copy(const InterchangeObject& rhs);
305           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
306           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
307           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
308           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
309           virtual bool     IsA(const byte_t* label);
310           virtual const char* ObjectName() { return "InterchangeObject"; }
311           virtual void     Dump(FILE* stream = 0);
312         };
313
314       //
315       typedef std::list<InterchangeObject*> InterchangeObject_list_t;
316
317       //
318       class Preface : public InterchangeObject
319         {
320           ASDCP_NO_COPY_CONSTRUCT(Preface);
321           Preface();
322
323         public:
324           const Dictionary*& m_Dict;
325           Kumu::Timestamp    LastModifiedDate;
326           ui16_t       Version;
327           optional_property<ui32_t> ObjectModelVersion;
328           optional_property<UUID> PrimaryPackage;
329           Array<UUID>  Identifications;
330           UUID         ContentStorage;
331           UL           OperationalPattern;
332           Batch<UL>    EssenceContainers;
333           Batch<UL>    DMSchemes;
334           optional_property<Batch<UL> > ApplicationSchemes;
335
336           Preface(const Dictionary*& d);
337           virtual ~Preface() {}
338
339           virtual void Copy(const Preface& rhs);
340           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
341           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
342           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
343           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
344           virtual void     Dump(FILE* = 0);
345         };
346
347       const ui32_t MaxIndexSegmentSize = 65536;
348
349       //
350       class IndexTableSegment : public InterchangeObject
351         {
352           IndexTableSegment();
353           ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
354
355         public:
356           //
357         class DeltaEntry : public Kumu::IArchive
358             {
359             public:
360               i8_t    PosTableIndex;
361               ui8_t   Slice;
362               ui32_t  ElementData;
363
364               DeltaEntry() : PosTableIndex(0), Slice(0), ElementData(0) {}
365               DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
366               inline bool HasValue() const { return true; }
367               ui32_t      ArchiveLength() const { return sizeof(ui32_t) + 2; }
368               bool        Unarchive(Kumu::MemIOReader* Reader);
369               bool        Archive(Kumu::MemIOWriter* Writer) const;
370               const char* EncodeString(char* str_buf, ui32_t buf_len) const;
371             };
372
373           //
374           class IndexEntry : public Kumu::IArchive
375             {
376             public:
377               i8_t               TemporalOffset;
378               i8_t               KeyFrameOffset;
379               ui8_t              Flags;
380               ui64_t             StreamOffset;
381
382               // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
383               // to a more suitable value
384               //              std::list<ui32_t>  SliceOffset;
385               //              Array<Rational>    PosTable;
386
387               IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
388               IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
389                     TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
390               inline bool HasValue() const { return true; }
391               ui32_t      ArchiveLength() const { return sizeof(ui64_t) + 3; };
392               bool        Unarchive(Kumu::MemIOReader* Reader);
393               bool        Archive(Kumu::MemIOWriter* Writer) const;
394               const char* EncodeString(char* str_buf, ui32_t buf_len) const;
395             };
396
397           const Dictionary*& m_Dict;
398           ui64_t  RtFileOffset; // not part of the MXF structure: used to manage runtime index access 
399           ui64_t  RtEntryOffset;
400
401           Rational    IndexEditRate;
402           ui64_t      IndexStartPosition;
403           ui64_t      IndexDuration;
404           ui32_t      EditUnitByteCount;
405           ui32_t      IndexSID;
406           ui32_t      BodySID;
407           ui8_t       SliceCount;
408           ui8_t       PosTableCount;
409           Array<DeltaEntry> DeltaEntryArray;
410           Array<IndexEntry> IndexEntryArray;
411
412           IndexTableSegment(const Dictionary*&);
413           virtual ~IndexTableSegment();
414
415           virtual void Copy(const IndexTableSegment& rhs);
416           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
417           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
418           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
419           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
420           virtual void     Dump(FILE* = 0);
421         };
422
423       //---------------------------------------------------------------------------------
424       //
425       class Identification;
426       class SourcePackage;
427
428       //
429       class OP1aHeader : public Partition
430         {
431           Kumu::ByteString m_HeaderData;
432           ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
433           OP1aHeader();
434
435         public:
436           const Dictionary*&  m_Dict;
437           ASDCP::MXF::Primer  m_Primer;
438           Preface*            m_Preface;
439
440           OP1aHeader(const Dictionary*&);
441           virtual ~OP1aHeader();
442           virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
443           virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
444           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
445           virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
446           virtual void     Dump(FILE* = 0);
447           virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
448           virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
449           virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
450           Identification*  GetIdentification();
451           SourcePackage*   GetSourcePackage();
452         };
453
454       // Searches the header object and returns the edit rate based on the contents of the
455       // File Package items.  Logs an error message and returns false if anthing goes wrong.
456       bool GetEditRateFromFP(ASDCP::MXF::OP1aHeader& header, ASDCP::Rational& edit_rate);
457
458       //
459       class OPAtomIndexFooter : public Partition
460         {
461           Kumu::ByteString    m_FooterData;
462           IndexTableSegment*  m_CurrentSegment;
463           ui32_t              m_BytesPerEditUnit;
464           Rational            m_EditRate;
465           ui32_t              m_BodySID;
466           IndexTableSegment::DeltaEntry m_DefaultDeltaEntry;
467
468           ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
469           OPAtomIndexFooter();
470
471         public:
472           const Dictionary*&   m_Dict;
473           Kumu::fpos_t        m_ECOffset;
474           IPrimerLookup*      m_Lookup;
475          
476           OPAtomIndexFooter(const Dictionary*&);
477           virtual ~OPAtomIndexFooter();
478           virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
479           virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
480           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
481           virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration);
482           virtual void     Dump(FILE* = 0);
483
484           virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
485           virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
486           virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
487
488           virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const;
489           virtual void     PushIndexEntry(const IndexTableSegment::IndexEntry&);
490           virtual void     SetDeltaParams(const IndexTableSegment::DeltaEntry&);
491           virtual void     SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate);
492           virtual void     SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset);
493         };
494
495       //---------------------------------------------------------------------------------
496       //
497
498       //
499       inline std::string to_lower(std::string str) {
500         std::transform(str.begin(), str.end(), str.begin(), ::tolower);
501         return str;
502       }
503
504       // ignore case when searching for audio labels
505       struct ci_comp
506       {
507         inline bool operator()(const std::string& a, const std::string& b) const {
508           return to_lower(a) < to_lower(b);
509         }
510       };
511
512       struct label_traits
513       {
514         const std::string tag_name;
515         const bool requires_prefix;
516         const UL ul;
517
518       label_traits(const std::string& tag_name, const bool requires_prefix, const UL ul) : 
519         tag_name(tag_name), requires_prefix(requires_prefix), ul(ul) { }
520       };
521
522       typedef std::map<const std::string, const label_traits, ci_comp> mca_label_map_t;
523
524       bool decode_mca_string(const std::string& s, const mca_label_map_t& labels,
525                              const Dictionary*& dict, const std::string& language, InterchangeObject_list_t&, ui32_t&);
526
527       //
528       class ASDCP_MCAConfigParser : public InterchangeObject_list_t
529         {
530           KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser);
531           ASDCP_MCAConfigParser();
532
533         protected:
534           mca_label_map_t m_LabelMap;
535           ui32_t m_ChannelCount;
536           const Dictionary*& m_Dict;
537
538           
539         public:
540           ASDCP_MCAConfigParser(const Dictionary*&);
541           bool DecodeString(const std::string& s, const std::string& language = "en-US");
542
543           // Valid only after a successful call to DecodeString
544           ui32_t ChannelCount() const;
545         };
546
547       //
548       class AS02_MCAConfigParser : public ASDCP_MCAConfigParser
549         {
550           KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser);
551           AS02_MCAConfigParser();
552           
553         public:
554           AS02_MCAConfigParser(const Dictionary*&);
555         };
556
557     } // namespace MXF
558 } // namespace ASDCP
559
560
561 #endif // _MXF_H_
562
563 //
564 // end MXF.h
565 //