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