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
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() :
72 m_HeaderSize(0), m_EssenceStart(0),
73 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
77 ASDCP::h__Writer::~h__Writer()
82 // add DMS CryptographicFramework entry to source package
84 AddDMScrypt(Partition& HeaderPart, SourcePackage& Package, WriterInfo& Descr, const UL& WrappingUL)
87 StaticTrack* NewTrack = new StaticTrack;
88 HeaderPart.AddChildObject(NewTrack);
89 Package.Tracks.push_back(NewTrack->InstanceUID);
90 NewTrack->TrackName = "Descriptive Track";
91 NewTrack->TrackID = 3;
93 Sequence* Seq = new Sequence;
94 HeaderPart.AddChildObject(Seq);
95 NewTrack->Sequence = Seq->InstanceUID;
96 Seq->DataDefinition = UL(Dict::ul(MDD_DescriptiveMetaDataDef));
98 DMSegment* Segment = new DMSegment;
99 HeaderPart.AddChildObject(Segment);
100 Seq->StructuralComponents.push_back(Segment->InstanceUID);
101 Segment->EventComment = "AS-DCP KLV Encryption";
103 CryptographicFramework* CFW = new CryptographicFramework;
104 HeaderPart.AddChildObject(CFW);
105 Segment->DMFramework = CFW->InstanceUID;
107 CryptographicContext* Context = new CryptographicContext;
108 HeaderPart.AddChildObject(Context);
109 CFW->ContextSR = Context->InstanceUID;
111 Context->ContextID.Set(Descr.ContextID);
112 Context->SourceEssenceContainer = WrappingUL; // ??????
113 Context->CipherAlgorithm.Set(Dict::ul(MDD_CipherAlgorithm_AES));
114 Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict::ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict::ul(MDD_MICAlgorithm_NONE) );
115 Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
120 ASDCP::h__Writer::InitHeader()
122 assert(m_EssenceDescriptor);
124 m_HeaderPart.m_Primer.ClearTagList();
125 m_HeaderPart.m_Preface = new Preface;
126 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
128 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
129 // so we tell the world by using OP1a
130 m_HeaderPart.m_Preface->OperationalPattern = UL(Dict::ul(MDD_OP1a));
131 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
134 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
135 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
137 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
142 Identification* Ident = new Identification;
143 m_HeaderPart.AddChildObject(Ident);
144 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
146 Kumu::GenRandomValue(Ident->ThisGenerationUID);
147 Ident->CompanyName = m_Info.CompanyName.c_str();
148 Ident->ProductName = m_Info.ProductName.c_str();
149 Ident->VersionString = m_Info.ProductVersion.c_str();
150 Ident->ProductUID.Set(m_Info.ProductUUID);
151 Ident->Platform = ASDCP_PLATFORM;
153 std::vector<int> version = version_split(Version());
155 Ident->ToolkitVersion.Major = version[0];
156 Ident->ToolkitVersion.Minor = version[1];
157 Ident->ToolkitVersion.Patch = version[2];
158 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
159 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
163 template <class ClipT>
167 MXF::Sequence* Sequence;
170 TrackSet() : Track(0), Sequence(0), Clip(0) {}
174 template <class PackageT, class ClipT>
176 CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
177 const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID)
179 TrackSet<ClipT> NewTrack;
181 NewTrack.Track = new Track;
182 Header.AddChildObject(NewTrack.Track);
183 NewTrack.Track->EditRate = EditRate;
184 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
185 NewTrack.Track->TrackID = TrackID;
186 NewTrack.Track->TrackName = TrackName.c_str();
188 NewTrack.Sequence = new Sequence;
189 Header.AddChildObject(NewTrack.Sequence);
190 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
191 NewTrack.Sequence->DataDefinition = Definition;
197 template <class PackageT>
198 TrackSet<TimecodeComponent>
199 CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
200 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart)
202 UL TCUL(Dict::ul(MDD_TimecodeDataDef));
204 TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1);
206 NewTrack.Clip = new TimecodeComponent;
207 Header.AddChildObject(NewTrack.Clip);
208 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
209 NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
210 NewTrack.Clip->StartTimecode = TCStart;
211 NewTrack.Clip->DataDefinition = TCUL;
219 ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
220 const std::string& TrackName, const UL& DataDefinition,
221 const std::string& PackageLabel)
224 ContentStorage* Storage = new ContentStorage;
225 m_HeaderPart.AddChildObject(Storage);
226 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
228 EssenceContainerData* ECD = new EssenceContainerData;
229 m_HeaderPart.AddChildObject(ECD);
230 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
234 UUID assetUUID(m_Info.AssetUUID);
235 UMID SourcePackageUMID, MaterialPackageUMID;
236 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
237 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
242 m_MaterialPackage = new MaterialPackage;
243 m_MaterialPackage->Name = "AS-DCP Material Package";
244 m_MaterialPackage->PackageUID = MaterialPackageUMID;
245 m_HeaderPart.AddChildObject(m_MaterialPackage);
246 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
248 TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
249 EditRate, TCFrameRate, 0);
250 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
251 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
253 TrackSet<SourceClip> MPTrack = CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
254 TrackName, EditRate, DataDefinition, 2);
255 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
257 MPTrack.Clip = new SourceClip;
258 m_HeaderPart.AddChildObject(MPTrack.Clip);
259 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
260 MPTrack.Clip->DataDefinition = DataDefinition;
261 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
262 MPTrack.Clip->SourceTrackID = 2;
263 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
267 // File (Source) Package
269 m_FilePackage = new SourcePackage;
270 m_FilePackage->Name = PackageLabel.c_str();
271 m_FilePackage->PackageUID = SourcePackageUMID;
272 ECD->LinkedPackageUID = SourcePackageUMID;
274 m_HeaderPart.AddChildObject(m_FilePackage);
275 Storage->Packages.push_back(m_FilePackage->InstanceUID);
277 TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
278 EditRate, TCFrameRate, ui64_C(3600) * TCFrameRate);
279 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
280 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
282 TrackSet<SourceClip> FPTrack = CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
283 TrackName, EditRate, DataDefinition, 2);
284 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
286 FPTrack.Clip = new SourceClip;
287 m_HeaderPart.AddChildObject(FPTrack.Clip);
288 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
289 FPTrack.Clip->DataDefinition = DataDefinition;
291 // for now we do not allow setting this value, so all files will be 'original'
292 FPTrack.Clip->SourceTrackID = 0;
293 FPTrack.Clip->SourcePackageID = NilUMID;
294 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
296 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
301 ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
302 const std::string& TrackName, const UL& DataDefinition,
303 const std::string& PackageLabel)
306 ContentStorage* Storage = new ContentStorage;
307 m_HeaderPart.AddChildObject(Storage);
308 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
310 EssenceContainerData* ECD = new EssenceContainerData;
311 m_HeaderPart.AddChildObject(ECD);
312 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
316 UUID assetUUID(m_Info.AssetUUID);
317 UMID SourcePackageUMID, MaterialPackageUMID;
318 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
319 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
324 m_MaterialPackage = new MaterialPackage;
325 m_MaterialPackage->Name = "AS-DCP Material Package";
326 m_MaterialPackage->PackageUID = MaterialPackageUMID;
327 m_HeaderPart.AddChildObject(m_MaterialPackage);
328 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
330 TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
331 EditRate, TCFrameRate, 0);
332 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
333 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
335 TrackSet<DMSegment> MPTrack = CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
336 TrackName, EditRate, DataDefinition, 2);
337 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
339 MPTrack.Clip = new DMSegment;
340 m_HeaderPart.AddChildObject(MPTrack.Clip);
341 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
342 MPTrack.Clip->DataDefinition = DataDefinition;
343 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
344 // MPTrack.Clip->SourceTrackID = 2;
345 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
349 // File (Source) Package
351 m_FilePackage = new SourcePackage;
352 m_FilePackage->Name = PackageLabel.c_str();
353 m_FilePackage->PackageUID = SourcePackageUMID;
354 ECD->LinkedPackageUID = SourcePackageUMID;
356 m_HeaderPart.AddChildObject(m_FilePackage);
357 Storage->Packages.push_back(m_FilePackage->InstanceUID);
359 TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
360 EditRate, TCFrameRate, ui64_C(3600) * TCFrameRate);
361 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
362 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
364 TrackSet<DMSegment> FPTrack = CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
365 TrackName, EditRate, DataDefinition, 2);
366 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
368 FPTrack.Clip = new DMSegment;
369 m_HeaderPart.AddChildObject(FPTrack.Clip);
370 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
371 FPTrack.Clip->DataDefinition = DataDefinition;
372 FPTrack.Clip->EventComment = "D-Cinema Timed Text";
374 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
375 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
380 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
383 // Essence Descriptor
385 m_EssenceDescriptor->EssenceContainer = WrappingUL;
386 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
389 // Essence Descriptors
391 UL GenericContainerUL(Dict::ul(MDD_GCMulti));
392 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
394 if ( m_Info.EncryptedEssence )
396 UL CryptEssenceUL(Dict::ul(MDD_EncryptedContainerLabel));
397 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
398 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(Dict::ul(MDD_CryptographicFrameworkLabel)));
399 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL);
403 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
406 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
407 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
409 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
410 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
411 m_HeaderPart.AddChildObject(*sdli);
413 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
418 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
420 Result_t result = RESULT_OK;
422 // create a body partition if we're writing proper 429-3/OP-Atom
423 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
426 m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
427 m_BodyPart.ThisPartition = m_File.Tell();
428 m_BodyPart.BodySID = 1;
429 UL OPAtomUL(Dict::ul(MDD_OPAtom));
430 m_BodyPart.OperationalPattern = OPAtomUL;
431 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
433 UL BodyUL(Dict::ul(MDD_ClosedCompleteBodyPartition));
434 result = m_BodyPart.WriteToFile(m_File, BodyUL);
438 m_HeaderPart.BodySID = 1;
441 if ( ASDCP_SUCCESS(result) )
444 Kumu::fpos_t ECoffset = m_File.Tell();
445 m_FooterPart.IndexSID = 129;
447 if ( BytesPerEditUnit == 0 )
448 m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
450 m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
458 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
459 const std::string& TrackName, const UL& DataDefinition,
460 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
463 AddSourceClip(EditRate, TCFrameRate, TrackName, DataDefinition, PackageLabel);
464 AddEssenceDescriptor(WrappingUL);
466 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
468 if ( KM_SUCCESS(result) )
469 result = CreateBodyPart(EditRate, BytesPerEditUnit);
475 // standard method of writing a plaintext or encrypted frame
477 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
478 AESEncContext* Ctx, HMACContext* HMAC)
480 Result_t result = RESULT_OK;
481 IntegrityPack IntPack;
483 byte_t overhead[128];
484 Kumu::MemIOWriter Overhead(overhead, 128);
486 if ( FrameBuf.Size() == 0 )
488 DefaultLogSink().Error("Cannot write empty frame buffer\n");
489 return RESULT_EMPTY_FB;
492 if ( m_Info.EncryptedEssence )
495 return RESULT_CRYPT_CTX;
497 if ( m_Info.UsesHMAC && ! HMAC )
498 return RESULT_HMAC_CTX;
500 if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
501 return RESULT_LARGE_PTO;
503 // encrypt the essence data (create encrypted source value)
504 result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
507 if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
508 result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
510 if ( ASDCP_SUCCESS(result) )
512 if ( m_Info.LabelSetType == LS_MXF_INTEROP )
513 Overhead.WriteRaw(Dict::ul(MDD_MXFInterop_CryptEssence), SMPTE_UL_LENGTH);
515 Overhead.WriteRaw(Dict::ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
517 // construct encrypted triplet header
518 ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
520 if ( m_Info.UsesHMAC )
521 ETLength += klv_intpack_size;
523 ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
525 Overhead.WriteBER(ETLength, MXF_BER_LENGTH); // write encrypted triplet length
526 Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH); // write ContextID length
527 Overhead.WriteRaw(m_Info.ContextID, UUIDlen); // write ContextID
528 Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH); // write PlaintextOffset length
529 Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()); // write PlaintextOffset
530 Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH); // write essence UL length
531 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH); // write the essence UL
532 Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH); // write SourceLength length
533 Overhead.WriteUi64BE(FrameBuf.Size()); // write SourceLength
534 Overhead.WriteBER(m_CtFrameBuf.Size(), MXF_BER_LENGTH); // write ESV length
536 result = m_File.Writev(Overhead.Data(), Overhead.Length());
539 if ( ASDCP_SUCCESS(result) )
541 m_StreamOffset += Overhead.Length();
542 // write encrypted source value
543 result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
546 if ( ASDCP_SUCCESS(result) )
548 m_StreamOffset += m_CtFrameBuf.Size();
550 byte_t hmoverhead[512];
551 Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
554 if ( m_Info.UsesHMAC )
556 HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
559 { // we still need the var-pack length values if the intpack is empty
560 for ( ui32_t i = 0; i < 3 ; i++ )
561 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
565 result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
566 m_StreamOffset += HMACOverhead.Length();
571 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
572 Overhead.WriteBER(FrameBuf.Size(), MXF_BER_LENGTH);
573 result = m_File.Writev(Overhead.Data(), Overhead.Length());
575 if ( ASDCP_SUCCESS(result) )
576 result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
578 if ( ASDCP_SUCCESS(result) )
579 m_StreamOffset += Overhead.Length() + FrameBuf.Size();
582 if ( ASDCP_SUCCESS(result) )
583 result = m_File.Writev();
589 // standard method of writing the header and footer of a completed MXF file
592 ASDCP::h__Writer::WriteMXFFooter()
594 // Set top-level file package correctly for OP-Atom
596 // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
597 // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
599 DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
601 for (; dli != m_DurationUpdateList.end(); dli++ )
602 **dli = m_FramesWritten;
604 m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
605 m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
607 Kumu::fpos_t here = m_File.Tell();
608 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
609 m_HeaderPart.FooterPartition = here;
611 // re-label the partition
612 UL OPAtomUL(Dict::ul(MDD_OPAtom));
614 if ( m_Info.LabelSetType == LS_MXF_INTEROP )
615 OPAtomUL.Set(Dict::ul(MDD_MXFInterop_OPAtom));
617 m_HeaderPart.OperationalPattern = OPAtomUL;
618 m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
620 m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
621 m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
622 m_FooterPart.FooterPartition = here;
623 m_FooterPart.ThisPartition = here;
625 Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
627 if ( ASDCP_SUCCESS(result) )
628 result = m_HeaderPart.m_RIP.WriteToFile(m_File);
630 if ( ASDCP_SUCCESS(result) )
631 result = m_File.Seek(0);
633 if ( ASDCP_SUCCESS(result) )
634 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);