2 Copyright (c) 2004-2010, 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& EssenceUL,
226 const UL& DataDefinition, 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 =
254 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
255 EditRate, TCFrameRate, 0, m_Dict);
256 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
257 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
259 TrackSet<SourceClip> MPTrack =
260 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
261 TrackName, EditRate, DataDefinition,
263 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
265 MPTrack.Clip = new SourceClip(m_Dict);
266 m_HeaderPart.AddChildObject(MPTrack.Clip);
267 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
268 MPTrack.Clip->DataDefinition = DataDefinition;
269 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
270 MPTrack.Clip->SourceTrackID = 2;
271 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
275 // File (Source) Package
277 m_FilePackage = new SourcePackage(m_Dict);
278 m_FilePackage->Name = PackageLabel.c_str();
279 m_FilePackage->PackageUID = SourcePackageUMID;
280 ECD->LinkedPackageUID = SourcePackageUMID;
282 m_HeaderPart.AddChildObject(m_FilePackage);
283 Storage->Packages.push_back(m_FilePackage->InstanceUID);
285 TrackSet<TimecodeComponent> FPTCTrack =
286 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
287 EditRate, TCFrameRate,
288 ui64_C(3600) * TCFrameRate, m_Dict);
289 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
290 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
291 TrackSet<SourceClip> FPTrack =
292 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
293 TrackName, EditRate, DataDefinition,
295 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
297 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
298 FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
300 FPTrack.Clip = new SourceClip(m_Dict);
301 m_HeaderPart.AddChildObject(FPTrack.Clip);
302 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
303 FPTrack.Clip->DataDefinition = DataDefinition;
305 // for now we do not allow setting this value, so all files will be 'original'
306 FPTrack.Clip->SourceTrackID = 0;
307 FPTrack.Clip->SourcePackageID = NilUMID;
308 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
310 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
315 ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
316 const std::string& TrackName, const UL& DataDefinition,
317 const std::string& PackageLabel)
320 ContentStorage* Storage = new ContentStorage(m_Dict);
321 m_HeaderPart.AddChildObject(Storage);
322 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
324 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
325 m_HeaderPart.AddChildObject(ECD);
326 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
330 UUID assetUUID(m_Info.AssetUUID);
331 UMID SourcePackageUMID, MaterialPackageUMID;
332 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
333 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
338 m_MaterialPackage = new MaterialPackage(m_Dict);
339 m_MaterialPackage->Name = "AS-DCP Material Package";
340 m_MaterialPackage->PackageUID = MaterialPackageUMID;
341 m_HeaderPart.AddChildObject(m_MaterialPackage);
342 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
344 TrackSet<TimecodeComponent> MPTCTrack =
345 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
346 EditRate, TCFrameRate, 0, m_Dict);
347 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
348 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
350 TrackSet<DMSegment> MPTrack =
351 CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
352 TrackName, EditRate, DataDefinition,
354 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
356 MPTrack.Clip = new DMSegment(m_Dict);
357 m_HeaderPart.AddChildObject(MPTrack.Clip);
358 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
359 MPTrack.Clip->DataDefinition = DataDefinition;
360 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
361 // MPTrack.Clip->SourceTrackID = 2;
362 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
366 // File (Source) Package
368 m_FilePackage = new SourcePackage(m_Dict);
369 m_FilePackage->Name = PackageLabel.c_str();
370 m_FilePackage->PackageUID = SourcePackageUMID;
371 ECD->LinkedPackageUID = SourcePackageUMID;
373 m_HeaderPart.AddChildObject(m_FilePackage);
374 Storage->Packages.push_back(m_FilePackage->InstanceUID);
376 TrackSet<TimecodeComponent> FPTCTrack =
377 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
378 EditRate, TCFrameRate,
379 ui64_C(3600) * TCFrameRate, m_Dict);
380 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
381 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
383 TrackSet<DMSegment> FPTrack =
384 CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
385 TrackName, EditRate, DataDefinition,
387 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
389 FPTrack.Clip = new DMSegment(m_Dict);
390 m_HeaderPart.AddChildObject(FPTrack.Clip);
391 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
392 FPTrack.Clip->DataDefinition = DataDefinition;
393 FPTrack.Clip->EventComment = "D-Cinema Timed Text";
395 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
396 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
401 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
404 // Essence Descriptor
406 m_EssenceDescriptor->EssenceContainer = WrappingUL;
407 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
410 // Essence Descriptors
413 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
414 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
416 if ( m_Info.EncryptedEssence )
418 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
419 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
420 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
421 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
425 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
428 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
429 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
431 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
432 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
433 m_HeaderPart.AddChildObject(*sdli);
435 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
440 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
443 Result_t result = RESULT_OK;
445 // create a body partition if we're writing proper 429-3/OP-Atom
446 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
449 m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
450 m_BodyPart.ThisPartition = m_File.Tell();
451 m_BodyPart.BodySID = 1;
452 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
453 m_BodyPart.OperationalPattern = OPAtomUL;
454 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
456 UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
457 result = m_BodyPart.WriteToFile(m_File, BodyUL);
461 m_HeaderPart.BodySID = 1;
464 if ( ASDCP_SUCCESS(result) )
467 Kumu::fpos_t ECoffset = m_File.Tell();
468 m_FooterPart.IndexSID = 129;
470 if ( BytesPerEditUnit == 0 )
471 m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
473 m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
481 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
482 const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition,
483 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
486 AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
487 AddEssenceDescriptor(WrappingUL);
489 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
491 if ( KM_SUCCESS(result) )
492 result = CreateBodyPart(EditRate, BytesPerEditUnit);
498 // standard method of writing a plaintext or encrypted frame
500 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
501 AESEncContext* Ctx, HMACContext* HMAC)
503 Result_t result = RESULT_OK;
504 IntegrityPack IntPack;
506 byte_t overhead[128];
507 Kumu::MemIOWriter Overhead(overhead, 128);
510 if ( FrameBuf.Size() == 0 )
512 DefaultLogSink().Error("Cannot write empty frame buffer\n");
513 return RESULT_EMPTY_FB;
516 if ( m_Info.EncryptedEssence )
519 return RESULT_CRYPT_CTX;
521 if ( m_Info.UsesHMAC && ! HMAC )
522 return RESULT_HMAC_CTX;
524 if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
525 return RESULT_LARGE_PTO;
527 // encrypt the essence data (create encrypted source value)
528 result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
531 if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
532 result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
534 if ( ASDCP_SUCCESS(result) )
536 Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
538 // construct encrypted triplet header
539 ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
540 ui32_t BER_length = MXF_BER_LENGTH;
542 if ( m_Info.UsesHMAC )
543 ETLength += klv_intpack_size;
545 ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
547 if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
549 BER_length = Kumu::get_BER_length_for_value(ETLength);
551 // the packet is longer by the difference in expected vs. actual BER length
552 ETLength += BER_length - MXF_BER_LENGTH;
554 if ( BER_length == 0 )
555 result = RESULT_KLV_CODING;
558 if ( ASDCP_SUCCESS(result) )
560 if ( ! ( Overhead.WriteBER(ETLength, BER_length) // write encrypted triplet length
561 && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH) // write ContextID length
562 && Overhead.WriteRaw(m_Info.ContextID, UUIDlen) // write ContextID
563 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write PlaintextOffset length
564 && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()) // write PlaintextOffset
565 && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH) // write essence UL length
566 && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH) // write the essence UL
567 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write SourceLength length
568 && Overhead.WriteUi64BE(FrameBuf.Size()) // write SourceLength
569 && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) ) // write ESV length
571 result = RESULT_KLV_CODING;
575 if ( ASDCP_SUCCESS(result) )
576 result = m_File.Writev(Overhead.Data(), Overhead.Length());
579 if ( ASDCP_SUCCESS(result) )
581 m_StreamOffset += Overhead.Length();
582 // write encrypted source value
583 result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
586 if ( ASDCP_SUCCESS(result) )
588 m_StreamOffset += m_CtFrameBuf.Size();
590 byte_t hmoverhead[512];
591 Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
594 if ( m_Info.UsesHMAC )
596 HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
599 { // we still need the var-pack length values if the intpack is empty
600 for ( ui32_t i = 0; i < 3 ; i++ )
601 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
605 result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
606 m_StreamOffset += HMACOverhead.Length();
611 ui32_t BER_length = MXF_BER_LENGTH;
613 if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
615 BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
617 if ( BER_length == 0 )
618 result = RESULT_KLV_CODING;
621 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
622 Overhead.WriteBER(FrameBuf.Size(), BER_length);
624 if ( ASDCP_SUCCESS(result) )
625 result = m_File.Writev(Overhead.Data(), Overhead.Length());
627 if ( ASDCP_SUCCESS(result) )
628 result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
630 if ( ASDCP_SUCCESS(result) )
631 m_StreamOffset += Overhead.Length() + FrameBuf.Size();
634 if ( ASDCP_SUCCESS(result) )
635 result = m_File.Writev();
641 // standard method of writing the header and footer of a completed MXF file
644 ASDCP::h__Writer::WriteMXFFooter()
646 // Set top-level file package correctly for OP-Atom
648 // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
649 // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
651 DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
653 for (; dli != m_DurationUpdateList.end(); dli++ )
654 **dli = m_FramesWritten;
656 m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
657 m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
659 Kumu::fpos_t here = m_File.Tell();
660 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
661 m_HeaderPart.FooterPartition = here;
664 // re-label the partition
665 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
666 m_HeaderPart.OperationalPattern = OPAtomUL;
667 m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
669 m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
670 m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
671 m_FooterPart.FooterPartition = here;
672 m_FooterPart.ThisPartition = here;
674 Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
676 if ( ASDCP_SUCCESS(result) )
677 result = m_HeaderPart.m_RIP.WriteToFile(m_File);
679 if ( ASDCP_SUCCESS(result) )
680 result = m_File.Seek(0);
682 if ( ASDCP_SUCCESS(result) )
683 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);