2 Copyright (c) 2004-2013, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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.
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.
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
32 #ifndef _AS_DCP_INTERNAL_H_
33 #define _AS_DCP_INTERNAL_H_
35 #include <KM_platform.h>
40 using Kumu::DefaultLogSink;
41 using namespace ASDCP;
42 using namespace ASDCP::MXF;
44 // a magic number identifying asdcplib
45 #ifndef ASDCP_BUILD_NUMBER
46 #define ASDCP_BUILD_NUMBER 0x6A68
50 #ifdef DEFAULT_MD_DECL
51 ASDCP::MXF::OP1aHeader *g_OP1aHeader;
52 ASDCP::MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
53 ASDCP::MXF::RIP *g_RIP;
55 extern MXF::OP1aHeader *g_OP1aHeader;
56 extern MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
57 extern MXF::RIP *g_RIP;
65 static std::vector<int>
66 version_split(const char* str)
68 std::vector<int> result;
69 const char* pstr = str;
70 const char* r = strchr(pstr, '.');
76 result.push_back(strtol(pstr, 0, 10));
79 r = strchr(pstr, '.');
82 if( strlen(pstr) > 0 )
83 result.push_back(strtol(pstr, 0, 10));
85 assert(result.size() == 3);
89 // constant values used to calculate KLV and EKLV packet sizes
90 static const ui32_t klv_cryptinfo_size =
92 + UUIDlen /* ContextID */
94 + sizeof(ui64_t) /* PlaintextOffset */
96 + SMPTE_UL_LENGTH /* SourceKey */
98 + sizeof(ui64_t) /* SourceLength */
99 + MXF_BER_LENGTH /* ESV length */ ;
101 static const ui32_t klv_intpack_size =
103 + UUIDlen /* TrackFileID */
105 + sizeof(ui64_t) /* SequenceNumber */
107 + 20; /* HMAC length*/
109 // calculate size of encrypted essence with IV, CheckValue, and padding
111 calc_esv_length(ui32_t source_length, ui32_t plaintext_offset)
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);
119 // the check value for EKLV packets
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 };
125 //------------------------------------------------------------------------------------------
128 ui32_t derive_timecode_rate_from_edit_rate(const ASDCP::Rational& edit_rate);
130 Result_t MD_to_WriterInfo(MXF::Identification*, WriterInfo&);
131 Result_t MD_to_CryptoInfo(MXF::CryptographicContext*, WriterInfo&, const Dictionary&);
133 Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*);
134 Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*);
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);
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);
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);
149 void AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
150 WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict);
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);
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);
163 class KLReader : public ASDCP::KLVPacket
165 ASDCP_NO_COPY_CONSTRUCT(KLReader);
166 byte_t m_KeyBuf[SMPTE_UL_LENGTH*2];
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; }
176 Result_t ReadKLFromFile(Kumu::FileReader& Reader);
181 //---------------------------------------------------------------------------------
184 /// void default_md_object_init();
186 template <class HeaderType, class IndexAccessType>
187 class TrackFileReader
189 KM_NO_COPY_CONSTRUCT(TrackFileReader);
193 const Dictionary* m_Dict;
194 Kumu::FileReader m_File;
195 HeaderType m_HeaderPart;
196 IndexAccessType m_IndexAccess;
199 ASDCP::FrameBuffer m_CtFrameBuf;
200 Kumu::fpos_t m_LastPosition;
202 TrackFileReader(const Dictionary& d) :
203 m_Dict(&d), m_HeaderPart(m_Dict), m_IndexAccess(m_Dict), m_RIP(m_Dict)
205 default_md_object_init();
208 virtual ~TrackFileReader() {
212 const MXF::RIP& GetRIP() const { return m_RIP; }
215 Result_t OpenMXFRead(const std::string& filename)
218 Result_t result = m_File.OpenRead(filename);
220 if ( ASDCP_SUCCESS(result) )
221 result = SeekToRIP(m_File);
223 if ( ASDCP_SUCCESS(result) )
225 result = m_RIP.InitFromFile(m_File);
227 if ( ASDCP_FAILURE(result) )
229 DefaultLogSink().Error("File contains no RIP\n");
231 else if ( m_RIP.PairArray.empty() )
233 DefaultLogSink().Error("RIP contains no Pairs.\n");
238 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, SeekToRIP failed\n");
242 result = m_HeaderPart.InitFromFile(m_File);
244 if ( KM_FAILURE(result) )
246 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, header init failed\n");
256 InterchangeObject* Object;
259 Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
261 // Writer Info and SourcePackage
262 if ( KM_SUCCESS(result) )
264 MD_to_WriterInfo((Identification*)Object, m_Info);
265 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
268 if ( KM_SUCCESS(result) )
270 SourcePackage* SP = (SourcePackage*)Object;
271 memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
274 // optional CryptographicContext
275 if ( KM_SUCCESS(result) )
277 Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
279 if ( KM_SUCCESS(cr_result) )
280 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
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)
292 // look up frame index node
293 IndexTableSegment::IndexEntry TmpEntry;
295 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
297 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
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;
305 if ( FilePosition != m_LastPosition )
307 m_LastPosition = FilePosition;
308 result = m_File.Seek(FilePosition);
311 if ( KM_SUCCESS(result) )
312 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
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)
322 // look up frame index node
323 IndexTableSegment::IndexEntry TmpEntry;
325 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
327 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
331 // get absolute frame position and go read the frame's key and length
332 Result_t result = RESULT_OK;
334 if ( TmpEntry.StreamOffset != m_LastPosition )
336 m_LastPosition = TmpEntry.StreamOffset;
337 result = m_File.Seek(TmpEntry.StreamOffset);
340 if ( KM_SUCCESS(result) )
341 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
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)
351 return Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
352 FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
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)
360 // look up frame index node
361 IndexTableSegment::IndexEntry TmpEntry;
363 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
365 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
369 // get frame position, temporal offset, and key frame ofset
370 streamOffset = body_offset + TmpEntry.StreamOffset;
371 temporalOffset = TmpEntry.TemporalOffset;
372 keyFrameOffset = TmpEntry.KeyFrameOffset;
384 //------------------------------------------------------------------------------------------
388 template <class ClipT>
392 MXF::Sequence* Sequence;
395 TrackSet() : Track(0), Sequence(0), Clip(0) {}
399 template <class PackageT, class 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)
404 TrackSet<ClipT> NewTrack;
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();
413 NewTrack.Sequence = new Sequence(Dict);
414 Header.AddChildObject(NewTrack.Sequence);
415 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
416 NewTrack.Sequence->DataDefinition = Definition;
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)
428 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
430 TrackSet<TimecodeComponent> NewTrack =
431 CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track",
432 tc_edit_rate, TCUL, 1, Dict);
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;
445 // state machine for mxf writer
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
455 // implementation of h__WriterState class Goto_* methods
456 #define Goto_body(s1,s2) \
457 if ( m_State != (s1) ) { \
458 return RESULT_STATE; \
465 ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
468 WriterState_t m_State;
469 h__WriterState() : m_State(ST_BEGIN) {}
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); }
483 //------------------------------------------------------------------------------------------
487 template <class HeaderType>
488 class TrackFileWriter
490 KM_NO_COPY_CONSTRUCT(TrackFileWriter);
494 const Dictionary* m_Dict;
495 Kumu::FileWriter m_File;
497 HeaderType m_HeaderPart;
500 MaterialPackage* m_MaterialPackage;
501 SourcePackage* m_FilePackage;
502 ContentStorage* m_ContentStorage;
504 FileDescriptor* m_EssenceDescriptor;
505 std::list<InterchangeObject*> m_EssenceSubDescriptorList;
507 ui32_t m_FramesWritten;
508 ui64_t m_StreamOffset;
509 ASDCP::FrameBuffer m_CtFrameBuf;
510 h__WriterState m_State;
513 typedef std::list<ui64_t*> DurationElementList_t;
514 DurationElementList_t m_DurationUpdateList;
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)
521 default_md_object_init();
524 virtual ~TrackFileWriter() {
528 const MXF::RIP& GetRIP() const { return m_RIP; }
533 assert(m_EssenceDescriptor);
535 m_HeaderPart.m_Primer.ClearTagList();
536 m_HeaderPart.m_Preface = new Preface(m_Dict);
537 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
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;
545 Identification* Ident = new Identification(m_Dict);
546 m_HeaderPart.AddChildObject(Ident);
547 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
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;
556 std::vector<int> version = version_split(Version());
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;
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)
571 if ( m_ContentStorage == 0 )
573 m_ContentStorage = new ContentStorage(m_Dict);
574 m_HeaderPart.AddChildObject(m_ContentStorage);
575 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
578 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
579 m_HeaderPart.AddChildObject(ECD);
580 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
584 UUID assetUUID(m_Info.AssetUUID);
585 UMID SourcePackageUMID, MaterialPackageUMID;
586 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
587 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
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);
598 TrackSet<TimecodeComponent> MPTCTrack =
599 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
600 tc_edit_rate, TCFrameRate, 0, m_Dict);
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()));
607 TrackSet<SourceClip> MPTrack =
608 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
609 TrackName, clip_edit_rate, DataDefinition,
611 MPTrack.Sequence->Duration.set_has_value();
612 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
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;
621 MPTrack.Clip->Duration.set_has_value();
622 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration.get()));
626 // File (Source) Package
628 m_FilePackage = new SourcePackage(m_Dict);
629 m_FilePackage->Name = PackageLabel.c_str();
630 m_FilePackage->PackageUID = SourcePackageUMID;
631 ECD->LinkedPackageUID = SourcePackageUMID;
633 m_HeaderPart.AddChildObject(m_FilePackage);
634 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
636 TrackSet<TimecodeComponent> FPTCTrack =
637 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
638 tc_edit_rate, TCFrameRate,
639 ui64_C(3600) * TCFrameRate, m_Dict);
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()));
646 TrackSet<SourceClip> FPTrack =
647 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
648 TrackName, clip_edit_rate, DataDefinition,
651 FPTrack.Sequence->Duration.set_has_value();
652 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
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)));
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;
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;
666 FPTrack.Clip->Duration.set_has_value();
667 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration.get()));
669 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
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)
678 if ( m_ContentStorage == 0 )
680 m_ContentStorage = new ContentStorage(m_Dict);
681 m_HeaderPart.AddChildObject(m_ContentStorage);
682 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
685 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
686 m_HeaderPart.AddChildObject(ECD);
687 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
691 UUID assetUUID(m_Info.AssetUUID);
692 UMID SourcePackageUMID, MaterialPackageUMID;
693 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
694 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
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);
705 TrackSet<TimecodeComponent> MPTCTrack =
706 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
707 tc_edit_rate, tc_frame_rate, 0, m_Dict);
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()));
714 TrackSet<DMSegment> MPTrack =
715 CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
716 TrackName, clip_edit_rate, DataDefinition,
718 MPTrack.Sequence->Duration.set_has_value();
719 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
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;
728 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
732 // File (Source) Package
734 m_FilePackage = new SourcePackage(m_Dict);
735 m_FilePackage->Name = PackageLabel.c_str();
736 m_FilePackage->PackageUID = SourcePackageUMID;
737 ECD->LinkedPackageUID = SourcePackageUMID;
739 m_HeaderPart.AddChildObject(m_FilePackage);
740 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
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);
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()));
752 TrackSet<DMSegment> FPTrack =
753 CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
754 TrackName, clip_edit_rate, DataDefinition,
757 FPTrack.Sequence->Duration.set_has_value();
758 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
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";
766 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
768 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
772 void AddEssenceDescriptor(const UL& WrappingUL)
775 // Essence Descriptor
777 m_EssenceDescriptor->EssenceContainer = WrappingUL;
778 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
781 // Essence Descriptors
784 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
785 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
787 if ( m_Info.EncryptedEssence )
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
797 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
800 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
801 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
803 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
804 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
805 m_HeaderPart.AddChildObject(*sdli);
807 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
820 //------------------------------------------------------------------------------------------
824 class h__ASDCPReader : public MXF::TrackFileReader<OP1aHeader, OPAtomIndexFooter>
826 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
830 Partition m_BodyPart;
832 h__ASDCPReader(const Dictionary&);
833 virtual ~h__ASDCPReader();
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);
843 class h__ASDCPWriter : public MXF::TrackFileWriter<OP1aHeader>
845 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPWriter);
849 Partition m_BodyPart;
850 OPAtomIndexFooter m_FooterPart;
852 h__ASDCPWriter(const Dictionary&);
853 virtual ~h__ASDCPWriter();
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);
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();
868 // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
873 byte_t Data[klv_intpack_size];
876 memset(Data, 0, klv_intpack_size);
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);
888 #endif // _AS_DCP_INTERNAL_H_
892 // end AS_DCP_internal.h