2 Copyright (c) 2004-2016, 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 // Version of MXF spec to which an MXF file conforms
133 //------------------------------------------------------------------------------------------
136 ui32_t derive_timecode_rate_from_edit_rate(const ASDCP::Rational& edit_rate);
138 Result_t MD_to_WriterInfo(MXF::Identification*, WriterInfo&);
139 Result_t MD_to_CryptoInfo(MXF::CryptographicContext*, WriterInfo&, const Dictionary&);
141 Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*);
142 Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*);
144 Result_t MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
145 const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
146 const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
147 ASDCP::JP2K::PictureDescriptor& PDesc);
149 Result_t JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc,
150 const ASDCP::Dictionary& dict,
151 ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
152 ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor);
154 Result_t PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj);
155 Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc);
157 void AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
158 WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict);
160 Result_t Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict,
161 const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
162 ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
163 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
165 Result_t Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict, const MXF::OP1aHeader& HeaderPart,
166 const ASDCP::WriterInfo& Info, ASDCP::FrameBuffer& CtFrameBuf, ui32_t& FramesWritten,
167 ui64_t & StreamOffset, const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
168 AESEncContext* Ctx, HMACContext* HMAC);
171 class KLReader : public ASDCP::KLVPacket
173 ASDCP_NO_COPY_CONSTRUCT(KLReader);
174 byte_t m_KeyBuf[SMPTE_UL_LENGTH*2];
180 inline const byte_t* Key() { return m_KeyBuf; }
181 inline const ui64_t Length() { return m_ValueLength; }
182 inline const ui64_t KLLength() { return m_KLLength; }
184 Result_t ReadKLFromFile(Kumu::FileReader& Reader);
189 //---------------------------------------------------------------------------------
192 /// void default_md_object_init();
194 template <class HeaderType, class IndexAccessType>
195 class TrackFileReader
197 KM_NO_COPY_CONSTRUCT(TrackFileReader);
201 const Dictionary* m_Dict;
202 Kumu::FileReader m_File;
203 HeaderType m_HeaderPart;
204 IndexAccessType m_IndexAccess;
207 ASDCP::FrameBuffer m_CtFrameBuf;
208 Kumu::fpos_t m_LastPosition;
210 TrackFileReader(const Dictionary& d) :
211 m_HeaderPart(m_Dict), m_IndexAccess(m_Dict), m_RIP(m_Dict), m_Dict(&d)
213 default_md_object_init();
216 virtual ~TrackFileReader() {
220 const MXF::RIP& GetRIP() const { return m_RIP; }
223 Result_t OpenMXFRead(const std::string& filename)
226 Result_t result = m_File.OpenRead(filename);
228 if ( ASDCP_SUCCESS(result) )
229 result = SeekToRIP(m_File);
231 if ( ASDCP_SUCCESS(result) )
233 result = m_RIP.InitFromFile(m_File);
234 ui32_t test_s = m_RIP.PairArray.size();
236 if ( ASDCP_FAILURE(result) )
238 DefaultLogSink().Error("File contains no RIP\n");
240 else if ( m_RIP.PairArray.empty() )
242 DefaultLogSink().Error("RIP contains no Pairs.\n");
247 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, SeekToRIP failed\n");
251 result = m_HeaderPart.InitFromFile(m_File);
253 if ( KM_FAILURE(result) )
255 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, header init failed\n");
265 InterchangeObject* Object;
268 Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
270 // Writer Info and SourcePackage
271 if ( KM_SUCCESS(result) )
273 MD_to_WriterInfo((Identification*)Object, m_Info);
274 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
277 if ( KM_SUCCESS(result) )
279 SourcePackage* SP = (SourcePackage*)Object;
280 memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
283 // optional CryptographicContext
284 if ( KM_SUCCESS(result) )
286 Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
288 if ( KM_SUCCESS(cr_result) )
289 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
295 // positions file before reading
296 // allows external control of index offset
297 Result_t ReadEKLVFrame(const ui64_t& body_offset,
298 ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
299 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
301 // look up frame index node
302 IndexTableSegment::IndexEntry TmpEntry;
304 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
306 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
310 // get relative frame position, apply offset and go read the frame's key and length
311 Kumu::fpos_t FilePosition = body_offset + TmpEntry.StreamOffset;
312 Result_t result = RESULT_OK;
314 if ( FilePosition != m_LastPosition )
316 m_LastPosition = FilePosition;
317 result = m_File.Seek(FilePosition);
320 if ( KM_SUCCESS(result) )
321 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
326 // positions file before reading
327 // assumes "processed" index entries have absolute positions
328 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
329 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
331 // look up frame index node
332 IndexTableSegment::IndexEntry TmpEntry;
334 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
336 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
340 // get absolute frame position and go read the frame's key and length
341 Result_t result = RESULT_OK;
343 if ( TmpEntry.StreamOffset != m_LastPosition )
345 m_LastPosition = TmpEntry.StreamOffset;
346 result = m_File.Seek(TmpEntry.StreamOffset);
349 if ( KM_SUCCESS(result) )
350 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
355 // reads from current position
356 Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
357 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
360 return Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
361 FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
364 // Get the position of a frame from a track file
365 Result_t LocateFrame(const ui64_t& body_offset,
366 ui32_t FrameNum, Kumu::fpos_t& streamOffset,
367 i8_t& temporalOffset, i8_t& keyFrameOffset)
369 // look up frame index node
370 IndexTableSegment::IndexEntry TmpEntry;
372 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
374 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
378 // get frame position, temporal offset, and key frame ofset
379 streamOffset = body_offset + TmpEntry.StreamOffset;
380 temporalOffset = TmpEntry.TemporalOffset;
381 keyFrameOffset = TmpEntry.KeyFrameOffset;
393 //------------------------------------------------------------------------------------------
397 template <class ClipT>
401 MXF::Sequence* Sequence;
404 TrackSet() : Track(0), Sequence(0), Clip(0) {}
408 template <class PackageT, class ClipT>
410 CreateTrackAndSequence(OP1aHeader& Header, PackageT& Package, const std::string TrackName,
411 const MXF::Rational& clip_edit_rate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
413 TrackSet<ClipT> NewTrack;
415 NewTrack.Track = new Track(Dict);
416 Header.AddChildObject(NewTrack.Track);
417 NewTrack.Track->EditRate = clip_edit_rate;
418 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
419 NewTrack.Track->TrackID = TrackID;
420 NewTrack.Track->TrackName = TrackName.c_str();
422 NewTrack.Sequence = new Sequence(Dict);
423 Header.AddChildObject(NewTrack.Sequence);
424 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
425 NewTrack.Sequence->DataDefinition = Definition;
431 template <class PackageT>
432 TrackSet<TimecodeComponent>
433 CreateTimecodeTrack(OP1aHeader& Header, PackageT& Package,
434 const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate, ui64_t TCStart, const Dictionary*& Dict)
437 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
439 TrackSet<TimecodeComponent> NewTrack =
440 CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track",
441 tc_edit_rate, TCUL, 1, Dict);
443 NewTrack.Clip = new TimecodeComponent(Dict);
444 Header.AddChildObject(NewTrack.Clip);
445 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
446 NewTrack.Clip->RoundedTimecodeBase = tc_frame_rate;
447 NewTrack.Clip->StartTimecode = TCStart;
448 NewTrack.Clip->DataDefinition = TCUL;
454 // state machine for mxf writer
456 ST_BEGIN, // waiting for Open()
457 ST_INIT, // waiting for SetSourceStream()
458 ST_READY, // ready to write frames
459 ST_RUNNING, // one or more frames written
460 ST_FINAL, // index written, file closed
464 // implementation of h__WriterState class Goto_* methods
465 #define Goto_body(s1,s2) \
466 if ( m_State != (s1) ) { \
467 return RESULT_STATE; \
474 ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
477 WriterState_t m_State;
478 h__WriterState() : m_State(ST_BEGIN) {}
481 inline bool Test_BEGIN() { return m_State == ST_BEGIN; }
482 inline bool Test_INIT() { return m_State == ST_INIT; }
483 inline bool Test_READY() { return m_State == ST_READY;}
484 inline bool Test_RUNNING() { return m_State == ST_RUNNING; }
485 inline bool Test_FINAL() { return m_State == ST_FINAL; }
486 inline Result_t Goto_INIT() { Goto_body(ST_BEGIN, ST_INIT); }
487 inline Result_t Goto_READY() { Goto_body(ST_INIT, ST_READY); }
488 inline Result_t Goto_RUNNING() { Goto_body(ST_READY, ST_RUNNING); }
489 inline Result_t Goto_FINAL() { Goto_body(ST_RUNNING, ST_FINAL); }
492 //------------------------------------------------------------------------------------------
496 template <class HeaderType>
497 class TrackFileWriter
499 KM_NO_COPY_CONSTRUCT(TrackFileWriter);
503 const Dictionary* m_Dict;
504 Kumu::FileWriter m_File;
506 HeaderType m_HeaderPart;
509 MaterialPackage* m_MaterialPackage;
510 SourcePackage* m_FilePackage;
511 ContentStorage* m_ContentStorage;
513 FileDescriptor* m_EssenceDescriptor;
514 std::list<InterchangeObject*> m_EssenceSubDescriptorList;
516 ui32_t m_FramesWritten;
517 ui64_t m_StreamOffset;
518 ASDCP::FrameBuffer m_CtFrameBuf;
519 h__WriterState m_State;
522 typedef std::list<ui64_t*> DurationElementList_t;
523 DurationElementList_t m_DurationUpdateList;
525 TrackFileWriter(const Dictionary& d) :
526 m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict), m_RIP(m_Dict),
527 m_MaterialPackage(0), m_FilePackage(0), m_ContentStorage(0),
528 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
530 default_md_object_init();
533 virtual ~TrackFileWriter() {
537 const MXF::RIP& GetRIP() const { return m_RIP; }
539 void InitHeader(const MXFVersion& mxf_ver)
542 assert(m_EssenceDescriptor);
544 m_HeaderPart.m_Primer.ClearTagList();
545 m_HeaderPart.m_Preface = new Preface(m_Dict);
546 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
548 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
549 // so we tell the world by using OP1a
550 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
551 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
553 if ( mxf_ver == MXFVersion_2004 )
555 m_HeaderPart.MinorVersion = 2;
556 m_HeaderPart.m_Preface->Version = 258;
557 m_HeaderPart.m_Preface->ObjectModelVersion = 1;
561 assert(mxf_ver == MXFVersion_2011);
562 m_HeaderPart.MinorVersion = 3;
563 m_HeaderPart.m_Preface->Version = 259;
564 m_HeaderPart.m_Preface->ObjectModelVersion = 1;
568 Identification* Ident = new Identification(m_Dict);
569 m_HeaderPart.AddChildObject(Ident);
570 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
572 Kumu::GenRandomValue(Ident->ThisGenerationUID);
573 Ident->CompanyName = m_Info.CompanyName.c_str();
574 Ident->ProductName = m_Info.ProductName.c_str();
575 Ident->VersionString = m_Info.ProductVersion.c_str();
576 Ident->ProductUID.Set(m_Info.ProductUUID);
577 Ident->Platform = ASDCP_PLATFORM;
579 std::vector<int> version = version_split(Version());
581 Ident->ToolkitVersion.Major = version[0];
582 Ident->ToolkitVersion.Minor = version[1];
583 Ident->ToolkitVersion.Patch = version[2];
584 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
585 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
589 void AddSourceClip(const MXF::Rational& clip_edit_rate,
590 const MXF::Rational& tc_edit_rate, ui32_t TCFrameRate,
591 const std::string& TrackName, const UL& EssenceUL,
592 const UL& DataDefinition, const std::string& PackageLabel)
594 if ( m_ContentStorage == 0 )
596 m_ContentStorage = new ContentStorage(m_Dict);
597 m_HeaderPart.AddChildObject(m_ContentStorage);
598 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
601 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
602 m_HeaderPart.AddChildObject(ECD);
603 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
607 UUID assetUUID(m_Info.AssetUUID);
608 UMID SourcePackageUMID, MaterialPackageUMID;
609 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
610 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
615 m_MaterialPackage = new MaterialPackage(m_Dict);
616 m_MaterialPackage->Name = "AS-DCP Material Package";
617 m_MaterialPackage->PackageUID = MaterialPackageUMID;
618 m_HeaderPart.AddChildObject(m_MaterialPackage);
619 m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
621 TrackSet<TimecodeComponent> MPTCTrack =
622 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
623 tc_edit_rate, TCFrameRate, 0, m_Dict);
625 MPTCTrack.Sequence->Duration.set_has_value();
626 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
627 MPTCTrack.Clip->Duration.set_has_value();
628 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
630 TrackSet<SourceClip> MPTrack =
631 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
632 TrackName, clip_edit_rate, DataDefinition,
634 MPTrack.Sequence->Duration.set_has_value();
635 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
637 MPTrack.Clip = new SourceClip(m_Dict);
638 m_HeaderPart.AddChildObject(MPTrack.Clip);
639 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
640 MPTrack.Clip->DataDefinition = DataDefinition;
641 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
642 MPTrack.Clip->SourceTrackID = 2;
644 MPTrack.Clip->Duration.set_has_value();
645 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration.get()));
649 // File (Source) Package
651 m_FilePackage = new SourcePackage(m_Dict);
652 m_FilePackage->Name = PackageLabel.c_str();
653 m_FilePackage->PackageUID = SourcePackageUMID;
654 ECD->LinkedPackageUID = SourcePackageUMID;
656 m_HeaderPart.AddChildObject(m_FilePackage);
657 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
659 TrackSet<TimecodeComponent> FPTCTrack =
660 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
661 tc_edit_rate, TCFrameRate,
662 ui64_C(3600) * TCFrameRate, m_Dict);
664 FPTCTrack.Sequence->Duration.set_has_value();
665 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
666 FPTCTrack.Clip->Duration.set_has_value();
667 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
669 TrackSet<SourceClip> FPTrack =
670 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
671 TrackName, clip_edit_rate, DataDefinition,
674 FPTrack.Sequence->Duration.set_has_value();
675 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
677 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
678 FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
680 FPTrack.Clip = new SourceClip(m_Dict);
681 m_HeaderPart.AddChildObject(FPTrack.Clip);
682 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
683 FPTrack.Clip->DataDefinition = DataDefinition;
685 // for now we do not allow setting this value, so all files will be 'original'
686 FPTrack.Clip->SourceTrackID = 0;
687 FPTrack.Clip->SourcePackageID = NilUMID;
689 FPTrack.Clip->Duration.set_has_value();
690 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration.get()));
692 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
696 void AddDMSegment(const MXF::Rational& clip_edit_rate,
697 const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate,
698 const std::string& TrackName, const UL& DataDefinition,
699 const std::string& PackageLabel)
701 if ( m_ContentStorage == 0 )
703 m_ContentStorage = new ContentStorage(m_Dict);
704 m_HeaderPart.AddChildObject(m_ContentStorage);
705 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
708 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
709 m_HeaderPart.AddChildObject(ECD);
710 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
714 UUID assetUUID(m_Info.AssetUUID);
715 UMID SourcePackageUMID, MaterialPackageUMID;
716 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
717 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
722 m_MaterialPackage = new MaterialPackage(m_Dict);
723 m_MaterialPackage->Name = "AS-DCP Material Package";
724 m_MaterialPackage->PackageUID = MaterialPackageUMID;
725 m_HeaderPart.AddChildObject(m_MaterialPackage);
726 m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
728 TrackSet<TimecodeComponent> MPTCTrack =
729 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
730 tc_edit_rate, tc_frame_rate, 0, m_Dict);
732 MPTCTrack.Sequence->Duration.set_has_value();
733 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
734 MPTCTrack.Clip->Duration.set_has_value();
735 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
737 TrackSet<DMSegment> MPTrack =
738 CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
739 TrackName, clip_edit_rate, DataDefinition,
741 MPTrack.Sequence->Duration.set_has_value();
742 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
744 MPTrack.Clip = new DMSegment(m_Dict);
745 m_HeaderPart.AddChildObject(MPTrack.Clip);
746 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
747 MPTrack.Clip->DataDefinition = DataDefinition;
748 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
749 // MPTrack.Clip->SourceTrackID = 2;
751 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
755 // File (Source) Package
757 m_FilePackage = new SourcePackage(m_Dict);
758 m_FilePackage->Name = PackageLabel.c_str();
759 m_FilePackage->PackageUID = SourcePackageUMID;
760 ECD->LinkedPackageUID = SourcePackageUMID;
762 m_HeaderPart.AddChildObject(m_FilePackage);
763 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
765 TrackSet<TimecodeComponent> FPTCTrack =
766 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
767 clip_edit_rate, tc_frame_rate,
768 ui64_C(3600) * tc_frame_rate, m_Dict);
770 FPTCTrack.Sequence->Duration.set_has_value();
771 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
772 FPTCTrack.Clip->Duration.set_has_value();
773 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
775 TrackSet<DMSegment> FPTrack =
776 CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
777 TrackName, clip_edit_rate, DataDefinition,
780 FPTrack.Sequence->Duration.set_has_value();
781 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
783 FPTrack.Clip = new DMSegment(m_Dict);
784 m_HeaderPart.AddChildObject(FPTrack.Clip);
785 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
786 FPTrack.Clip->DataDefinition = DataDefinition;
787 FPTrack.Clip->EventComment = "ST 429-5 Timed Text";
789 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
791 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
795 void AddEssenceDescriptor(const UL& WrappingUL)
798 // Essence Descriptor
800 m_EssenceDescriptor->EssenceContainer = WrappingUL;
801 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
804 // Essence Descriptors
807 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
808 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
810 if ( m_Info.EncryptedEssence )
812 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
813 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
814 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
815 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
816 //// TODO: fix DMSegment Duration value
820 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
823 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
824 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
826 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
827 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
828 m_HeaderPart.AddChildObject(*sdli);
830 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
843 //------------------------------------------------------------------------------------------
847 class h__ASDCPReader : public MXF::TrackFileReader<OP1aHeader, OPAtomIndexFooter>
849 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
853 Partition m_BodyPart;
855 h__ASDCPReader(const Dictionary&);
856 virtual ~h__ASDCPReader();
858 Result_t OpenMXFRead(const std::string& filename);
859 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
860 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
861 Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
862 i8_t& temporalOffset, i8_t& keyFrameOffset);
866 class h__ASDCPWriter : public MXF::TrackFileWriter<OP1aHeader>
868 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPWriter);
872 Partition m_BodyPart;
873 OPAtomIndexFooter m_FooterPart;
875 h__ASDCPWriter(const Dictionary&);
876 virtual ~h__ASDCPWriter();
878 // all the above for a single source clip
879 Result_t WriteASDCPHeader(const std::string& PackageLabel, const UL& WrappingUL,
880 const std::string& TrackName, const UL& EssenceUL,
881 const UL& DataDefinition, const MXF::Rational& EditRate,
882 ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0);
884 Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
885 Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
886 AESEncContext* Ctx, HMACContext* HMAC);
887 Result_t WriteASDCPFooter();
891 // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
896 byte_t Data[klv_intpack_size];
899 memset(Data, 0, klv_intpack_size);
904 Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
905 Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
911 #endif // _AS_DCP_INTERNAL_H_
915 // end AS_DCP_internal.h