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