2 Copyright (c) 2004-2009, 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
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_HeaderPart(m_Dict), m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_Dict(&d),
73 m_HeaderSize(0), m_EssenceStart(0),
74 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
78 ASDCP::h__Writer::~h__Writer()
83 // add DMS CryptographicFramework entry to source package
85 AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
86 WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
90 StaticTrack* NewTrack = new StaticTrack(Dict);
91 HeaderPart.AddChildObject(NewTrack);
92 Package.Tracks.push_back(NewTrack->InstanceUID);
93 NewTrack->TrackName = "Descriptive Track";
94 NewTrack->TrackID = 3;
96 Sequence* Seq = new Sequence(Dict);
97 HeaderPart.AddChildObject(Seq);
98 NewTrack->Sequence = Seq->InstanceUID;
99 Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
101 DMSegment* Segment = new DMSegment(Dict);
102 HeaderPart.AddChildObject(Segment);
103 Seq->StructuralComponents.push_back(Segment->InstanceUID);
104 Segment->EventComment = "AS-DCP KLV Encryption";
106 CryptographicFramework* CFW = new CryptographicFramework(Dict);
107 HeaderPart.AddChildObject(CFW);
108 Segment->DMFramework = CFW->InstanceUID;
110 CryptographicContext* Context = new CryptographicContext(Dict);
111 HeaderPart.AddChildObject(Context);
112 CFW->ContextSR = Context->InstanceUID;
114 Context->ContextID.Set(Descr.ContextID);
115 Context->SourceEssenceContainer = WrappingUL; // ??????
116 Context->CipherAlgorithm.Set(Dict->ul(MDD_CipherAlgorithm_AES));
117 Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict->ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict->ul(MDD_MICAlgorithm_NONE) );
118 Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
123 ASDCP::h__Writer::InitHeader()
126 assert(m_EssenceDescriptor);
128 m_HeaderPart.m_Primer.ClearTagList();
129 m_HeaderPart.m_Preface = new Preface(m_Dict);
130 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
132 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
133 // so we tell the world by using OP1a
134 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
135 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
138 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
139 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
141 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
146 Identification* Ident = new Identification(m_Dict);
147 m_HeaderPart.AddChildObject(Ident);
148 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
150 Kumu::GenRandomValue(Ident->ThisGenerationUID);
151 Ident->CompanyName = m_Info.CompanyName.c_str();
152 Ident->ProductName = m_Info.ProductName.c_str();
153 Ident->VersionString = m_Info.ProductVersion.c_str();
154 Ident->ProductUID.Set(m_Info.ProductUUID);
155 Ident->Platform = ASDCP_PLATFORM;
157 std::vector<int> version = version_split(Version());
159 Ident->ToolkitVersion.Major = version[0];
160 Ident->ToolkitVersion.Minor = version[1];
161 Ident->ToolkitVersion.Patch = version[2];
162 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
163 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
167 template <class ClipT>
171 MXF::Sequence* Sequence;
174 TrackSet() : Track(0), Sequence(0), Clip(0) {}
178 template <class PackageT, class ClipT>
180 CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
181 const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
183 TrackSet<ClipT> NewTrack;
185 NewTrack.Track = new Track(Dict);
186 Header.AddChildObject(NewTrack.Track);
187 NewTrack.Track->EditRate = EditRate;
188 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
189 NewTrack.Track->TrackID = TrackID;
190 NewTrack.Track->TrackName = TrackName.c_str();
192 NewTrack.Sequence = new Sequence(Dict);
193 Header.AddChildObject(NewTrack.Sequence);
194 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
195 NewTrack.Sequence->DataDefinition = Definition;
201 template <class PackageT>
202 TrackSet<TimecodeComponent>
203 CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
204 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict)
207 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
209 TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
211 NewTrack.Clip = new TimecodeComponent(Dict);
212 Header.AddChildObject(NewTrack.Clip);
213 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
214 NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
215 NewTrack.Clip->StartTimecode = TCStart;
216 NewTrack.Clip->DataDefinition = TCUL;
224 ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
225 const std::string& TrackName, const UL& DataDefinition,
226 const std::string& PackageLabel)
229 ContentStorage* Storage = new ContentStorage(m_Dict);
230 m_HeaderPart.AddChildObject(Storage);
231 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
233 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
234 m_HeaderPart.AddChildObject(ECD);
235 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
239 UUID assetUUID(m_Info.AssetUUID);
240 UMID SourcePackageUMID, MaterialPackageUMID;
241 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
242 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
247 m_MaterialPackage = new MaterialPackage(m_Dict);
248 m_MaterialPackage->Name = "AS-DCP Material Package";
249 m_MaterialPackage->PackageUID = MaterialPackageUMID;
250 m_HeaderPart.AddChildObject(m_MaterialPackage);
251 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
253 TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
254 EditRate, TCFrameRate, 0, m_Dict);
255 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
256 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
258 TrackSet<SourceClip> MPTrack = CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
259 TrackName, EditRate, DataDefinition,
261 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
263 MPTrack.Clip = new SourceClip(m_Dict);
264 m_HeaderPart.AddChildObject(MPTrack.Clip);
265 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
266 MPTrack.Clip->DataDefinition = DataDefinition;
267 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
268 MPTrack.Clip->SourceTrackID = 2;
269 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
273 // File (Source) Package
275 m_FilePackage = new SourcePackage(m_Dict);
276 m_FilePackage->Name = PackageLabel.c_str();
277 m_FilePackage->PackageUID = SourcePackageUMID;
278 ECD->LinkedPackageUID = SourcePackageUMID;
280 m_HeaderPart.AddChildObject(m_FilePackage);
281 Storage->Packages.push_back(m_FilePackage->InstanceUID);
283 TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
284 EditRate, TCFrameRate,
285 ui64_C(3600) * TCFrameRate, m_Dict);
286 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
287 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
289 TrackSet<SourceClip> FPTrack = CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
290 TrackName, EditRate, DataDefinition,
292 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
294 FPTrack.Clip = new SourceClip(m_Dict);
295 m_HeaderPart.AddChildObject(FPTrack.Clip);
296 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
297 FPTrack.Clip->DataDefinition = DataDefinition;
299 // for now we do not allow setting this value, so all files will be 'original'
300 FPTrack.Clip->SourceTrackID = 0;
301 FPTrack.Clip->SourcePackageID = NilUMID;
302 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
304 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
309 ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
310 const std::string& TrackName, const UL& DataDefinition,
311 const std::string& PackageLabel)
314 ContentStorage* Storage = new ContentStorage(m_Dict);
315 m_HeaderPart.AddChildObject(Storage);
316 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
318 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
319 m_HeaderPart.AddChildObject(ECD);
320 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
324 UUID assetUUID(m_Info.AssetUUID);
325 UMID SourcePackageUMID, MaterialPackageUMID;
326 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
327 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
332 m_MaterialPackage = new MaterialPackage(m_Dict);
333 m_MaterialPackage->Name = "AS-DCP Material Package";
334 m_MaterialPackage->PackageUID = MaterialPackageUMID;
335 m_HeaderPart.AddChildObject(m_MaterialPackage);
336 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
338 TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
339 EditRate, TCFrameRate, 0, m_Dict);
340 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
341 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
343 TrackSet<DMSegment> MPTrack = CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
344 TrackName, EditRate, DataDefinition,
346 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
348 MPTrack.Clip = new DMSegment(m_Dict);
349 m_HeaderPart.AddChildObject(MPTrack.Clip);
350 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
351 MPTrack.Clip->DataDefinition = DataDefinition;
352 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
353 // MPTrack.Clip->SourceTrackID = 2;
354 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
358 // File (Source) Package
360 m_FilePackage = new SourcePackage(m_Dict);
361 m_FilePackage->Name = PackageLabel.c_str();
362 m_FilePackage->PackageUID = SourcePackageUMID;
363 ECD->LinkedPackageUID = SourcePackageUMID;
365 m_HeaderPart.AddChildObject(m_FilePackage);
366 Storage->Packages.push_back(m_FilePackage->InstanceUID);
368 TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
369 EditRate, TCFrameRate,
370 ui64_C(3600) * TCFrameRate, m_Dict);
371 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
372 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
374 TrackSet<DMSegment> FPTrack = CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
375 TrackName, EditRate, DataDefinition,
377 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
379 FPTrack.Clip = new DMSegment(m_Dict);
380 m_HeaderPart.AddChildObject(FPTrack.Clip);
381 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
382 FPTrack.Clip->DataDefinition = DataDefinition;
383 FPTrack.Clip->EventComment = "D-Cinema Timed Text";
385 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
386 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
391 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
394 // Essence Descriptor
396 m_EssenceDescriptor->EssenceContainer = WrappingUL;
397 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
400 // Essence Descriptors
403 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
404 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
406 if ( m_Info.EncryptedEssence )
408 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
409 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
410 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
411 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
415 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
418 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
419 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
421 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
422 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
423 m_HeaderPart.AddChildObject(*sdli);
425 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
430 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
433 Result_t result = RESULT_OK;
435 // create a body partition if we're writing proper 429-3/OP-Atom
436 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
439 m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
440 m_BodyPart.ThisPartition = m_File.Tell();
441 m_BodyPart.BodySID = 1;
442 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
443 m_BodyPart.OperationalPattern = OPAtomUL;
444 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
446 UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
447 result = m_BodyPart.WriteToFile(m_File, BodyUL);
451 m_HeaderPart.BodySID = 1;
454 if ( ASDCP_SUCCESS(result) )
457 Kumu::fpos_t ECoffset = m_File.Tell();
458 m_FooterPart.IndexSID = 129;
460 if ( BytesPerEditUnit == 0 )
461 m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
463 m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
471 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
472 const std::string& TrackName, const UL& DataDefinition,
473 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
476 AddSourceClip(EditRate, TCFrameRate, TrackName, DataDefinition, PackageLabel);
477 AddEssenceDescriptor(WrappingUL);
479 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
481 if ( KM_SUCCESS(result) )
482 result = CreateBodyPart(EditRate, BytesPerEditUnit);
488 // standard method of writing a plaintext or encrypted frame
490 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
491 AESEncContext* Ctx, HMACContext* HMAC)
493 Result_t result = RESULT_OK;
494 IntegrityPack IntPack;
496 byte_t overhead[128];
497 Kumu::MemIOWriter Overhead(overhead, 128);
500 if ( FrameBuf.Size() == 0 )
502 DefaultLogSink().Error("Cannot write empty frame buffer\n");
503 return RESULT_EMPTY_FB;
506 if ( m_Info.EncryptedEssence )
509 return RESULT_CRYPT_CTX;
511 if ( m_Info.UsesHMAC && ! HMAC )
512 return RESULT_HMAC_CTX;
514 if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
515 return RESULT_LARGE_PTO;
517 // encrypt the essence data (create encrypted source value)
518 result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
521 if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
522 result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
524 if ( ASDCP_SUCCESS(result) )
526 Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
528 // construct encrypted triplet header
529 ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
530 ui32_t BER_length = MXF_BER_LENGTH;
532 if ( m_Info.UsesHMAC )
533 ETLength += klv_intpack_size;
535 ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
537 if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
539 BER_length = Kumu::get_BER_length_for_value(ETLength);
541 if ( BER_length == 0 )
542 result = RESULT_KLV_CODING;
545 if ( ASDCP_SUCCESS(result) )
547 if ( ! ( Overhead.WriteBER(ETLength, BER_length) // write encrypted triplet length
548 && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH) // write ContextID length
549 && Overhead.WriteRaw(m_Info.ContextID, UUIDlen) // write ContextID
550 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write PlaintextOffset length
551 && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()) // write PlaintextOffset
552 && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH) // write essence UL length
553 && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH) // write the essence UL
554 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write SourceLength length
555 && Overhead.WriteUi64BE(FrameBuf.Size()) // write SourceLength
556 && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) ) // write ESV length
558 result = RESULT_KLV_CODING;
562 if ( ASDCP_SUCCESS(result) )
563 result = m_File.Writev(Overhead.Data(), Overhead.Length());
566 if ( ASDCP_SUCCESS(result) )
568 m_StreamOffset += Overhead.Length();
569 // write encrypted source value
570 result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
573 if ( ASDCP_SUCCESS(result) )
575 m_StreamOffset += m_CtFrameBuf.Size();
577 byte_t hmoverhead[512];
578 Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
581 if ( m_Info.UsesHMAC )
583 HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
586 { // we still need the var-pack length values if the intpack is empty
587 for ( ui32_t i = 0; i < 3 ; i++ )
588 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
592 result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
593 m_StreamOffset += HMACOverhead.Length();
598 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
599 Overhead.WriteBER(FrameBuf.Size(), MXF_BER_LENGTH);
600 result = m_File.Writev(Overhead.Data(), Overhead.Length());
602 if ( ASDCP_SUCCESS(result) )
603 result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
605 if ( ASDCP_SUCCESS(result) )
606 m_StreamOffset += Overhead.Length() + FrameBuf.Size();
609 if ( ASDCP_SUCCESS(result) )
610 result = m_File.Writev();
616 // standard method of writing the header and footer of a completed MXF file
619 ASDCP::h__Writer::WriteMXFFooter()
621 // Set top-level file package correctly for OP-Atom
623 // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
624 // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
626 DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
628 for (; dli != m_DurationUpdateList.end(); dli++ )
629 **dli = m_FramesWritten;
631 m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
632 m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
634 Kumu::fpos_t here = m_File.Tell();
635 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
636 m_HeaderPart.FooterPartition = here;
639 // re-label the partition
640 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
641 m_HeaderPart.OperationalPattern = OPAtomUL;
642 m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
644 m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
645 m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
646 m_FooterPart.FooterPartition = here;
647 m_FooterPart.ThisPartition = here;
649 Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
651 if ( ASDCP_SUCCESS(result) )
652 result = m_HeaderPart.m_RIP.WriteToFile(m_File);
654 if ( ASDCP_SUCCESS(result) )
655 result = m_File.Seek(0);
657 if ( ASDCP_SUCCESS(result) )
658 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);