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 AddDmsTrackGenericPartUtf8Text(Kumu::FileWriter&, ASDCP::MXF::OP1aHeader&, SourcePackage&,
168 ASDCP::MXF::RIP&, const Dictionary*&);
170 Result_t WriteGenericStreamPartition(Kumu::FileWriter&, ASDCP::MXF::OP1aHeader&, ASDCP::MXF::RIP&, const Dictionary*&,
171 const ASDCP::FrameBuffer&, ASDCP::AESEncContext* = 0, ASDCP::HMACContext* = 0);
173 Result_t Read_EKLV_Packet(Kumu::FileReader& File, const ASDCP::Dictionary& Dict,
174 const ASDCP::WriterInfo& Info, Kumu::fpos_t& LastPosition, ASDCP::FrameBuffer& CtFrameBuf,
175 ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
176 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
178 Result_t Write_EKLV_Packet(Kumu::FileWriter& File, const ASDCP::Dictionary& Dict, const MXF::OP1aHeader& HeaderPart,
179 const ASDCP::WriterInfo& Info, ASDCP::FrameBuffer& CtFrameBuf, ui32_t& FramesWritten,
180 ui64_t & StreamOffset, const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
181 AESEncContext* Ctx, HMACContext* HMAC);
184 class KLReader : public ASDCP::KLVPacket
186 ASDCP_NO_COPY_CONSTRUCT(KLReader);
187 byte_t m_KeyBuf[SMPTE_UL_LENGTH*2];
193 inline const byte_t* Key() { return m_KeyBuf; }
194 inline const ui64_t Length() { return m_ValueLength; }
195 inline const ui64_t KLLength() { return m_KLLength; }
197 Result_t ReadKLFromFile(Kumu::FileReader& Reader);
202 //---------------------------------------------------------------------------------
205 /// void default_md_object_init();
207 template <class HeaderType, class IndexAccessType>
208 class TrackFileReader
210 KM_NO_COPY_CONSTRUCT(TrackFileReader);
214 const Dictionary* m_Dict;
215 Kumu::FileReader m_File;
216 HeaderType m_HeaderPart;
217 IndexAccessType m_IndexAccess;
220 ASDCP::FrameBuffer m_CtFrameBuf;
221 Kumu::fpos_t m_LastPosition;
223 TrackFileReader(const Dictionary& d) :
224 m_HeaderPart(m_Dict), m_IndexAccess(m_Dict), m_RIP(m_Dict), m_Dict(&d)
226 default_md_object_init();
229 virtual ~TrackFileReader() {
233 const MXF::RIP& GetRIP() const { return m_RIP; }
236 Result_t OpenMXFRead(const std::string& filename)
239 Result_t result = m_File.OpenRead(filename);
241 if ( ASDCP_SUCCESS(result) )
242 result = SeekToRIP(m_File);
244 if ( ASDCP_SUCCESS(result) )
246 result = m_RIP.InitFromFile(m_File);
247 ui32_t test_s = (ui32_t)m_RIP.PairArray.size();
249 if ( ASDCP_FAILURE(result) )
251 DefaultLogSink().Error("File contains no RIP\n");
253 else if ( m_RIP.PairArray.empty() )
255 DefaultLogSink().Error("RIP contains no Pairs.\n");
260 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, SeekToRIP failed\n");
264 result = m_HeaderPart.InitFromFile(m_File);
266 if ( KM_FAILURE(result) )
268 DefaultLogSink().Error("TrackFileReader::OpenMXFRead, header init failed\n");
278 InterchangeObject* Object;
281 Result_t result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(Identification), &Object);
283 // Writer Info and SourcePackage
284 if ( KM_SUCCESS(result) )
286 MD_to_WriterInfo((Identification*)Object, m_Info);
287 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(SourcePackage), &Object);
290 if ( KM_SUCCESS(result) )
292 SourcePackage* SP = (SourcePackage*)Object;
293 memcpy(m_Info.AssetUUID, SP->PackageUID.Value() + 16, UUIDlen);
296 // optional CryptographicContext
297 if ( KM_SUCCESS(result) )
299 Result_t cr_result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CryptographicContext), &Object);
301 if ( KM_SUCCESS(cr_result) )
302 MD_to_CryptoInfo((CryptographicContext*)Object, m_Info, *m_Dict);
308 // positions file before reading
309 // allows external control of index offset
310 Result_t ReadEKLVFrame(const ui64_t& body_offset,
311 ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
312 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
314 // look up frame index node
315 IndexTableSegment::IndexEntry TmpEntry;
317 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
319 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
323 // get relative frame position, apply offset and go read the frame's key and length
324 Kumu::fpos_t FilePosition = body_offset + TmpEntry.StreamOffset;
325 Result_t result = RESULT_OK;
327 if ( FilePosition != m_LastPosition )
329 m_LastPosition = FilePosition;
330 result = m_File.Seek(FilePosition);
333 if ( KM_SUCCESS(result) )
334 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
339 // positions file before reading
340 // assumes "processed" index entries have absolute positions
341 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
342 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
344 // look up frame index node
345 IndexTableSegment::IndexEntry TmpEntry;
347 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
349 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
353 // get absolute frame position and go read the frame's key and length
354 Result_t result = RESULT_OK;
356 if ( TmpEntry.StreamOffset != m_LastPosition )
358 m_LastPosition = TmpEntry.StreamOffset;
359 result = m_File.Seek(TmpEntry.StreamOffset);
362 if ( KM_SUCCESS(result) )
363 result = ReadEKLVPacket(FrameNum, FrameNum + 1, FrameBuf, EssenceUL, Ctx, HMAC);
368 // reads from current position
369 Result_t ReadEKLVPacket(ui32_t FrameNum, ui32_t SequenceNum, ASDCP::FrameBuffer& FrameBuf,
370 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC)
373 return Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
374 FrameNum, SequenceNum, FrameBuf, EssenceUL, Ctx, HMAC);
377 // Get the position of a frame from a track file
378 Result_t LocateFrame(const ui64_t& body_offset,
379 ui32_t FrameNum, Kumu::fpos_t& streamOffset,
380 i8_t& temporalOffset, i8_t& keyFrameOffset)
382 // look up frame index node
383 IndexTableSegment::IndexEntry TmpEntry;
385 if ( KM_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
387 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
391 // get frame position, temporal offset, and key frame ofset
392 streamOffset = body_offset + TmpEntry.StreamOffset;
393 temporalOffset = TmpEntry.TemporalOffset;
394 keyFrameOffset = TmpEntry.KeyFrameOffset;
399 // Reads a Generic Stream Partition payload. Returns RESULT_FORMAT if the SID is
400 // not present in the RIP, or if the actual partition at ByteOffset does not have
401 // a matching BodySID value. Encryption is not currently supported.
402 Result_t ReadGenericStreamPartitionPayload(const ui32_t sid, ASDCP::FrameBuffer& frame_buf)
404 Kumu::fpos_t start_offset = 0, end_offset = 0;
407 // locate SID, record the offset
408 // Count the sequence length in because this is the sequence
409 // value needed to complete the HMAC.
410 ASDCP::MXF::RIP::const_pair_iterator i;
411 for ( i = m_RIP.PairArray.begin(); i != m_RIP.PairArray.end(); ++i, ++sequence )
413 if ( sid == i->BodySID )
415 start_offset = i->ByteOffset;
417 else if ( start_offset != 0 )
419 end_offset = i->ByteOffset;
424 if ( start_offset == 0 || end_offset == 0 )
426 DefaultLogSink().Error("Body SID not found: %d.\n", sid);
427 return RESULT_NOT_FOUND;
430 // Read the Partition header and then read the payload.
431 Result_t result = m_File.Seek(start_offset);
433 if ( KM_SUCCESS(result) )
435 result = frame_buf.Capacity(end_offset-start_offset);
438 if ( KM_SUCCESS(result) )
440 // read the partition header
441 ASDCP::MXF::Partition GSPart(m_Dict);
442 result = GSPart.InitFromFile(m_File);
444 if ( KM_SUCCESS(result) )
447 if ( GSPart.BodySID != sid )
449 DefaultLogSink().Error("Generic stream partition Body SID differs: %s\n", sid);
450 result = RESULT_FORMAT;
454 result = ReadEKLVPacket(0, sequence, frame_buf, m_Dict->ul(MDD_GenericStream_DataElement), 0, 0);
469 //------------------------------------------------------------------------------------------
473 template <class ClipT>
477 MXF::Sequence* Sequence;
480 TrackSet() : Track(0), Sequence(0), Clip(0) {}
484 template <class PackageT, class ClipT>
486 CreateTrackAndSequence(OP1aHeader& Header, PackageT& Package, const std::string TrackName,
487 const MXF::Rational& clip_edit_rate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
489 TrackSet<ClipT> NewTrack;
491 NewTrack.Track = new Track(Dict);
492 Header.AddChildObject(NewTrack.Track);
493 NewTrack.Track->EditRate = clip_edit_rate;
494 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
495 NewTrack.Track->TrackID = TrackID;
496 NewTrack.Track->TrackName = TrackName.c_str();
498 NewTrack.Sequence = new Sequence(Dict);
499 Header.AddChildObject(NewTrack.Sequence);
500 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
501 NewTrack.Sequence->DataDefinition = Definition;
507 template <class PackageT>
508 TrackSet<TimecodeComponent>
509 CreateTimecodeTrack(OP1aHeader& Header, PackageT& Package,
510 const MXF::Rational& tc_edit_rate, ui32_t tc_frame_rate, ui64_t TCStart, const Dictionary*& Dict)
513 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
515 TrackSet<TimecodeComponent> NewTrack =
516 CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track",
517 tc_edit_rate, TCUL, 1, Dict);
519 NewTrack.Clip = new TimecodeComponent(Dict);
520 Header.AddChildObject(NewTrack.Clip);
521 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
522 NewTrack.Clip->RoundedTimecodeBase = tc_frame_rate;
523 NewTrack.Clip->StartTimecode = TCStart;
524 NewTrack.Clip->DataDefinition = TCUL;
530 // state machine for mxf writer
532 ST_BEGIN, // waiting for Open()
533 ST_INIT, // waiting for SetSourceStream()
534 ST_READY, // ready to write frames
535 ST_RUNNING, // one or more frames written
536 ST_FINAL, // index written, file closed
540 // implementation of h__WriterState class Goto_* methods
541 #define Goto_body(s1,s2) \
542 if ( m_State != (s1) ) { \
543 return RESULT_STATE; \
550 ASDCP_NO_COPY_CONSTRUCT(h__WriterState);
553 WriterState_t m_State;
554 h__WriterState() : m_State(ST_BEGIN) {}
557 inline bool Test_BEGIN() { return m_State == ST_BEGIN; }
558 inline bool Test_INIT() { return m_State == ST_INIT; }
559 inline bool Test_READY() { return m_State == ST_READY;}
560 inline bool Test_RUNNING() { return m_State == ST_RUNNING; }
561 inline bool Test_FINAL() { return m_State == ST_FINAL; }
562 inline Result_t Goto_INIT() { Goto_body(ST_BEGIN, ST_INIT); }
563 inline Result_t Goto_READY() { Goto_body(ST_INIT, ST_READY); }
564 inline Result_t Goto_RUNNING() { Goto_body(ST_READY, ST_RUNNING); }
565 inline Result_t Goto_FINAL() { Goto_body(ST_RUNNING, ST_FINAL); }
568 //------------------------------------------------------------------------------------------
572 template <class HeaderType>
573 class TrackFileWriter
575 KM_NO_COPY_CONSTRUCT(TrackFileWriter);
579 const Dictionary* m_Dict;
580 Kumu::FileWriter m_File;
582 HeaderType m_HeaderPart;
585 MaterialPackage* m_MaterialPackage;
586 SourcePackage* m_FilePackage;
587 ContentStorage* m_ContentStorage;
589 FileDescriptor* m_EssenceDescriptor;
590 std::list<InterchangeObject*> m_EssenceSubDescriptorList;
592 ui32_t m_FramesWritten;
593 ui64_t m_StreamOffset;
594 ASDCP::FrameBuffer m_CtFrameBuf;
595 h__WriterState m_State;
598 typedef std::list<ui64_t*> DurationElementList_t;
599 DurationElementList_t m_DurationUpdateList;
601 TrackFileWriter(const Dictionary& d) :
602 m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict), m_RIP(m_Dict),
603 m_MaterialPackage(0), m_FilePackage(0), m_ContentStorage(0),
604 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
606 default_md_object_init();
609 virtual ~TrackFileWriter() {
613 const MXF::RIP& GetRIP() const { return m_RIP; }
615 void InitHeader(const MXFVersion& mxf_ver)
618 assert(m_EssenceDescriptor);
620 m_HeaderPart.m_Primer.ClearTagList();
621 m_HeaderPart.m_Preface = new Preface(m_Dict);
622 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
624 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
625 // so we tell the world by using OP1a
626 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
627 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
629 if ( mxf_ver == MXFVersion_2004 )
631 m_HeaderPart.MinorVersion = MXF_2004_MinorVersion;
632 m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion < 8) | MXF_2004_MinorVersion);
633 m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
637 assert(mxf_ver == MXFVersion_2011);
638 m_HeaderPart.MinorVersion = MXF_2011_MinorVersion;
639 m_HeaderPart.m_Preface->Version = ((MXF_ObjectModelVersion < 8) | MXF_2011_MinorVersion);
640 m_HeaderPart.m_Preface->ObjectModelVersion = MXF_ObjectModelVersion;
644 Identification* Ident = new Identification(m_Dict);
645 m_HeaderPart.AddChildObject(Ident);
646 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
648 Kumu::GenRandomValue(Ident->ThisGenerationUID);
649 Ident->CompanyName = m_Info.CompanyName.c_str();
650 Ident->ProductName = m_Info.ProductName.c_str();
651 Ident->VersionString = m_Info.ProductVersion.c_str();
652 Ident->ProductUID.Set(m_Info.ProductUUID);
653 Ident->Platform = ASDCP_PLATFORM;
655 std::vector<int> version = version_split(Version());
657 Ident->ToolkitVersion.Major = version[0];
658 Ident->ToolkitVersion.Minor = version[1];
659 Ident->ToolkitVersion.Patch = version[2];
660 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
661 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
665 void AddSourceClip(const MXF::Rational& clip_edit_rate,
666 const MXF::Rational& tc_edit_rate, ui32_t TCFrameRate,
667 const std::string& TrackName, const UL& EssenceUL,
668 const UL& DataDefinition, const std::string& PackageLabel)
670 if ( m_ContentStorage == 0 )
672 m_ContentStorage = new ContentStorage(m_Dict);
673 m_HeaderPart.AddChildObject(m_ContentStorage);
674 m_HeaderPart.m_Preface->ContentStorage = m_ContentStorage->InstanceUID;
677 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
678 m_HeaderPart.AddChildObject(ECD);
679 m_ContentStorage->EssenceContainerData.push_back(ECD->InstanceUID);
683 UUID assetUUID(m_Info.AssetUUID);
684 UMID SourcePackageUMID, MaterialPackageUMID;
685 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
686 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
691 m_MaterialPackage = new MaterialPackage(m_Dict);
692 m_MaterialPackage->Name = "Material Package";
693 m_MaterialPackage->PackageUID = MaterialPackageUMID;
694 m_HeaderPart.AddChildObject(m_MaterialPackage);
695 m_ContentStorage->Packages.push_back(m_MaterialPackage->InstanceUID);
697 TrackSet<TimecodeComponent> MPTCTrack =
698 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
699 tc_edit_rate, TCFrameRate, 0, m_Dict);
701 MPTCTrack.Sequence->Duration.set_has_value();
702 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration.get()));
703 MPTCTrack.Clip->Duration.set_has_value();
704 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration.get()));
706 TrackSet<SourceClip> MPTrack =
707 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
708 TrackName, clip_edit_rate, DataDefinition,
710 MPTrack.Sequence->Duration.set_has_value();
711 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration.get()));
713 MPTrack.Clip = new SourceClip(m_Dict);
714 m_HeaderPart.AddChildObject(MPTrack.Clip);
715 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
716 MPTrack.Clip->DataDefinition = DataDefinition;
717 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
718 MPTrack.Clip->SourceTrackID = 2;
720 MPTrack.Clip->Duration.set_has_value();
721 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration.get()));
725 // File (Source) Package
727 m_FilePackage = new SourcePackage(m_Dict);
728 m_FilePackage->Name = PackageLabel.c_str();
729 m_FilePackage->PackageUID = SourcePackageUMID;
730 ECD->LinkedPackageUID = SourcePackageUMID;
732 m_HeaderPart.AddChildObject(m_FilePackage);
733 m_ContentStorage->Packages.push_back(m_FilePackage->InstanceUID);
735 TrackSet<TimecodeComponent> FPTCTrack =
736 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
737 tc_edit_rate, TCFrameRate, 0, m_Dict);
739 FPTCTrack.Sequence->Duration.set_has_value();
740 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration.get()));
741 FPTCTrack.Clip->Duration.set_has_value();
742 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration.get()));
744 TrackSet<SourceClip> FPTrack =
745 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
746 TrackName, clip_edit_rate, DataDefinition,
749 FPTrack.Sequence->Duration.set_has_value();
750 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration.get()));
752 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
753 FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
755 FPTrack.Clip = new SourceClip(m_Dict);
756 m_HeaderPart.AddChildObject(FPTrack.Clip);
757 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
758 FPTrack.Clip->DataDefinition = DataDefinition;
760 // for now we do not allow setting this value, so all files will be 'original'
761 FPTrack.Clip->SourceTrackID = 0;
762 FPTrack.Clip->SourcePackageID = NilUMID;
764 FPTrack.Clip->Duration.set_has_value();
765 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration.get()));
767 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
771 void AddEssenceDescriptor(const UL& WrappingUL)
774 // Essence Descriptor
776 m_EssenceDescriptor->EssenceContainer = WrappingUL;
777 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
780 // Essence Descriptors
783 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
784 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
786 if ( m_Info.EncryptedEssence )
788 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
789 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
790 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
791 AddDmsCrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
792 //// TODO: fix DMSegment Duration value
796 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
799 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
800 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
802 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
803 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
804 m_HeaderPart.AddChildObject(*sdli);
806 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
809 Result_t AddDmsGenericPartUtf8Text(const ASDCP::FrameBuffer& frame_buffer,
810 ASDCP::AESEncContext* enc = 0, ASDCP::HMACContext* hmac = 0)
812 Kumu::fpos_t previous_partition_offset = m_RIP.PairArray.back().ByteOffset;
813 Result_t result = AddDmsTrackGenericPartUtf8Text(m_File, m_HeaderPart, *m_FilePackage, m_RIP, m_Dict);
815 if ( KM_SUCCESS(result) )
817 // m_RIP now contains an entry (at the back) for the new generic stream
818 // (this entry was created during the call to AddDmsTrackGenericPartUtf8Text())
819 if ( m_File.Tell() != m_RIP.PairArray.back().ByteOffset )
821 DefaultLogSink().Error("File offset has moved since RIP modification. Unrecoverable error.\n");
825 // create generic stream partition header
826 static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
827 ASDCP::MXF::Partition GSPart(m_Dict);
829 GSPart.MajorVersion = m_HeaderPart.MajorVersion;
830 GSPart.MinorVersion = m_HeaderPart.MinorVersion;
831 GSPart.ThisPartition = m_RIP.PairArray.back().ByteOffset;
832 GSPart.PreviousPartition = previous_partition_offset;
833 GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
834 GSPart.BodySID = m_RIP.PairArray.back().BodySID;
835 GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
837 static UL gs_part_ul(m_Dict->ul(MDD_GenericStreamPartition));
838 Result_t result = GSPart.WriteToFile(m_File, gs_part_ul);
840 if ( KM_SUCCESS(result) )
842 result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
843 m_StreamOffset, frame_buffer, GenericStream_DataElement.Value(), enc, hmac);
860 //------------------------------------------------------------------------------------------
864 class h__ASDCPReader : public MXF::TrackFileReader<OP1aHeader, OPAtomIndexFooter>
866 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPReader);
870 Partition m_BodyPart;
872 h__ASDCPReader(const Dictionary&);
873 virtual ~h__ASDCPReader();
875 Result_t OpenMXFRead(const std::string& filename);
876 Result_t ReadEKLVFrame(ui32_t FrameNum, ASDCP::FrameBuffer& FrameBuf,
877 const byte_t* EssenceUL, AESDecContext* Ctx, HMACContext* HMAC);
878 Result_t LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
879 i8_t& temporalOffset, i8_t& keyFrameOffset);
883 class h__ASDCPWriter : public MXF::TrackFileWriter<OP1aHeader>
885 ASDCP_NO_COPY_CONSTRUCT(h__ASDCPWriter);
889 Partition m_BodyPart;
890 OPAtomIndexFooter m_FooterPart;
892 h__ASDCPWriter(const Dictionary&);
893 virtual ~h__ASDCPWriter();
895 // all the above for a single source clip
896 Result_t WriteASDCPHeader(const std::string& PackageLabel, const UL& WrappingUL,
897 const std::string& TrackName, const UL& EssenceUL,
898 const UL& DataDefinition, const MXF::Rational& EditRate,
899 ui32_t TCFrameRate, ui32_t BytesPerEditUnit = 0);
901 Result_t CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit = 0);
902 Result_t WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf,const byte_t* EssenceUL,
903 AESEncContext* Ctx, HMACContext* HMAC);
904 Result_t WriteASDCPFooter();
908 // helper class for calculating Integrity Packs, used by WriteEKLVPacket() below.
913 byte_t Data[klv_intpack_size];
916 memset(Data, 0, klv_intpack_size);
921 Result_t CalcValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
922 Result_t TestValues(const ASDCP::FrameBuffer&, const byte_t* AssetID, ui32_t sequence, HMACContext* HMAC);
928 #endif // _AS_DCP_INTERNAL_H_
932 // end AS_DCP_internal.h