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