2 Copyright (c) 2004-2012, 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
28 \version $Id: h__Writer.cpp,v 1.51 2012/02/07 18:54:25 jhurst Exp $
29 \brief MXF file writer base class
32 #include "AS_DCP_internal.h"
36 using namespace ASDCP;
37 using namespace ASDCP::MXF;
39 // a magic number identifying asdcplib
40 #ifndef ASDCP_BUILD_NUMBER
41 #define ASDCP_BUILD_NUMBER 0x6A68
45 static std::vector<int>
46 version_split(const char* str)
48 std::vector<int> result;
50 const char* pstr = str;
51 const char* r = strchr(pstr, '.');
57 result.push_back(atoi(pstr));
60 r = strchr(pstr, '.');
63 if( strlen(pstr) > 0 )
64 result.push_back(atoi(pstr));
66 assert(result.size() == 3);
72 ASDCP::h__Writer::h__Writer(const Dictionary& d) :
73 m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict),
74 m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_EssenceStart(0),
75 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
77 default_md_object_init();
80 ASDCP::h__Writer::~h__Writer()
85 // add DMS CryptographicFramework entry to source package
87 AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
88 WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
92 StaticTrack* NewTrack = new StaticTrack(Dict);
93 HeaderPart.AddChildObject(NewTrack);
94 Package.Tracks.push_back(NewTrack->InstanceUID);
95 NewTrack->TrackName = "Descriptive Track";
96 NewTrack->TrackID = 3;
98 Sequence* Seq = new Sequence(Dict);
99 HeaderPart.AddChildObject(Seq);
100 NewTrack->Sequence = Seq->InstanceUID;
101 Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
103 DMSegment* Segment = new DMSegment(Dict);
104 HeaderPart.AddChildObject(Segment);
105 Seq->StructuralComponents.push_back(Segment->InstanceUID);
106 Segment->EventComment = "AS-DCP KLV Encryption";
108 CryptographicFramework* CFW = new CryptographicFramework(Dict);
109 HeaderPart.AddChildObject(CFW);
110 Segment->DMFramework = CFW->InstanceUID;
112 CryptographicContext* Context = new CryptographicContext(Dict);
113 HeaderPart.AddChildObject(Context);
114 CFW->ContextSR = Context->InstanceUID;
116 Context->ContextID.Set(Descr.ContextID);
117 Context->SourceEssenceContainer = WrappingUL; // ??????
118 Context->CipherAlgorithm.Set(Dict->ul(MDD_CipherAlgorithm_AES));
119 Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict->ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict->ul(MDD_MICAlgorithm_NONE) );
120 Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
125 ASDCP::h__Writer::InitHeader()
128 assert(m_EssenceDescriptor);
130 m_HeaderPart.m_Primer.ClearTagList();
131 m_HeaderPart.m_Preface = new Preface(m_Dict);
132 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
134 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
135 // so we tell the world by using OP1a
136 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
137 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
140 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
141 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
143 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
148 Identification* Ident = new Identification(m_Dict);
149 m_HeaderPart.AddChildObject(Ident);
150 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
152 Kumu::GenRandomValue(Ident->ThisGenerationUID);
153 Ident->CompanyName = m_Info.CompanyName.c_str();
154 Ident->ProductName = m_Info.ProductName.c_str();
155 Ident->VersionString = m_Info.ProductVersion.c_str();
156 Ident->ProductUID.Set(m_Info.ProductUUID);
157 Ident->Platform = ASDCP_PLATFORM;
159 std::vector<int> version = version_split(Version());
161 Ident->ToolkitVersion.Major = version[0];
162 Ident->ToolkitVersion.Minor = version[1];
163 Ident->ToolkitVersion.Patch = version[2];
164 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
165 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
169 template <class ClipT>
173 MXF::Sequence* Sequence;
176 TrackSet() : Track(0), Sequence(0), Clip(0) {}
180 template <class PackageT, class ClipT>
182 CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
183 const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
185 TrackSet<ClipT> NewTrack;
187 NewTrack.Track = new Track(Dict);
188 Header.AddChildObject(NewTrack.Track);
189 NewTrack.Track->EditRate = EditRate;
190 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
191 NewTrack.Track->TrackID = TrackID;
192 NewTrack.Track->TrackName = TrackName.c_str();
194 NewTrack.Sequence = new Sequence(Dict);
195 Header.AddChildObject(NewTrack.Sequence);
196 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
197 NewTrack.Sequence->DataDefinition = Definition;
203 template <class PackageT>
204 TrackSet<TimecodeComponent>
205 CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
206 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict)
209 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
211 TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
213 NewTrack.Clip = new TimecodeComponent(Dict);
214 Header.AddChildObject(NewTrack.Clip);
215 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
216 NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
217 NewTrack.Clip->StartTimecode = TCStart;
218 NewTrack.Clip->DataDefinition = TCUL;
226 ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
227 const std::string& TrackName, const UL& EssenceUL,
228 const UL& DataDefinition, const std::string& PackageLabel)
231 ContentStorage* Storage = new ContentStorage(m_Dict);
232 m_HeaderPart.AddChildObject(Storage);
233 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
235 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
236 m_HeaderPart.AddChildObject(ECD);
237 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
241 UUID assetUUID(m_Info.AssetUUID);
242 UMID SourcePackageUMID, MaterialPackageUMID;
243 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
244 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
249 m_MaterialPackage = new MaterialPackage(m_Dict);
250 m_MaterialPackage->Name = "AS-DCP Material Package";
251 m_MaterialPackage->PackageUID = MaterialPackageUMID;
252 m_HeaderPart.AddChildObject(m_MaterialPackage);
253 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
255 TrackSet<TimecodeComponent> MPTCTrack =
256 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
257 EditRate, TCFrameRate, 0, m_Dict);
258 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
259 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
261 TrackSet<SourceClip> MPTrack =
262 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
263 TrackName, EditRate, DataDefinition,
265 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
267 MPTrack.Clip = new SourceClip(m_Dict);
268 m_HeaderPart.AddChildObject(MPTrack.Clip);
269 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
270 MPTrack.Clip->DataDefinition = DataDefinition;
271 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
272 MPTrack.Clip->SourceTrackID = 2;
273 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
277 // File (Source) Package
279 m_FilePackage = new SourcePackage(m_Dict);
280 m_FilePackage->Name = PackageLabel.c_str();
281 m_FilePackage->PackageUID = SourcePackageUMID;
282 ECD->LinkedPackageUID = SourcePackageUMID;
284 m_HeaderPart.AddChildObject(m_FilePackage);
285 Storage->Packages.push_back(m_FilePackage->InstanceUID);
287 TrackSet<TimecodeComponent> FPTCTrack =
288 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
289 EditRate, TCFrameRate,
290 ui64_C(3600) * TCFrameRate, m_Dict);
291 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
292 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
293 TrackSet<SourceClip> FPTrack =
294 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
295 TrackName, EditRate, DataDefinition,
297 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
299 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
300 FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
302 FPTrack.Clip = new SourceClip(m_Dict);
303 m_HeaderPart.AddChildObject(FPTrack.Clip);
304 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
305 FPTrack.Clip->DataDefinition = DataDefinition;
307 // for now we do not allow setting this value, so all files will be 'original'
308 FPTrack.Clip->SourceTrackID = 0;
309 FPTrack.Clip->SourcePackageID = NilUMID;
310 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
312 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
317 ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
318 const std::string& TrackName, const UL& DataDefinition,
319 const std::string& PackageLabel)
322 ContentStorage* Storage = new ContentStorage(m_Dict);
323 m_HeaderPart.AddChildObject(Storage);
324 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
326 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
327 m_HeaderPart.AddChildObject(ECD);
328 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
332 UUID assetUUID(m_Info.AssetUUID);
333 UMID SourcePackageUMID, MaterialPackageUMID;
334 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
335 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
340 m_MaterialPackage = new MaterialPackage(m_Dict);
341 m_MaterialPackage->Name = "AS-DCP Material Package";
342 m_MaterialPackage->PackageUID = MaterialPackageUMID;
343 m_HeaderPart.AddChildObject(m_MaterialPackage);
344 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
346 TrackSet<TimecodeComponent> MPTCTrack =
347 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
348 EditRate, TCFrameRate, 0, m_Dict);
349 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
350 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
352 TrackSet<DMSegment> MPTrack =
353 CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
354 TrackName, EditRate, DataDefinition,
356 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
358 MPTrack.Clip = new DMSegment(m_Dict);
359 m_HeaderPart.AddChildObject(MPTrack.Clip);
360 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
361 MPTrack.Clip->DataDefinition = DataDefinition;
362 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
363 // MPTrack.Clip->SourceTrackID = 2;
364 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
368 // File (Source) Package
370 m_FilePackage = new SourcePackage(m_Dict);
371 m_FilePackage->Name = PackageLabel.c_str();
372 m_FilePackage->PackageUID = SourcePackageUMID;
373 ECD->LinkedPackageUID = SourcePackageUMID;
375 m_HeaderPart.AddChildObject(m_FilePackage);
376 Storage->Packages.push_back(m_FilePackage->InstanceUID);
378 TrackSet<TimecodeComponent> FPTCTrack =
379 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
380 EditRate, TCFrameRate,
381 ui64_C(3600) * TCFrameRate, m_Dict);
382 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
383 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
385 TrackSet<DMSegment> FPTrack =
386 CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
387 TrackName, EditRate, DataDefinition,
389 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
391 FPTrack.Clip = new DMSegment(m_Dict);
392 m_HeaderPart.AddChildObject(FPTrack.Clip);
393 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
394 FPTrack.Clip->DataDefinition = DataDefinition;
395 FPTrack.Clip->EventComment = "D-Cinema Timed Text";
397 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
398 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
403 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
406 // Essence Descriptor
408 m_EssenceDescriptor->EssenceContainer = WrappingUL;
409 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
412 // Essence Descriptors
415 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
416 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
418 if ( m_Info.EncryptedEssence )
420 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
421 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
422 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
423 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
427 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
430 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
431 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
433 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
434 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
435 m_HeaderPart.AddChildObject(*sdli);
437 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
442 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
445 Result_t result = RESULT_OK;
447 // create a body partition if we're writing proper 429-3/OP-Atom
448 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
451 m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
452 m_BodyPart.ThisPartition = m_File.Tell();
453 m_BodyPart.BodySID = 1;
454 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
455 m_BodyPart.OperationalPattern = OPAtomUL;
456 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
458 UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
459 result = m_BodyPart.WriteToFile(m_File, BodyUL);
463 m_HeaderPart.BodySID = 1;
466 if ( ASDCP_SUCCESS(result) )
469 Kumu::fpos_t ECoffset = m_File.Tell();
470 m_FooterPart.IndexSID = 129;
472 if ( BytesPerEditUnit == 0 )
473 m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
475 m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
483 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
484 const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition,
485 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
488 AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
489 AddEssenceDescriptor(WrappingUL);
491 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
493 if ( KM_SUCCESS(result) )
494 result = CreateBodyPart(EditRate, BytesPerEditUnit);
500 // standard method of writing a plaintext or encrypted frame
502 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
503 AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
505 Result_t result = RESULT_OK;
506 IntegrityPack IntPack;
508 m_File.StartHashing();
510 byte_t overhead[128];
511 Kumu::MemIOWriter Overhead(overhead, 128);
514 if ( FrameBuf.Size() == 0 )
516 DefaultLogSink().Error("Cannot write empty frame buffer\n");
517 return RESULT_EMPTY_FB;
520 if ( m_Info.EncryptedEssence )
523 return RESULT_CRYPT_CTX;
525 if ( m_Info.UsesHMAC && ! HMAC )
526 return RESULT_HMAC_CTX;
528 if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
529 return RESULT_LARGE_PTO;
531 // encrypt the essence data (create encrypted source value)
532 result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
535 if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
536 result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
538 if ( ASDCP_SUCCESS(result) )
540 Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
542 // construct encrypted triplet header
543 ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
544 ui32_t BER_length = MXF_BER_LENGTH;
546 if ( m_Info.UsesHMAC )
547 ETLength += klv_intpack_size;
549 ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
551 if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
553 BER_length = Kumu::get_BER_length_for_value(ETLength);
555 // the packet is longer by the difference in expected vs. actual BER length
556 ETLength += BER_length - MXF_BER_LENGTH;
558 if ( BER_length == 0 )
559 result = RESULT_KLV_CODING;
562 if ( ASDCP_SUCCESS(result) )
564 if ( ! ( Overhead.WriteBER(ETLength, BER_length) // write encrypted triplet length
565 && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH) // write ContextID length
566 && Overhead.WriteRaw(m_Info.ContextID, UUIDlen) // write ContextID
567 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write PlaintextOffset length
568 && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()) // write PlaintextOffset
569 && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH) // write essence UL length
570 && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH) // write the essence UL
571 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write SourceLength length
572 && Overhead.WriteUi64BE(FrameBuf.Size()) // write SourceLength
573 && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) ) // write ESV length
575 result = RESULT_KLV_CODING;
579 if ( ASDCP_SUCCESS(result) )
580 result = m_File.Writev(Overhead.Data(), Overhead.Length());
583 if ( ASDCP_SUCCESS(result) )
585 m_StreamOffset += Overhead.Length();
586 // write encrypted source value
587 result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
590 if ( ASDCP_SUCCESS(result) )
592 m_StreamOffset += m_CtFrameBuf.Size();
594 byte_t hmoverhead[512];
595 Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
598 if ( m_Info.UsesHMAC )
600 HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
603 { // we still need the var-pack length values if the intpack is empty
604 for ( ui32_t i = 0; i < 3 ; i++ )
605 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
609 result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
610 m_StreamOffset += HMACOverhead.Length();
615 ui32_t BER_length = MXF_BER_LENGTH;
617 if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
619 BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
621 if ( BER_length == 0 )
622 result = RESULT_KLV_CODING;
625 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
626 Overhead.WriteBER(FrameBuf.Size(), BER_length);
628 if ( ASDCP_SUCCESS(result) )
629 result = m_File.Writev(Overhead.Data(), Overhead.Length());
631 if ( ASDCP_SUCCESS(result) )
632 result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
634 if ( ASDCP_SUCCESS(result) )
635 m_StreamOffset += Overhead.Length() + FrameBuf.Size();
638 if ( ASDCP_SUCCESS(result) )
639 result = m_File.Writev();
642 *hash = m_File.StopHashing();
649 ASDCP::h__Writer::FakeWriteEKLVPacket(int size)
651 Result_t result = RESULT_OK;
653 m_StreamOffset += size;
654 m_File.Seek(size, Kumu::SP_POS);
660 // standard method of writing the header and footer of a completed MXF file
663 ASDCP::h__Writer::WriteMXFFooter()
665 // Set top-level file package correctly for OP-Atom
667 // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
668 // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
670 DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
672 for (; dli != m_DurationUpdateList.end(); dli++ )
673 **dli = m_FramesWritten;
675 m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
676 m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
678 Kumu::fpos_t here = m_File.Tell();
679 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
680 m_HeaderPart.FooterPartition = here;
683 // re-label the partition
684 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
685 m_HeaderPart.OperationalPattern = OPAtomUL;
686 m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
688 m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
689 m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
690 m_FooterPart.FooterPartition = here;
691 m_FooterPart.ThisPartition = here;
693 Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
695 if ( ASDCP_SUCCESS(result) )
696 result = m_HeaderPart.m_RIP.WriteToFile(m_File);
698 if ( ASDCP_SUCCESS(result) )
699 result = m_File.Seek(0);
701 if ( ASDCP_SUCCESS(result) )
702 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);