IMF MCA labels
[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
222       //
223       class InterchangeObject : public ASDCP::KLVPacket
224         {
225           InterchangeObject();
226
227         public:
228           const Dictionary*& m_Dict;
229           IPrimerLookup* m_Lookup;
230           UUID           InstanceUID;
231           UUID           GenerationUID;
232
233         InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
234           virtual ~InterchangeObject() {}
235
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);
244         };
245
246       //
247       typedef std::list<InterchangeObject*> InterchangeObject_list_t;
248
249       //
250       class Preface : public InterchangeObject
251         {
252           ASDCP_NO_COPY_CONSTRUCT(Preface);
253           Preface();
254
255         public:
256           const Dictionary*& m_Dict;
257           Kumu::Timestamp    LastModifiedDate;
258           ui16_t       Version;
259           ui32_t       ObjectModelVersion;
260           UUID         PrimaryPackage;
261           Batch<UUID>  Identifications;
262           UUID         ContentStorage;
263           UL           OperationalPattern;
264           Batch<UL>    EssenceContainers;
265           Batch<UL>    DMSchemes;
266
267           Preface(const Dictionary*& d);
268           virtual ~Preface() {}
269
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);
276         };
277
278       const ui32_t MaxIndexSegmentSize = 65536;
279
280       //
281       class IndexTableSegment : public InterchangeObject
282         {
283           ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
284
285         public:
286           //
287         class DeltaEntry : public Kumu::IArchive
288             {
289             public:
290               i8_t    PosTableIndex;
291               ui8_t   Slice;
292               ui32_t  ElementData;
293
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;
301             };
302
303           //
304           class IndexEntry : public Kumu::IArchive
305             {
306             public:
307               i8_t               TemporalOffset;
308               i8_t               KeyFrameOffset;
309               ui8_t              Flags;
310               ui64_t             StreamOffset;
311
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;
316
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;
325             };
326
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;
330
331           Rational    IndexEditRate;
332           ui64_t      IndexStartPosition;
333           ui64_t      IndexDuration;
334           ui32_t      EditUnitByteCount;
335           ui32_t      IndexSID;
336           ui32_t      BodySID;
337           ui8_t       SliceCount;
338           ui8_t       PosTableCount;
339           Batch<DeltaEntry> DeltaEntryArray;
340           Batch<IndexEntry> IndexEntryArray;
341
342           IndexTableSegment(const Dictionary*&);
343           virtual ~IndexTableSegment();
344
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);
351         };
352
353       //---------------------------------------------------------------------------------
354       //
355       class Identification;
356       class SourcePackage;
357
358       //
359       class OP1aHeader : public Partition
360         {
361           Kumu::ByteString m_HeaderData;
362           ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
363           OP1aHeader();
364
365         public:
366           const Dictionary*&  m_Dict;
367           ASDCP::MXF::Primer  m_Primer;
368           Preface*            m_Preface;
369
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();
382         };
383
384       //
385       class OPAtomIndexFooter : public Partition
386         {
387           Kumu::ByteString    m_FooterData;
388           IndexTableSegment*  m_CurrentSegment;
389           ui32_t              m_BytesPerEditUnit;
390           Rational            m_EditRate;
391           ui32_t              m_BodySID;
392
393           ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
394           OPAtomIndexFooter();
395
396         public:
397           const Dictionary*&   m_Dict;
398           Kumu::fpos_t        m_ECOffset;
399           IPrimerLookup*      m_Lookup;
400          
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);
408
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);
412
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);
417         };
418
419       //---------------------------------------------------------------------------------
420       //
421
422       //
423       inline std::string to_lower(std::string str) {
424         std::transform(str.begin(), str.end(), str.begin(), ::tolower);
425         return str;
426       }
427
428       // ignore case when searching for audio labels
429       struct ci_comp
430       {
431         inline bool operator()(const std::string& a, const std::string& b) const {
432           return to_lower(a) < to_lower(b);
433         }
434       };
435
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&);
438
439       //
440       class ASDCP_MCAConfigParser : public InterchangeObject_list_t
441         {
442           KM_NO_COPY_CONSTRUCT(ASDCP_MCAConfigParser);
443           ASDCP_MCAConfigParser();
444
445         protected:
446           mca_label_map_t m_LabelMap;
447           ui32_t m_ChannelCount;
448           const Dictionary*& m_Dict;
449
450           
451         public:
452           ASDCP_MCAConfigParser(const Dictionary*&);
453           bool DecodeString(const std::string& s, const std::string& language = "en");
454
455           // Valid only after a successful call to DecodeString
456           ui32_t ChannelCount() const;
457         };
458
459       //
460       class AS02_MCAConfigParser : public ASDCP_MCAConfigParser
461         {
462           KM_NO_COPY_CONSTRUCT(AS02_MCAConfigParser);
463           AS02_MCAConfigParser();
464           
465         public:
466           AS02_MCAConfigParser(const Dictionary*&);
467         };
468
469     } // namespace MXF
470 } // namespace ASDCP
471
472
473 #endif // _MXF_H_
474
475 //
476 // end MXF.h
477 //