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 ui64_t Length() { return m_ValueLength; }
200 inline 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_Dict(&d), m_HeaderPart(m_Dict), m_IndexAccess(m_Dict), m_RIP(m_Dict)
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);
253 if ( ASDCP_FAILURE(result) )
255 DefaultLogSink().Error("File contains no RIP\n");
257 else if ( m_RIP.PairArray.empty() )
259 DefaultLogSink().Error("RIP contains no Pairs.\n");
264 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, SeekToRIP failed\n");
268 result = m_HeaderPart.InitFromFile(m_File);
270 if ( KM_FAILURE(result) )
272 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, header init failed\n");
282 InterchangeObject* Object;
285 Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
287 // Writer Info and SourcePackage
288 if ( KM_SUCCESS(result) )
290 MD_to_WriterInfo((Identification*)Object, m_Info);
291 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
294 if ( KM_SUCCESS(result) )
296 SourcePackage* SP = (SourcePackage*)Object;
297 memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
300 // optional CryptographicContext
301 if ( KM_SUCCESS(result) )
303 Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
305 if ( KM_SUCCESS(cr_result) )
306 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
312 // positions file before reading
313 // allows external control of index offset
314 Result_t ReadEKLVFrame(const ui64_t& body_offset,
315 ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
316 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
318 // look up frame index node
319 IndexTableSegment::IndexEntry TmpEntry;
321 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
323 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
327 // get relative frame position, apply offset and go read the frame's key and length
328 Kumu::fpos_t FilePosition = body_offset + TmpEntry.StreamOffset;
329 Result_t result = RESULT_OK;
331 if ( FilePosition != m_LastPosition )
333 m_LastPosition = FilePosition;
334 result = m_File.Seek(FilePosition);
337 if ( KM_SUCCESS(result) )
338 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
343 // positions file before reading
344 // assumes "processed" index entries have absolute positions
345 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
346 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
348 // look up frame index node
349 IndexTableSegment::IndexEntry TmpEntry;
351 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
353 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
357 // get absolute frame position and go read the frame's key and length
358 Result_t result = RESULT_OK;
360 if ( static_cast<Kumu::fpos_t>(TmpEntry.StreamOffset) != m_LastPosition )
362 m_LastPosition = TmpEntry.StreamOffset;
363 result = m_File.Seek(TmpEntry.StreamOffset);
366 if ( KM_SUCCESS(result) )
367 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
372 // reads from current position
373 Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
374 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
377 return Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
378 FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
381 // Get the position of a frame from a track file
382 Result_t LocateFrame(const ui64_t& body_offset,
383 ui32_t FrameNum, Kumu::fpos_t& streamOffset,
384 i8_t& temporalOffset, i8_t& keyFrameOffset)
386 // look up frame index node
387 IndexTableSegment::IndexEntry TmpEntry;
389 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
391 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
395 // get frame position, temporal offset, and key frame ofset
396 streamOffset = body_offset + TmpEntry.StreamOffset;
397 temporalOffset = TmpEntry.TemporalOffset;
398 keyFrameOffset = TmpEntry.KeyFrameOffset;
403 // Reads a Generic Stream Partition payload. Returns RESULT_FORMAT if the SID is
404 // not present in the RIP, or if the actual partition at ByteOffset does not have
405 // a matching BodySID value. Encryption is not currently supported.
406 Result_t ReadGenericStreamPartitionPayload(const ui32_t sid, ASDCP::FrameBuffer& frame_buf,
407 AESDecContext* Ctx, HMACContext* HMAC)
409 Kumu::fpos_t start_offset = 0, end_offset = 0;
412 // locate SID, record the offset
413 // Count the sequence length in because this is the sequence
414 // value needed to complete the HMAC.
415 ASDCP::MXF::RIP::const_pair_iterator i;
416 for ( i = m_RIP.PairArray.begin(); i != m_RIP.PairArray.end(); ++i)
418 if ( sid == i->BodySID )
420 assert( start_offset == 0);
421 start_offset = i->ByteOffset;
423 else if ( start_offset != 0 )
425 end_offset = i->ByteOffset;
429 if ( i->BodySID > 0 )
435 if ( start_offset == 0 || end_offset == 0 )
437 DefaultLogSink().Error("Body SID not found: %d.\n", sid);
438 return RESULT_NOT_FOUND;
441 // Read the Partition header and then read the payload.
442 Result_t result = m_File.Seek(start_offset);
444 if ( KM_SUCCESS(result) )
446 result = frame_buf.Capacity(end_offset-start_offset);
449 if ( KM_SUCCESS(result) )
451 // read the partition header
452 ASDCP::MXF::Partition GSPart(m_Dict);
453 result = GSPart.InitFromFile(m_File);
455 if ( KM_SUCCESS(result) )
458 if ( GSPart.BodySID != sid )
460 DefaultLogSink().Error("Generic stream partition Body SID differs: %s\n", sid);
461 result = RESULT_FORMAT;
465 result = ReadEKLVPacket(0, sequence, frame_buf, m_Dict->ul(MDD_GenericStream_DataElement), Ctx, HMAC);
480 //------------------------------------------------------------------------------------------
484 template <class ClipT>
488 MXF::Sequence* Sequence;
491 TrackSet() : Track(0), Sequence(0), Clip(0) {}
495 template <class PackageT, class ClipT>
497 CreateTrackAndSequence(OP1aHeader& Header, PackageT& Package, const std::string TrackName,
498 const MXF::Rational& clip_edit_rate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
500 TrackSet<ClipT> NewTrack;
502 NewTrack.Track = new Track(Dict);
503 Header.AddChildObject(NewTrack.Track);
504 NewTrack.Track->EditRate = clip_edit_rate;
505 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
506 NewTrack.Track->TrackID = TrackID;
507 NewTrack.Track->TrackName = TrackName.c_str();
509 NewTrack.Sequence = new Sequence(Dict);
510 Header.AddChildObject(NewTrack.Sequence);
511 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
512 NewTrack.Sequence->DataDefinition = Definition;
518 template <class PackageT>
519 TrackSet<TimecodeComponent>
520 CreateTimecodeTrack(OP1aHeader& Header, PackageT& Package,
521 const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate, ui64_t TCStart, const Dictionary*& Dict)
524 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
526 TrackSet<TimecodeComponent> NewTrack =
527 CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track",
528 tc_edit_rate, TCUL, 1, Dict);
530 NewTrack.Clip = new TimecodeComponent(Dict);
531 Header.AddChildObject(NewTrack.Clip);
532 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
533 NewTrack.Clip->RoundedTimecodeBase = tc_frame_rate;
534 NewTrack.Clip->StartTimecode = TCStart;
535 NewTrack.Clip->DataDefinition = TCUL;
541 // state machine for mxf writer
543 ST_BEGIN, // waiting for Open()
544 ST_INIT, // waiting for SetSourceStream()
545 ST_READY, // ready to write frames
546 ST_RUNNING, // one or more frames written
547 ST_FINAL, // index written, file closed
551 // implementation of h__WriterState class Goto_* methods
552 #define Goto_body(s1,s2) \
553 if ( m_State != (s1) ) { \
554 return RESULT_STATE; \
561 ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
564 WriterState_t m_State;
565 h__WriterState() : m_State(ST_BEGIN) {}
568 inline bool Test_BEGIN() { return m_State == ST_BEGIN; }
569 inline bool Test_INIT() { return m_State == ST_INIT; }
570 inline bool Test_READY() { return m_State == ST_READY;}
571 inline bool Test_RUNNING() { return m_State == ST_RUNNING; }
572 inline bool Test_FINAL() { return m_State == ST_FINAL; }
573 inline Result_t Goto_INIT() { Goto_body(ST_BEGIN, ST_INIT); }
574 inline Result_t Goto_READY() { Goto_body(ST_INIT, ST_READY); }
575 inline Result_t Goto_RUNNING() { Goto_body(ST_READY, ST_RUNNING); }
576 inline Result_t Goto_FINAL() { Goto_body(ST_RUNNING, ST_FINAL); }
579 //------------------------------------------------------------------------------------------
583 template <class HeaderType>
584 class TrackFileWriter
586 KM_NO_COPY_CONSTRUCT(TrackFileWriter);
590 const Dictionary* m_Dict;
591 Kumu::FileWriter m_File;
593 HeaderType m_HeaderPart;
596 MaterialPackage* m_MaterialPackage;
597 SourcePackage* m_FilePackage;
598 ContentStorage* m_ContentStorage;
600 FileDescriptor* m_EssenceDescriptor;
601 std::list<InterchangeObject*> m_EssenceSubDescriptorList;
603 ui32_t m_FramesWritten;
604 ui64_t m_StreamOffset;
605 ASDCP::FrameBuffer m_CtFrameBuf;
606 h__WriterState m_State;
609 typedef std::list<ui64_t*> DurationElementList_t;
610 DurationElementList_t m_DurationUpdateList;
612 TrackFileWriter(const Dictionary& d) :
613 m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict), m_RIP(m_Dict),
614 m_MaterialPackage(0), m_FilePackage(0), m_ContentStorage(0),
615 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
617 default_md_object_init();
620 virtual ~TrackFileWriter() {
624 const MXF::RIP& GetRIP() const { return m_RIP; }
626 void InitHeader(const MXFVersion& mxf_ver)
629 assert(m_EssenceDescriptor);
631 m_HeaderPart.m_Primer.ClearTagList();
632 m_HeaderPart.m_Preface = new Preface(m_Dict);
633 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
635 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
636 // so we tell the world by using OP1a
637 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
638 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
640 if ( mxf_ver == MXFVersion_2004 )
642 m_HeaderPart.MinorVersion = MXF_2004_MinorVersion;
643 m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion << 8) | MXF_2004_MinorVersion);
644 m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
648 assert(mxf_ver == MXFVersion_2011);
649 m_HeaderPart.MinorVersion = MXF_2011_MinorVersion;
650 m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion << 8) | MXF_2011_MinorVersion);
651 m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
655 Identification* Ident = new Identification(m_Dict);
656 m_HeaderPart.AddChildObject(Ident);
657 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
659 Kumu::GenRandomValue(Ident->ThisGenerationUID);
660 Ident->CompanyName = m_Info.CompanyName.c_str();
661 Ident->ProductName = m_Info.ProductName.c_str();
662 Ident->VersionString = m_Info.ProductVersion.c_str();
663 Ident->ProductUID.Set(m_Info.ProductUUID);
664 Ident->Platform = ASDCP_PLATFORM;
666 std::vector<int> version = version_split(Version());
668 Ident->ToolkitVersion.Major = version[0];
669 Ident->ToolkitVersion.Minor = version[1];
670 Ident->ToolkitVersion.Patch = version[2];
671 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
672 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
676 void AddSourceClip(const MXF::Rational& clip_edit_rate,
677 const MXF::Rational& tc_edit_rate, ui32_t TCFrameRate,
678 const std::string& TrackName, const UL& EssenceUL,
679 const UL& DataDefinition, const std::string& PackageLabel)
681 if ( m_ContentStorage == 0 )
683 m_ContentStorage = new ContentStorage(m_Dict);
684 m_HeaderPart.AddChildObject(m_ContentStorage);
685 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
688 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
689 m_HeaderPart.AddChildObject(ECD);
690 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
694 UUID assetUUID(m_Info.AssetUUID);
695 UMID SourcePackageUMID, MaterialPackageUMID;
696 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
697 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
702 m_MaterialPackage = new MaterialPackage(m_Dict);
703 m_MaterialPackage->Name = "Material Package";
704 m_MaterialPackage->PackageUID = MaterialPackageUMID;
705 m_HeaderPart.AddChildObject(m_MaterialPackage);
706 m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
708 TrackSet<TimecodeComponent> MPTCTrack =
709 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
710 tc_edit_rate, TCFrameRate, 0, m_Dict);
712 MPTCTrack.Sequence->Duration.set_has_value();
713 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
714 MPTCTrack.Clip->Duration.set_has_value();
715 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
717 TrackSet<SourceClip> MPTrack =
718 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
719 TrackName, clip_edit_rate, DataDefinition,
721 MPTrack.Sequence->Duration.set_has_value();
722 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
724 MPTrack.Clip = new SourceClip(m_Dict);
725 m_HeaderPart.AddChildObject(MPTrack.Clip);
726 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
727 MPTrack.Clip->DataDefinition = DataDefinition;
728 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
729 MPTrack.Clip->SourceTrackID = 2;
731 MPTrack.Clip->Duration.set_has_value();
732 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration.get()));
736 // File (Source) Package
738 m_FilePackage = new SourcePackage(m_Dict);
739 m_FilePackage->Name = PackageLabel.c_str();
740 m_FilePackage->PackageUID = SourcePackageUMID;
741 ECD->LinkedPackageUID = SourcePackageUMID;
743 m_HeaderPart.AddChildObject(m_FilePackage);
744 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
746 TrackSet<TimecodeComponent> FPTCTrack =
747 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
748 tc_edit_rate, TCFrameRate, 0, m_Dict);
750 FPTCTrack.Sequence->Duration.set_has_value();
751 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
752 FPTCTrack.Clip->Duration.set_has_value();
753 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
755 TrackSet<SourceClip> FPTrack =
756 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
757 TrackName, clip_edit_rate, DataDefinition,
760 FPTrack.Sequence->Duration.set_has_value();
761 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
763 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
764 FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
766 FPTrack.Clip = new SourceClip(m_Dict);
767 m_HeaderPart.AddChildObject(FPTrack.Clip);
768 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
769 FPTrack.Clip->DataDefinition = DataDefinition;
771 // for now we do not allow setting this value, so all files will be 'original'
772 FPTrack.Clip->SourceTrackID = 0;
773 FPTrack.Clip->SourcePackageID = NilUMID;
775 FPTrack.Clip->Duration.set_has_value();
776 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration.get()));
778 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
782 void AddEssenceDescriptor(const UL& WrappingUL)
785 // Essence Descriptor
787 m_EssenceDescriptor->EssenceContainer = WrappingUL;
788 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
791 // Essence Descriptors
794 #ifndef ASDCP_GCMULTI_PATCH
795 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
796 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
799 if ( m_Info.EncryptedEssence )
801 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
802 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
803 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
804 AddDmsCrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
805 //// TODO: fix DMSegment Duration value
809 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
812 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
813 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
815 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
816 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
817 m_HeaderPart.AddChildObject(*sdli);
819 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
822 Result_t AddDmsGenericPartUtf8Text(const ASDCP::FrameBuffer& frame_buffer,
823 ASDCP::AESEncContext* enc = 0, ASDCP::HMACContext* hmac = 0)
825 Kumu::fpos_t previous_partition_offset = m_RIP.PairArray.back().ByteOffset;
826 Result_t result = AddDmsTrackGenericPartUtf8Text(m_File, m_HeaderPart, *m_FilePackage, m_RIP, m_Dict);
828 if ( KM_SUCCESS(result) )
830 // m_RIP now contains an entry (at the back) for the new generic stream
831 // (this entry was created during the call to AddDmsTrackGenericPartUtf8Text())
832 if ( m_File.Tell() != m_RIP.PairArray.back().ByteOffset )
834 DefaultLogSink().Error("File offset has moved since RIP modification. Unrecoverable error.\n");
838 // create generic stream partition header
839 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
840 ASDCP::MXF::Partition GSPart(m_Dict);
842 GSPart.MajorVersion = m_HeaderPart.MajorVersion;
843 GSPart.MinorVersion = m_HeaderPart.MinorVersion;
844 GSPart.ThisPartition = m_RIP.PairArray.back().ByteOffset;
845 GSPart.PreviousPartition = previous_partition_offset;
846 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
847 GSPart.BodySID = m_RIP.PairArray.back().BodySID;
848 GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
850 static UL gs_part_ul(m_Dict->ul(MDD_GenericStreamPartition));
851 Result_t result = GSPart.WriteToFile(m_File, gs_part_ul);
853 if ( KM_SUCCESS(result) )
855 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
856 m_StreamOffset, frame_buffer, GenericStream_DataElement.Value(),
857 MXF_BER_LENGTH, enc, hmac);
874 //------------------------------------------------------------------------------------------
878 class h__ASDCPReader : public MXF::TrackFileReader<OP1aHeader, OPAtomIndexFooter>
880 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
884 Partition m_BodyPart;
886 h__ASDCPReader(const Dictionary&);
887 virtual ~h__ASDCPReader();
889 Result_t OpenMXFRead(const std::string& filename);
890 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
891 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
892 Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
893 i8_t& temporalOffset, i8_t& keyFrameOffset);
897 class h__ASDCPWriter : public MXF::TrackFileWriter<OP1aHeader>
899 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPWriter);
903 Partition m_BodyPart;
904 OPAtomIndexFooter m_FooterPart;
906 h__ASDCPWriter(const Dictionary&);
907 virtual ~h__ASDCPWriter();
909 // all the above for a single source clip
910 Result_t WriteASDCPHeader(const std::string& PackageLabel, const UL& WrappingUL,
911 const std::string& TrackName, const UL& EssenceUL,
912 const UL& DataDefinition, const MXF::Rational& EditRate,
913 ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0);
915 Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
916 Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
917 const ui32_t& MinEssenceElementBerLength,
918 AESEncContext* Ctx, HMACContext* HMAC);
919 Result_t WriteASDCPFooter();
923 // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
928 byte_t Data[klv_intpack_size];
931 memset(Data, 0, klv_intpack_size);
936 Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
937 Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
943 #endif // _AS_DCP_INTERNAL_H_
947 // end AS_DCP_internal.h