2 Copyright (c) 2004-2012, 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 h__Writer.cpp
28 \version $Id: h__Writer.cpp,v 1.51 2012/02/07 18:54:25 jhurst Exp $
29 \brief MXF file writer base class
32 #include "AS_DCP_internal.h"
35 using namespace ASDCP;
36 using namespace ASDCP::MXF;
38 // a magic number identifying asdcplib
39 #ifndef ASDCP_BUILD_NUMBER
40 #define ASDCP_BUILD_NUMBER 0x6A68
44 static std::vector<int>
45 version_split(const char* str)
47 std::vector<int> result;
49 const char* pstr = str;
50 const char* r = strchr(pstr, '.');
56 result.push_back(atoi(pstr));
59 r = strchr(pstr, '.');
62 if( strlen(pstr) > 0 )
63 result.push_back(atoi(pstr));
65 assert(result.size() == 3);
71 ASDCP::h__Writer::h__Writer(const Dictionary& d) :
72 m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict),
73 m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_EssenceStart(0),
74 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
76 default_md_object_init();
79 ASDCP::h__Writer::~h__Writer()
84 // add DMS CryptographicFramework entry to source package
86 AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
87 WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
91 StaticTrack* NewTrack = new StaticTrack(Dict);
92 HeaderPart.AddChildObject(NewTrack);
93 Package.Tracks.push_back(NewTrack->InstanceUID);
94 NewTrack->TrackName = "Descriptive Track";
95 NewTrack->TrackID = 3;
97 Sequence* Seq = new Sequence(Dict);
98 HeaderPart.AddChildObject(Seq);
99 NewTrack->Sequence = Seq->InstanceUID;
100 Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
102 DMSegment* Segment = new DMSegment(Dict);
103 HeaderPart.AddChildObject(Segment);
104 Seq->StructuralComponents.push_back(Segment->InstanceUID);
105 Segment->EventComment = "AS-DCP KLV Encryption";
107 CryptographicFramework* CFW = new CryptographicFramework(Dict);
108 HeaderPart.AddChildObject(CFW);
109 Segment->DMFramework = CFW->InstanceUID;
111 CryptographicContext* Context = new CryptographicContext(Dict);
112 HeaderPart.AddChildObject(Context);
113 CFW->ContextSR = Context->InstanceUID;
115 Context->ContextID.Set(Descr.ContextID);
116 Context->SourceEssenceContainer = WrappingUL; // ??????
117 Context->CipherAlgorithm.Set(Dict->ul(MDD_CipherAlgorithm_AES));
118 Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict->ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict->ul(MDD_MICAlgorithm_NONE) );
119 Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
124 ASDCP::h__Writer::InitHeader()
127 assert(m_EssenceDescriptor);
129 m_HeaderPart.m_Primer.ClearTagList();
130 m_HeaderPart.m_Preface = new Preface(m_Dict);
131 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
133 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
134 // so we tell the world by using OP1a
135 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
136 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
139 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
140 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
142 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
147 Identification* Ident = new Identification(m_Dict);
148 m_HeaderPart.AddChildObject(Ident);
149 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
151 Kumu::GenRandomValue(Ident->ThisGenerationUID);
152 Ident->CompanyName = m_Info.CompanyName.c_str();
153 Ident->ProductName = m_Info.ProductName.c_str();
154 Ident->VersionString = m_Info.ProductVersion.c_str();
155 Ident->ProductUID.Set(m_Info.ProductUUID);
156 Ident->Platform = ASDCP_PLATFORM;
158 std::vector<int> version = version_split(Version());
160 Ident->ToolkitVersion.Major = version[0];
161 Ident->ToolkitVersion.Minor = version[1];
162 Ident->ToolkitVersion.Patch = version[2];
163 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
164 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
168 template <class ClipT>
172 MXF::Sequence* Sequence;
175 TrackSet() : Track(0), Sequence(0), Clip(0) {}
179 template <class PackageT, class ClipT>
181 CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
182 const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
184 TrackSet<ClipT> NewTrack;
186 NewTrack.Track = new Track(Dict);
187 Header.AddChildObject(NewTrack.Track);
188 NewTrack.Track->EditRate = EditRate;
189 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
190 NewTrack.Track->TrackID = TrackID;
191 NewTrack.Track->TrackName = TrackName.c_str();
193 NewTrack.Sequence = new Sequence(Dict);
194 Header.AddChildObject(NewTrack.Sequence);
195 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
196 NewTrack.Sequence->DataDefinition = Definition;
202 template <class PackageT>
203 TrackSet<TimecodeComponent>
204 CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
205 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict)
208 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
210 TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
212 NewTrack.Clip = new TimecodeComponent(Dict);
213 Header.AddChildObject(NewTrack.Clip);
214 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
215 NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
216 NewTrack.Clip->StartTimecode = TCStart;
217 NewTrack.Clip->DataDefinition = TCUL;
225 ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
226 const std::string& TrackName, const UL& EssenceUL,
227 const UL& DataDefinition, const std::string& PackageLabel)
230 ContentStorage* Storage = new ContentStorage(m_Dict);
231 m_HeaderPart.AddChildObject(Storage);
232 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
234 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
235 m_HeaderPart.AddChildObject(ECD);
236 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
240 UUID assetUUID(m_Info.AssetUUID);
241 UMID SourcePackageUMID, MaterialPackageUMID;
242 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
243 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
248 m_MaterialPackage = new MaterialPackage(m_Dict);
249 m_MaterialPackage->Name = "AS-DCP Material Package";
250 m_MaterialPackage->PackageUID = MaterialPackageUMID;
251 m_HeaderPart.AddChildObject(m_MaterialPackage);
252 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
254 TrackSet<TimecodeComponent> MPTCTrack =
255 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
256 EditRate, TCFrameRate, 0, m_Dict);
257 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
258 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
260 TrackSet<SourceClip> MPTrack =
261 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
262 TrackName, EditRate, DataDefinition,
264 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
266 MPTrack.Clip = new SourceClip(m_Dict);
267 m_HeaderPart.AddChildObject(MPTrack.Clip);
268 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
269 MPTrack.Clip->DataDefinition = DataDefinition;
270 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
271 MPTrack.Clip->SourceTrackID = 2;
272 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
276 // File (Source) Package
278 m_FilePackage = new SourcePackage(m_Dict);
279 m_FilePackage->Name = PackageLabel.c_str();
280 m_FilePackage->PackageUID = SourcePackageUMID;
281 ECD->LinkedPackageUID = SourcePackageUMID;
283 m_HeaderPart.AddChildObject(m_FilePackage);
284 Storage->Packages.push_back(m_FilePackage->InstanceUID);
286 TrackSet<TimecodeComponent> FPTCTrack =
287 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
288 EditRate, TCFrameRate,
289 ui64_C(3600) * TCFrameRate, m_Dict);
290 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
291 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
292 TrackSet<SourceClip> FPTrack =
293 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
294 TrackName, EditRate, DataDefinition,
296 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
298 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
299 FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
301 FPTrack.Clip = new SourceClip(m_Dict);
302 m_HeaderPart.AddChildObject(FPTrack.Clip);
303 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
304 FPTrack.Clip->DataDefinition = DataDefinition;
306 // for now we do not allow setting this value, so all files will be 'original'
307 FPTrack.Clip->SourceTrackID = 0;
308 FPTrack.Clip->SourcePackageID = NilUMID;
309 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
311 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
316 ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
317 const std::string& TrackName, const UL& DataDefinition,
318 const std::string& PackageLabel)
321 ContentStorage* Storage = new ContentStorage(m_Dict);
322 m_HeaderPart.AddChildObject(Storage);
323 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
325 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
326 m_HeaderPart.AddChildObject(ECD);
327 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
331 UUID assetUUID(m_Info.AssetUUID);
332 UMID SourcePackageUMID, MaterialPackageUMID;
333 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
334 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
339 m_MaterialPackage = new MaterialPackage(m_Dict);
340 m_MaterialPackage->Name = "AS-DCP Material Package";
341 m_MaterialPackage->PackageUID = MaterialPackageUMID;
342 m_HeaderPart.AddChildObject(m_MaterialPackage);
343 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
345 TrackSet<TimecodeComponent> MPTCTrack =
346 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
347 EditRate, TCFrameRate, 0, m_Dict);
348 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
349 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
351 TrackSet<DMSegment> MPTrack =
352 CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
353 TrackName, EditRate, DataDefinition,
355 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
357 MPTrack.Clip = new DMSegment(m_Dict);
358 m_HeaderPart.AddChildObject(MPTrack.Clip);
359 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
360 MPTrack.Clip->DataDefinition = DataDefinition;
361 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
362 // MPTrack.Clip->SourceTrackID = 2;
363 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
367 // File (Source) Package
369 m_FilePackage = new SourcePackage(m_Dict);
370 m_FilePackage->Name = PackageLabel.c_str();
371 m_FilePackage->PackageUID = SourcePackageUMID;
372 ECD->LinkedPackageUID = SourcePackageUMID;
374 m_HeaderPart.AddChildObject(m_FilePackage);
375 Storage->Packages.push_back(m_FilePackage->InstanceUID);
377 TrackSet<TimecodeComponent> FPTCTrack =
378 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
379 EditRate, TCFrameRate,
380 ui64_C(3600) * TCFrameRate, m_Dict);
381 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
382 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
384 TrackSet<DMSegment> FPTrack =
385 CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
386 TrackName, EditRate, DataDefinition,
388 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
390 FPTrack.Clip = new DMSegment(m_Dict);
391 m_HeaderPart.AddChildObject(FPTrack.Clip);
392 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
393 FPTrack.Clip->DataDefinition = DataDefinition;
394 FPTrack.Clip->EventComment = "D-Cinema Timed Text";
396 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
397 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
402 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
405 // Essence Descriptor
407 m_EssenceDescriptor->EssenceContainer = WrappingUL;
408 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
411 // Essence Descriptors
414 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
415 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
417 if ( m_Info.EncryptedEssence )
419 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
420 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
421 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
422 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
426 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
429 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
430 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
432 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
433 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
434 m_HeaderPart.AddChildObject(*sdli);
436 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
441 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
444 Result_t result = RESULT_OK;
446 // create a body partition if we're writing proper 429-3/OP-Atom
447 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
450 m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
451 m_BodyPart.ThisPartition = m_File.Tell();
452 m_BodyPart.BodySID = 1;
453 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
454 m_BodyPart.OperationalPattern = OPAtomUL;
455 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
457 UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
458 result = m_BodyPart.WriteToFile(m_File, BodyUL);
462 m_HeaderPart.BodySID = 1;
465 if ( ASDCP_SUCCESS(result) )
468 Kumu::fpos_t ECoffset = m_File.Tell();
469 m_FooterPart.IndexSID = 129;
471 if ( BytesPerEditUnit == 0 )
472 m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
474 m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
482 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
483 const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition,
484 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
487 AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
488 AddEssenceDescriptor(WrappingUL);
490 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
492 if ( KM_SUCCESS(result) )
493 result = CreateBodyPart(EditRate, BytesPerEditUnit);
499 // standard method of writing a plaintext or encrypted frame
501 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
502 AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
504 Result_t result = RESULT_OK;
505 IntegrityPack IntPack;
507 m_File.StartHashing();
509 byte_t overhead[128];
510 Kumu::MemIOWriter Overhead(overhead, 128);
513 if ( FrameBuf.Size() == 0 )
515 DefaultLogSink().Error("Cannot write empty frame buffer\n");
516 return RESULT_EMPTY_FB;
519 if ( m_Info.EncryptedEssence )
522 return RESULT_CRYPT_CTX;
524 if ( m_Info.UsesHMAC && ! HMAC )
525 return RESULT_HMAC_CTX;
527 if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
528 return RESULT_LARGE_PTO;
530 // encrypt the essence data (create encrypted source value)
531 result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
534 if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
535 result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
537 if ( ASDCP_SUCCESS(result) )
539 Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
541 // construct encrypted triplet header
542 ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
543 ui32_t BER_length = MXF_BER_LENGTH;
545 if ( m_Info.UsesHMAC )
546 ETLength += klv_intpack_size;
548 ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
550 if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
552 BER_length = Kumu::get_BER_length_for_value(ETLength);
554 // the packet is longer by the difference in expected vs. actual BER length
555 ETLength += BER_length - MXF_BER_LENGTH;
557 if ( BER_length == 0 )
558 result = RESULT_KLV_CODING;
561 if ( ASDCP_SUCCESS(result) )
563 if ( ! ( Overhead.WriteBER(ETLength, BER_length) // write encrypted triplet length
564 && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH) // write ContextID length
565 && Overhead.WriteRaw(m_Info.ContextID, UUIDlen) // write ContextID
566 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write PlaintextOffset length
567 && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()) // write PlaintextOffset
568 && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH) // write essence UL length
569 && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH) // write the essence UL
570 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write SourceLength length
571 && Overhead.WriteUi64BE(FrameBuf.Size()) // write SourceLength
572 && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) ) // write ESV length
574 result = RESULT_KLV_CODING;
578 if ( ASDCP_SUCCESS(result) )
579 result = m_File.Writev(Overhead.Data(), Overhead.Length());
582 if ( ASDCP_SUCCESS(result) )
584 m_StreamOffset += Overhead.Length();
585 // write encrypted source value
586 result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
589 if ( ASDCP_SUCCESS(result) )
591 m_StreamOffset += m_CtFrameBuf.Size();
593 byte_t hmoverhead[512];
594 Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
597 if ( m_Info.UsesHMAC )
599 HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
602 { // we still need the var-pack length values if the intpack is empty
603 for ( ui32_t i = 0; i < 3 ; i++ )
604 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
608 result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
609 m_StreamOffset += HMACOverhead.Length();
614 ui32_t BER_length = MXF_BER_LENGTH;
616 if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
618 BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
620 if ( BER_length == 0 )
621 result = RESULT_KLV_CODING;
624 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
625 Overhead.WriteBER(FrameBuf.Size(), BER_length);
627 if ( ASDCP_SUCCESS(result) )
628 result = m_File.Writev(Overhead.Data(), Overhead.Length());
630 if ( ASDCP_SUCCESS(result) )
631 result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
633 if ( ASDCP_SUCCESS(result) )
634 m_StreamOffset += Overhead.Length() + FrameBuf.Size();
637 if ( ASDCP_SUCCESS(result) )
638 result = m_File.Writev();
641 *hash = m_File.StopHashing();
648 ASDCP::h__Writer::FakeWriteEKLVPacket(int size)
650 Result_t result = RESULT_OK;
652 m_StreamOffset += size;
653 m_File.Seek(size, Kumu::SP_POS);
659 // standard method of writing the header and footer of a completed MXF file
662 ASDCP::h__Writer::WriteMXFFooter()
664 // Set top-level file package correctly for OP-Atom
666 // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
667 // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
669 DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
671 for (; dli != m_DurationUpdateList.end(); dli++ )
672 **dli = m_FramesWritten;
674 m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
675 m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
677 Kumu::fpos_t here = m_File.Tell();
678 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
679 m_HeaderPart.FooterPartition = here;
682 // re-label the partition
683 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
684 m_HeaderPart.OperationalPattern = OPAtomUL;
685 m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
687 m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
688 m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
689 m_FooterPart.FooterPartition = here;
690 m_FooterPart.ThisPartition = here;
692 Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
694 if ( ASDCP_SUCCESS(result) )
695 result = m_HeaderPart.m_RIP.WriteToFile(m_File);
697 if ( ASDCP_SUCCESS(result) )
698 result = m_File.Seek(0);
700 if ( ASDCP_SUCCESS(result) )
701 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);