Fix ADSCP warnings.
[libdcp.git] / asdcplib / src / h__Writer.cpp
1 /*
2 Copyright (c) 2004-2012, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
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.
15
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.
26 */
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
30 */
31
32 #include "AS_DCP_internal.h"
33 #include "KLV.h"
34
35 using namespace ASDCP;
36 using namespace ASDCP::MXF;
37
38 // a magic number identifying asdcplib
39 #ifndef ASDCP_BUILD_NUMBER
40 #define ASDCP_BUILD_NUMBER 0x6A68
41 #endif
42
43
44 static std::vector<int>
45 version_split(const char* str)
46 {
47   std::vector<int> result;
48
49   const char* pstr = str;
50   const char* r = strchr(pstr, '.');
51
52   while ( r != 0 )
53     {
54       assert(r >= pstr);
55       if ( r > pstr )
56         result.push_back(atoi(pstr));
57
58       pstr = r + 1;
59       r = strchr(pstr, '.');
60     }
61
62   if( strlen(pstr) > 0 )
63     result.push_back(atoi(pstr));
64
65   assert(result.size() == 3);
66   return result;
67 }
68
69
70 //
71 ASDCP::h__Writer::h__Writer(const Dictionary& d) :
72   m_Dict(&d), m_HeaderSize(0), m_HeaderPart(m_Dict),
73   m_BodyPart(m_Dict), m_FooterPart(m_Dict), m_EssenceStart(0),
74   m_EssenceDescriptor(0), m_FramesWritten(0), m_StreamOffset(0)
75 {
76   default_md_object_init();
77 }
78
79 ASDCP::h__Writer::~h__Writer()
80 {
81 }
82
83 //
84 // add DMS CryptographicFramework entry to source package
85 void
86 AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
87             WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
88 {
89   assert(Dict);
90   // Essence Track
91   StaticTrack* NewTrack = new StaticTrack(Dict);
92   HeaderPart.AddChildObject(NewTrack);
93   Package.Tracks.push_back(NewTrack->InstanceUID);
94   NewTrack->TrackName = "Descriptive Track";
95   NewTrack->TrackID = 3;
96
97   Sequence* Seq = new Sequence(Dict);
98   HeaderPart.AddChildObject(Seq);
99   NewTrack->Sequence = Seq->InstanceUID;
100   Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
101
102   DMSegment* Segment = new DMSegment(Dict);
103   HeaderPart.AddChildObject(Segment);
104   Seq->StructuralComponents.push_back(Segment->InstanceUID);
105   Segment->EventComment = "AS-DCP KLV Encryption";
106   
107   CryptographicFramework* CFW = new CryptographicFramework(Dict);
108   HeaderPart.AddChildObject(CFW);
109   Segment->DMFramework = CFW->InstanceUID;
110
111   CryptographicContext* Context = new CryptographicContext(Dict);
112   HeaderPart.AddChildObject(Context);
113   CFW->ContextSR = Context->InstanceUID;
114
115   Context->ContextID.Set(Descr.ContextID);
116   Context->SourceEssenceContainer = WrappingUL; // ??????
117   Context->CipherAlgorithm.Set(Dict->ul(MDD_CipherAlgorithm_AES));
118   Context->MICAlgorithm.Set( Descr.UsesHMAC ? Dict->ul(MDD_MICAlgorithm_HMAC_SHA1) : Dict->ul(MDD_MICAlgorithm_NONE) );
119   Context->CryptographicKeyID.Set(Descr.CryptographicKeyID);
120 }
121
122 //
123 void
124 ASDCP::h__Writer::InitHeader()
125 {
126   assert(m_Dict);
127   assert(m_EssenceDescriptor);
128
129   m_HeaderPart.m_Primer.ClearTagList();
130   m_HeaderPart.m_Preface = new Preface(m_Dict);
131   m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
132
133   // Set the Operational Pattern label -- we're just starting and have no RIP or index,
134   // so we tell the world by using OP1a
135   m_HeaderPart.m_Preface->OperationalPattern = UL(m_Dict->ul(MDD_OP1a));
136   m_HeaderPart.OperationalPattern = m_HeaderPart.m_Preface->OperationalPattern;
137
138   // First RIP Entry
139   if ( m_Info.LabelSetType == LS_MXF_SMPTE )
140     m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, 0)); // 3-part, no essence in header
141   else
142     m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
143
144   //
145   // Identification
146   //
147   Identification* Ident = new Identification(m_Dict);
148   m_HeaderPart.AddChildObject(Ident);
149   m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
150
151   Kumu::GenRandomValue(Ident->ThisGenerationUID);
152   Ident->CompanyName = m_Info.CompanyName.c_str();
153   Ident->ProductName = m_Info.ProductName.c_str();
154   Ident->VersionString = m_Info.ProductVersion.c_str();
155   Ident->ProductUID.Set(m_Info.ProductUUID);
156   Ident->Platform = ASDCP_PLATFORM;
157
158   std::vector<int> version = version_split(Version());
159
160   Ident->ToolkitVersion.Major = version[0];
161   Ident->ToolkitVersion.Minor = version[1];
162   Ident->ToolkitVersion.Patch = version[2];
163   Ident->ToolkitVersion.Build = ASDCP_BUILD_NUMBER;
164   Ident->ToolkitVersion.Release = VersionType::RL_RELEASE;
165 }
166
167 //
168 template <class ClipT>
169 struct TrackSet
170 {
171   MXF::Track*    Track;
172   MXF::Sequence* Sequence;
173   ClipT*         Clip;
174
175   TrackSet() : Track(0), Sequence(0), Clip(0) {}
176 };
177
178 //
179 template <class PackageT, class ClipT>
180 TrackSet<ClipT>
181 CreateTrackAndSequence(OPAtomHeader& Header, PackageT& Package, const std::string TrackName,
182                        const MXF::Rational& EditRate, const UL& Definition, ui32_t TrackID, const Dictionary*& Dict)
183 {
184   TrackSet<ClipT> NewTrack;
185
186   NewTrack.Track = new Track(Dict);
187   Header.AddChildObject(NewTrack.Track);
188   NewTrack.Track->EditRate = EditRate;
189   Package.Tracks.push_back(NewTrack.Track->InstanceUID);
190   NewTrack.Track->TrackID = TrackID;
191   NewTrack.Track->TrackName = TrackName.c_str();
192
193   NewTrack.Sequence = new Sequence(Dict);
194   Header.AddChildObject(NewTrack.Sequence);
195   NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
196   NewTrack.Sequence->DataDefinition = Definition;
197
198   return NewTrack;
199 }
200
201 //
202 template <class PackageT>
203 TrackSet<TimecodeComponent>
204 CreateTimecodeTrack(OPAtomHeader& Header, PackageT& Package,
205                     const MXF::Rational& EditRate, ui32_t TCFrameRate, ui64_t TCStart, const Dictionary*& Dict)
206 {
207   assert(Dict);
208   UL TCUL(Dict->ul(MDD_TimecodeDataDef));
209
210   TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
211
212   NewTrack.Clip = new TimecodeComponent(Dict);
213   Header.AddChildObject(NewTrack.Clip);
214   NewTrack.Sequence->StructuralComponents.push_back(NewTrack.Clip->InstanceUID);
215   NewTrack.Clip->RoundedTimecodeBase = TCFrameRate;
216   NewTrack.Clip->StartTimecode = TCStart;
217   NewTrack.Clip->DataDefinition = TCUL;
218
219   return NewTrack;
220 }
221
222
223 //
224 void
225 ASDCP::h__Writer::AddSourceClip(const MXF::Rational& EditRate, ui32_t TCFrameRate,
226                                 const std::string& TrackName, const UL& EssenceUL,
227                                 const UL& DataDefinition, const std::string& PackageLabel)
228 {
229   //
230   ContentStorage* Storage = new ContentStorage(m_Dict);
231   m_HeaderPart.AddChildObject(Storage);
232   m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
233
234   EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
235   m_HeaderPart.AddChildObject(ECD);
236   Storage->EssenceContainerData.push_back(ECD->InstanceUID);
237   ECD->IndexSID = 129;
238   ECD->BodySID = 1;
239
240   UUID assetUUID(m_Info.AssetUUID);
241   UMID SourcePackageUMID, MaterialPackageUMID;
242   SourcePackageUMID.MakeUMID(0x0f, assetUUID);
243   MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
244
245   //
246   // Material Package
247   //
248   m_MaterialPackage = new MaterialPackage(m_Dict);
249   m_MaterialPackage->Name = "AS-DCP Material Package";
250   m_MaterialPackage->PackageUID = MaterialPackageUMID;
251   m_HeaderPart.AddChildObject(m_MaterialPackage);
252   Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
253
254   TrackSet<TimecodeComponent> MPTCTrack =
255     CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
256                                          EditRate, TCFrameRate, 0, m_Dict);
257   m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
258   m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
259
260   TrackSet<SourceClip> MPTrack =
261     CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
262                                                         TrackName, EditRate, DataDefinition,
263                                                         2, m_Dict);
264   m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
265
266   MPTrack.Clip = new SourceClip(m_Dict);
267   m_HeaderPart.AddChildObject(MPTrack.Clip);
268   MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
269   MPTrack.Clip->DataDefinition = DataDefinition;
270   MPTrack.Clip->SourcePackageID = SourcePackageUMID;
271   MPTrack.Clip->SourceTrackID = 2;
272   m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
273
274   
275   //
276   // File (Source) Package
277   //
278   m_FilePackage = new SourcePackage(m_Dict);
279   m_FilePackage->Name = PackageLabel.c_str();
280   m_FilePackage->PackageUID = SourcePackageUMID;
281   ECD->LinkedPackageUID = SourcePackageUMID;
282
283   m_HeaderPart.AddChildObject(m_FilePackage);
284   Storage->Packages.push_back(m_FilePackage->InstanceUID);
285
286   TrackSet<TimecodeComponent> FPTCTrack =
287     CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
288                                        EditRate, TCFrameRate,
289                                        ui64_C(3600) * TCFrameRate, m_Dict);
290   m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
291   m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
292   TrackSet<SourceClip> FPTrack =
293     CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
294                                                       TrackName, EditRate, DataDefinition,
295                                                       2, m_Dict);
296   m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
297
298   // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
299   FPTrack.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((EssenceUL.Value() + 12)));
300
301   FPTrack.Clip = new SourceClip(m_Dict);
302   m_HeaderPart.AddChildObject(FPTrack.Clip);
303   FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
304   FPTrack.Clip->DataDefinition = DataDefinition;
305
306   // for now we do not allow setting this value, so all files will be 'original'
307   FPTrack.Clip->SourceTrackID = 0;
308   FPTrack.Clip->SourcePackageID = NilUMID;
309   m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
310
311   m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
312 }
313
314 //
315 void
316 ASDCP::h__Writer::AddDMSegment(const MXF::Rational& EditRate, ui32_t TCFrameRate,
317                                const std::string& TrackName, const UL& DataDefinition,
318                                const std::string& PackageLabel)
319 {
320   //
321   ContentStorage* Storage = new ContentStorage(m_Dict);
322   m_HeaderPart.AddChildObject(Storage);
323   m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
324
325   EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
326   m_HeaderPart.AddChildObject(ECD);
327   Storage->EssenceContainerData.push_back(ECD->InstanceUID);
328   ECD->IndexSID = 129;
329   ECD->BodySID = 1;
330
331   UUID assetUUID(m_Info.AssetUUID);
332   UMID SourcePackageUMID, MaterialPackageUMID;
333   SourcePackageUMID.MakeUMID(0x0f, assetUUID);
334   MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
335
336   //
337   // Material Package
338   //
339   m_MaterialPackage = new MaterialPackage(m_Dict);
340   m_MaterialPackage->Name = "AS-DCP Material Package";
341   m_MaterialPackage->PackageUID = MaterialPackageUMID;
342   m_HeaderPart.AddChildObject(m_MaterialPackage);
343   Storage->Packages.push_back(m_MaterialPackage->InstanceUID);
344
345   TrackSet<TimecodeComponent> MPTCTrack =
346     CreateTimecodeTrack<MaterialPackage>(m_HeaderPart, *m_MaterialPackage,
347                                          EditRate, TCFrameRate, 0, m_Dict);
348   m_DurationUpdateList.push_back(&(MPTCTrack.Sequence->Duration));
349   m_DurationUpdateList.push_back(&(MPTCTrack.Clip->Duration));
350
351   TrackSet<DMSegment> MPTrack =
352     CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
353                                                        TrackName, EditRate, DataDefinition,
354                                                        2, m_Dict);
355   m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
356
357   MPTrack.Clip = new DMSegment(m_Dict);
358   m_HeaderPart.AddChildObject(MPTrack.Clip);
359   MPTrack.Sequence->StructuralComponents.push_back(MPTrack.Clip->InstanceUID);
360   MPTrack.Clip->DataDefinition = DataDefinition;
361   //  MPTrack.Clip->SourcePackageID = SourcePackageUMID;
362   //  MPTrack.Clip->SourceTrackID = 2;
363   m_DurationUpdateList.push_back(&(MPTrack.Clip->Duration));
364
365   
366   //
367   // File (Source) Package
368   //
369   m_FilePackage = new SourcePackage(m_Dict);
370   m_FilePackage->Name = PackageLabel.c_str();
371   m_FilePackage->PackageUID = SourcePackageUMID;
372   ECD->LinkedPackageUID = SourcePackageUMID;
373
374   m_HeaderPart.AddChildObject(m_FilePackage);
375   Storage->Packages.push_back(m_FilePackage->InstanceUID);
376
377   TrackSet<TimecodeComponent> FPTCTrack =
378     CreateTimecodeTrack<SourcePackage>(m_HeaderPart, *m_FilePackage,
379                                        EditRate, TCFrameRate,
380                                        ui64_C(3600) * TCFrameRate, m_Dict);
381   m_DurationUpdateList.push_back(&(FPTCTrack.Sequence->Duration));
382   m_DurationUpdateList.push_back(&(FPTCTrack.Clip->Duration));
383
384   TrackSet<DMSegment> FPTrack =
385     CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
386                                                      TrackName, EditRate, DataDefinition,
387                                                      2, m_Dict);
388   m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
389
390   FPTrack.Clip = new DMSegment(m_Dict);
391   m_HeaderPart.AddChildObject(FPTrack.Clip);
392   FPTrack.Sequence->StructuralComponents.push_back(FPTrack.Clip->InstanceUID);
393   FPTrack.Clip->DataDefinition = DataDefinition;
394   FPTrack.Clip->EventComment = "D-Cinema Timed Text";
395
396   m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
397   m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
398 }
399
400 //
401 void
402 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
403 {
404   //
405   // Essence Descriptor
406   //
407   m_EssenceDescriptor->EssenceContainer = WrappingUL;
408   m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
409
410   //
411   // Essence Descriptors
412   //
413   assert(m_Dict);
414   UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
415   m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
416
417   if ( m_Info.EncryptedEssence )
418     {
419       UL CryptEssenceUL(m_Dict->ul(MDD_EncryptedContainerLabel));
420       m_HeaderPart.EssenceContainers.push_back(CryptEssenceUL);
421       m_HeaderPart.m_Preface->DMSchemes.push_back(UL(m_Dict->ul(MDD_CryptographicFrameworkLabel)));
422       AddDMScrypt(m_HeaderPart, *m_FilePackage, m_Info, WrappingUL, m_Dict);
423     }
424   else
425     {
426       m_HeaderPart.EssenceContainers.push_back(WrappingUL);
427     }
428
429   m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
430   m_HeaderPart.AddChildObject(m_EssenceDescriptor);
431
432   std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
433   for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
434       m_HeaderPart.AddChildObject(*sdli);
435
436   m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
437 }
438
439 //
440 Result_t
441 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
442 {
443   assert(m_Dict);
444   Result_t result = RESULT_OK;
445
446   // create a body partition if we're writing proper 429-3/OP-Atom
447   if ( m_Info.LabelSetType == LS_MXF_SMPTE )
448     {
449       // Body Partition
450       m_BodyPart.EssenceContainers = m_HeaderPart.EssenceContainers;
451       m_BodyPart.ThisPartition = m_File.Tell();
452       m_BodyPart.BodySID = 1;
453       UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
454       m_BodyPart.OperationalPattern = OPAtomUL;
455       m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, m_BodyPart.ThisPartition)); // Second RIP Entry
456       
457       UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
458       result = m_BodyPart.WriteToFile(m_File, BodyUL);
459     }
460   else
461     {
462       m_HeaderPart.BodySID = 1;
463     }
464
465   if ( ASDCP_SUCCESS(result) )
466     {
467       // Index setup
468       Kumu::fpos_t ECoffset = m_File.Tell();
469       m_FooterPart.IndexSID = 129;
470
471       if ( BytesPerEditUnit == 0 )
472         m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
473       else
474         m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
475     }
476
477   return result;
478 }
479
480 //
481 Result_t
482 ASDCP::h__Writer::WriteMXFHeader(const std::string& PackageLabel, const UL& WrappingUL,
483                                  const std::string& TrackName, const UL& EssenceUL, const UL& DataDefinition,
484                                  const MXF::Rational& EditRate, ui32_t TCFrameRate, ui32_t BytesPerEditUnit)
485 {
486   InitHeader();
487   AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
488   AddEssenceDescriptor(WrappingUL);
489
490   Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
491
492   if ( KM_SUCCESS(result) )
493     result = CreateBodyPart(EditRate, BytesPerEditUnit);
494
495   return result;
496 }
497
498
499 // standard method of writing a plaintext or encrypted frame
500 Result_t
501 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
502                                   AESEncContext* Ctx, HMACContext* HMAC)
503 {
504   Result_t result = RESULT_OK;
505   IntegrityPack IntPack;
506
507   byte_t overhead[128];
508   Kumu::MemIOWriter Overhead(overhead, 128);
509   assert(m_Dict);
510
511   if ( FrameBuf.Size() == 0 )
512     {
513       DefaultLogSink().Error("Cannot write empty frame buffer\n");
514       return RESULT_EMPTY_FB;
515     }
516
517   if ( m_Info.EncryptedEssence )
518     {
519       if ( ! Ctx )
520         return RESULT_CRYPT_CTX;
521
522       if ( m_Info.UsesHMAC && ! HMAC )
523         return RESULT_HMAC_CTX;
524
525       if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
526         return RESULT_LARGE_PTO;
527
528       // encrypt the essence data (create encrypted source value)
529       result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
530
531       // create HMAC
532       if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
533         result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
534
535       if ( ASDCP_SUCCESS(result) )
536         { // write UL
537           Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
538
539           // construct encrypted triplet header
540           ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
541           ui32_t BER_length = MXF_BER_LENGTH;
542
543           if ( m_Info.UsesHMAC )
544             ETLength += klv_intpack_size;
545           else
546             ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
547
548           if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
549             {
550               BER_length = Kumu::get_BER_length_for_value(ETLength);
551
552               // the packet is longer by the difference in expected vs. actual BER length
553               ETLength += BER_length - MXF_BER_LENGTH;
554
555               if ( BER_length == 0 )
556                 result = RESULT_KLV_CODING;
557             }
558
559           if ( ASDCP_SUCCESS(result) )
560             {
561               if ( ! ( Overhead.WriteBER(ETLength, BER_length)                      // write encrypted triplet length
562                        && Overhead.WriteBER(UUIDlen, MXF_BER_LENGTH)                // write ContextID length
563                        && Overhead.WriteRaw(m_Info.ContextID, UUIDlen)              // write ContextID
564                        && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH)         // write PlaintextOffset length
565                        && Overhead.WriteUi64BE(FrameBuf.PlaintextOffset())          // write PlaintextOffset
566                        && Overhead.WriteBER(SMPTE_UL_LENGTH, MXF_BER_LENGTH)        // write essence UL length
567                        && Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH)    // write the essence UL
568                        && Overhead.WriteBER(sizeof(ui64_t), MXF_BER_LENGTH)         // write SourceLength length
569                        && Overhead.WriteUi64BE(FrameBuf.Size())                     // write SourceLength
570                        && Overhead.WriteBER(m_CtFrameBuf.Size(), BER_length) ) )    // write ESV length
571                 {
572                   result = RESULT_KLV_CODING;
573                 }
574             }
575
576           if ( ASDCP_SUCCESS(result) )
577             result = m_File.Writev(Overhead.Data(), Overhead.Length());
578         }
579
580       if ( ASDCP_SUCCESS(result) )
581         {
582           m_StreamOffset += Overhead.Length();
583           // write encrypted source value
584           result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
585         }
586
587       if ( ASDCP_SUCCESS(result) )
588         {
589           m_StreamOffset += m_CtFrameBuf.Size();
590
591           byte_t hmoverhead[512];
592           Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
593
594           // write the HMAC
595           if ( m_Info.UsesHMAC )
596             {
597               HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
598             }
599           else
600             { // we still need the var-pack length values if the intpack is empty
601               for ( ui32_t i = 0; i < 3 ; i++ )
602                 HMACOverhead.WriteBER(0, MXF_BER_LENGTH);
603             }
604
605           // write HMAC
606           result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
607           m_StreamOffset += HMACOverhead.Length();
608         }
609     }
610   else
611     {
612       ui32_t BER_length = MXF_BER_LENGTH;
613
614       if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
615         {
616           BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
617
618           if ( BER_length == 0 )
619             result = RESULT_KLV_CODING;
620         }
621
622       Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
623       Overhead.WriteBER(FrameBuf.Size(), BER_length);
624
625       if ( ASDCP_SUCCESS(result) )
626         result = m_File.Writev(Overhead.Data(), Overhead.Length());
627  
628       if ( ASDCP_SUCCESS(result) )
629         result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
630
631       if ( ASDCP_SUCCESS(result) )
632         m_StreamOffset += Overhead.Length() + FrameBuf.Size();
633     }
634
635   if ( ASDCP_SUCCESS(result) )
636     result = m_File.Writev();
637
638   return result;
639 }
640
641
642 // standard method of writing the header and footer of a completed MXF file
643 //
644 Result_t
645 ASDCP::h__Writer::WriteMXFFooter()
646 {
647   // Set top-level file package correctly for OP-Atom
648
649   //  m_MPTCSequence->Duration = m_MPTimecode->Duration = m_MPClSequence->Duration = m_MPClip->Duration = 
650   //    m_FPTCSequence->Duration = m_FPTimecode->Duration = m_FPClSequence->Duration = m_FPClip->Duration = 
651
652   DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
653
654   for (; dli != m_DurationUpdateList.end(); dli++ )
655     **dli = m_FramesWritten;
656
657   m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
658   m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
659
660   Kumu::fpos_t here = m_File.Tell();
661   m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(0, here)); // Last RIP Entry
662   m_HeaderPart.FooterPartition = here;
663
664   assert(m_Dict);
665   // re-label the partition
666   UL OPAtomUL(m_Dict->ul(MDD_OPAtom));
667   m_HeaderPart.OperationalPattern = OPAtomUL;
668   m_HeaderPart.m_Preface->OperationalPattern = m_HeaderPart.OperationalPattern;
669
670   m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
671   m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
672   m_FooterPart.FooterPartition = here;
673   m_FooterPart.ThisPartition = here;
674
675   Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
676
677   if ( ASDCP_SUCCESS(result) )
678     result = m_HeaderPart.m_RIP.WriteToFile(m_File);
679
680   if ( ASDCP_SUCCESS(result) )
681     result = m_File.Seek(0);
682
683   if ( ASDCP_SUCCESS(result) )
684     result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
685
686   m_File.Close();
687   return result;
688 }
689
690 //
691 // end h__Writer.cpp
692 //