more optional stuff
[asdcplib.git] / src / MXF.h
1 /*
2 Copyright (c) 2005-2013, 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(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 Pair : public Kumu::IArchive
68             {
69             public:
70               ui32_t BodySID;
71               ui64_t ByteOffset;
72
73               Pair() : BodySID(0), ByteOffset(0) {}
74               Pair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {}
75               virtual ~Pair() {}
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           Array<Pair> PairArray;
103
104         RIP(const Dictionary*& d) : m_Dict(d) {}
105           virtual ~RIP() {}
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);
110         };
111
112
113       //
114       class Partition : public ASDCP::KLVFilePacket
115         {
116           ASDCP_NO_COPY_CONSTRUCT(Partition);
117           Partition();
118
119         protected:
120           class PacketList
121           {
122           public:
123             std::list<InterchangeObject*> m_List;
124             std::map<UUID, InterchangeObject*> m_Map;
125
126             ~PacketList();
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);
131           };
132
133           mem_ptr<PacketList> m_PacketList;
134
135         public:
136           const Dictionary*& m_Dict;
137
138           ui16_t    MajorVersion;
139           ui16_t    MinorVersion;
140           ui32_t    KAGSize;
141           ui64_t    ThisPartition;
142           ui64_t    PreviousPartition;
143           ui64_t    FooterPartition;
144           ui64_t    HeaderByteCount;
145           ui64_t    IndexByteCount;
146           ui32_t    IndexSID;
147           ui64_t    BodyOffset;
148           ui32_t    BodySID;
149           UL        OperationalPattern;
150           Batch<UL> EssenceContainers;
151
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);
160         };
161
162
163       //
164       class Primer : public ASDCP::KLVFilePacket, public ASDCP::IPrimerLookup
165         {
166           class h__PrimerLookup;
167           mem_ptr<h__PrimerLookup> m_Lookup;
168           ui8_t   m_LocalTag;
169           ASDCP_NO_COPY_CONSTRUCT(Primer);
170           Primer();
171
172         public:
173           //
174         class LocalTagEntry : Kumu::IArchive
175             {
176             public:
177               TagValue    Tag;
178               ASDCP::UL   UL;
179
180               LocalTagEntry() { Tag.a = Tag.b = 0; }
181             LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {}
182
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));
186                 return str_buf;
187               }
188
189               inline bool HasValue() const { return UL.HasValue(); }
190               inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); }
191
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);
196               }
197
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);
202               }
203             };
204
205           Batch<LocalTagEntry> LocalTagEntryBatch;
206           const Dictionary*& m_Dict;
207
208           Primer(const Dictionary*&);
209           virtual ~Primer();
210
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);
214
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);
219         };
220
221       // wrapper object manages optional properties
222       template <class PropertyType>
223         class optional_property
224         {
225           PropertyType m_property;
226           bool m_has_value;
227
228         public:
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& cget() const { return m_property; }
241         };
242
243       // base class of all metadata objects
244       //
245       class InterchangeObject : public ASDCP::KLVPacket
246         {
247           InterchangeObject();
248
249         public:
250           const Dictionary*& m_Dict;
251           IPrimerLookup* m_Lookup;
252           UUID           InstanceUID;
253           optional_property<UUID>  GenerationUID;
254
255         InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
256           virtual ~InterchangeObject() {}
257
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);
266         };
267
268       //
269       typedef std::list<InterchangeObject*> InterchangeObject_list_t;
270
271       //
272       class Preface : public InterchangeObject
273         {
274           ASDCP_NO_COPY_CONSTRUCT(Preface);
275           Preface();
276
277         public:
278           const Dictionary*& m_Dict;
279           Kumu::Timestamp    LastModifiedDate;
280           ui16_t       Version;
281           optional_property<ui32_t> ObjectModelVersion;
282           optional_property<UUID> PrimaryPackage;
283           Batch<UUID>  Identifications;
284           UUID         ContentStorage;
285           UL           OperationalPattern;
286           Batch<UL>    EssenceContainers;
287           Batch<UL>    DMSchemes;
288           optional_property<Batch<UL> > ApplicationSchemes;
289
290           Preface(const Dictionary*& d);
291           virtual ~Preface() {}
292
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);
299         };
300
301       const ui32_t MaxIndexSegmentSize = 65536;
302
303       //
304       class IndexTableSegment : public InterchangeObject
305         {
306           ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
307
308         public:
309           //
310         class DeltaEntry : public Kumu::IArchive
311             {
312             public:
313               i8_t    PosTableIndex;
314               ui8_t   Slice;
315               ui32_t  ElementData;
316
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;
324             };
325
326           //
327           class IndexEntry : public Kumu::IArchive
328             {
329             public:
330               i8_t               TemporalOffset;
331               i8_t               KeyFrameOffset;
332               ui8_t              Flags;
333               ui64_t             StreamOffset;
334
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;
339
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;
348             };
349
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;
353
354           Rational    IndexEditRate;
355           ui64_t      IndexStartPosition;
356           ui64_t      IndexDuration;
357           ui32_t      EditUnitByteCount;
358           ui32_t      IndexSID;
359           ui32_t      BodySID;
360           ui8_t       SliceCount;
361           ui8_t       PosTableCount;
362           Batch<DeltaEntry> DeltaEntryArray;
363           Batch<IndexEntry> IndexEntryArray;
364
365           IndexTableSegment(const Dictionary*&);
366           virtual ~IndexTableSegment();
367
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);
374         };
375
376       //---------------------------------------------------------------------------------
377       //
378       class Identification;
379       class SourcePackage;
380
381       //
382       class OP1aHeader : public Partition
383         {
384           Kumu::ByteString m_HeaderData;
385           ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
386           OP1aHeader();
387
388         public:
389           const Dictionary*&  m_Dict;
390           ASDCP::MXF::Primer  m_Primer;
391           Preface*            m_Preface;
392
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();
405         };
406
407       //
408       class OPAtomIndexFooter : public Partition
409         {
410           Kumu::ByteString    m_FooterData;
411           IndexTableSegment*  m_CurrentSegment;
412           ui32_t              m_BytesPerEditUnit;
413           Rational            m_EditRate;
414           ui32_t              m_BodySID;
415
416           ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
417           OPAtomIndexFooter();
418
419         public:
420           const Dictionary*&   m_Dict;
421           Kumu::fpos_t        m_ECOffset;
422           IPrimerLookup*      m_Lookup;
423          
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);
431
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);
435
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);
440         };
441
442       //---------------------------------------------------------------------------------
443       //
444
445       //
446       inline std::string to_lower(std::string str) {
447         std::transform(str.begin(), str.end(), str.begin(), ::tolower);
448         return str;
449       }
450
451       // ignore case when searching for audio labels
452       struct ci_comp
453       {
454         inline bool operator()(const std::string& a, const std::string& b) const {
455           return to_lower(a) < to_lower(b);
456         }
457       };
458
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&);
461
462       //
463       class ASDCP_MCAConfigParser : public InterchangeObject_list_t
464         {
465           KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser);
466           ASDCP_MCAConfigParser();
467
468         protected:
469           mca_label_map_t m_LabelMap;
470           ui32_t m_ChannelCount;
471           const Dictionary*& m_Dict;
472
473           
474         public:
475           ASDCP_MCAConfigParser(const Dictionary*&);
476           bool DecodeString(const std::string& s, const std::string& language = "en");
477
478           // Valid only after a successful call to DecodeString
479           ui32_t ChannelCount() const;
480         };
481
482       //
483       class AS02_MCAConfigParser : public ASDCP_MCAConfigParser
484         {
485           KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser);
486           AS02_MCAConfigParser();
487           
488         public:
489           AS02_MCAConfigParser(const Dictionary*&);
490         };
491
492     } // namespace MXF
493 } // namespace ASDCP
494
495
496 #endif // _MXF_H_
497
498 //
499 // end MXF.h
500 //