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)
89 StaticTrack* NewTrack = new StaticTrack(Dict);
90 HeaderPart.AddChildObject(NewTrack);
91 Package.Tracks.push_back(NewTrack->InstanceUID);
92 NewTrack->TrackName = "Descriptive Track";
93 NewTrack->TrackID = 3;
95 Sequence* Seq = new Sequence(Dict);
96 HeaderPart.AddChildObject(Seq);
97 NewTrack->Sequence = Seq->InstanceUID;
98 Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
100 DMSegment* Segment = new DMSegment(Dict);
101 HeaderPart.AddChildObject(Segment);
102 Seq->StructuralComponents.push_back(Segment->InstanceUID);
103 Segment->EventComment = "AS-DCP KLV Encryption";
105 CryptographicFramework* CFW = new CryptographicFramework(Dict);
106 HeaderPart.AddChildObject(CFW);
107 Segment->DMFramework = CFW->InstanceUID;
109 CryptographicContext* Context = new CryptographicContext(Dict);
110 HeaderPart.AddChildObject(Context);
111 CFW->ContextSR = Context->InstanceUID;
113 Context->ContextID.Set(Descr.ContextID);
114 Context->SourceEssenceContainer = WrappingUL; // ??????
115 Context->CipherAlgorithm.Set(Dict->ul(MDD_CipherAlgorithm_AES));
116 Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict->ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict->ul(MDD_MICAlgorithm_NONE) );
117 Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
122 ASDCP::h__Writer::InitHeader()
124 assert(m_EssenceDescriptor);
126 m_HeaderPart.m_Primer.ClearTagList();
127 m_HeaderPart.m_Preface = new Preface(m_Dict);
128 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
130 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
131 // so we tell the world by using OP1a
132 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
133 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
136 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
137 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
139 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
144 Identification* Ident = new Identification(m_Dict);
145 m_HeaderPart.AddChildObject(Ident);
146 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
148 Kumu::GenRandomValue(Ident->ThisGenerationUID);
149 Ident->CompanyName = m_Info.CompanyName.c_str();
150 Ident->ProductName = m_Info.ProductName.c_str();
151 Ident->VersionString = m_Info.ProductVersion.c_str();
152 Ident->ProductUID.Set(m_Info.ProductUUID);
153 Ident->Platform = ASDCP_PLATFORM;
155 std::vector<int> version = version_split(Version());
157 Ident->ToolkitVersion.Major = version[0];
158 Ident->ToolkitVersion.Minor = version[1];
159 Ident->ToolkitVersion.Patch = version[2];
160 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
161 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
165 template <class ClipT>
169 MXF::Sequence* Sequence;
172 TrackSet() : Track(0), Sequence(0), Clip(0) {}
176 template <class PackageT, class ClipT>
178 CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
179 const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
181 TrackSet<ClipT> NewTrack;
183 NewTrack.Track = new Track(Dict);
184 Header.AddChildObject(NewTrack.Track);
185 NewTrack.Track->EditRate = EditRate;
186 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
187 NewTrack.Track->TrackID = TrackID;
188 NewTrack.Track->TrackName = TrackName.c_str();
190 NewTrack.Sequence = new Sequence(Dict);
191 Header.AddChildObject(NewTrack.Sequence);
192 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
193 NewTrack.Sequence->DataDefinition = Definition;
199 template <class PackageT>
200 TrackSet<TimecodeComponent>
201 CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
202 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict)
204 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
206 TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
208 NewTrack.Clip = new TimecodeComponent(Dict);
209 Header.AddChildObject(NewTrack.Clip);
210 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
211 NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
212 NewTrack.Clip->StartTimecode = TCStart;
213 NewTrack.Clip->DataDefinition = TCUL;
221 ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
222 const std::string& TrackName, const UL& DataDefinition,
223 const std::string& PackageLabel)
226 ContentStorage* Storage = new ContentStorage(m_Dict);
227 m_HeaderPart.AddChildObject(Storage);
228 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
230 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
231 m_HeaderPart.AddChildObject(ECD);
232 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
236 UUID assetUUID(m_Info.AssetUUID);
237 UMID SourcePackageUMID, MaterialPackageUMID;
238 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
239 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
244 m_MaterialPackage = new MaterialPackage(m_Dict);
245 m_MaterialPackage->Name = "AS-DCP Material Package";
246 m_MaterialPackage->PackageUID = MaterialPackageUMID;
247 m_HeaderPart.AddChildObject(m_MaterialPackage);
248 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
250 TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
251 EditRate, TCFrameRate, 0, m_Dict);
252 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
253 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
255 TrackSet<SourceClip> MPTrack = CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
256 TrackName, EditRate, DataDefinition,
258 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
260 MPTrack.Clip = new SourceClip(m_Dict);
261 m_HeaderPart.AddChildObject(MPTrack.Clip);
262 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
263 MPTrack.Clip->DataDefinition = DataDefinition;
264 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
265 MPTrack.Clip->SourceTrackID = 2;
266 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
270 // File (Source) Package
272 m_FilePackage = new SourcePackage(m_Dict);
273 m_FilePackage->Name = PackageLabel.c_str();
274 m_FilePackage->PackageUID = SourcePackageUMID;
275 ECD->LinkedPackageUID = SourcePackageUMID;
277 m_HeaderPart.AddChildObject(m_FilePackage);
278 Storage->Packages.push_back(m_FilePackage->InstanceUID);
280 TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
281 EditRate, TCFrameRate,
282 ui64_C(3600) * TCFrameRate, m_Dict);
283 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
284 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
286 TrackSet<SourceClip> FPTrack = CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
287 TrackName, EditRate, DataDefinition,
289 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
291 FPTrack.Clip = new SourceClip(m_Dict);
292 m_HeaderPart.AddChildObject(FPTrack.Clip);
293 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
294 FPTrack.Clip->DataDefinition = DataDefinition;
296 // for now we do not allow setting this value, so all files will be 'original'
297 FPTrack.Clip->SourceTrackID = 0;
298 FPTrack.Clip->SourcePackageID = NilUMID;
299 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
301 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
306 ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
307 const std::string& TrackName, const UL& DataDefinition,
308 const std::string& PackageLabel)
311 ContentStorage* Storage = new ContentStorage(m_Dict);
312 m_HeaderPart.AddChildObject(Storage);
313 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
315 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
316 m_HeaderPart.AddChildObject(ECD);
317 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
321 UUID assetUUID(m_Info.AssetUUID);
322 UMID SourcePackageUMID, MaterialPackageUMID;
323 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
324 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
329 m_MaterialPackage = new MaterialPackage(m_Dict);
330 m_MaterialPackage->Name = "AS-DCP Material Package";
331 m_MaterialPackage->PackageUID = MaterialPackageUMID;
332 m_HeaderPart.AddChildObject(m_MaterialPackage);
333 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
335 TrackSet<TimecodeComponent> MPTCTrack = CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
336 EditRate, TCFrameRate, 0, m_Dict);
337 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
338 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
340 TrackSet<DMSegment> MPTrack = CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
341 TrackName, EditRate, DataDefinition,
343 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
345 MPTrack.Clip = new DMSegment(m_Dict);
346 m_HeaderPart.AddChildObject(MPTrack.Clip);
347 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
348 MPTrack.Clip->DataDefinition = DataDefinition;
349 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
350 // MPTrack.Clip->SourceTrackID = 2;
351 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
355 // File (Source) Package
357 m_FilePackage = new SourcePackage(m_Dict);
358 m_FilePackage->Name = PackageLabel.c_str();
359 m_FilePackage->PackageUID = SourcePackageUMID;
360 ECD->LinkedPackageUID = SourcePackageUMID;
362 m_HeaderPart.AddChildObject(m_FilePackage);
363 Storage->Packages.push_back(m_FilePackage->InstanceUID);
365 TrackSet<TimecodeComponent> FPTCTrack = CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
366 EditRate, TCFrameRate,
367 ui64_C(3600) * TCFrameRate, m_Dict);
368 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
369 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
371 TrackSet<DMSegment> FPTrack = CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
372 TrackName, EditRate, DataDefinition,
374 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
376 FPTrack.Clip = new DMSegment(m_Dict);
377 m_HeaderPart.AddChildObject(FPTrack.Clip);
378 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
379 FPTrack.Clip->DataDefinition = DataDefinition;
380 FPTrack.Clip->EventComment = "D-Cinema Timed Text";
382 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
383 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
388 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
391 // Essence Descriptor
393 m_EssenceDescriptor->EssenceContainer = WrappingUL;
394 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
397 // Essence Descriptors
399 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
400 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
402 if ( m_Info.EncryptedEssence )
404 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
405 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
406 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
407 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
411 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
414 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
415 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
417 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
418 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
419 m_HeaderPart.AddChildObject(*sdli);
421 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
426 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
428 Result_t result = RESULT_OK;
430 // create a body partition if we're writing proper 429-3/OP-Atom
431 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
434 m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
435 m_BodyPart.ThisPartition = m_File.Tell();
436 m_BodyPart.BodySID = 1;
437 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
438 m_BodyPart.OperationalPattern = OPAtomUL;
439 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
441 UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
442 result = m_BodyPart.WriteToFile(m_File, BodyUL);
446 m_HeaderPart.BodySID = 1;
449 if ( ASDCP_SUCCESS(result) )
452 Kumu::fpos_t ECoffset = m_File.Tell();
453 m_FooterPart.IndexSID = 129;
455 if ( BytesPerEditUnit == 0 )
456 m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
458 m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
466 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
467 const std::string& TrackName, const UL& DataDefinition,
468 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
471 AddSourceClip(EditRate, TCFrameRate, TrackName, DataDefinition, PackageLabel);
472 AddEssenceDescriptor(WrappingUL);
474 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
476 if ( KM_SUCCESS(result) )
477 result = CreateBodyPart(EditRate, BytesPerEditUnit);
483 // standard method of writing a plaintext or encrypted frame
485 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
486 AESEncContext* Ctx, HMACContext* HMAC)
488 Result_t result = RESULT_OK;
489 IntegrityPack IntPack;
491 byte_t overhead[128];
492 Kumu::MemIOWriter Overhead(overhead, 128);
494 if ( FrameBuf.Size() == 0 )
496 DefaultLogSink().Error("Cannot write empty frame buffer\n");
497 return RESULT_EMPTY_FB;
500 if ( m_Info.EncryptedEssence )
503 return RESULT_CRYPT_CTX;
505 if ( m_Info.UsesHMAC && ! HMAC )
506 return RESULT_HMAC_CTX;
508 if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
509 return RESULT_LARGE_PTO;
511 // encrypt the essence data (create encrypted source value)
512 result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
515 if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
516 result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
518 if ( ASDCP_SUCCESS(result) )
520 if ( m_Info.LabelSetType == LS_MXF_INTEROP )
521 Overhead.WriteRaw(m_Dict->ul(MDD_MXFInterop_CryptEssence), SMPTE_UL_LENGTH);
523 Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
525 // construct encrypted triplet header
526 ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
528 if ( m_Info.UsesHMAC )
529 ETLength += klv_intpack_size;
531 ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
533 Overhead.WriteBER(ETLength, MXF_BER_LENGTH); // write encrypted triplet length
534 Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH); // write ContextID length
535 Overhead.WriteRaw(m_Info.ContextID, UUIDlen); // write ContextID
536 Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH); // write PlaintextOffset length
537 Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()); // write PlaintextOffset
538 Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH); // write essence UL length
539 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH); // write the essence UL
540 Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH); // write SourceLength length
541 Overhead.WriteUi64BE(FrameBuf.Size()); // write SourceLength
542 Overhead.WriteBER(m_CtFrameBuf.Size(), MXF_BER_LENGTH); // write ESV length
544 result = m_File.Writev(Overhead.Data(), Overhead.Length());
547 if ( ASDCP_SUCCESS(result) )
549 m_StreamOffset += Overhead.Length();
550 // write encrypted source value
551 result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
554 if ( ASDCP_SUCCESS(result) )
556 m_StreamOffset += m_CtFrameBuf.Size();
558 byte_t hmoverhead[512];
559 Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
562 if ( m_Info.UsesHMAC )
564 HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
567 { // we still need the var-pack length values if the intpack is empty
568 for ( ui32_t i = 0; i < 3 ; i++ )
569 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
573 result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
574 m_StreamOffset += HMACOverhead.Length();
579 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
580 Overhead.WriteBER(FrameBuf.Size(), MXF_BER_LENGTH);
581 result = m_File.Writev(Overhead.Data(), Overhead.Length());
583 if ( ASDCP_SUCCESS(result) )
584 result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
586 if ( ASDCP_SUCCESS(result) )
587 m_StreamOffset += Overhead.Length() + FrameBuf.Size();
590 if ( ASDCP_SUCCESS(result) )
591 result = m_File.Writev();
597 // standard method of writing the header and footer of a completed MXF file
600 ASDCP::h__Writer::WriteMXFFooter()
602 // Set top-level file package correctly for OP-Atom
604 // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
605 // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
607 DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
609 for (; dli != m_DurationUpdateList.end(); dli++ )
610 **dli = m_FramesWritten;
612 m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
613 m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
615 Kumu::fpos_t here = m_File.Tell();
616 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
617 m_HeaderPart.FooterPartition = here;
619 // re-label the partition
620 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
622 if ( m_Info.LabelSetType == LS_MXF_INTEROP )
623 OPAtomUL.Set(m_Dict->ul(MDD_MXFInterop_OPAtom));
625 m_HeaderPart.OperationalPattern = OPAtomUL;
626 m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
628 m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
629 m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
630 m_FooterPart.FooterPartition = here;
631 m_FooterPart.ThisPartition = here;
633 Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
635 if ( ASDCP_SUCCESS(result) )
636 result = m_HeaderPart.m_RIP.WriteToFile(m_File);
638 if ( ASDCP_SUCCESS(result) )
639 result = m_File.Seek(0);
641 if ( ASDCP_SUCCESS(result) )
642 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);