BN API usage update
[asdcplib.git] / src / AS_DCP_internal.h
1 /*
2 Copyright (c) 2004-2018, 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    AS_DCP_internal.h
28     \version $Id$
29     \brief   AS-DCP library, non-public common elements
30 */
31
32 #ifndef _AS_DCP_INTERNAL_H_
33 #define _AS_DCP_INTERNAL_H_
34
35 #include <KM_platform.h>
36 #include <KM_util.h>
37 #include <KM_log.h>
38 #include "Metadata.h"
39
40 using Kumu::DefaultLogSink;
41 using namespace ASDCP;
42 using namespace ASDCP::MXF;
43
44 // a magic number identifying asdcplib
45 #ifndef ASDCP_BUILD_NUMBER
46 #define ASDCP_BUILD_NUMBER 0x6A68
47 #endif
48
49
50 #ifdef DEFAULT_MD_DECL
51 ASDCP::MXF::OP1aHeader *g_OP1aHeader;
52 ASDCP::MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
53 ASDCP::MXF::RIP *g_RIP;
54 #else
55 extern MXF::OP1aHeader *g_OP1aHeader;
56 extern MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
57 extern MXF::RIP *g_RIP;
58 #endif
59
60
61 namespace ASDCP
62 {
63
64   //
65   static std::vector<int>
66     version_split(const char* str)
67   {
68     std::vector<int> result;
69     const char* pstr = str;
70     const char* r = strchr(pstr, '.');
71
72     while ( r != 0 )
73       {
74         assert(r >= pstr);
75         if ( r > pstr )
76           result.push_back(strtol(pstr, 0, 10));
77
78         pstr = r + 1;
79         r = strchr(pstr, '.');
80       }
81
82     if( strlen(pstr) > 0 )
83       result.push_back(strtol(pstr, 0, 10));
84
85     assert(result.size() == 3);
86     return result;
87   }
88
89   // constant values used to calculate KLV and EKLV packet sizes
90   static const ui32_t klv_cryptinfo_size =
91     MXF_BER_LENGTH
92     + UUIDlen /* ContextID */
93     + MXF_BER_LENGTH
94     + sizeof(ui64_t) /* PlaintextOffset */
95     + MXF_BER_LENGTH
96     + SMPTE_UL_LENGTH /* SourceKey */
97     + MXF_BER_LENGTH
98     + sizeof(ui64_t) /* SourceLength */
99     + MXF_BER_LENGTH /* ESV length */ ;
100
101   static const ui32_t klv_intpack_size =
102     MXF_BER_LENGTH
103     + UUIDlen /* TrackFileID */
104     + MXF_BER_LENGTH
105     + sizeof(ui64_t) /* SequenceNumber */
106     + MXF_BER_LENGTH
107     + 20; /* HMAC length*/
108
109   // calculate size of encrypted essence with IV, CheckValue, and padding
110   inline ui32_t
111     calc_esv_length(ui32_t source_length, ui32_t plaintext_offset)
112     {
113       ui32_t ct_size = source_length - plaintext_offset;
114       ui32_t diff = ct_size % CBC_BLOCK_SIZE;
115       ui32_t block_size = ct_size - diff;
116       return plaintext_offset + block_size + (CBC_BLOCK_SIZE * 3);
117     }
118
119   // the check value for EKLV packets
120   // CHUKCHUKCHUKCHUK
121   static const byte_t ESV_CheckValue[CBC_BLOCK_SIZE] =
122   { 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b,
123     0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b };
124
125   // Version of MXF spec to which an MXF file conforms
126   enum MXFVersion
127   {
128     MXFVersion_2004,
129     MXFVersion_2011,
130     MXFVersion_MAX
131   };
132
133   // version numbers from the MXF spec, to be written into files
134   
135   ui8_t const MXF_ObjectModelVersion = 1;
136   ui8_t const MXF_2004_MinorVersion = 2;
137   ui8_t const MXF_2011_MinorVersion = 3;
138             
139
140   //------------------------------------------------------------------------------------------
141   //
142
143   ui32_t derive_timecode_rate_from_edit_rate(const ASDCP::Rational& edit_rate);
144
145   Result_t MD_to_WriterInfo(MXF::Identification*, WriterInfo&);
146   Result_t MD_to_CryptoInfo(MXF::CryptographicContext*, WriterInfo&, const Dictionary&);
147
148   Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*);
149   Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*);
150
151   Result_t MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor&  EssenceDescriptor,
152                             const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
153                             const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
154                             ASDCP::JP2K::PictureDescriptor& PDesc);
155
156   Result_t JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc,
157                             const ASDCP::Dictionary& dict,
158                             ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
159                             ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor);
160
161   Result_t PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj);
162   Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc);
163
164   void     AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
165                        WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict);
166
167   Result_t Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict,
168                             const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
169                             ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
170                             const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
171
172   Result_t Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict, const MXF::OP1aHeader& HeaderPart,
173                              const ASDCP::WriterInfo& Info, ASDCP::FrameBuffer& CtFrameBuf, ui32_t& FramesWritten,
174                              ui64_t & StreamOffset, const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
175                              AESEncContext* Ctx, HMACContext* HMAC);
176
177   //
178  class KLReader : public ASDCP::KLVPacket
179     {
180       ASDCP_NO_COPY_CONSTRUCT(KLReader);
181       byte_t m_KeyBuf[SMPTE_UL_LENGTH*2];
182
183     public:
184       KLReader() {}
185       ~KLReader() {}
186
187       inline const byte_t* Key() { return m_KeyBuf; }
188       inline const ui64_t  Length() { return m_ValueLength; }
189       inline const ui64_t  KLLength() { return m_KLLength; }
190
191       Result_t ReadKLFromFile(Kumu::FileReader& Reader);
192     };
193
194   namespace MXF
195   {
196       //---------------------------------------------------------------------------------
197       //
198
199     ///      void default_md_object_init();
200
201       template <class HeaderType, class IndexAccessType>
202       class TrackFileReader
203       {
204         KM_NO_COPY_CONSTRUCT(TrackFileReader);
205         TrackFileReader();
206
207       public:
208         const Dictionary*  m_Dict;
209         Kumu::FileReader   m_File;
210         HeaderType         m_HeaderPart;
211         IndexAccessType    m_IndexAccess;
212         RIP                m_RIP;
213         WriterInfo         m_Info;
214         ASDCP::FrameBuffer m_CtFrameBuf;
215         Kumu::fpos_t       m_LastPosition;
216
217       TrackFileReader(const Dictionary& d) :
218         m_HeaderPart(m_Dict), m_IndexAccess(m_Dict), m_RIP(m_Dict), m_Dict(&d)
219           {
220             default_md_object_init();
221           }
222
223         virtual ~TrackFileReader() {
224           Close();
225         }
226
227         const MXF::RIP& GetRIP() const { return m_RIP; }
228
229         //
230         Result_t OpenMXFRead(const std::string& filename)
231         {
232           m_LastPosition = 0;
233           Result_t result = m_File.OpenRead(filename);
234
235           if ( ASDCP_SUCCESS(result) )
236             result = SeekToRIP(m_File);
237
238           if ( ASDCP_SUCCESS(result) )
239             {
240               result = m_RIP.InitFromFile(m_File);
241               ui32_t test_s = m_RIP.PairArray.size();
242
243               if ( ASDCP_FAILURE(result) )
244                 {
245                   DefaultLogSink().Error("File contains no RIP\n");
246                 }
247               else if ( m_RIP.PairArray.empty() )
248                 {
249                   DefaultLogSink().Error("RIP contains no Pairs.\n");
250                 }
251             }
252           else
253             {
254               DefaultLogSink().Error("TrackFileReader::OpenMXFRead, SeekToRIP failed\n");
255             }
256
257           m_File.Seek(0);
258           result = m_HeaderPart.InitFromFile(m_File);
259
260           if ( KM_FAILURE(result) )
261             {
262               DefaultLogSink().Error("TrackFileReader::OpenMXFRead, header init failed\n");
263             }
264
265           return result;
266         }
267
268         //
269         Result_t InitInfo()
270         {
271           assert(m_Dict);
272           InterchangeObject* Object;
273
274           // Identification
275           Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
276
277           // Writer Info and SourcePackage
278           if ( KM_SUCCESS(result) )
279             {
280               MD_to_WriterInfo((Identification*)Object, m_Info);
281               result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
282             }
283
284           if ( KM_SUCCESS(result) )
285             {
286               SourcePackage* SP = (SourcePackage*)Object;
287               memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
288             }
289
290           // optional CryptographicContext
291           if ( KM_SUCCESS(result) )
292             {
293               Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
294
295               if ( KM_SUCCESS(cr_result) )
296                 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
297             }
298
299           return result;
300         }
301
302         // positions file before reading
303         // allows external control of index offset
304         Result_t ReadEKLVFrame(const ui64_t& body_offset,
305                                ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
306                                const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
307         {
308           // look up frame index node
309           IndexTableSegment::IndexEntry TmpEntry;
310
311           if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
312             {
313               DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
314               return RESULT_RANGE;
315             }
316
317           // get relative frame position, apply offset and go read the frame's key and length
318           Kumu::fpos_t FilePosition = body_offset + TmpEntry.StreamOffset;
319           Result_t result = RESULT_OK;
320
321           if ( FilePosition != m_LastPosition )
322             {
323               m_LastPosition = FilePosition;
324               result = m_File.Seek(FilePosition);
325             }
326
327           if ( KM_SUCCESS(result) )
328             result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
329
330           return result;
331         }
332
333         // positions file before reading
334         // assumes "processed" index entries have absolute positions
335         Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
336                                const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
337         {
338           // look up frame index node
339           IndexTableSegment::IndexEntry TmpEntry;
340
341           if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
342             {
343               DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
344               return RESULT_RANGE;
345             }
346
347           // get absolute frame position and go read the frame's key and length
348           Result_t result = RESULT_OK;
349
350           if ( TmpEntry.StreamOffset != m_LastPosition )
351             {
352               m_LastPosition = TmpEntry.StreamOffset;
353               result = m_File.Seek(TmpEntry.StreamOffset);
354             }
355
356           if ( KM_SUCCESS(result) )
357             result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
358
359           return result;
360         }
361
362         // reads from current position
363         Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
364                                 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
365         {
366           assert(m_Dict);
367           return Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
368                                   FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
369         }
370
371         // Get the position of a frame from a track file
372         Result_t LocateFrame(const ui64_t& body_offset,
373                              ui32_t FrameNum, Kumu::fpos_t& streamOffset,
374                              i8_t& temporalOffset, i8_t& keyFrameOffset)
375         {
376           // look up frame index node
377           IndexTableSegment::IndexEntry TmpEntry;
378
379           if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
380             {
381               DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
382               return RESULT_RANGE;
383             }
384
385           // get frame position, temporal offset, and key frame ofset
386           streamOffset = body_offset + TmpEntry.StreamOffset;
387           temporalOffset = TmpEntry.TemporalOffset;
388           keyFrameOffset = TmpEntry.KeyFrameOffset;
389           
390           return RESULT_OK;
391         }
392
393         //
394         void Close()
395         {
396           m_File.Close();
397         }
398       };
399       
400       //------------------------------------------------------------------------------------------
401       //
402
403       //
404       template <class ClipT>
405         struct TrackSet
406         {
407           MXF::Track*    Track;
408           MXF::Sequence* Sequence;
409           ClipT*         Clip;
410
411         TrackSet() : Track(0), Sequence(0), Clip(0) {}
412         };
413
414       //
415       template <class PackageT, class ClipT>
416         TrackSet<ClipT>
417         CreateTrackAndSequence(OP1aHeader& Header, PackageT& Package, const std::string TrackName,
418                                const MXF::Rational& clip_edit_rate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
419         {
420           TrackSet<ClipT> NewTrack;
421
422           NewTrack.Track = new Track(Dict);
423           Header.AddChildObject(NewTrack.Track);
424           NewTrack.Track->EditRate = clip_edit_rate;
425           Package.Tracks.push_back(NewTrack.Track->InstanceUID);
426           NewTrack.Track->TrackID = TrackID;
427           NewTrack.Track->TrackName = TrackName.c_str();
428
429           NewTrack.Sequence = new Sequence(Dict);
430           Header.AddChildObject(NewTrack.Sequence);
431           NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
432           NewTrack.Sequence->DataDefinition = Definition;
433
434           return NewTrack;
435         }
436
437       //
438       template <class PackageT>
439         TrackSet<TimecodeComponent>
440         CreateTimecodeTrack(OP1aHeader& Header, PackageT& Package,
441                             const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate, ui64_t TCStart, const Dictionary*& Dict)
442         {
443           assert(Dict);
444           UL TCUL(Dict->ul(MDD_TimecodeDataDef));
445
446           TrackSet<TimecodeComponent> NewTrack =
447             CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track",
448                                                                 tc_edit_rate, TCUL, 1, Dict);
449
450           NewTrack.Clip = new TimecodeComponent(Dict);
451           Header.AddChildObject(NewTrack.Clip);
452           NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
453           NewTrack.Clip->RoundedTimecodeBase = tc_frame_rate;
454           NewTrack.Clip->StartTimecode = TCStart;
455           NewTrack.Clip->DataDefinition = TCUL;
456
457           return NewTrack;
458         }
459
460
461       // state machine for mxf writer
462       enum WriterState_t {
463         ST_BEGIN,   // waiting for Open()
464         ST_INIT,    // waiting for SetSourceStream()
465         ST_READY,   // ready to write frames
466         ST_RUNNING, // one or more frames written
467         ST_FINAL,   // index written, file closed
468         ST_MAX
469       };
470
471       // implementation of h__WriterState class Goto_* methods
472 #define Goto_body(s1,s2)                        \
473       if ( m_State != (s1) ) {                  \
474         return RESULT_STATE;                    \
475       }                                         \
476       m_State = (s2);                           \
477       return RESULT_OK
478       //
479       class h__WriterState
480       {
481         ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
482
483       public:
484         WriterState_t m_State;
485       h__WriterState() : m_State(ST_BEGIN) {}
486         ~h__WriterState() {}
487
488         inline bool     Test_BEGIN()   { return m_State == ST_BEGIN; }
489         inline bool     Test_INIT()    { return m_State == ST_INIT; }
490         inline bool     Test_READY()   { return m_State == ST_READY;}
491         inline bool     Test_RUNNING() { return m_State == ST_RUNNING; }
492         inline bool     Test_FINAL()   { return m_State == ST_FINAL; }
493         inline Result_t Goto_INIT()    { Goto_body(ST_BEGIN,   ST_INIT); }
494         inline Result_t Goto_READY()   { Goto_body(ST_INIT,    ST_READY); }
495         inline Result_t Goto_RUNNING() { Goto_body(ST_READY,   ST_RUNNING); }
496         inline Result_t Goto_FINAL()   { Goto_body(ST_RUNNING, ST_FINAL); }
497       };
498
499       //------------------------------------------------------------------------------------------
500       //
501
502       //
503       template <class HeaderType>
504         class TrackFileWriter
505       {
506         KM_NO_COPY_CONSTRUCT(TrackFileWriter);
507         TrackFileWriter();
508
509       public:
510         const Dictionary*  m_Dict;
511         Kumu::FileWriter   m_File;
512         ui32_t             m_HeaderSize;
513         HeaderType         m_HeaderPart;
514         RIP                m_RIP;
515
516         MaterialPackage*   m_MaterialPackage;
517         SourcePackage*     m_FilePackage;
518         ContentStorage*    m_ContentStorage;
519
520         FileDescriptor*    m_EssenceDescriptor;
521         std::list<InterchangeObject*> m_EssenceSubDescriptorList;
522
523         ui32_t             m_FramesWritten;
524         ui64_t             m_StreamOffset;
525         ASDCP::FrameBuffer m_CtFrameBuf;
526         h__WriterState     m_State;
527         WriterInfo         m_Info;
528
529         typedef std::list<ui64_t*> DurationElementList_t;
530         DurationElementList_t m_DurationUpdateList;
531
532       TrackFileWriter(const Dictionary& d) :
533         m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict), m_RIP(m_Dict),
534           m_MaterialPackage(0), m_FilePackage(0), m_ContentStorage(0),
535           m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
536           {
537             default_md_object_init();
538           }
539
540         virtual ~TrackFileWriter() {
541           Close();
542         }
543
544         const MXF::RIP& GetRIP() const { return m_RIP; }
545
546         void InitHeader(const MXFVersion& mxf_ver)
547         {
548           assert(m_Dict);
549           assert(m_EssenceDescriptor);
550  
551           m_HeaderPart.m_Primer.ClearTagList();
552           m_HeaderPart.m_Preface = new Preface(m_Dict);
553           m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
554
555           // Set the Operational Pattern label -- we're just starting and have no RIP or index,
556           // so we tell the world by using OP1a
557           m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
558           m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
559
560           if ( mxf_ver == MXFVersion_2004 )
561             {
562               m_HeaderPart.MinorVersion = MXF_2004_MinorVersion;
563               m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion < 8) | MXF_2004_MinorVersion);
564               m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
565             }
566           else
567             {
568               assert(mxf_ver == MXFVersion_2011);
569               m_HeaderPart.MinorVersion = MXF_2011_MinorVersion;
570               m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion < 8) | MXF_2011_MinorVersion);
571               m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
572             }
573
574           // Identification
575           Identification* Ident = new Identification(m_Dict);
576           m_HeaderPart.AddChildObject(Ident);
577           m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
578
579           Kumu::GenRandomValue(Ident->ThisGenerationUID);
580           Ident->CompanyName = m_Info.CompanyName.c_str();
581           Ident->ProductName = m_Info.ProductName.c_str();
582           Ident->VersionString = m_Info.ProductVersion.c_str();
583           Ident->ProductUID.Set(m_Info.ProductUUID);
584           Ident->Platform = ASDCP_PLATFORM;
585
586           std::vector<int> version = version_split(Version());
587
588           Ident->ToolkitVersion.Major = version[0];
589           Ident->ToolkitVersion.Minor = version[1];
590           Ident->ToolkitVersion.Patch = version[2];
591           Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
592           Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
593         }
594
595         //
596         void AddSourceClip(const MXF::Rational& clip_edit_rate,
597                            const MXF::Rational& tc_edit_rate, ui32_t TCFrameRate,
598                            const std::string& TrackName, const UL& EssenceUL,
599                            const UL& DataDefinition, const std::string& PackageLabel)
600         {
601           if ( m_ContentStorage == 0 )
602             {
603               m_ContentStorage = new ContentStorage(m_Dict);
604               m_HeaderPart.AddChildObject(m_ContentStorage);
605               m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
606             }
607
608           EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
609           m_HeaderPart.AddChildObject(ECD);
610           m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
611           ECD->IndexSID = 129;
612           ECD->BodySID = 1;
613
614           UUID assetUUID(m_Info.AssetUUID);
615           UMID SourcePackageUMID, MaterialPackageUMID;
616           SourcePackageUMID.MakeUMID(0x0f, assetUUID);
617           MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
618
619           //
620           // Material Package
621           //
622           m_MaterialPackage = new MaterialPackage(m_Dict);
623           m_MaterialPackage->Name = "AS-DCP Material Package";
624           m_MaterialPackage->PackageUID = MaterialPackageUMID;
625           m_HeaderPart.AddChildObject(m_MaterialPackage);
626           m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
627
628           TrackSet<TimecodeComponent> MPTCTrack =
629             CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
630                                                  tc_edit_rate, TCFrameRate, 0, m_Dict);
631
632           MPTCTrack.Sequence->Duration.set_has_value();
633           m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
634           MPTCTrack.Clip->Duration.set_has_value();
635           m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
636
637           TrackSet<SourceClip> MPTrack =
638             CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
639                                                                 TrackName, clip_edit_rate, DataDefinition,
640                                                                 2, m_Dict);
641           MPTrack.Sequence->Duration.set_has_value();
642           m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
643
644           MPTrack.Clip = new SourceClip(m_Dict);
645           m_HeaderPart.AddChildObject(MPTrack.Clip);
646           MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
647           MPTrack.Clip->DataDefinition = DataDefinition;
648           MPTrack.Clip->SourcePackageID = SourcePackageUMID;
649           MPTrack.Clip->SourceTrackID = 2;
650
651           MPTrack.Clip->Duration.set_has_value();
652           m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration.get()));
653
654   
655           //
656           // File (Source) Package
657           //
658           m_FilePackage = new SourcePackage(m_Dict);
659           m_FilePackage->Name = PackageLabel.c_str();
660           m_FilePackage->PackageUID = SourcePackageUMID;
661           ECD->LinkedPackageUID = SourcePackageUMID;
662
663           m_HeaderPart.AddChildObject(m_FilePackage);
664           m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
665
666           TrackSet<TimecodeComponent> FPTCTrack =
667             CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
668                                                tc_edit_rate, TCFrameRate, 0, m_Dict);
669
670           FPTCTrack.Sequence->Duration.set_has_value();
671           m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
672           FPTCTrack.Clip->Duration.set_has_value();
673           m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
674
675           TrackSet<SourceClip> FPTrack =
676             CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
677                                                               TrackName, clip_edit_rate, DataDefinition,
678                                                               2, m_Dict);
679
680           FPTrack.Sequence->Duration.set_has_value();
681           m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
682
683           // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
684           FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
685
686           FPTrack.Clip = new SourceClip(m_Dict);
687           m_HeaderPart.AddChildObject(FPTrack.Clip);
688           FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
689           FPTrack.Clip->DataDefinition = DataDefinition;
690
691           // for now we do not allow setting this value, so all files will be 'original'
692           FPTrack.Clip->SourceTrackID = 0;
693           FPTrack.Clip->SourcePackageID = NilUMID;
694
695           FPTrack.Clip->Duration.set_has_value();
696           m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration.get()));
697
698           m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
699         }
700
701         //
702         void AddDMSegment(const MXF::Rational& clip_edit_rate,
703                           const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate,
704                           const std::string& TrackName, const UL& DataDefinition,
705                           const std::string& PackageLabel)
706         {
707           if ( m_ContentStorage == 0 )
708             {
709               m_ContentStorage = new ContentStorage(m_Dict);
710               m_HeaderPart.AddChildObject(m_ContentStorage);
711               m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
712             }
713
714           EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
715           m_HeaderPart.AddChildObject(ECD);
716           m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
717           ECD->IndexSID = 129;
718           ECD->BodySID = 1;
719
720           UUID assetUUID(m_Info.AssetUUID);
721           UMID SourcePackageUMID, MaterialPackageUMID;
722           SourcePackageUMID.MakeUMID(0x0f, assetUUID);
723           MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
724
725           //
726           // Material Package
727           //
728           m_MaterialPackage = new MaterialPackage(m_Dict);
729           m_MaterialPackage->Name = "AS-DCP Material Package";
730           m_MaterialPackage->PackageUID = MaterialPackageUMID;
731           m_HeaderPart.AddChildObject(m_MaterialPackage);
732           m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
733
734           TrackSet<TimecodeComponent> MPTCTrack =
735             CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
736                                                  tc_edit_rate, tc_frame_rate, 0, m_Dict);
737
738           MPTCTrack.Sequence->Duration.set_has_value();
739           m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
740           MPTCTrack.Clip->Duration.set_has_value();
741           m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
742
743           TrackSet<DMSegment> MPTrack =
744             CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
745                                                                TrackName, clip_edit_rate, DataDefinition,
746                                                                2, m_Dict);
747           MPTrack.Sequence->Duration.set_has_value();
748           m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
749
750           MPTrack.Clip = new DMSegment(m_Dict);
751           m_HeaderPart.AddChildObject(MPTrack.Clip);
752           MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
753           MPTrack.Clip->DataDefinition = DataDefinition;
754           //  MPTrack.Clip->SourcePackageID = SourcePackageUMID;
755           //  MPTrack.Clip->SourceTrackID = 2;
756
757           m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
758
759   
760           //
761           // File (Source) Package
762           //
763           m_FilePackage = new SourcePackage(m_Dict);
764           m_FilePackage->Name = PackageLabel.c_str();
765           m_FilePackage->PackageUID = SourcePackageUMID;
766           ECD->LinkedPackageUID = SourcePackageUMID;
767
768           m_HeaderPart.AddChildObject(m_FilePackage);
769           m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
770
771           TrackSet<TimecodeComponent> FPTCTrack =
772             CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
773                                                clip_edit_rate, tc_frame_rate,
774                                                ui64_C(3600) * tc_frame_rate, m_Dict);
775
776           FPTCTrack.Sequence->Duration.set_has_value();
777           m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
778           FPTCTrack.Clip->Duration.set_has_value();
779           m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
780
781           TrackSet<DMSegment> FPTrack =
782             CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
783                                                              TrackName, clip_edit_rate, DataDefinition,
784                                                              2, m_Dict);
785
786           FPTrack.Sequence->Duration.set_has_value();
787           m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
788
789           FPTrack.Clip = new DMSegment(m_Dict);
790           m_HeaderPart.AddChildObject(FPTrack.Clip);
791           FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
792           FPTrack.Clip->DataDefinition = DataDefinition;
793           FPTrack.Clip->EventComment = "ST 429-5 Timed Text";
794
795           m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
796
797           m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
798         }
799
800         //
801         void AddEssenceDescriptor(const UL& WrappingUL)
802         {
803           //
804           // Essence Descriptor
805           //
806           m_EssenceDescriptor->EssenceContainer = WrappingUL;
807           m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
808
809           //
810           // Essence Descriptors
811           //
812           assert(m_Dict);
813           UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
814           m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
815
816           if ( m_Info.EncryptedEssence )
817             {
818               UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
819               m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
820               m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
821               AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
822               //// TODO: fix DMSegment Duration value
823             }
824           else
825             {
826               m_HeaderPart.EssenceContainers.push_back(WrappingUL);
827             }
828
829           m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
830           m_HeaderPart.AddChildObject(m_EssenceDescriptor);
831
832           std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
833           for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
834             m_HeaderPart.AddChildObject(*sdli);
835
836           m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
837         }
838
839         //
840         void Close()
841         {
842           m_File.Close();
843         }
844
845       };
846       
847   }/// namespace MXF
848
849   //------------------------------------------------------------------------------------------
850   //
851
852   //
853   class h__ASDCPReader : public MXF::TrackFileReader<OP1aHeader, OPAtomIndexFooter>
854     {
855       ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
856       h__ASDCPReader();
857
858     public:
859       Partition m_BodyPart;
860
861       h__ASDCPReader(const Dictionary&);
862       virtual ~h__ASDCPReader();
863
864       Result_t OpenMXFRead(const std::string& filename);
865       Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
866                              const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
867       Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
868                            i8_t& temporalOffset, i8_t& keyFrameOffset);
869     };
870
871   //
872   class h__ASDCPWriter : public MXF::TrackFileWriter<OP1aHeader>
873     {
874       ASDCP_NO_COPY_CONSTRUCT(h__ASDCPWriter);
875       h__ASDCPWriter();
876
877     public:
878       Partition          m_BodyPart;
879       OPAtomIndexFooter  m_FooterPart;
880
881       h__ASDCPWriter(const Dictionary&);
882       virtual ~h__ASDCPWriter();
883
884       // all the above for a single source clip
885       Result_t WriteASDCPHeader(const std::string& PackageLabel, const UL& WrappingUL,
886                                 const std::string& TrackName, const UL& EssenceUL,
887                                 const UL& DataDefinition, const MXF::Rational& EditRate,
888                                 ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0);
889
890       Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
891       Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
892                                AESEncContext* Ctx, HMACContext* HMAC);
893       Result_t WriteASDCPFooter();
894     };
895
896
897   // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
898   //
899   class IntegrityPack
900     {
901     public:
902       byte_t Data[klv_intpack_size];
903
904       IntegrityPack() {
905         memset(Data, 0, klv_intpack_size);
906       }
907
908       ~IntegrityPack() {}
909
910       Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
911       Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
912     };
913
914
915 } // namespace ASDCP
916
917 #endif // _AS_DCP_INTERNAL_H_
918
919
920 //
921 // end AS_DCP_internal.h
922 //