2 Copyright (c) 2004-2018, 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 // version numbers from the MXF spec, to be written into files
135 ui8_t const MXF_ObjectModelVersion = 1;
136 ui8_t const MXF_2004_MinorVersion = 2;
137 ui8_t const MXF_2011_MinorVersion = 3;
140 //------------------------------------------------------------------------------------------
143 ui32_t derive_timecode_rate_from_edit_rate(const ASDCP::Rational& edit_rate);
145 Result_t MD_to_WriterInfo(MXF::Identification*, WriterInfo&);
146 Result_t MD_to_CryptoInfo(MXF::CryptographicContext*, WriterInfo&, const Dictionary&);
148 Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*);
149 Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*);
151 Result_t MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
152 const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
153 const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
154 ASDCP::JP2K::PictureDescriptor& PDesc);
156 Result_t JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc,
157 const ASDCP::Dictionary& dict,
158 ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
159 ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor);
161 Result_t PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj);
162 Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc);
164 void AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
165 WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict);
167 Result_t Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict,
168 const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
169 ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
170 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
172 Result_t Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict, const MXF::OP1aHeader& HeaderPart,
173 const ASDCP::WriterInfo& Info, ASDCP::FrameBuffer& CtFrameBuf, ui32_t& FramesWritten,
174 ui64_t & StreamOffset, const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
175 AESEncContext* Ctx, HMACContext* HMAC);
178 class KLReader : public ASDCP::KLVPacket
180 ASDCP_NO_COPY_CONSTRUCT(KLReader);
181 byte_t m_KeyBuf[SMPTE_UL_LENGTH*2];
187 inline const byte_t* Key() { return m_KeyBuf; }
188 inline const ui64_t Length() { return m_ValueLength; }
189 inline const ui64_t KLLength() { return m_KLLength; }
191 Result_t ReadKLFromFile(Kumu::FileReader& Reader);
196 //---------------------------------------------------------------------------------
199 /// void default_md_object_init();
201 template <class HeaderType, class IndexAccessType>
202 class TrackFileReader
204 KM_NO_COPY_CONSTRUCT(TrackFileReader);
208 const Dictionary* m_Dict;
209 Kumu::FileReader m_File;
210 HeaderType m_HeaderPart;
211 IndexAccessType m_IndexAccess;
214 ASDCP::FrameBuffer m_CtFrameBuf;
215 Kumu::fpos_t m_LastPosition;
217 TrackFileReader(const Dictionary& d) :
218 m_HeaderPart(m_Dict), m_IndexAccess(m_Dict), m_RIP(m_Dict), m_Dict(&d)
220 default_md_object_init();
223 virtual ~TrackFileReader() {
227 const MXF::RIP& GetRIP() const { return m_RIP; }
230 Result_t OpenMXFRead(const std::string& filename)
233 Result_t result = m_File.OpenRead(filename);
235 if ( ASDCP_SUCCESS(result) )
236 result = SeekToRIP(m_File);
238 if ( ASDCP_SUCCESS(result) )
240 result = m_RIP.InitFromFile(m_File);
241 ui32_t test_s = m_RIP.PairArray.size();
243 if ( ASDCP_FAILURE(result) )
245 DefaultLogSink().Error("File contains no RIP\n");
247 else if ( m_RIP.PairArray.empty() )
249 DefaultLogSink().Error("RIP contains no Pairs.\n");
254 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, SeekToRIP failed\n");
258 result = m_HeaderPart.InitFromFile(m_File);
260 if ( KM_FAILURE(result) )
262 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, header init failed\n");
272 InterchangeObject* Object;
275 Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
277 // Writer Info and SourcePackage
278 if ( KM_SUCCESS(result) )
280 MD_to_WriterInfo((Identification*)Object, m_Info);
281 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
284 if ( KM_SUCCESS(result) )
286 SourcePackage* SP = (SourcePackage*)Object;
287 memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
290 // optional CryptographicContext
291 if ( KM_SUCCESS(result) )
293 Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
295 if ( KM_SUCCESS(cr_result) )
296 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
302 // positions file before reading
303 // allows external control of index offset
304 Result_t ReadEKLVFrame(const ui64_t& body_offset,
305 ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
306 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
308 // look up frame index node
309 IndexTableSegment::IndexEntry TmpEntry;
311 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
313 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
317 // get relative frame position, apply offset and go read the frame's key and length
318 Kumu::fpos_t FilePosition = body_offset + TmpEntry.StreamOffset;
319 Result_t result = RESULT_OK;
321 if ( FilePosition != m_LastPosition )
323 m_LastPosition = FilePosition;
324 result = m_File.Seek(FilePosition);
327 if ( KM_SUCCESS(result) )
328 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
333 // positions file before reading
334 // assumes "processed" index entries have absolute positions
335 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
336 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
338 // look up frame index node
339 IndexTableSegment::IndexEntry TmpEntry;
341 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
343 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
347 // get absolute frame position and go read the frame's key and length
348 Result_t result = RESULT_OK;
350 if ( TmpEntry.StreamOffset != m_LastPosition )
352 m_LastPosition = TmpEntry.StreamOffset;
353 result = m_File.Seek(TmpEntry.StreamOffset);
356 if ( KM_SUCCESS(result) )
357 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
362 // reads from current position
363 Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
364 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
367 return Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
368 FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
371 // Get the position of a frame from a track file
372 Result_t LocateFrame(const ui64_t& body_offset,
373 ui32_t FrameNum, Kumu::fpos_t& streamOffset,
374 i8_t& temporalOffset, i8_t& keyFrameOffset)
376 // look up frame index node
377 IndexTableSegment::IndexEntry TmpEntry;
379 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
381 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
385 // get frame position, temporal offset, and key frame ofset
386 streamOffset = body_offset + TmpEntry.StreamOffset;
387 temporalOffset = TmpEntry.TemporalOffset;
388 keyFrameOffset = TmpEntry.KeyFrameOffset;
400 //------------------------------------------------------------------------------------------
404 template <class ClipT>
408 MXF::Sequence* Sequence;
411 TrackSet() : Track(0), Sequence(0), Clip(0) {}
415 template <class PackageT, class ClipT>
417 CreateTrackAndSequence(OP1aHeader& Header, PackageT& Package, const std::string TrackName,
418 const MXF::Rational& clip_edit_rate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
420 TrackSet<ClipT> NewTrack;
422 NewTrack.Track = new Track(Dict);
423 Header.AddChildObject(NewTrack.Track);
424 NewTrack.Track->EditRate = clip_edit_rate;
425 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
426 NewTrack.Track->TrackID = TrackID;
427 NewTrack.Track->TrackName = TrackName.c_str();
429 NewTrack.Sequence = new Sequence(Dict);
430 Header.AddChildObject(NewTrack.Sequence);
431 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
432 NewTrack.Sequence->DataDefinition = Definition;
438 template <class PackageT>
439 TrackSet<TimecodeComponent>
440 CreateTimecodeTrack(OP1aHeader& Header, PackageT& Package,
441 const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate, ui64_t TCStart, const Dictionary*& Dict)
444 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
446 TrackSet<TimecodeComponent> NewTrack =
447 CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track",
448 tc_edit_rate, TCUL, 1, Dict);
450 NewTrack.Clip = new TimecodeComponent(Dict);
451 Header.AddChildObject(NewTrack.Clip);
452 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
453 NewTrack.Clip->RoundedTimecodeBase = tc_frame_rate;
454 NewTrack.Clip->StartTimecode = TCStart;
455 NewTrack.Clip->DataDefinition = TCUL;
461 // state machine for mxf writer
463 ST_BEGIN, // waiting for Open()
464 ST_INIT, // waiting for SetSourceStream()
465 ST_READY, // ready to write frames
466 ST_RUNNING, // one or more frames written
467 ST_FINAL, // index written, file closed
471 // implementation of h__WriterState class Goto_* methods
472 #define Goto_body(s1,s2) \
473 if ( m_State != (s1) ) { \
474 return RESULT_STATE; \
481 ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
484 WriterState_t m_State;
485 h__WriterState() : m_State(ST_BEGIN) {}
488 inline bool Test_BEGIN() { return m_State == ST_BEGIN; }
489 inline bool Test_INIT() { return m_State == ST_INIT; }
490 inline bool Test_READY() { return m_State == ST_READY;}
491 inline bool Test_RUNNING() { return m_State == ST_RUNNING; }
492 inline bool Test_FINAL() { return m_State == ST_FINAL; }
493 inline Result_t Goto_INIT() { Goto_body(ST_BEGIN, ST_INIT); }
494 inline Result_t Goto_READY() { Goto_body(ST_INIT, ST_READY); }
495 inline Result_t Goto_RUNNING() { Goto_body(ST_READY, ST_RUNNING); }
496 inline Result_t Goto_FINAL() { Goto_body(ST_RUNNING, ST_FINAL); }
499 //------------------------------------------------------------------------------------------
503 template <class HeaderType>
504 class TrackFileWriter
506 KM_NO_COPY_CONSTRUCT(TrackFileWriter);
510 const Dictionary* m_Dict;
511 Kumu::FileWriter m_File;
513 HeaderType m_HeaderPart;
516 MaterialPackage* m_MaterialPackage;
517 SourcePackage* m_FilePackage;
518 ContentStorage* m_ContentStorage;
520 FileDescriptor* m_EssenceDescriptor;
521 std::list<InterchangeObject*> m_EssenceSubDescriptorList;
523 ui32_t m_FramesWritten;
524 ui64_t m_StreamOffset;
525 ASDCP::FrameBuffer m_CtFrameBuf;
526 h__WriterState m_State;
529 typedef std::list<ui64_t*> DurationElementList_t;
530 DurationElementList_t m_DurationUpdateList;
532 TrackFileWriter(const Dictionary& d) :
533 m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict), m_RIP(m_Dict),
534 m_MaterialPackage(0), m_FilePackage(0), m_ContentStorage(0),
535 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
537 default_md_object_init();
540 virtual ~TrackFileWriter() {
544 const MXF::RIP& GetRIP() const { return m_RIP; }
546 void InitHeader(const MXFVersion& mxf_ver)
549 assert(m_EssenceDescriptor);
551 m_HeaderPart.m_Primer.ClearTagList();
552 m_HeaderPart.m_Preface = new Preface(m_Dict);
553 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
555 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
556 // so we tell the world by using OP1a
557 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
558 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
560 if ( mxf_ver == MXFVersion_2004 )
562 m_HeaderPart.MinorVersion = MXF_2004_MinorVersion;
563 m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion < 8) | MXF_2004_MinorVersion);
564 m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
568 assert(mxf_ver == MXFVersion_2011);
569 m_HeaderPart.MinorVersion = MXF_2011_MinorVersion;
570 m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion < 8) | MXF_2011_MinorVersion);
571 m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
575 Identification* Ident = new Identification(m_Dict);
576 m_HeaderPart.AddChildObject(Ident);
577 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
579 Kumu::GenRandomValue(Ident->ThisGenerationUID);
580 Ident->CompanyName = m_Info.CompanyName.c_str();
581 Ident->ProductName = m_Info.ProductName.c_str();
582 Ident->VersionString = m_Info.ProductVersion.c_str();
583 Ident->ProductUID.Set(m_Info.ProductUUID);
584 Ident->Platform = ASDCP_PLATFORM;
586 std::vector<int> version = version_split(Version());
588 Ident->ToolkitVersion.Major = version[0];
589 Ident->ToolkitVersion.Minor = version[1];
590 Ident->ToolkitVersion.Patch = version[2];
591 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
592 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
596 void AddSourceClip(const MXF::Rational& clip_edit_rate,
597 const MXF::Rational& tc_edit_rate, ui32_t TCFrameRate,
598 const std::string& TrackName, const UL& EssenceUL,
599 const UL& DataDefinition, const std::string& PackageLabel)
601 if ( m_ContentStorage == 0 )
603 m_ContentStorage = new ContentStorage(m_Dict);
604 m_HeaderPart.AddChildObject(m_ContentStorage);
605 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
608 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
609 m_HeaderPart.AddChildObject(ECD);
610 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
614 UUID assetUUID(m_Info.AssetUUID);
615 UMID SourcePackageUMID, MaterialPackageUMID;
616 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
617 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
622 m_MaterialPackage = new MaterialPackage(m_Dict);
623 m_MaterialPackage->Name = "AS-DCP Material Package";
624 m_MaterialPackage->PackageUID = MaterialPackageUMID;
625 m_HeaderPart.AddChildObject(m_MaterialPackage);
626 m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
628 TrackSet<TimecodeComponent> MPTCTrack =
629 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
630 tc_edit_rate, TCFrameRate, 0, m_Dict);
632 MPTCTrack.Sequence->Duration.set_has_value();
633 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
634 MPTCTrack.Clip->Duration.set_has_value();
635 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
637 TrackSet<SourceClip> MPTrack =
638 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
639 TrackName, clip_edit_rate, DataDefinition,
641 MPTrack.Sequence->Duration.set_has_value();
642 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
644 MPTrack.Clip = new SourceClip(m_Dict);
645 m_HeaderPart.AddChildObject(MPTrack.Clip);
646 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
647 MPTrack.Clip->DataDefinition = DataDefinition;
648 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
649 MPTrack.Clip->SourceTrackID = 2;
651 MPTrack.Clip->Duration.set_has_value();
652 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration.get()));
656 // File (Source) Package
658 m_FilePackage = new SourcePackage(m_Dict);
659 m_FilePackage->Name = PackageLabel.c_str();
660 m_FilePackage->PackageUID = SourcePackageUMID;
661 ECD->LinkedPackageUID = SourcePackageUMID;
663 m_HeaderPart.AddChildObject(m_FilePackage);
664 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
666 TrackSet<TimecodeComponent> FPTCTrack =
667 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
668 tc_edit_rate, TCFrameRate, 0, m_Dict);
670 FPTCTrack.Sequence->Duration.set_has_value();
671 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
672 FPTCTrack.Clip->Duration.set_has_value();
673 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
675 TrackSet<SourceClip> FPTrack =
676 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
677 TrackName, clip_edit_rate, DataDefinition,
680 FPTrack.Sequence->Duration.set_has_value();
681 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
683 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
684 FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
686 FPTrack.Clip = new SourceClip(m_Dict);
687 m_HeaderPart.AddChildObject(FPTrack.Clip);
688 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
689 FPTrack.Clip->DataDefinition = DataDefinition;
691 // for now we do not allow setting this value, so all files will be 'original'
692 FPTrack.Clip->SourceTrackID = 0;
693 FPTrack.Clip->SourcePackageID = NilUMID;
695 FPTrack.Clip->Duration.set_has_value();
696 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration.get()));
698 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
702 void AddDMSegment(const MXF::Rational& clip_edit_rate,
703 const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate,
704 const std::string& TrackName, const UL& DataDefinition,
705 const std::string& PackageLabel)
707 if ( m_ContentStorage == 0 )
709 m_ContentStorage = new ContentStorage(m_Dict);
710 m_HeaderPart.AddChildObject(m_ContentStorage);
711 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
714 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
715 m_HeaderPart.AddChildObject(ECD);
716 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
720 UUID assetUUID(m_Info.AssetUUID);
721 UMID SourcePackageUMID, MaterialPackageUMID;
722 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
723 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
728 m_MaterialPackage = new MaterialPackage(m_Dict);
729 m_MaterialPackage->Name = "AS-DCP Material Package";
730 m_MaterialPackage->PackageUID = MaterialPackageUMID;
731 m_HeaderPart.AddChildObject(m_MaterialPackage);
732 m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
734 TrackSet<TimecodeComponent> MPTCTrack =
735 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
736 tc_edit_rate, tc_frame_rate, 0, m_Dict);
738 MPTCTrack.Sequence->Duration.set_has_value();
739 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
740 MPTCTrack.Clip->Duration.set_has_value();
741 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
743 TrackSet<DMSegment> MPTrack =
744 CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
745 TrackName, clip_edit_rate, DataDefinition,
747 MPTrack.Sequence->Duration.set_has_value();
748 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
750 MPTrack.Clip = new DMSegment(m_Dict);
751 m_HeaderPart.AddChildObject(MPTrack.Clip);
752 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
753 MPTrack.Clip->DataDefinition = DataDefinition;
754 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
755 // MPTrack.Clip->SourceTrackID = 2;
757 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
761 // File (Source) Package
763 m_FilePackage = new SourcePackage(m_Dict);
764 m_FilePackage->Name = PackageLabel.c_str();
765 m_FilePackage->PackageUID = SourcePackageUMID;
766 ECD->LinkedPackageUID = SourcePackageUMID;
768 m_HeaderPart.AddChildObject(m_FilePackage);
769 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
771 TrackSet<TimecodeComponent> FPTCTrack =
772 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
773 clip_edit_rate, tc_frame_rate,
774 ui64_C(3600) * tc_frame_rate, m_Dict);
776 FPTCTrack.Sequence->Duration.set_has_value();
777 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
778 FPTCTrack.Clip->Duration.set_has_value();
779 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
781 TrackSet<DMSegment> FPTrack =
782 CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
783 TrackName, clip_edit_rate, DataDefinition,
786 FPTrack.Sequence->Duration.set_has_value();
787 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
789 FPTrack.Clip = new DMSegment(m_Dict);
790 m_HeaderPart.AddChildObject(FPTrack.Clip);
791 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
792 FPTrack.Clip->DataDefinition = DataDefinition;
793 FPTrack.Clip->EventComment = "ST 429-5 Timed Text";
795 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
797 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
801 void AddEssenceDescriptor(const UL& WrappingUL)
804 // Essence Descriptor
806 m_EssenceDescriptor->EssenceContainer = WrappingUL;
807 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
810 // Essence Descriptors
813 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
814 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
816 if ( m_Info.EncryptedEssence )
818 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
819 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
820 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
821 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
822 //// TODO: fix DMSegment Duration value
826 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
829 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
830 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
832 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
833 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
834 m_HeaderPart.AddChildObject(*sdli);
836 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
849 //------------------------------------------------------------------------------------------
853 class h__ASDCPReader : public MXF::TrackFileReader<OP1aHeader, OPAtomIndexFooter>
855 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
859 Partition m_BodyPart;
861 h__ASDCPReader(const Dictionary&);
862 virtual ~h__ASDCPReader();
864 Result_t OpenMXFRead(const std::string& filename);
865 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
866 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
867 Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
868 i8_t& temporalOffset, i8_t& keyFrameOffset);
872 class h__ASDCPWriter : public MXF::TrackFileWriter<OP1aHeader>
874 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPWriter);
878 Partition m_BodyPart;
879 OPAtomIndexFooter m_FooterPart;
881 h__ASDCPWriter(const Dictionary&);
882 virtual ~h__ASDCPWriter();
884 // all the above for a single source clip
885 Result_t WriteASDCPHeader(const std::string& PackageLabel, const UL& WrappingUL,
886 const std::string& TrackName, const UL& EssenceUL,
887 const UL& DataDefinition, const MXF::Rational& EditRate,
888 ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0);
890 Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
891 Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
892 AESEncContext* Ctx, HMACContext* HMAC);
893 Result_t WriteASDCPFooter();
897 // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
902 byte_t Data[klv_intpack_size];
905 memset(Data, 0, klv_intpack_size);
910 Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
911 Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
917 #endif // _AS_DCP_INTERNAL_H_
921 // end AS_DCP_internal.h