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 // uncomment to remove MXFGCGenericEssenceMultipleMappings from your AS-02 files
51 // #define ASDCP_GCMULTI_PATCH
54 #ifdef DEFAULT_MD_DECL
55 ASDCP::MXF::OP1aHeader *g_OP1aHeader;
56 ASDCP::MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
57 ASDCP::MXF::RIP *g_RIP;
59 extern MXF::OP1aHeader *g_OP1aHeader;
60 extern MXF::OPAtomIndexFooter *g_OPAtomIndexFooter;
61 extern MXF::RIP *g_RIP;
69 static std::vector<int>
70 version_split(const char* str)
72 std::vector<int> result;
73 const char* pstr = str;
74 const char* r = strchr(pstr, '.');
80 result.push_back(strtol(pstr, 0, 10));
83 r = strchr(pstr, '.');
86 if( strlen(pstr) > 0 )
87 result.push_back(strtol(pstr, 0, 10));
89 assert(result.size() == 3);
93 // constant values used to calculate KLV and EKLV packet sizes
94 static const ui32_t klv_cryptinfo_size =
96 + UUIDlen /* ContextID */
98 + sizeof(ui64_t) /* PlaintextOffset */
100 + SMPTE_UL_LENGTH /* SourceKey */
102 + sizeof(ui64_t) /* SourceLength */
103 + MXF_BER_LENGTH /* ESV length */ ;
105 static const ui32_t klv_intpack_size =
107 + UUIDlen /* TrackFileID */
109 + sizeof(ui64_t) /* SequenceNumber */
111 + 20; /* HMAC length*/
113 // calculate size of encrypted essence with IV, CheckValue, and padding
115 calc_esv_length(ui32_t source_length, ui32_t plaintext_offset)
117 ui32_t ct_size = source_length - plaintext_offset;
118 ui32_t diff = ct_size % CBC_BLOCK_SIZE;
119 ui32_t block_size = ct_size - diff;
120 return plaintext_offset + block_size + (CBC_BLOCK_SIZE * 3);
123 // the check value for EKLV packets
125 static const byte_t ESV_CheckValue[CBC_BLOCK_SIZE] =
126 { 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b,
127 0x43, 0x48, 0x55, 0x4b, 0x43, 0x48, 0x55, 0x4b };
129 // Version of MXF spec to which an MXF file conforms
137 // version numbers from the MXF spec, to be written into files
139 ui8_t const MXF_ObjectModelVersion = 1;
140 ui8_t const MXF_2004_MinorVersion = 2;
141 ui8_t const MXF_2011_MinorVersion = 3;
144 //------------------------------------------------------------------------------------------
147 ui32_t derive_timecode_rate_from_edit_rate(const ASDCP::Rational& edit_rate);
149 Result_t MD_to_WriterInfo(MXF::Identification*, WriterInfo&);
150 Result_t MD_to_CryptoInfo(MXF::CryptographicContext*, WriterInfo&, const Dictionary&);
152 Result_t EncryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESEncContext*);
153 Result_t DecryptFrameBuffer(const ASDCP::FrameBuffer&, ASDCP::FrameBuffer&, AESDecContext*);
155 Result_t MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
156 const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
157 const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
158 ASDCP::JP2K::PictureDescriptor& PDesc);
160 Result_t JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc,
161 const ASDCP::Dictionary& dict,
162 ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
163 ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor);
165 Result_t PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj);
166 Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc);
168 void AddDmsCrypt(Partition& HeaderPart, SourcePackage& Package,
169 WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict);
171 Result_t AddDmsTrackGenericPartUtf8Text(Kumu::FileWriter&, ASDCP::MXF::OP1aHeader&, SourcePackage&,
172 ASDCP::MXF::RIP&, const Dictionary*&);
174 Result_t WriteGenericStreamPartition(Kumu::FileWriter&, ASDCP::MXF::OP1aHeader&, ASDCP::MXF::RIP&, const Dictionary*&,
175 const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
177 Result_t Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict,
178 const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
179 ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
180 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
182 Result_t Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict, const MXF::OP1aHeader& HeaderPart,
183 const ASDCP::WriterInfo& Info, ASDCP::FrameBuffer& CtFrameBuf, ui32_t& FramesWritten,
184 ui64_t & StreamOffset, const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
185 const ui32_t& MinEssenceElementBerLength,
186 AESEncContext* Ctx, HMACContext* HMAC);
189 class KLReader : public ASDCP::KLVPacket
191 ASDCP_NO_COPY_CONSTRUCT(KLReader);
192 byte_t m_KeyBuf[SMPTE_UL_LENGTH*2];
198 inline const byte_t* Key() { return m_KeyBuf; }
199 inline const ui64_t Length() { return m_ValueLength; }
200 inline const ui64_t KLLength() { return m_KLLength; }
202 Result_t ReadKLFromFile(Kumu::FileReader& Reader);
207 //---------------------------------------------------------------------------------
210 /// void default_md_object_init();
212 template <class HeaderType, class IndexAccessType>
213 class TrackFileReader
215 KM_NO_COPY_CONSTRUCT(TrackFileReader);
219 const Dictionary* m_Dict;
220 Kumu::FileReader m_File;
221 HeaderType m_HeaderPart;
222 IndexAccessType m_IndexAccess;
225 ASDCP::FrameBuffer m_CtFrameBuf;
226 Kumu::fpos_t m_LastPosition;
228 TrackFileReader(const Dictionary& d) :
229 m_HeaderPart(m_Dict), m_IndexAccess(m_Dict), m_RIP(m_Dict), m_Dict(&d)
231 default_md_object_init();
234 virtual ~TrackFileReader() {
238 const MXF::RIP& GetRIP() const { return m_RIP; }
241 Result_t OpenMXFRead(const std::string& filename)
244 Result_t result = m_File.OpenRead(filename);
246 if ( ASDCP_SUCCESS(result) )
247 result = SeekToRIP(m_File);
249 if ( ASDCP_SUCCESS(result) )
251 result = m_RIP.InitFromFile(m_File);
252 ui32_t test_s = (ui32_t)m_RIP.PairArray.size();
254 if ( ASDCP_FAILURE(result) )
256 DefaultLogSink().Error("File contains no RIP\n");
258 else if ( m_RIP.PairArray.empty() )
260 DefaultLogSink().Error("RIP contains no Pairs.\n");
265 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, SeekToRIP failed\n");
269 result = m_HeaderPart.InitFromFile(m_File);
271 if ( KM_FAILURE(result) )
273 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, header init failed\n");
283 InterchangeObject* Object;
286 Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
288 // Writer Info and SourcePackage
289 if ( KM_SUCCESS(result) )
291 MD_to_WriterInfo((Identification*)Object, m_Info);
292 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
295 if ( KM_SUCCESS(result) )
297 SourcePackage* SP = (SourcePackage*)Object;
298 memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
301 // optional CryptographicContext
302 if ( KM_SUCCESS(result) )
304 Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
306 if ( KM_SUCCESS(cr_result) )
307 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
313 // positions file before reading
314 // allows external control of index offset
315 Result_t ReadEKLVFrame(const ui64_t& body_offset,
316 ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
317 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
319 // look up frame index node
320 IndexTableSegment::IndexEntry TmpEntry;
322 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
324 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
328 // get relative frame position, apply offset and go read the frame's key and length
329 Kumu::fpos_t FilePosition = body_offset + TmpEntry.StreamOffset;
330 Result_t result = RESULT_OK;
332 if ( FilePosition != m_LastPosition )
334 m_LastPosition = FilePosition;
335 result = m_File.Seek(FilePosition);
338 if ( KM_SUCCESS(result) )
339 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
344 // positions file before reading
345 // assumes "processed" index entries have absolute positions
346 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
347 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
349 // look up frame index node
350 IndexTableSegment::IndexEntry TmpEntry;
352 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
354 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
358 // get absolute frame position and go read the frame's key and length
359 Result_t result = RESULT_OK;
361 if ( TmpEntry.StreamOffset != m_LastPosition )
363 m_LastPosition = TmpEntry.StreamOffset;
364 result = m_File.Seek(TmpEntry.StreamOffset);
367 if ( KM_SUCCESS(result) )
368 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
373 // reads from current position
374 Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
375 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
378 return Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
379 FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
382 // Get the position of a frame from a track file
383 Result_t LocateFrame(const ui64_t& body_offset,
384 ui32_t FrameNum, Kumu::fpos_t& streamOffset,
385 i8_t& temporalOffset, i8_t& keyFrameOffset)
387 // look up frame index node
388 IndexTableSegment::IndexEntry TmpEntry;
390 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
392 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
396 // get frame position, temporal offset, and key frame ofset
397 streamOffset = body_offset + TmpEntry.StreamOffset;
398 temporalOffset = TmpEntry.TemporalOffset;
399 keyFrameOffset = TmpEntry.KeyFrameOffset;
404 // Reads a Generic Stream Partition payload. Returns RESULT_FORMAT if the SID is
405 // not present in the RIP, or if the actual partition at ByteOffset does not have
406 // a matching BodySID value. Encryption is not currently supported.
407 Result_t ReadGenericStreamPartitionPayload(const ui32_t sid, ASDCP::FrameBuffer& frame_buf,
408 AESDecContext* Ctx, HMACContext* HMAC)
410 Kumu::fpos_t start_offset = 0, end_offset = 0;
413 // locate SID, record the offset
414 // Count the sequence length in because this is the sequence
415 // value needed to complete the HMAC.
416 ASDCP::MXF::RIP::const_pair_iterator i;
417 for ( i = m_RIP.PairArray.begin(); i != m_RIP.PairArray.end(); ++i, ++sequence )
419 if ( sid == i->BodySID )
421 start_offset = i->ByteOffset;
423 else if ( start_offset != 0 )
425 end_offset = i->ByteOffset;
430 if ( start_offset == 0 || end_offset == 0 )
432 DefaultLogSink().Error("Body SID not found: %d.\n", sid);
433 return RESULT_NOT_FOUND;
436 // Read the Partition header and then read the payload.
437 Result_t result = m_File.Seek(start_offset);
439 if ( KM_SUCCESS(result) )
441 result = frame_buf.Capacity(end_offset-start_offset);
444 if ( KM_SUCCESS(result) )
446 // read the partition header
447 ASDCP::MXF::Partition GSPart(m_Dict);
448 result = GSPart.InitFromFile(m_File);
450 if ( KM_SUCCESS(result) )
453 if ( GSPart.BodySID != sid )
455 DefaultLogSink().Error("Generic stream partition Body SID differs: %s\n", sid);
456 result = RESULT_FORMAT;
460 result = ReadEKLVPacket(0, sequence, frame_buf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
475 //------------------------------------------------------------------------------------------
479 template <class ClipT>
483 MXF::Sequence* Sequence;
486 TrackSet() : Track(0), Sequence(0), Clip(0) {}
490 template <class PackageT, class ClipT>
492 CreateTrackAndSequence(OP1aHeader& Header, PackageT& Package, const std::string TrackName,
493 const MXF::Rational& clip_edit_rate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
495 TrackSet<ClipT> NewTrack;
497 NewTrack.Track = new Track(Dict);
498 Header.AddChildObject(NewTrack.Track);
499 NewTrack.Track->EditRate = clip_edit_rate;
500 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
501 NewTrack.Track->TrackID = TrackID;
502 NewTrack.Track->TrackName = TrackName.c_str();
504 NewTrack.Sequence = new Sequence(Dict);
505 Header.AddChildObject(NewTrack.Sequence);
506 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
507 NewTrack.Sequence->DataDefinition = Definition;
513 template <class PackageT>
514 TrackSet<TimecodeComponent>
515 CreateTimecodeTrack(OP1aHeader& Header, PackageT& Package,
516 const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate, ui64_t TCStart, const Dictionary*& Dict)
519 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
521 TrackSet<TimecodeComponent> NewTrack =
522 CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track",
523 tc_edit_rate, TCUL, 1, Dict);
525 NewTrack.Clip = new TimecodeComponent(Dict);
526 Header.AddChildObject(NewTrack.Clip);
527 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
528 NewTrack.Clip->RoundedTimecodeBase = tc_frame_rate;
529 NewTrack.Clip->StartTimecode = TCStart;
530 NewTrack.Clip->DataDefinition = TCUL;
536 // state machine for mxf writer
538 ST_BEGIN, // waiting for Open()
539 ST_INIT, // waiting for SetSourceStream()
540 ST_READY, // ready to write frames
541 ST_RUNNING, // one or more frames written
542 ST_FINAL, // index written, file closed
546 // implementation of h__WriterState class Goto_* methods
547 #define Goto_body(s1,s2) \
548 if ( m_State != (s1) ) { \
549 return RESULT_STATE; \
556 ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
559 WriterState_t m_State;
560 h__WriterState() : m_State(ST_BEGIN) {}
563 inline bool Test_BEGIN() { return m_State == ST_BEGIN; }
564 inline bool Test_INIT() { return m_State == ST_INIT; }
565 inline bool Test_READY() { return m_State == ST_READY;}
566 inline bool Test_RUNNING() { return m_State == ST_RUNNING; }
567 inline bool Test_FINAL() { return m_State == ST_FINAL; }
568 inline Result_t Goto_INIT() { Goto_body(ST_BEGIN, ST_INIT); }
569 inline Result_t Goto_READY() { Goto_body(ST_INIT, ST_READY); }
570 inline Result_t Goto_RUNNING() { Goto_body(ST_READY, ST_RUNNING); }
571 inline Result_t Goto_FINAL() { Goto_body(ST_RUNNING, ST_FINAL); }
574 //------------------------------------------------------------------------------------------
578 template <class HeaderType>
579 class TrackFileWriter
581 KM_NO_COPY_CONSTRUCT(TrackFileWriter);
585 const Dictionary* m_Dict;
586 Kumu::FileWriter m_File;
588 HeaderType m_HeaderPart;
591 MaterialPackage* m_MaterialPackage;
592 SourcePackage* m_FilePackage;
593 ContentStorage* m_ContentStorage;
595 FileDescriptor* m_EssenceDescriptor;
596 std::list<InterchangeObject*> m_EssenceSubDescriptorList;
598 ui32_t m_FramesWritten;
599 ui64_t m_StreamOffset;
600 ASDCP::FrameBuffer m_CtFrameBuf;
601 h__WriterState m_State;
604 typedef std::list<ui64_t*> DurationElementList_t;
605 DurationElementList_t m_DurationUpdateList;
607 TrackFileWriter(const Dictionary& d) :
608 m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict), m_RIP(m_Dict),
609 m_MaterialPackage(0), m_FilePackage(0), m_ContentStorage(0),
610 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
612 default_md_object_init();
615 virtual ~TrackFileWriter() {
619 const MXF::RIP& GetRIP() const { return m_RIP; }
621 void InitHeader(const MXFVersion& mxf_ver)
624 assert(m_EssenceDescriptor);
626 m_HeaderPart.m_Primer.ClearTagList();
627 m_HeaderPart.m_Preface = new Preface(m_Dict);
628 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
630 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
631 // so we tell the world by using OP1a
632 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
633 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
635 if ( mxf_ver == MXFVersion_2004 )
637 m_HeaderPart.MinorVersion = MXF_2004_MinorVersion;
638 m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion << 8) | MXF_2004_MinorVersion);
639 m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
643 assert(mxf_ver == MXFVersion_2011);
644 m_HeaderPart.MinorVersion = MXF_2011_MinorVersion;
645 m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion << 8) | MXF_2011_MinorVersion);
646 m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
650 Identification* Ident = new Identification(m_Dict);
651 m_HeaderPart.AddChildObject(Ident);
652 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
654 Kumu::GenRandomValue(Ident->ThisGenerationUID);
655 Ident->CompanyName = m_Info.CompanyName.c_str();
656 Ident->ProductName = m_Info.ProductName.c_str();
657 Ident->VersionString = m_Info.ProductVersion.c_str();
658 Ident->ProductUID.Set(m_Info.ProductUUID);
659 Ident->Platform = ASDCP_PLATFORM;
661 std::vector<int> version = version_split(Version());
663 Ident->ToolkitVersion.Major = version[0];
664 Ident->ToolkitVersion.Minor = version[1];
665 Ident->ToolkitVersion.Patch = version[2];
666 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
667 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
671 void AddSourceClip(const MXF::Rational& clip_edit_rate,
672 const MXF::Rational& tc_edit_rate, ui32_t TCFrameRate,
673 const std::string& TrackName, const UL& EssenceUL,
674 const UL& DataDefinition, const std::string& PackageLabel)
676 if ( m_ContentStorage == 0 )
678 m_ContentStorage = new ContentStorage(m_Dict);
679 m_HeaderPart.AddChildObject(m_ContentStorage);
680 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
683 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
684 m_HeaderPart.AddChildObject(ECD);
685 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
689 UUID assetUUID(m_Info.AssetUUID);
690 UMID SourcePackageUMID, MaterialPackageUMID;
691 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
692 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
697 m_MaterialPackage = new MaterialPackage(m_Dict);
698 m_MaterialPackage->Name = "Material Package";
699 m_MaterialPackage->PackageUID = MaterialPackageUMID;
700 m_HeaderPart.AddChildObject(m_MaterialPackage);
701 m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
703 TrackSet<TimecodeComponent> MPTCTrack =
704 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
705 tc_edit_rate, TCFrameRate, 0, m_Dict);
707 MPTCTrack.Sequence->Duration.set_has_value();
708 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
709 MPTCTrack.Clip->Duration.set_has_value();
710 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
712 TrackSet<SourceClip> MPTrack =
713 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
714 TrackName, clip_edit_rate, DataDefinition,
716 MPTrack.Sequence->Duration.set_has_value();
717 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
719 MPTrack.Clip = new SourceClip(m_Dict);
720 m_HeaderPart.AddChildObject(MPTrack.Clip);
721 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
722 MPTrack.Clip->DataDefinition = DataDefinition;
723 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
724 MPTrack.Clip->SourceTrackID = 2;
726 MPTrack.Clip->Duration.set_has_value();
727 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration.get()));
731 // File (Source) Package
733 m_FilePackage = new SourcePackage(m_Dict);
734 m_FilePackage->Name = PackageLabel.c_str();
735 m_FilePackage->PackageUID = SourcePackageUMID;
736 ECD->LinkedPackageUID = SourcePackageUMID;
738 m_HeaderPart.AddChildObject(m_FilePackage);
739 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
741 TrackSet<TimecodeComponent> FPTCTrack =
742 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
743 tc_edit_rate, TCFrameRate, 0, m_Dict);
745 FPTCTrack.Sequence->Duration.set_has_value();
746 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
747 FPTCTrack.Clip->Duration.set_has_value();
748 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
750 TrackSet<SourceClip> FPTrack =
751 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
752 TrackName, clip_edit_rate, DataDefinition,
755 FPTrack.Sequence->Duration.set_has_value();
756 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
758 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
759 FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
761 FPTrack.Clip = new SourceClip(m_Dict);
762 m_HeaderPart.AddChildObject(FPTrack.Clip);
763 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
764 FPTrack.Clip->DataDefinition = DataDefinition;
766 // for now we do not allow setting this value, so all files will be 'original'
767 FPTrack.Clip->SourceTrackID = 0;
768 FPTrack.Clip->SourcePackageID = NilUMID;
770 FPTrack.Clip->Duration.set_has_value();
771 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration.get()));
773 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
777 void AddEssenceDescriptor(const UL& WrappingUL)
780 // Essence Descriptor
782 m_EssenceDescriptor->EssenceContainer = WrappingUL;
783 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
786 // Essence Descriptors
789 #ifndef ASDCP_GCMULTI_PATCH
790 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
791 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
794 if ( m_Info.EncryptedEssence )
796 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
797 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
798 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
799 AddDmsCrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
800 //// TODO: fix DMSegment Duration value
804 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
807 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
808 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
810 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
811 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
812 m_HeaderPart.AddChildObject(*sdli);
814 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
817 Result_t AddDmsGenericPartUtf8Text(const ASDCP::FrameBuffer& frame_buffer,
818 ASDCP::AESEncContext* enc = 0, ASDCP::HMACContext* hmac = 0)
820 Kumu::fpos_t previous_partition_offset = m_RIP.PairArray.back().ByteOffset;
821 Result_t result = AddDmsTrackGenericPartUtf8Text(m_File, m_HeaderPart, *m_FilePackage, m_RIP, m_Dict);
823 if ( KM_SUCCESS(result) )
825 // m_RIP now contains an entry (at the back) for the new generic stream
826 // (this entry was created during the call to AddDmsTrackGenericPartUtf8Text())
827 if ( m_File.Tell() != m_RIP.PairArray.back().ByteOffset )
829 DefaultLogSink().Error("File offset has moved since RIP modification. Unrecoverable error.\n");
833 // create generic stream partition header
834 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
835 ASDCP::MXF::Partition GSPart(m_Dict);
837 GSPart.MajorVersion = m_HeaderPart.MajorVersion;
838 GSPart.MinorVersion = m_HeaderPart.MinorVersion;
839 GSPart.ThisPartition = m_RIP.PairArray.back().ByteOffset;
840 GSPart.PreviousPartition = previous_partition_offset;
841 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
842 GSPart.BodySID = m_RIP.PairArray.back().BodySID;
843 GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
845 static UL gs_part_ul(m_Dict->ul(MDD_GenericStreamPartition));
846 Result_t result = GSPart.WriteToFile(m_File, gs_part_ul);
848 if ( KM_SUCCESS(result) )
850 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
851 m_StreamOffset, frame_buffer, GenericStream_DataElement.Value(),
852 MXF_BER_LENGTH, enc, hmac);
869 //------------------------------------------------------------------------------------------
873 class h__ASDCPReader : public MXF::TrackFileReader<OP1aHeader, OPAtomIndexFooter>
875 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
879 Partition m_BodyPart;
881 h__ASDCPReader(const Dictionary&);
882 virtual ~h__ASDCPReader();
884 Result_t OpenMXFRead(const std::string& filename);
885 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
886 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
887 Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
888 i8_t& temporalOffset, i8_t& keyFrameOffset);
892 class h__ASDCPWriter : public MXF::TrackFileWriter<OP1aHeader>
894 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPWriter);
898 Partition m_BodyPart;
899 OPAtomIndexFooter m_FooterPart;
901 h__ASDCPWriter(const Dictionary&);
902 virtual ~h__ASDCPWriter();
904 // all the above for a single source clip
905 Result_t WriteASDCPHeader(const std::string& PackageLabel, const UL& WrappingUL,
906 const std::string& TrackName, const UL& EssenceUL,
907 const UL& DataDefinition, const MXF::Rational& EditRate,
908 ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0);
910 Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
911 Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
912 const ui32_t& MinEssenceElementBerLength,
913 AESEncContext* Ctx, HMACContext* HMAC);
914 Result_t WriteASDCPFooter();
918 // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
923 byte_t Data[klv_intpack_size];
926 memset(Data, 0, klv_intpack_size);
931 Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
932 Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
938 #endif // _AS_DCP_INTERNAL_H_
942 // end AS_DCP_internal.h