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
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 const ui64_t Length() { return m_ValueLength; }
174 inline const 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_HeaderPart(m_Dict), m_IndexAccess(m_Dict), m_RIP(m_Dict), m_Dict(&d)
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);
226 ui32_t test_s = m_RIP.PairArray.size();
228 if ( ASDCP_FAILURE(result) )
230 DefaultLogSink().Error("File contains no RIP\n");
232 else if ( m_RIP.PairArray.empty() )
234 DefaultLogSink().Error("RIP contains no Pairs.\n");
239 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, SeekToRIP failed\n");
243 result = m_HeaderPart.InitFromFile(m_File);
245 if ( KM_FAILURE(result) )
247 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, header init failed\n");
257 InterchangeObject* Object;
260 Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
262 // Writer Info and SourcePackage
263 if ( KM_SUCCESS(result) )
265 MD_to_WriterInfo((Identification*)Object, m_Info);
266 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
269 if ( KM_SUCCESS(result) )
271 SourcePackage* SP = (SourcePackage*)Object;
272 memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
275 // optional CryptographicContext
276 if ( KM_SUCCESS(result) )
278 Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
280 if ( KM_SUCCESS(cr_result) )
281 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
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)
293 // look up frame index node
294 IndexTableSegment::IndexEntry TmpEntry;
296 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
298 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
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;
306 if ( FilePosition != m_LastPosition )
308 m_LastPosition = FilePosition;
309 result = m_File.Seek(FilePosition);
312 if ( KM_SUCCESS(result) )
313 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
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)
323 // look up frame index node
324 IndexTableSegment::IndexEntry TmpEntry;
326 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
328 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
332 // get absolute frame position and go read the frame's key and length
333 Result_t result = RESULT_OK;
335 if ( TmpEntry.StreamOffset != m_LastPosition )
337 m_LastPosition = TmpEntry.StreamOffset;
338 result = m_File.Seek(TmpEntry.StreamOffset);
341 if ( KM_SUCCESS(result) )
342 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
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)
352 return Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
353 FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
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)
361 // look up frame index node
362 IndexTableSegment::IndexEntry TmpEntry;
364 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
366 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
370 // get frame position, temporal offset, and key frame ofset
371 streamOffset = body_offset + TmpEntry.StreamOffset;
372 temporalOffset = TmpEntry.TemporalOffset;
373 keyFrameOffset = TmpEntry.KeyFrameOffset;
385 //------------------------------------------------------------------------------------------
389 template <class ClipT>
393 MXF::Sequence* Sequence;
396 TrackSet() : Track(0), Sequence(0), Clip(0) {}
400 template <class PackageT, class 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)
405 TrackSet<ClipT> NewTrack;
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();
414 NewTrack.Sequence = new Sequence(Dict);
415 Header.AddChildObject(NewTrack.Sequence);
416 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
417 NewTrack.Sequence->DataDefinition = Definition;
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)
429 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
431 TrackSet<TimecodeComponent> NewTrack =
432 CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track",
433 tc_edit_rate, TCUL, 1, Dict);
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;
446 // state machine for mxf writer
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
456 // implementation of h__WriterState class Goto_* methods
457 #define Goto_body(s1,s2) \
458 if ( m_State != (s1) ) { \
459 return RESULT_STATE; \
466 ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
469 WriterState_t m_State;
470 h__WriterState() : m_State(ST_BEGIN) {}
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); }
484 //------------------------------------------------------------------------------------------
488 template <class HeaderType>
489 class TrackFileWriter
491 KM_NO_COPY_CONSTRUCT(TrackFileWriter);
495 const Dictionary* m_Dict;
496 Kumu::FileWriter m_File;
498 HeaderType m_HeaderPart;
501 MaterialPackage* m_MaterialPackage;
502 SourcePackage* m_FilePackage;
503 ContentStorage* m_ContentStorage;
505 FileDescriptor* m_EssenceDescriptor;
506 std::list<InterchangeObject*> m_EssenceSubDescriptorList;
508 ui32_t m_FramesWritten;
509 ui64_t m_StreamOffset;
510 ASDCP::FrameBuffer m_CtFrameBuf;
511 h__WriterState m_State;
514 typedef std::list<ui64_t*> DurationElementList_t;
515 DurationElementList_t m_DurationUpdateList;
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)
522 default_md_object_init();
525 virtual ~TrackFileWriter() {
529 const MXF::RIP& GetRIP() const { return m_RIP; }
534 assert(m_EssenceDescriptor);
536 m_HeaderPart.m_Primer.ClearTagList();
537 m_HeaderPart.m_Preface = new Preface(m_Dict);
538 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
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;
546 Identification* Ident = new Identification(m_Dict);
547 m_HeaderPart.AddChildObject(Ident);
548 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
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;
557 std::vector<int> version = version_split(Version());
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;
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)
572 if ( m_ContentStorage == 0 )
574 m_ContentStorage = new ContentStorage(m_Dict);
575 m_HeaderPart.AddChildObject(m_ContentStorage);
576 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
579 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
580 m_HeaderPart.AddChildObject(ECD);
581 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
585 UUID assetUUID(m_Info.AssetUUID);
586 UMID SourcePackageUMID, MaterialPackageUMID;
587 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
588 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
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);
599 TrackSet<TimecodeComponent> MPTCTrack =
600 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
601 tc_edit_rate, TCFrameRate, 0, m_Dict);
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()));
608 TrackSet<SourceClip> MPTrack =
609 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
610 TrackName, clip_edit_rate, DataDefinition,
612 MPTrack.Sequence->Duration.set_has_value();
613 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
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;
622 MPTrack.Clip->Duration.set_has_value();
623 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration.get()));
627 // File (Source) Package
629 m_FilePackage = new SourcePackage(m_Dict);
630 m_FilePackage->Name = PackageLabel.c_str();
631 m_FilePackage->PackageUID = SourcePackageUMID;
632 ECD->LinkedPackageUID = SourcePackageUMID;
634 m_HeaderPart.AddChildObject(m_FilePackage);
635 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
637 TrackSet<TimecodeComponent> FPTCTrack =
638 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
639 tc_edit_rate, TCFrameRate,
640 ui64_C(3600) * TCFrameRate, m_Dict);
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()));
647 TrackSet<SourceClip> FPTrack =
648 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
649 TrackName, clip_edit_rate, DataDefinition,
652 FPTrack.Sequence->Duration.set_has_value();
653 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
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)));
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;
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;
667 FPTrack.Clip->Duration.set_has_value();
668 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration.get()));
670 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
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)
679 if ( m_ContentStorage == 0 )
681 m_ContentStorage = new ContentStorage(m_Dict);
682 m_HeaderPart.AddChildObject(m_ContentStorage);
683 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
686 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
687 m_HeaderPart.AddChildObject(ECD);
688 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
692 UUID assetUUID(m_Info.AssetUUID);
693 UMID SourcePackageUMID, MaterialPackageUMID;
694 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
695 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
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);
706 TrackSet<TimecodeComponent> MPTCTrack =
707 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
708 tc_edit_rate, tc_frame_rate, 0, m_Dict);
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()));
715 TrackSet<DMSegment> MPTrack =
716 CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
717 TrackName, clip_edit_rate, DataDefinition,
719 MPTrack.Sequence->Duration.set_has_value();
720 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
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;
729 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
733 // File (Source) Package
735 m_FilePackage = new SourcePackage(m_Dict);
736 m_FilePackage->Name = PackageLabel.c_str();
737 m_FilePackage->PackageUID = SourcePackageUMID;
738 ECD->LinkedPackageUID = SourcePackageUMID;
740 m_HeaderPart.AddChildObject(m_FilePackage);
741 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
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);
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()));
753 TrackSet<DMSegment> FPTrack =
754 CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
755 TrackName, clip_edit_rate, DataDefinition,
758 FPTrack.Sequence->Duration.set_has_value();
759 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
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";
767 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
769 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
773 void AddEssenceDescriptor(const UL& WrappingUL)
776 // Essence Descriptor
778 m_EssenceDescriptor->EssenceContainer = WrappingUL;
779 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
782 // Essence Descriptors
785 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
786 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
788 if ( m_Info.EncryptedEssence )
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
798 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
801 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
802 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
804 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
805 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
806 m_HeaderPart.AddChildObject(*sdli);
808 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
821 //------------------------------------------------------------------------------------------
825 class h__ASDCPReader : public MXF::TrackFileReader<OP1aHeader, OPAtomIndexFooter>
827 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
831 Partition m_BodyPart;
833 h__ASDCPReader(const Dictionary&);
834 virtual ~h__ASDCPReader();
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);
844 class h__ASDCPWriter : public MXF::TrackFileWriter<OP1aHeader>
846 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPWriter);
850 Partition m_BodyPart;
851 OPAtomIndexFooter m_FooterPart;
853 h__ASDCPWriter(const Dictionary&);
854 virtual ~h__ASDCPWriter();
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);
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();
869 // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
874 byte_t Data[klv_intpack_size];
877 memset(Data, 0, klv_intpack_size);
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);
889 #endif // _AS_DCP_INTERNAL_H_
893 // end AS_DCP_internal.h