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