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