2 Copyright (c) 2004-2006, 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
46 ASDCP::h__Writer::h__Writer() :
47 m_HeaderSize(0), m_EssenceStart(0),
48 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
52 ASDCP::h__Writer::~h__Writer()
57 // add DMS CryptographicFramework entry to source package
59 AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, WriterInfo& Descr, const UL& WrappingUL)
62 StaticTrack* NewTrack = new StaticTrack;
63 HeaderPart.AddChildObject(NewTrack);
64 Package.Tracks.push_back(NewTrack->InstanceUID);
65 NewTrack->TrackName = "Descriptive Track";
66 NewTrack->TrackID = 3;
68 Sequence* Seq = new Sequence;
69 HeaderPart.AddChildObject(Seq);
70 NewTrack->Sequence = Seq->InstanceUID;
71 Seq->DataDefinition = UL(Dict::ul(MDD_DescriptiveMetaDataDef));
73 DMSegment* Segment = new DMSegment;
74 HeaderPart.AddChildObject(Segment);
75 Seq->StructuralComponents.push_back(Segment->InstanceUID);
76 Segment->EventComment = "AS-DCP KLV Encryption";
78 CryptographicFramework* CFW = new CryptographicFramework;
79 HeaderPart.AddChildObject(CFW);
80 Segment->DMFramework = CFW->InstanceUID;
82 CryptographicContext* Context = new CryptographicContext;
83 HeaderPart.AddChildObject(Context);
84 CFW->ContextSR = Context->InstanceUID;
86 Context->ContextID.Set(Descr.ContextID);
87 Context->SourceEssenceContainer = WrappingUL; // ??????
88 Context->CipherAlgorithm.Set(Dict::ul(MDD_CipherAlgorithm_AES));
89 Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict::ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict::ul(MDD_MICAlgorithm_NONE) );
90 Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
95 ASDCP::h__Writer::InitHeader()
97 assert(m_EssenceDescriptor);
99 m_HeaderPart.m_Primer.ClearTagList();
100 m_HeaderPart.m_Preface = new Preface;
101 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
103 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
104 // so we tell the world by using OP1a
105 m_HeaderPart.m_Preface->OperationalPattern = UL(Dict::ul(MDD_OP1a));
106 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
109 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
110 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
112 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
117 Identification* Ident = new Identification;
118 m_HeaderPart.AddChildObject(Ident);
119 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
121 Kumu::GenRandomValue(Ident->ThisGenerationUID);
122 Ident->CompanyName = m_Info.CompanyName.c_str();
123 Ident->ProductName = m_Info.ProductName.c_str();
124 Ident->VersionString = m_Info.ProductVersion.c_str();
125 Ident->ProductUID.Set(m_Info.ProductUUID);
126 Ident->Platform = ASDCP_PLATFORM;
127 Ident->ToolkitVersion.Major = VERSION_MAJOR;
128 Ident->ToolkitVersion.Minor = VERSION_APIMINOR;
129 Ident->ToolkitVersion.Patch = VERSION_IMPMINOR;
130 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
131 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
135 template <class ClipT>
139 MXF::Sequence* Sequence;
142 TrackSet() : Track(0), Sequence(0), Clip(0) {}
146 template <class PackageT, class ClipT>
148 CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
149 const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID)
151 TrackSet<ClipT> NewTrack;
153 NewTrack.Track = new Track;
154 Header.AddChildObject(NewTrack.Track);
155 NewTrack.Track->EditRate = EditRate;
156 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
157 NewTrack.Track->TrackID = TrackID;
158 NewTrack.Track->TrackName = TrackName.c_str();
160 NewTrack.Sequence = new Sequence;
161 Header.AddChildObject(NewTrack.Sequence);
162 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
163 NewTrack.Sequence->DataDefinition = Definition;
169 template <class PackageT>
170 TrackSet<TimecodeComponent>
171 CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
172 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart)
174 UL TCUL(Dict::ul(MDD_TimecodeDataDef));
176 TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1);
178 NewTrack.Clip = new TimecodeComponent;
179 Header.AddChildObject(NewTrack.Clip);
180 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
181 NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
182 NewTrack.Clip->StartTimecode = TCStart;
183 NewTrack.Clip->DataDefinition = TCUL;
191 ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
192 const std::string& TrackName, const UL& DataDefinition,
193 const std::string& PackageLabel)
196 ContentStorage* Storage = new ContentStorage;
197 m_HeaderPart.AddChildObject(Storage);
198 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
200 EssenceContainerData* ECD = new EssenceContainerData;
201 m_HeaderPart.AddChildObject(ECD);
202 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
206 UUID assetUUID(m_Info.AssetUUID);
207 UMID SourcePackageUMID, MaterialPackageUMID;
208 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
209 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
214 m_MaterialPackage = new MaterialPackage;
215 m_MaterialPackage->Name = "AS-DCP Material Package";
216 m_MaterialPackage->PackageUID = MaterialPackageUMID;
217 m_HeaderPart.AddChildObject(m_MaterialPackage);
218 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
220 TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
221 EditRate, TCFrameRate, 0);
222 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
223 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
225 TrackSet<SourceClip> MPTrack = CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
226 TrackName, EditRate, DataDefinition, 2);
227 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
229 MPTrack.Clip = new SourceClip;
230 m_HeaderPart.AddChildObject(MPTrack.Clip);
231 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
232 MPTrack.Clip->DataDefinition = DataDefinition;
233 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
234 MPTrack.Clip->SourceTrackID = 2;
235 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
239 // File (Source) Package
241 m_FilePackage = new SourcePackage;
242 m_FilePackage->Name = PackageLabel.c_str();
243 m_FilePackage->PackageUID = SourcePackageUMID;
244 ECD->LinkedPackageUID = SourcePackageUMID;
246 m_HeaderPart.AddChildObject(m_FilePackage);
247 Storage->Packages.push_back(m_FilePackage->InstanceUID);
249 TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
250 EditRate, TCFrameRate, ui64_C(3600) * TCFrameRate);
251 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
252 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
254 TrackSet<SourceClip> FPTrack = CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
255 TrackName, EditRate, DataDefinition, 2);
256 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
258 FPTrack.Clip = new SourceClip;
259 m_HeaderPart.AddChildObject(FPTrack.Clip);
260 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
261 FPTrack.Clip->DataDefinition = DataDefinition;
263 // for now we do not allow setting this value, so all files will be 'original'
264 FPTrack.Clip->SourceTrackID = 0;
265 FPTrack.Clip->SourcePackageID = NilUMID;
266 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
268 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
273 ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
274 const std::string& TrackName, const UL& DataDefinition,
275 const std::string& PackageLabel)
278 ContentStorage* Storage = new ContentStorage;
279 m_HeaderPart.AddChildObject(Storage);
280 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
282 EssenceContainerData* ECD = new EssenceContainerData;
283 m_HeaderPart.AddChildObject(ECD);
284 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
288 UUID assetUUID(m_Info.AssetUUID);
289 UMID SourcePackageUMID, MaterialPackageUMID;
290 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
291 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
296 m_MaterialPackage = new MaterialPackage;
297 m_MaterialPackage->Name = "AS-DCP Material Package";
298 m_MaterialPackage->PackageUID = MaterialPackageUMID;
299 m_HeaderPart.AddChildObject(m_MaterialPackage);
300 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
302 TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
303 EditRate, TCFrameRate, 0);
304 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
305 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
307 TrackSet<DMSegment> MPTrack = CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
308 TrackName, EditRate, DataDefinition, 2);
309 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
311 MPTrack.Clip = new DMSegment;
312 m_HeaderPart.AddChildObject(MPTrack.Clip);
313 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
314 MPTrack.Clip->DataDefinition = DataDefinition;
315 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
316 // MPTrack.Clip->SourceTrackID = 2;
317 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
321 // File (Source) Package
323 m_FilePackage = new SourcePackage;
324 m_FilePackage->Name = PackageLabel.c_str();
325 m_FilePackage->PackageUID = SourcePackageUMID;
326 ECD->LinkedPackageUID = SourcePackageUMID;
328 m_HeaderPart.AddChildObject(m_FilePackage);
329 Storage->Packages.push_back(m_FilePackage->InstanceUID);
331 TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
332 EditRate, TCFrameRate, ui64_C(3600) * TCFrameRate);
333 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
334 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
336 TrackSet<DMSegment> FPTrack = CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
337 TrackName, EditRate, DataDefinition, 2);
338 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
340 FPTrack.Clip = new DMSegment;
341 m_HeaderPart.AddChildObject(FPTrack.Clip);
342 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
343 FPTrack.Clip->DataDefinition = DataDefinition;
344 FPTrack.Clip->EventComment = "D-Cinema Timed Text";
346 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
347 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
352 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
355 // Essence Descriptor
357 m_EssenceDescriptor->EssenceContainer = WrappingUL;
358 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
361 // Encryption Descriptor
363 if ( m_Info.EncryptedEssence )
365 UL CryptEssenceUL(Dict::ul(MDD_EncryptedContainerLabel));
366 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
367 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(Dict::ul(MDD_CryptographicFrameworkLabel)));
368 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL);
372 m_HeaderPart.EssenceContainers.push_back(UL(Dict::ul(MDD_GCMulti)));
373 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
376 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
377 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
379 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
380 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
381 m_HeaderPart.AddChildObject(*sdli);
383 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
388 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
390 Result_t result = RESULT_OK;
392 // create a body partition if we're writing proper 429-3/OP-Atom
393 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
396 m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
397 m_BodyPart.ThisPartition = m_File.Tell();
398 m_BodyPart.BodySID = 1;
399 UL OPAtomUL(Dict::ul(MDD_OPAtom));
400 m_BodyPart.OperationalPattern = OPAtomUL;
401 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
403 UL BodyUL(Dict::ul(MDD_ClosedCompleteBodyPartition));
404 result = m_BodyPart.WriteToFile(m_File, BodyUL);
408 m_HeaderPart.BodySID = 1;
411 if ( ASDCP_SUCCESS(result) )
414 Kumu::fpos_t ECoffset = m_File.Tell();
415 m_FooterPart.IndexSID = 129;
417 if ( BytesPerEditUnit == 0 )
418 m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
420 m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
428 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
429 const std::string& TrackName, const UL& DataDefinition,
430 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
433 AddSourceClip(EditRate, TCFrameRate, TrackName, DataDefinition, PackageLabel);
434 AddEssenceDescriptor(WrappingUL);
436 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
438 if ( KM_SUCCESS(result) )
439 result = CreateBodyPart(EditRate, BytesPerEditUnit);
445 // standard method of writing a plaintext or encrypted frame
447 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
448 AESEncContext* Ctx, HMACContext* HMAC)
450 Result_t result = RESULT_OK;
451 IntegrityPack IntPack;
453 byte_t overhead[128];
454 Kumu::MemIOWriter Overhead(overhead, 128);
456 if ( FrameBuf.Size() == 0 )
458 DefaultLogSink().Error("Cannot write empty frame buffer\n");
459 return RESULT_EMPTY_FB;
462 if ( m_Info.EncryptedEssence )
465 return RESULT_CRYPT_CTX;
467 if ( m_Info.UsesHMAC && ! HMAC )
468 return RESULT_HMAC_CTX;
470 if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
471 return RESULT_LARGE_PTO;
473 // encrypt the essence data (create encrypted source value)
474 result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
477 if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
478 result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
480 if ( ASDCP_SUCCESS(result) )
482 if ( m_Info.LabelSetType == LS_MXF_INTEROP )
483 Overhead.WriteRaw(Dict::ul(MDD_MXFInterop_CryptEssence), SMPTE_UL_LENGTH);
485 Overhead.WriteRaw(Dict::ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
487 // construct encrypted triplet header
488 ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
490 if ( m_Info.UsesHMAC )
491 ETLength += klv_intpack_size;
493 ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
495 Overhead.WriteBER(ETLength, MXF_BER_LENGTH); // write encrypted triplet length
496 Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH); // write ContextID length
497 Overhead.WriteRaw(m_Info.ContextID, UUIDlen); // write ContextID
498 Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH); // write PlaintextOffset length
499 Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()); // write PlaintextOffset
500 Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH); // write essence UL length
501 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH); // write the essence UL
502 Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH); // write SourceLength length
503 Overhead.WriteUi64BE(FrameBuf.Size()); // write SourceLength
504 Overhead.WriteBER(m_CtFrameBuf.Size(), MXF_BER_LENGTH); // write ESV length
506 result = m_File.Writev(Overhead.Data(), Overhead.Length());
509 if ( ASDCP_SUCCESS(result) )
511 m_StreamOffset += Overhead.Length();
512 // write encrypted source value
513 result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
516 if ( ASDCP_SUCCESS(result) )
518 m_StreamOffset += m_CtFrameBuf.Size();
520 byte_t hmoverhead[512];
521 Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
524 if ( m_Info.UsesHMAC )
526 HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
529 { // we still need the var-pack length values if the intpack is empty
530 for ( ui32_t i = 0; i < 3 ; i++ )
531 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
535 result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
536 m_StreamOffset += HMACOverhead.Length();
541 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
542 Overhead.WriteBER(FrameBuf.Size(), MXF_BER_LENGTH);
543 result = m_File.Writev(Overhead.Data(), Overhead.Length());
545 if ( ASDCP_SUCCESS(result) )
546 result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
548 if ( ASDCP_SUCCESS(result) )
549 m_StreamOffset += Overhead.Length() + FrameBuf.Size();
552 if ( ASDCP_SUCCESS(result) )
553 result = m_File.Writev();
559 // standard method of writing the header and footer of a completed MXF file
562 ASDCP::h__Writer::WriteMXFFooter()
564 // Set top-level file package correctly for OP-Atom
566 // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
567 // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
569 DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
571 for (; dli != m_DurationUpdateList.end(); dli++ )
572 **dli = m_FramesWritten;
574 m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
575 m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
577 Kumu::fpos_t here = m_File.Tell();
578 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
579 m_HeaderPart.FooterPartition = here;
581 // re-label the partition
582 UL OPAtomUL(Dict::ul(MDD_OPAtom));
584 if ( m_Info.LabelSetType == LS_MXF_INTEROP )
585 OPAtomUL.Set(Dict::ul(MDD_MXFInterop_OPAtom));
587 m_HeaderPart.OperationalPattern = OPAtomUL;
588 m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
590 m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
591 m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
592 m_FooterPart.FooterPartition = here;
593 m_FooterPart.ThisPartition = here;
595 Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
597 if ( ASDCP_SUCCESS(result) )
598 result = m_HeaderPart.m_RIP.WriteToFile(m_File);
600 if ( ASDCP_SUCCESS(result) )
601 result = m_File.Seek(0);
603 if ( ASDCP_SUCCESS(result) )
604 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);