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