o Moved personal dev environment from older gcc to newer clang. Many small changes...
[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 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           HeadlessArray<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& const_get() 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           IndexTableSegment();
307           ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
308
309         public:
310           //
311         class DeltaEntry : public Kumu::IArchive
312             {
313             public:
314               i8_t    PosTableIndex;
315               ui8_t   Slice;
316               ui32_t  ElementData;
317
318               DeltaEntry() : PosTableIndex(0), Slice(0), ElementData(0) {}
319               DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
320               inline bool HasValue() const { return true; }
321               ui32_t      ArchiveLength() const { return sizeof(ui32_t) + 2; }
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;
325             };
326
327           //
328           class IndexEntry : public Kumu::IArchive
329             {
330             public:
331               i8_t               TemporalOffset;
332               i8_t               KeyFrameOffset;
333               ui8_t              Flags;
334               ui64_t             StreamOffset;
335
336               // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
337               // to a more suitable value
338               //              std::list<ui32_t>  SliceOffset;
339               //              Array<Rational>    PosTable;
340
341               IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
342               IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
343                     TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
344               inline bool HasValue() const { return true; }
345               ui32_t      ArchiveLength() const { return sizeof(ui64_t) + 3; };
346               bool        Unarchive(Kumu::MemIOReader* Reader);
347               bool        Archive(Kumu::MemIOWriter* Writer) const;
348               const char* EncodeString(char* str_buf, ui32_t buf_len) const;
349             };
350
351           const Dictionary*& m_Dict;
352           ui64_t  RtFileOffset; // not part of the MXF structure: used to manage runtime index access 
353           ui64_t  RtEntryOffset;
354
355           Rational    IndexEditRate;
356           ui64_t      IndexStartPosition;
357           ui64_t      IndexDuration;
358           ui32_t      EditUnitByteCount;
359           ui32_t      IndexSID;
360           ui32_t      BodySID;
361           ui8_t       SliceCount;
362           ui8_t       PosTableCount;
363           Batch<DeltaEntry> DeltaEntryArray;
364           Batch<IndexEntry> IndexEntryArray;
365
366           IndexTableSegment(const Dictionary*&);
367           virtual ~IndexTableSegment();
368
369           virtual void Copy(const IndexTableSegment& rhs);
370           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
371           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
372           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
373           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
374           virtual void     Dump(FILE* = 0);
375         };
376
377       //---------------------------------------------------------------------------------
378       //
379       class Identification;
380       class SourcePackage;
381
382       //
383       class OP1aHeader : public Partition
384         {
385           Kumu::ByteString m_HeaderData;
386           ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
387           OP1aHeader();
388
389         public:
390           const Dictionary*&  m_Dict;
391           ASDCP::MXF::Primer  m_Primer;
392           Preface*            m_Preface;
393
394           OP1aHeader(const Dictionary*&);
395           virtual ~OP1aHeader();
396           virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
397           virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
398           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
399           virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
400           virtual void     Dump(FILE* = 0);
401           virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
402           virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
403           virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
404           Identification*  GetIdentification();
405           SourcePackage*   GetSourcePackage();
406         };
407
408       // Searches the header object and returns the edit rate based on the contents of the
409       // File Package items.  Logs an error message and returns false if anthing goes wrong.
410       bool GetEditRateFromFP(ASDCP::MXF::OP1aHeader& header, ASDCP::Rational& edit_rate);
411
412       //
413       class OPAtomIndexFooter : public Partition
414         {
415           Kumu::ByteString    m_FooterData;
416           IndexTableSegment*  m_CurrentSegment;
417           ui32_t              m_BytesPerEditUnit;
418           Rational            m_EditRate;
419           ui32_t              m_BodySID;
420           IndexTableSegment::DeltaEntry m_DefaultDeltaEntry;
421
422           ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
423           OPAtomIndexFooter();
424
425         public:
426           const Dictionary*&   m_Dict;
427           Kumu::fpos_t        m_ECOffset;
428           IPrimerLookup*      m_Lookup;
429          
430           OPAtomIndexFooter(const Dictionary*&);
431           virtual ~OPAtomIndexFooter();
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, ui64_t duration);
436           virtual void     Dump(FILE* = 0);
437
438           virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
439           virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
440           virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
441
442           virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const;
443           virtual void     PushIndexEntry(const IndexTableSegment::IndexEntry&);
444           virtual void     SetDeltaParams(const IndexTableSegment::DeltaEntry&);
445           virtual void     SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate);
446           virtual void     SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset);
447         };
448
449       //---------------------------------------------------------------------------------
450       //
451
452       //
453       inline std::string to_lower(std::string str) {
454         std::transform(str.begin(), str.end(), str.begin(), ::tolower);
455         return str;
456       }
457
458       // ignore case when searching for audio labels
459       struct ci_comp
460       {
461         inline bool operator()(const std::string& a, const std::string& b) const {
462           return to_lower(a) < to_lower(b);
463         }
464       };
465
466       struct label_traits
467       {
468         const std::string tag_name;
469         const bool requires_prefix;
470         const UL ul;
471
472       label_traits(const std::string& tag_name, const bool requires_prefix, const UL ul) : 
473         tag_name(tag_name), requires_prefix(requires_prefix), ul(ul) { }
474       };
475
476       typedef std::map<const std::string, const label_traits, ci_comp> mca_label_map_t;
477
478       bool decode_mca_string(const std::string& s, const mca_label_map_t& labels,
479                              const Dictionary*& dict, const std::string& language, InterchangeObject_list_t&, ui32_t&);
480
481       //
482       class ASDCP_MCAConfigParser : public InterchangeObject_list_t
483         {
484           KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser);
485           ASDCP_MCAConfigParser();
486
487         protected:
488           mca_label_map_t m_LabelMap;
489           ui32_t m_ChannelCount;
490           const Dictionary*& m_Dict;
491
492           
493         public:
494           ASDCP_MCAConfigParser(const Dictionary*&);
495           bool DecodeString(const std::string& s, const std::string& language = "en-US");
496
497           // Valid only after a successful call to DecodeString
498           ui32_t ChannelCount() const;
499         };
500
501       //
502       class AS02_MCAConfigParser : public ASDCP_MCAConfigParser
503         {
504           KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser);
505           AS02_MCAConfigParser();
506           
507         public:
508           AS02_MCAConfigParser(const Dictionary*&);
509         };
510
511     } // namespace MXF
512 } // namespace ASDCP
513
514
515 #endif // _MXF_H_
516
517 //
518 // end MXF.h
519 //