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"
37 using namespace ASDCP;
38 using namespace ASDCP::MXF;
40 // a magic number identifying asdcplib
41 #ifndef ASDCP_BUILD_NUMBER
42 #define ASDCP_BUILD_NUMBER 0x6A68
46 static std::vector<int>
47 version_split(const char* str)
49 std::vector<int> result;
51 const char* pstr = str;
52 const char* r = strchr(pstr, '.');
58 result.push_back(atoi(pstr));
61 r = strchr(pstr, '.');
64 if( strlen(pstr) > 0 )
65 result.push_back(atoi(pstr));
67 assert(result.size() == 3);
73 ASDCP::h__Writer::h__Writer(const Dictionary& d) :
74 m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict),
75 m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_EssenceStart(0),
76 m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
78 default_md_object_init();
81 ASDCP::h__Writer::~h__Writer()
86 // add DMS CryptographicFramework entry to source package
88 AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
89 WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
93 StaticTrack* NewTrack = new StaticTrack(Dict);
94 HeaderPart.AddChildObject(NewTrack);
95 Package.Tracks.push_back(NewTrack->InstanceUID);
96 NewTrack->TrackName = "Descriptive Track";
97 NewTrack->TrackID = 3;
99 Sequence* Seq = new Sequence(Dict);
100 HeaderPart.AddChildObject(Seq);
101 NewTrack->Sequence = Seq->InstanceUID;
102 Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
104 DMSegment* Segment = new DMSegment(Dict);
105 HeaderPart.AddChildObject(Segment);
106 Seq->StructuralComponents.push_back(Segment->InstanceUID);
107 Segment->EventComment = "AS-DCP KLV Encryption";
109 CryptographicFramework* CFW = new CryptographicFramework(Dict);
110 HeaderPart.AddChildObject(CFW);
111 Segment->DMFramework = CFW->InstanceUID;
113 CryptographicContext* Context = new CryptographicContext(Dict);
114 HeaderPart.AddChildObject(Context);
115 CFW->ContextSR = Context->InstanceUID;
117 Context->ContextID.Set(Descr.ContextID);
118 Context->SourceEssenceContainer = WrappingUL; // ??????
119 Context->CipherAlgorithm.Set(Dict->ul(MDD_CipherAlgorithm_AES));
120 Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict->ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict->ul(MDD_MICAlgorithm_NONE) );
121 Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
126 ASDCP::h__Writer::InitHeader()
129 assert(m_EssenceDescriptor);
131 m_HeaderPart.m_Primer.ClearTagList();
132 m_HeaderPart.m_Preface = new Preface(m_Dict);
133 m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
135 // Set the Operational Pattern label -- we're just starting and have no RIP or index,
136 // so we tell the world by using OP1a
137 m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
138 m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
141 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
142 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
144 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
149 Identification* Ident = new Identification(m_Dict);
150 m_HeaderPart.AddChildObject(Ident);
151 m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
153 Kumu::GenRandomValue(Ident->ThisGenerationUID);
154 Ident->CompanyName = m_Info.CompanyName.c_str();
155 Ident->ProductName = m_Info.ProductName.c_str();
156 Ident->VersionString = m_Info.ProductVersion.c_str();
157 Ident->ProductUID.Set(m_Info.ProductUUID);
158 Ident->Platform = ASDCP_PLATFORM;
160 std::vector<int> version = version_split(Version());
162 Ident->ToolkitVersion.Major = version[0];
163 Ident->ToolkitVersion.Minor = version[1];
164 Ident->ToolkitVersion.Patch = version[2];
165 Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
166 Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
170 template <class ClipT>
174 MXF::Sequence* Sequence;
177 TrackSet() : Track(0), Sequence(0), Clip(0) {}
181 template <class PackageT, class ClipT>
183 CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
184 const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
186 TrackSet<ClipT> NewTrack;
188 NewTrack.Track = new Track(Dict);
189 Header.AddChildObject(NewTrack.Track);
190 NewTrack.Track->EditRate = EditRate;
191 Package.Tracks.push_back(NewTrack.Track->InstanceUID);
192 NewTrack.Track->TrackID = TrackID;
193 NewTrack.Track->TrackName = TrackName.c_str();
195 NewTrack.Sequence = new Sequence(Dict);
196 Header.AddChildObject(NewTrack.Sequence);
197 NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
198 NewTrack.Sequence->DataDefinition = Definition;
204 template <class PackageT>
205 TrackSet<TimecodeComponent>
206 CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
207 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict)
210 UL TCUL(Dict->ul(MDD_TimecodeDataDef));
212 TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
214 NewTrack.Clip = new TimecodeComponent(Dict);
215 Header.AddChildObject(NewTrack.Clip);
216 NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
217 NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
218 NewTrack.Clip->StartTimecode = TCStart;
219 NewTrack.Clip->DataDefinition = TCUL;
227 ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
228 const std::string& TrackName, const UL& EssenceUL,
229 const UL& DataDefinition, const std::string& PackageLabel)
232 ContentStorage* Storage = new ContentStorage(m_Dict);
233 m_HeaderPart.AddChildObject(Storage);
234 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
236 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
237 m_HeaderPart.AddChildObject(ECD);
238 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
242 UUID assetUUID(m_Info.AssetUUID);
243 UMID SourcePackageUMID, MaterialPackageUMID;
244 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
245 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
250 m_MaterialPackage = new MaterialPackage(m_Dict);
251 m_MaterialPackage->Name = "AS-DCP Material Package";
252 m_MaterialPackage->PackageUID = MaterialPackageUMID;
253 m_HeaderPart.AddChildObject(m_MaterialPackage);
254 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
256 TrackSet<TimecodeComponent> MPTCTrack =
257 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
258 EditRate, TCFrameRate, 0, m_Dict);
259 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
260 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
262 TrackSet<SourceClip> MPTrack =
263 CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
264 TrackName, EditRate, DataDefinition,
266 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
268 MPTrack.Clip = new SourceClip(m_Dict);
269 m_HeaderPart.AddChildObject(MPTrack.Clip);
270 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
271 MPTrack.Clip->DataDefinition = DataDefinition;
272 MPTrack.Clip->SourcePackageID = SourcePackageUMID;
273 MPTrack.Clip->SourceTrackID = 2;
274 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
278 // File (Source) Package
280 m_FilePackage = new SourcePackage(m_Dict);
281 m_FilePackage->Name = PackageLabel.c_str();
282 m_FilePackage->PackageUID = SourcePackageUMID;
283 ECD->LinkedPackageUID = SourcePackageUMID;
285 m_HeaderPart.AddChildObject(m_FilePackage);
286 Storage->Packages.push_back(m_FilePackage->InstanceUID);
288 TrackSet<TimecodeComponent> FPTCTrack =
289 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
290 EditRate, TCFrameRate,
291 ui64_C(3600) * TCFrameRate, m_Dict);
292 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
293 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
294 TrackSet<SourceClip> FPTrack =
295 CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
296 TrackName, EditRate, DataDefinition,
298 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
300 // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
301 FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
303 FPTrack.Clip = new SourceClip(m_Dict);
304 m_HeaderPart.AddChildObject(FPTrack.Clip);
305 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
306 FPTrack.Clip->DataDefinition = DataDefinition;
308 // for now we do not allow setting this value, so all files will be 'original'
309 FPTrack.Clip->SourceTrackID = 0;
310 FPTrack.Clip->SourcePackageID = NilUMID;
311 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
313 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
318 ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
319 const std::string& TrackName, const UL& DataDefinition,
320 const std::string& PackageLabel)
323 ContentStorage* Storage = new ContentStorage(m_Dict);
324 m_HeaderPart.AddChildObject(Storage);
325 m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
327 EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
328 m_HeaderPart.AddChildObject(ECD);
329 Storage->EssenceContainerData.push_back(ECD->InstanceUID);
333 UUID assetUUID(m_Info.AssetUUID);
334 UMID SourcePackageUMID, MaterialPackageUMID;
335 SourcePackageUMID.MakeUMID(0x0f, assetUUID);
336 MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
341 m_MaterialPackage = new MaterialPackage(m_Dict);
342 m_MaterialPackage->Name = "AS-DCP Material Package";
343 m_MaterialPackage->PackageUID = MaterialPackageUMID;
344 m_HeaderPart.AddChildObject(m_MaterialPackage);
345 Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
347 TrackSet<TimecodeComponent> MPTCTrack =
348 CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
349 EditRate, TCFrameRate, 0, m_Dict);
350 m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
351 m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
353 TrackSet<DMSegment> MPTrack =
354 CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
355 TrackName, EditRate, DataDefinition,
357 m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
359 MPTrack.Clip = new DMSegment(m_Dict);
360 m_HeaderPart.AddChildObject(MPTrack.Clip);
361 MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
362 MPTrack.Clip->DataDefinition = DataDefinition;
363 // MPTrack.Clip->SourcePackageID = SourcePackageUMID;
364 // MPTrack.Clip->SourceTrackID = 2;
365 m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
369 // File (Source) Package
371 m_FilePackage = new SourcePackage(m_Dict);
372 m_FilePackage->Name = PackageLabel.c_str();
373 m_FilePackage->PackageUID = SourcePackageUMID;
374 ECD->LinkedPackageUID = SourcePackageUMID;
376 m_HeaderPart.AddChildObject(m_FilePackage);
377 Storage->Packages.push_back(m_FilePackage->InstanceUID);
379 TrackSet<TimecodeComponent> FPTCTrack =
380 CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
381 EditRate, TCFrameRate,
382 ui64_C(3600) * TCFrameRate, m_Dict);
383 m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
384 m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
386 TrackSet<DMSegment> FPTrack =
387 CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
388 TrackName, EditRate, DataDefinition,
390 m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
392 FPTrack.Clip = new DMSegment(m_Dict);
393 m_HeaderPart.AddChildObject(FPTrack.Clip);
394 FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
395 FPTrack.Clip->DataDefinition = DataDefinition;
396 FPTrack.Clip->EventComment = "D-Cinema Timed Text";
398 m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
399 m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
404 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
407 // Essence Descriptor
409 m_EssenceDescriptor->EssenceContainer = WrappingUL;
410 m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
413 // Essence Descriptors
416 UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
417 m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
419 if ( m_Info.EncryptedEssence )
421 UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
422 m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
423 m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
424 AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
428 m_HeaderPart.EssenceContainers.push_back(WrappingUL);
431 m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
432 m_HeaderPart.AddChildObject(m_EssenceDescriptor);
434 std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
435 for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
436 m_HeaderPart.AddChildObject(*sdli);
438 m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
443 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
446 Result_t result = RESULT_OK;
448 // create a body partition if we're writing proper 429-3/OP-Atom
449 if ( m_Info.LabelSetType == LS_MXF_SMPTE )
452 m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
453 m_BodyPart.ThisPartition = m_File.Tell();
454 m_BodyPart.BodySID = 1;
455 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
456 m_BodyPart.OperationalPattern = OPAtomUL;
457 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
459 UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
460 result = m_BodyPart.WriteToFile(m_File, BodyUL);
464 m_HeaderPart.BodySID = 1;
467 if ( ASDCP_SUCCESS(result) )
470 Kumu::fpos_t ECoffset = m_File.Tell();
471 m_FooterPart.IndexSID = 129;
473 if ( BytesPerEditUnit == 0 )
474 m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
476 m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
484 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
485 const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition,
486 const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
489 AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
490 AddEssenceDescriptor(WrappingUL);
492 Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
494 if ( KM_SUCCESS(result) )
495 result = CreateBodyPart(EditRate, BytesPerEditUnit);
501 // standard method of writing a plaintext or encrypted frame
503 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
504 AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
506 Result_t result = RESULT_OK;
507 IntegrityPack IntPack;
509 m_File.StartHashing();
511 byte_t overhead[128];
512 Kumu::MemIOWriter Overhead(overhead, 128);
515 if ( FrameBuf.Size() == 0 )
517 DefaultLogSink().Error("Cannot write empty frame buffer\n");
518 return RESULT_EMPTY_FB;
521 if ( m_Info.EncryptedEssence )
524 return RESULT_CRYPT_CTX;
526 if ( m_Info.UsesHMAC && ! HMAC )
527 return RESULT_HMAC_CTX;
529 if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
530 return RESULT_LARGE_PTO;
532 // encrypt the essence data (create encrypted source value)
533 result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
536 if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
537 result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
539 if ( ASDCP_SUCCESS(result) )
541 Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
543 // construct encrypted triplet header
544 ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
545 ui32_t BER_length = MXF_BER_LENGTH;
547 if ( m_Info.UsesHMAC )
548 ETLength += klv_intpack_size;
550 ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
552 if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
554 BER_length = Kumu::get_BER_length_for_value(ETLength);
556 // the packet is longer by the difference in expected vs. actual BER length
557 ETLength += BER_length - MXF_BER_LENGTH;
559 if ( BER_length == 0 )
560 result = RESULT_KLV_CODING;
563 if ( ASDCP_SUCCESS(result) )
565 if ( ! ( Overhead.WriteBER(ETLength, BER_length) // write encrypted triplet length
566 && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH) // write ContextID length
567 && Overhead.WriteRaw(m_Info.ContextID, UUIDlen) // write ContextID
568 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write PlaintextOffset length
569 && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset()) // write PlaintextOffset
570 && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH) // write essence UL length
571 && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH) // write the essence UL
572 && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH) // write SourceLength length
573 && Overhead.WriteUi64BE(FrameBuf.Size()) // write SourceLength
574 && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) ) // write ESV length
576 result = RESULT_KLV_CODING;
580 if ( ASDCP_SUCCESS(result) )
581 result = m_File.Writev(Overhead.Data(), Overhead.Length());
584 if ( ASDCP_SUCCESS(result) )
586 m_StreamOffset += Overhead.Length();
587 // write encrypted source value
588 result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
591 if ( ASDCP_SUCCESS(result) )
593 m_StreamOffset += m_CtFrameBuf.Size();
595 byte_t hmoverhead[512];
596 Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
599 if ( m_Info.UsesHMAC )
601 HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
604 { // we still need the var-pack length values if the intpack is empty
605 for ( ui32_t i = 0; i < 3 ; i++ )
606 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
610 result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
611 m_StreamOffset += HMACOverhead.Length();
616 ui32_t BER_length = MXF_BER_LENGTH;
618 if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
620 BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
622 if ( BER_length == 0 )
623 result = RESULT_KLV_CODING;
626 Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
627 Overhead.WriteBER(FrameBuf.Size(), BER_length);
629 if ( ASDCP_SUCCESS(result) )
630 result = m_File.Writev(Overhead.Data(), Overhead.Length());
632 if ( ASDCP_SUCCESS(result) )
633 result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
635 if ( ASDCP_SUCCESS(result) )
636 m_StreamOffset += Overhead.Length() + FrameBuf.Size();
639 if ( ASDCP_SUCCESS(result) )
640 result = m_File.Writev();
643 *hash = m_File.StopHashing();
650 ASDCP::h__Writer::FakeWriteEKLVPacket(int size)
652 Result_t result = RESULT_OK;
654 m_StreamOffset += size;
655 m_File.Seek(size, Kumu::SP_POS);
661 // standard method of writing the header and footer of a completed MXF file
664 ASDCP::h__Writer::WriteMXFFooter()
666 // Set top-level file package correctly for OP-Atom
668 // m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration =
669 // m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration =
671 DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
673 for (; dli != m_DurationUpdateList.end(); dli++ )
674 **dli = m_FramesWritten;
676 m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
677 m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
679 Kumu::fpos_t here = m_File.Tell();
680 m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
681 m_HeaderPart.FooterPartition = here;
684 // re-label the partition
685 UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
686 m_HeaderPart.OperationalPattern = OPAtomUL;
687 m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
689 m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
690 m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
691 m_FooterPart.FooterPartition = here;
692 m_FooterPart.ThisPartition = here;
694 Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
696 if ( ASDCP_SUCCESS(result) )
697 result = m_HeaderPart.m_RIP.WriteToFile(m_File);
699 if ( ASDCP_SUCCESS(result) )
700 result = m_File.Seek(0);
702 if ( ASDCP_SUCCESS(result) )
703 result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);