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