2 Copyright (c) 2004-2008, 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 // Essence Descriptors
363 UL GenericContainerUL(Dict::ul(MDD_GCMulti));
364 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
366 if ( m_Info.EncryptedEssence )
368 UL CryptEssenceUL(Dict::ul(MDD_EncryptedContainerLabel));
369 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
370 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(Dict::ul(MDD_CryptographicFrameworkLabel)));
371 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL);
375 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
378 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
379 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
381 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
382 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
383 m_HeaderPart.AddChildObject(*sdli);
385 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
390 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
392 Result_t result = RESULT_OK;
394 // create a body partition if we're writing proper 429-3/OP-Atom
395 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
398 m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
399 m_BodyPart.ThisPartition = m_File.Tell();
400 m_BodyPart.BodySID = 1;
401 UL OPAtomUL(Dict::ul(MDD_OPAtom));
402 m_BodyPart.OperationalPattern = OPAtomUL;
403 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
405 UL BodyUL(Dict::ul(MDD_ClosedCompleteBodyPartition));
406 result = m_BodyPart.WriteToFile(m_File, BodyUL);
410 m_HeaderPart.BodySID = 1;
413 if ( ASDCP_SUCCESS(result) )
416 Kumu::fpos_t ECoffset = m_File.Tell();
417 m_FooterPart.IndexSID = 129;
419 if ( BytesPerEditUnit == 0 )
420 m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
422 m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
430 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
431 const std::string& TrackName, const UL& DataDefinition,
432 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
435 AddSourceClip(EditRate, TCFrameRate, TrackName, DataDefinition, PackageLabel);
436 AddEssenceDescriptor(WrappingUL);
438 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
440 if ( KM_SUCCESS(result) )
441 result = CreateBodyPart(EditRate, BytesPerEditUnit);
447 // standard method of writing a plaintext or encrypted frame
449 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
450 AESEncContext* Ctx, HMACContext* HMAC)
452 Result_t result = RESULT_OK;
453 IntegrityPack IntPack;
455 byte_t overhead[128];
456 Kumu::MemIOWriter Overhead(overhead, 128);
458 if ( FrameBuf.Size() == 0 )
460 DefaultLogSink().Error("Cannot write empty frame buffer\n");
461 return RESULT_EMPTY_FB;
464 if ( m_Info.EncryptedEssence )
467 return RESULT_CRYPT_CTX;
469 if ( m_Info.UsesHMAC && ! HMAC )
470 return RESULT_HMAC_CTX;
472 if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
473 return RESULT_LARGE_PTO;
475 // encrypt the essence data (create encrypted source value)
476 result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
479 if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
480 result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
482 if ( ASDCP_SUCCESS(result) )
484 if ( m_Info.LabelSetType == LS_MXF_INTEROP )
485 Overhead.WriteRaw(Dict::ul(MDD_MXFInterop_CryptEssence), SMPTE_UL_LENGTH);
487 Overhead.WriteRaw(Dict::ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
489 // construct encrypted triplet header
490 ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
492 if ( m_Info.UsesHMAC )
493 ETLength += klv_intpack_size;
495 ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
497 Overhead.WriteBER(ETLength, MXF_BER_LENGTH); // write encrypted triplet length
498 Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH); // write ContextID length
499 Overhead.WriteRaw(m_Info.ContextID, UUIDlen); // write ContextID
500 Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH); // write PlaintextOffset length
501 Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()); // write PlaintextOffset
502 Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH); // write essence UL length
503 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH); // write the essence UL
504 Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH); // write SourceLength length
505 Overhead.WriteUi64BE(FrameBuf.Size()); // write SourceLength
506 Overhead.WriteBER(m_CtFrameBuf.Size(), MXF_BER_LENGTH); // write ESV length
508 result = m_File.Writev(Overhead.Data(), Overhead.Length());
511 if ( ASDCP_SUCCESS(result) )
513 m_StreamOffset += Overhead.Length();
514 // write encrypted source value
515 result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
518 if ( ASDCP_SUCCESS(result) )
520 m_StreamOffset += m_CtFrameBuf.Size();
522 byte_t hmoverhead[512];
523 Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
526 if ( m_Info.UsesHMAC )
528 HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
531 { // we still need the var-pack length values if the intpack is empty
532 for ( ui32_t i = 0; i < 3 ; i++ )
533 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
537 result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
538 m_StreamOffset += HMACOverhead.Length();
543 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
544 Overhead.WriteBER(FrameBuf.Size(), MXF_BER_LENGTH);
545 result = m_File.Writev(Overhead.Data(), Overhead.Length());
547 if ( ASDCP_SUCCESS(result) )
548 result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
550 if ( ASDCP_SUCCESS(result) )
551 m_StreamOffset += Overhead.Length() + FrameBuf.Size();
554 if ( ASDCP_SUCCESS(result) )
555 result = m_File.Writev();
561 // standard method of writing the header and footer of a completed MXF file
564 ASDCP::h__Writer::WriteMXFFooter()
566 // Set top-level file package correctly for OP-Atom
568 // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
569 // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
571 DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
573 for (; dli != m_DurationUpdateList.end(); dli++ )
574 **dli = m_FramesWritten;
576 m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
577 m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
579 Kumu::fpos_t here = m_File.Tell();
580 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
581 m_HeaderPart.FooterPartition = here;
583 // re-label the partition
584 UL OPAtomUL(Dict::ul(MDD_OPAtom));
586 if ( m_Info.LabelSetType == LS_MXF_INTEROP )
587 OPAtomUL.Set(Dict::ul(MDD_MXFInterop_OPAtom));
589 m_HeaderPart.OperationalPattern = OPAtomUL;
590 m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
592 m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
593 m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
594 m_FooterPart.FooterPartition = here;
595 m_FooterPart.ThisPartition = here;
597 Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
599 if ( ASDCP_SUCCESS(result) )
600 result = m_HeaderPart.m_RIP.WriteToFile(m_File);
602 if ( ASDCP_SUCCESS(result) )
603 result = m_File.Seek(0);
605 if ( ASDCP_SUCCESS(result) )
606 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);