tweezes
[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
37 namespace ASDCP
38 {
39   namespace MXF
40     {
41       class InterchangeObject;
42
43       const ui32_t kl_length = ASDCP::SMPTE_UL_LENGTH + ASDCP::MXF_BER_LENGTH;
44
45       //
46       typedef ASDCP::MXF::InterchangeObject* (*MXFObjectFactory_t)(const Dictionary*&);
47
48       //
49       void SetObjectFactory(UL label, MXFObjectFactory_t factory);
50
51       //
52       InterchangeObject* CreateObject(const Dictionary*& Dict, const UL& label);
53
54
55       // seek an open file handle to the start of the RIP KLV packet
56       Result_t SeekToRIP(const Kumu::FileReader&);
57       
58       //
59       class RIP : public ASDCP::KLVFilePacket
60         {
61           ASDCP_NO_COPY_CONSTRUCT(RIP);
62           RIP();
63
64         public:
65           //
66           class Pair : public Kumu::IArchive
67             {
68             public:
69               ui32_t BodySID;
70               ui64_t ByteOffset;
71
72               Pair() : BodySID(0), ByteOffset(0) {}
73               Pair(ui32_t sid, ui64_t offset) : BodySID(sid), ByteOffset(offset) {}
74               virtual ~Pair() {}
75
76               ui32_t Size() { return sizeof(ui32_t) + sizeof(ui64_t); }
77
78               inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
79                 Kumu::ui64Printer offset_str(ByteOffset);
80                 snprintf(str_buf, buf_len, "%-6u: %s", BodySID, offset_str.c_str());
81                 return str_buf;
82               }
83
84               inline bool HasValue() const { return true; }
85               inline ui32_t ArchiveLength() const { return sizeof(ui32_t) + sizeof(ui64_t); }
86
87               inline bool Unarchive(Kumu::MemIOReader* Reader) {
88                 if ( ! Reader->ReadUi32BE(&BodySID) ) return false;
89                 if ( ! Reader->ReadUi64BE(&ByteOffset) ) return false;
90                 return true;
91               }
92               
93               inline bool Archive(Kumu::MemIOWriter* Writer) const {
94                 if ( ! Writer->WriteUi32BE(BodySID) ) return false;
95                 if ( ! Writer->WriteUi64BE(ByteOffset) ) return false;
96                 return true;
97               }
98             };
99
100           const Dictionary*& m_Dict;
101           Array<Pair> PairArray;
102
103         RIP(const Dictionary*& d) : m_Dict(d) {}
104           virtual ~RIP() {}
105           virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
106           virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
107           virtual Result_t GetPairBySID(ui32_t, Pair&) const;
108           virtual void     Dump(FILE* = 0);
109         };
110
111
112       //
113       class Partition : public ASDCP::KLVFilePacket
114         {
115           ASDCP_NO_COPY_CONSTRUCT(Partition);
116           Partition();
117
118         protected:
119           class PacketList
120           {
121           public:
122             std::list<InterchangeObject*> m_List;
123             std::map<UUID, InterchangeObject*> m_Map;
124
125             ~PacketList();
126             void AddPacket(InterchangeObject* ThePacket); // takes ownership
127             Result_t GetMDObjectByID(const UUID& ObjectID, InterchangeObject** Object);
128             Result_t GetMDObjectByType(const byte_t* ObjectID, InterchangeObject** Object);
129             Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
130           };
131
132           mem_ptr<PacketList> m_PacketList;
133
134         public:
135           const Dictionary*& m_Dict;
136
137           ui16_t    MajorVersion;
138           ui16_t    MinorVersion;
139           ui32_t    KAGSize;
140           ui64_t    ThisPartition;
141           ui64_t    PreviousPartition;
142           ui64_t    FooterPartition;
143           ui64_t    HeaderByteCount;
144           ui64_t    IndexByteCount;
145           ui32_t    IndexSID;
146           ui64_t    BodyOffset;
147           ui32_t    BodySID;
148           UL        OperationalPattern;
149           Batch<UL> EssenceContainers;
150
151           Partition(const Dictionary*&);
152           virtual ~Partition();
153           virtual void     AddChildObject(InterchangeObject*); // takes ownership
154           virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
155           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
156           virtual Result_t WriteToFile(Kumu::FileWriter& Writer, UL& PartitionLabel);
157           virtual ui32_t   ArchiveSize(); // returns the size of the archived structure
158           virtual void     Dump(FILE* = 0);
159         };
160
161
162       //
163       class Primer : public ASDCP::KLVFilePacket, public ASDCP::IPrimerLookup
164         {
165           class h__PrimerLookup;
166           mem_ptr<h__PrimerLookup> m_Lookup;
167           ui8_t   m_LocalTag;
168           ASDCP_NO_COPY_CONSTRUCT(Primer);
169           Primer();
170
171         public:
172           //
173         class LocalTagEntry : Kumu::IArchive
174             {
175             public:
176               TagValue    Tag;
177               ASDCP::UL   UL;
178
179               LocalTagEntry() { Tag.a = Tag.b = 0; }
180             LocalTagEntry(const TagValue& tag, ASDCP::UL& ul) : Tag(tag), UL(ul) {}
181
182               inline const char* EncodeString(char* str_buf, ui32_t buf_len) const {
183                 snprintf(str_buf, buf_len, "%02x %02x: ", Tag.a, Tag.b);
184                 UL.EncodeString(str_buf + strlen(str_buf), buf_len - strlen(str_buf));
185                 return str_buf;
186               }
187
188               inline bool HasValue() const { return UL.HasValue(); }
189               inline ui32_t ArchiveLength() const { return 2 + UL.ArchiveLength(); }
190
191               inline bool Unarchive(Kumu::MemIOReader* Reader) {
192                 if ( ! Reader->ReadUi8(&Tag.a) ) return false;
193                 if ( ! Reader->ReadUi8(&Tag.b) ) return false;
194                 return UL.Unarchive(Reader);
195               }
196
197               inline bool Archive(Kumu::MemIOWriter* Writer) const {
198                 if ( ! Writer->WriteUi8(Tag.a) ) return false;
199                 if ( ! Writer->WriteUi8(Tag.b) ) return false;
200                 return UL.Archive(Writer);
201               }
202             };
203
204           Batch<LocalTagEntry> LocalTagEntryBatch;
205           const Dictionary*& m_Dict;
206
207           Primer(const Dictionary*&);
208           virtual ~Primer();
209
210           virtual void     ClearTagList();
211           virtual Result_t InsertTag(const MDDEntry& Entry, ASDCP::TagValue& Tag);
212           virtual Result_t TagForKey(const ASDCP::UL& Key, ASDCP::TagValue& Tag);
213
214           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
215           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
216           virtual Result_t WriteToFile(Kumu::FileWriter& Writer);
217           virtual void     Dump(FILE* = 0);
218         };
219
220
221       //
222       class InterchangeObject : public ASDCP::KLVPacket
223         {
224           InterchangeObject();
225
226         public:
227           const Dictionary*& m_Dict;
228           IPrimerLookup* m_Lookup;
229           UUID           InstanceUID;
230           UUID           GenerationUID;
231
232         InterchangeObject(const Dictionary*& d) : m_Dict(d), m_Lookup(0) {}
233           virtual ~InterchangeObject() {}
234
235           virtual void Copy(const InterchangeObject& rhs);
236           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
237           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
238           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
239           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
240           virtual bool     IsA(const byte_t* label);
241           virtual const char* ObjectName() { return "InterchangeObject"; }
242           virtual void     Dump(FILE* stream = 0);
243         };
244
245       //
246       typedef std::list<InterchangeObject*> InterchangeObject_list_t;
247
248       //
249       class Preface : public InterchangeObject
250         {
251           ASDCP_NO_COPY_CONSTRUCT(Preface);
252           Preface();
253
254         public:
255           const Dictionary*& m_Dict;
256           Kumu::Timestamp    LastModifiedDate;
257           ui16_t       Version;
258           ui32_t       ObjectModelVersion;
259           UUID         PrimaryPackage;
260           Batch<UUID>  Identifications;
261           UUID         ContentStorage;
262           UL           OperationalPattern;
263           Batch<UL>    EssenceContainers;
264           Batch<UL>    DMSchemes;
265
266           Preface(const Dictionary*& d);
267           virtual ~Preface() {}
268
269           virtual void Copy(const Preface& rhs);
270           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
271           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
272           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
273           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
274           virtual void     Dump(FILE* = 0);
275         };
276
277       const ui32_t MaxIndexSegmentSize = 65536;
278
279       //
280       class IndexTableSegment : public InterchangeObject
281         {
282           ASDCP_NO_COPY_CONSTRUCT(IndexTableSegment);
283
284         public:
285           //
286         class DeltaEntry : public Kumu::IArchive
287             {
288             public:
289               i8_t    PosTableIndex;
290               ui8_t   Slice;
291               ui32_t  ElementData;
292
293               DeltaEntry() : PosTableIndex(-1), Slice(0), ElementData(0) {}
294               DeltaEntry(i8_t pos, ui8_t slice, ui32_t data) : PosTableIndex(pos), Slice(slice), ElementData(data) {}
295               inline bool HasValue() const { return true; }
296               ui32_t      ArchiveLength() const { return sizeof(ui32_t) + 2; }
297               bool        Unarchive(Kumu::MemIOReader* Reader);
298               bool        Archive(Kumu::MemIOWriter* Writer) const;
299               const char* EncodeString(char* str_buf, ui32_t buf_len) const;
300             };
301
302           //
303           class IndexEntry : public Kumu::IArchive
304             {
305             public:
306               i8_t               TemporalOffset;
307               i8_t               KeyFrameOffset;
308               ui8_t              Flags;
309               ui64_t             StreamOffset;
310
311               // if you use these, you will need to change CBRIndexEntriesPerSegment in MXF.cpp
312               // to a more suitable value
313               //              std::list<ui32_t>  SliceOffset;
314               //              Array<Rational>    PosTable;
315
316               IndexEntry() : TemporalOffset(0), KeyFrameOffset(0), Flags(0), StreamOffset(0) {}
317               IndexEntry(i8_t t_ofst, i8_t k_ofst, ui8_t flags, ui64_t s_ofst) :
318                     TemporalOffset(t_ofst), KeyFrameOffset(k_ofst), Flags(flags), StreamOffset(s_ofst) {}
319               inline bool HasValue() const { return true; }
320               ui32_t      ArchiveLength() const { return sizeof(ui64_t) + 3; };
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           const Dictionary*& m_Dict;
327           ui64_t  RtFileOffset; // not part of the MXF structure: used to manage runtime index access 
328           ui64_t  RtEntryOffset;
329
330           Rational    IndexEditRate;
331           ui64_t      IndexStartPosition;
332           ui64_t      IndexDuration;
333           ui32_t      EditUnitByteCount;
334           ui32_t      IndexSID;
335           ui32_t      BodySID;
336           ui8_t       SliceCount;
337           ui8_t       PosTableCount;
338           Batch<DeltaEntry> DeltaEntryArray;
339           Batch<IndexEntry> IndexEntryArray;
340
341           IndexTableSegment(const Dictionary*&);
342           virtual ~IndexTableSegment();
343
344           virtual void Copy(const IndexTableSegment& rhs);
345           virtual Result_t InitFromTLVSet(TLVReader& TLVSet);
346           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
347           virtual Result_t WriteToTLVSet(TLVWriter& TLVSet);
348           virtual Result_t WriteToBuffer(ASDCP::FrameBuffer&);
349           virtual void     Dump(FILE* = 0);
350         };
351
352       //---------------------------------------------------------------------------------
353       //
354       class Identification;
355       class SourcePackage;
356
357       //
358       class OP1aHeader : public Partition
359         {
360           Kumu::ByteString m_HeaderData;
361           ASDCP_NO_COPY_CONSTRUCT(OP1aHeader);
362           OP1aHeader();
363
364         public:
365           const Dictionary*&  m_Dict;
366           ASDCP::MXF::Primer  m_Primer;
367           Preface*            m_Preface;
368
369           OP1aHeader(const Dictionary*&);
370           virtual ~OP1aHeader();
371           virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
372           virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
373           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
374           virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui32_t HeaderLength = 16384);
375           virtual void     Dump(FILE* = 0);
376           virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
377           virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
378           virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
379           Identification*  GetIdentification();
380           SourcePackage*   GetSourcePackage();
381         };
382
383       //
384       class OPAtomIndexFooter : public Partition
385         {
386           Kumu::ByteString    m_FooterData;
387           IndexTableSegment*  m_CurrentSegment;
388           ui32_t              m_BytesPerEditUnit;
389           Rational            m_EditRate;
390           ui32_t              m_BodySID;
391
392           ASDCP_NO_COPY_CONSTRUCT(OPAtomIndexFooter);
393           OPAtomIndexFooter();
394
395         public:
396           const Dictionary*&   m_Dict;
397           Kumu::fpos_t        m_ECOffset;
398           IPrimerLookup*      m_Lookup;
399          
400           OPAtomIndexFooter(const Dictionary*&);
401           virtual ~OPAtomIndexFooter();
402           virtual Result_t InitFromFile(const Kumu::FileReader& Reader);
403           virtual Result_t InitFromPartitionBuffer(const byte_t* p, ui32_t l);
404           virtual Result_t InitFromBuffer(const byte_t* p, ui32_t l);
405           virtual Result_t WriteToFile(Kumu::FileWriter& Writer, ui64_t duration);
406           virtual void     Dump(FILE* = 0);
407
408           virtual Result_t GetMDObjectByID(const UUID&, InterchangeObject** = 0);
409           virtual Result_t GetMDObjectByType(const byte_t*, InterchangeObject** = 0);
410           virtual Result_t GetMDObjectsByType(const byte_t* ObjectID, std::list<InterchangeObject*>& ObjectList);
411
412           virtual Result_t Lookup(ui32_t frame_num, IndexTableSegment::IndexEntry&) const;
413           virtual void     PushIndexEntry(const IndexTableSegment::IndexEntry&);
414           virtual void     SetIndexParamsCBR(IPrimerLookup* lookup, ui32_t size, const Rational& Rate);
415           virtual void     SetIndexParamsVBR(IPrimerLookup* lookup, const Rational& Rate, Kumu::fpos_t offset);
416         };
417
418       //---------------------------------------------------------------------------------
419       //
420
421       //
422       inline std::string to_lower(std::string str) {
423         std::transform(str.begin(), str.end(), str.begin(), ::tolower);
424         return str;
425       }
426
427       // ignore case when searching for audio labels
428       struct ci_comp
429       {
430         inline bool operator()(const std::string& a, const std::string& b) const {
431           return to_lower(a) < to_lower(b);
432         }
433       };
434
435       //
436       class MCAConfigParser : public InterchangeObject_list_t
437         {
438           typedef std::map<const std::string, const UL, ci_comp> label_map_t;
439           label_map_t label_map;
440           ui32_t m_ChannelCount;
441
442           const Dictionary*& m_Dict;
443
444           KM_NO_COPY_CONSTRUCT(MCAConfigParser);
445           MCAConfigParser();
446           
447         public:
448           MCAConfigParser(const Dictionary*&);
449           bool DecodeString(const std::string& s, const std::string& language = "en");
450
451           // Valid only after a successful call to DecodeString
452           ui32_t ChannelCount() const;
453         };
454
455     } // namespace MXF
456 } // namespace ASDCP
457
458
459 #endif // _MXF_H_
460
461 //
462 // end MXF.h
463 //