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