fscking OpenBSD?
[asdcplib.git] / src / h__Writer.cpp
1 /*
2 Copyright (c) 2004-2010, 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$
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_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)
75 {
76 }
77
78 ASDCP::h__Writer::~h__Writer()
79 {
80 }
81
82 //
83 // add DMS CryptographicFramework entry to source package
84 void
85 AddDMScrypt(Partition& HeaderPart, SourcePackage& Package,
86             WriterInfo& Descr, const UL& WrappingUL, const Dictionary*& Dict)
87 {
88   assert(Dict);
89   // Essence Track
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;
95
96   Sequence* Seq = new Sequence(Dict);
97   HeaderPart.AddChildObject(Seq);
98   NewTrack->Sequence = Seq->InstanceUID;
99   Seq->DataDefinition = UL(Dict->ul(MDD_DescriptiveMetaDataDef));
100
101   DMSegment* Segment = new DMSegment(Dict);
102   HeaderPart.AddChildObject(Segment);
103   Seq->StructuralComponents.push_back(Segment->InstanceUID);
104   Segment->EventComment = "AS-DCP KLV Encryption";
105   
106   CryptographicFramework* CFW = new CryptographicFramework(Dict);
107   HeaderPart.AddChildObject(CFW);
108   Segment->DMFramework = CFW->InstanceUID;
109
110   CryptographicContext* Context = new CryptographicContext(Dict);
111   HeaderPart.AddChildObject(Context);
112   CFW->ContextSR = Context->InstanceUID;
113
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);
119 }
120
121 //
122 void
123 ASDCP::h__Writer::InitHeader()
124 {
125   assert(m_Dict);
126   assert(m_EssenceDescriptor);
127
128   m_HeaderPart.m_Primer.ClearTagList();
129   m_HeaderPart.m_Preface = new Preface(m_Dict);
130   m_HeaderPart.AddChildObject(m_HeaderPart.m_Preface);
131
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;
136
137   // First RIP Entry
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
140   else
141     m_HeaderPart.m_RIP.PairArray.push_back(RIP::Pair(1, 0)); // 2-part, essence in header
142
143   //
144   // Identification
145   //
146   Identification* Ident = new Identification(m_Dict);
147   m_HeaderPart.AddChildObject(Ident);
148   m_HeaderPart.m_Preface->Identifications.push_back(Ident->InstanceUID);
149
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;
156
157   std::vector<int> version = version_split(Version());
158
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;
164 }
165
166 //
167 template <class ClipT>
168 struct TrackSet
169 {
170   MXF::Track*    Track;
171   MXF::Sequence* Sequence;
172   ClipT*         Clip;
173
174   TrackSet() : Track(0), Sequence(0), Clip(0) {}
175 };
176
177 //
178 template <class PackageT, class ClipT>
179 TrackSet<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)
182 {
183   TrackSet<ClipT> NewTrack;
184
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();
191
192   NewTrack.Sequence = new Sequence(Dict);
193   Header.AddChildObject(NewTrack.Sequence);
194   NewTrack.Track->Sequence = NewTrack.Sequence->InstanceUID;
195   NewTrack.Sequence->DataDefinition = Definition;
196
197   return NewTrack;
198 }
199
200 //
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)
205 {
206   assert(Dict);
207   UL TCUL(Dict->ul(MDD_TimecodeDataDef));
208
209   TrackSet<TimecodeComponent> NewTrack = CreateTrackAndSequence<PackageT, TimecodeComponent>(Header, Package, "Timecode Track", EditRate, TCUL, 1, Dict);
210
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;
217
218   return NewTrack;
219 }
220
221
222 //
223 void
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)
227 {
228   //
229   ContentStorage* Storage = new ContentStorage(m_Dict);
230   m_HeaderPart.AddChildObject(Storage);
231   m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
232
233   EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
234   m_HeaderPart.AddChildObject(ECD);
235   Storage->EssenceContainerData.push_back(ECD->InstanceUID);
236   ECD->IndexSID = 129;
237   ECD->BodySID = 1;
238
239   UUID assetUUID(m_Info.AssetUUID);
240   UMID SourcePackageUMID, MaterialPackageUMID;
241   SourcePackageUMID.MakeUMID(0x0f, assetUUID);
242   MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
243
244   //
245   // Material Package
246   //
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);
252
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));
258
259   TrackSet<SourceClip> MPTrack =
260     CreateTrackAndSequence<MaterialPackage, SourceClip>(m_HeaderPart, *m_MaterialPackage,
261                                                         TrackName, EditRate, DataDefinition,
262                                                         2, m_Dict);
263   m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
264
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));
272
273   
274   //
275   // File (Source) Package
276   //
277   m_FilePackage = new SourcePackage(m_Dict);
278   m_FilePackage->Name = PackageLabel.c_str();
279   m_FilePackage->PackageUID = SourcePackageUMID;
280   ECD->LinkedPackageUID = SourcePackageUMID;
281
282   m_HeaderPart.AddChildObject(m_FilePackage);
283   Storage->Packages.push_back(m_FilePackage->InstanceUID);
284
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,
294                                                       2, m_Dict);
295   m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
296
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)));
299
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;
304
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));
309
310   m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
311 }
312
313 //
314 void
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)
318 {
319   //
320   ContentStorage* Storage = new ContentStorage(m_Dict);
321   m_HeaderPart.AddChildObject(Storage);
322   m_HeaderPart.m_Preface->ContentStorage = Storage->InstanceUID;
323
324   EssenceContainerData* ECD = new EssenceContainerData(m_Dict);
325   m_HeaderPart.AddChildObject(ECD);
326   Storage->EssenceContainerData.push_back(ECD->InstanceUID);
327   ECD->IndexSID = 129;
328   ECD->BodySID = 1;
329
330   UUID assetUUID(m_Info.AssetUUID);
331   UMID SourcePackageUMID, MaterialPackageUMID;
332   SourcePackageUMID.MakeUMID(0x0f, assetUUID);
333   MaterialPackageUMID.MakeUMID(0x0f); // unidentified essence
334
335   //
336   // Material Package
337   //
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);
343
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));
349
350   TrackSet<DMSegment> MPTrack =
351     CreateTrackAndSequence<MaterialPackage, DMSegment>(m_HeaderPart, *m_MaterialPackage,
352                                                        TrackName, EditRate, DataDefinition,
353                                                        2, m_Dict);
354   m_DurationUpdateList.push_back(&(MPTrack.Sequence->Duration));
355
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));
363
364   
365   //
366   // File (Source) Package
367   //
368   m_FilePackage = new SourcePackage(m_Dict);
369   m_FilePackage->Name = PackageLabel.c_str();
370   m_FilePackage->PackageUID = SourcePackageUMID;
371   ECD->LinkedPackageUID = SourcePackageUMID;
372
373   m_HeaderPart.AddChildObject(m_FilePackage);
374   Storage->Packages.push_back(m_FilePackage->InstanceUID);
375
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));
382
383   TrackSet<DMSegment> FPTrack =
384     CreateTrackAndSequence<SourcePackage, DMSegment>(m_HeaderPart, *m_FilePackage,
385                                                      TrackName, EditRate, DataDefinition,
386                                                      2, m_Dict);
387   m_DurationUpdateList.push_back(&(FPTrack.Sequence->Duration));
388
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";
394
395   m_DurationUpdateList.push_back(&(FPTrack.Clip->Duration));
396   m_EssenceDescriptor->LinkedTrackID = FPTrack.Track->TrackID;
397 }
398
399 //
400 void
401 ASDCP::h__Writer::AddEssenceDescriptor(const UL& WrappingUL)
402 {
403   //
404   // Essence Descriptor
405   //
406   m_EssenceDescriptor->EssenceContainer = WrappingUL;
407   m_HeaderPart.m_Preface->PrimaryPackage = m_FilePackage->InstanceUID;
408
409   //
410   // Essence Descriptors
411   //
412   assert(m_Dict);
413   UL GenericContainerUL(m_Dict->ul(MDD_GCMulti));
414   m_HeaderPart.EssenceContainers.push_back(GenericContainerUL);
415
416   if ( m_Info.EncryptedEssence )
417     {
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);
422     }
423   else
424     {
425       m_HeaderPart.EssenceContainers.push_back(WrappingUL);
426     }
427
428   m_HeaderPart.m_Preface->EssenceContainers = m_HeaderPart.EssenceContainers;
429   m_HeaderPart.AddChildObject(m_EssenceDescriptor);
430
431   std::list<InterchangeObject*>::iterator sdli = m_EssenceSubDescriptorList.begin();
432   for ( ; sdli != m_EssenceSubDescriptorList.end(); sdli++ )
433       m_HeaderPart.AddChildObject(*sdli);
434
435   m_FilePackage->Descriptor = m_EssenceDescriptor->InstanceUID;
436 }
437
438 //
439 Result_t
440 ASDCP::h__Writer::CreateBodyPart(const MXF::Rational& EditRate, ui32_t BytesPerEditUnit)
441 {
442   assert(m_Dict);
443   Result_t result = RESULT_OK;
444
445   // create a body partition if we're writing proper 429-3/OP-Atom
446   if ( m_Info.LabelSetType == LS_MXF_SMPTE )
447     {
448       // Body Partition
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
455       
456       UL BodyUL(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
457       result = m_BodyPart.WriteToFile(m_File, BodyUL);
458     }
459   else
460     {
461       m_HeaderPart.BodySID = 1;
462     }
463
464   if ( ASDCP_SUCCESS(result) )
465     {
466       // Index setup
467       Kumu::fpos_t ECoffset = m_File.Tell();
468       m_FooterPart.IndexSID = 129;
469
470       if ( BytesPerEditUnit == 0 )
471         m_FooterPart.SetIndexParamsVBR(&m_HeaderPart.m_Primer, EditRate, ECoffset);
472       else
473         m_FooterPart.SetIndexParamsCBR(&m_HeaderPart.m_Primer, BytesPerEditUnit, EditRate);
474     }
475
476   return result;
477 }
478
479 //
480 Result_t
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)
484 {
485   InitHeader();
486   AddSourceClip(EditRate, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
487   AddEssenceDescriptor(WrappingUL);
488
489   Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
490
491   if ( KM_SUCCESS(result) )
492     result = CreateBodyPart(EditRate, BytesPerEditUnit);
493
494   return result;
495 }
496
497
498 // standard method of writing a plaintext or encrypted frame
499 Result_t
500 ASDCP::h__Writer::WriteEKLVPacket(const ASDCP::FrameBuffer& FrameBuf, const byte_t* EssenceUL,
501                                   AESEncContext* Ctx, HMACContext* HMAC)
502 {
503   Result_t result = RESULT_OK;
504   IntegrityPack IntPack;
505
506   byte_t overhead[128];
507   Kumu::MemIOWriter Overhead(overhead, 128);
508   assert(m_Dict);
509
510   if ( FrameBuf.Size() == 0 )
511     {
512       DefaultLogSink().Error("Cannot write empty frame buffer\n");
513       return RESULT_EMPTY_FB;
514     }
515
516   if ( m_Info.EncryptedEssence )
517     {
518       if ( ! Ctx )
519         return RESULT_CRYPT_CTX;
520
521       if ( m_Info.UsesHMAC && ! HMAC )
522         return RESULT_HMAC_CTX;
523
524       if ( FrameBuf.PlaintextOffset() > FrameBuf.Size() )
525         return RESULT_LARGE_PTO;
526
527       // encrypt the essence data (create encrypted source value)
528       result = EncryptFrameBuffer(FrameBuf, m_CtFrameBuf, Ctx);
529
530       // create HMAC
531       if ( ASDCP_SUCCESS(result) && m_Info.UsesHMAC )
532         result = IntPack.CalcValues(m_CtFrameBuf, m_Info.AssetUUID, m_FramesWritten + 1, HMAC);
533
534       if ( ASDCP_SUCCESS(result) )
535         { // write UL
536           Overhead.WriteRaw(m_Dict->ul(MDD_CryptEssence), SMPTE_UL_LENGTH);
537
538           // construct encrypted triplet header
539           ui32_t ETLength = klv_cryptinfo_size + m_CtFrameBuf.Size();
540           ui32_t BER_length = MXF_BER_LENGTH;
541
542           if ( m_Info.UsesHMAC )
543             ETLength += klv_intpack_size;
544           else
545             ETLength += (MXF_BER_LENGTH * 3); // for empty intpack
546
547           if ( ETLength > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
548             {
549               BER_length = Kumu::get_BER_length_for_value(ETLength);
550
551               // the packet is longer by the difference in expected vs. actual BER length
552               ETLength += BER_length - MXF_BER_LENGTH;
553
554               if ( BER_length == 0 )
555                 result = RESULT_KLV_CODING;
556             }
557
558           if ( ASDCP_SUCCESS(result) )
559             {
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
570                 {
571                   result = RESULT_KLV_CODING;
572                 }
573             }
574
575           if ( ASDCP_SUCCESS(result) )
576             result = m_File.Writev(Overhead.Data(), Overhead.Length());
577         }
578
579       if ( ASDCP_SUCCESS(result) )
580         {
581           m_StreamOffset += Overhead.Length();
582           // write encrypted source value
583           result = m_File.Writev((byte_t*)m_CtFrameBuf.RoData(), m_CtFrameBuf.Size());
584         }
585
586       if ( ASDCP_SUCCESS(result) )
587         {
588           m_StreamOffset += m_CtFrameBuf.Size();
589
590           byte_t hmoverhead[512];
591           Kumu::MemIOWriter HMACOverhead(hmoverhead, 512);
592
593           // write the HMAC
594           if ( m_Info.UsesHMAC )
595             {
596               HMACOverhead.WriteRaw(IntPack.Data, klv_intpack_size);
597             }
598           else
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);
602             }
603
604           // write HMAC
605           result = m_File.Writev(HMACOverhead.Data(), HMACOverhead.Length());
606           m_StreamOffset += HMACOverhead.Length();
607         }
608     }
609   else
610     {
611       ui32_t BER_length = MXF_BER_LENGTH;
612
613       if ( FrameBuf.Size() > 0x00ffffff ) // Need BER integer longer than MXF_BER_LENGTH bytes
614         {
615           BER_length = Kumu::get_BER_length_for_value(FrameBuf.Size());
616
617           if ( BER_length == 0 )
618             result = RESULT_KLV_CODING;
619         }
620
621       Overhead.WriteRaw((byte_t*)EssenceUL, SMPTE_UL_LENGTH);
622       Overhead.WriteBER(FrameBuf.Size(), BER_length);
623
624       if ( ASDCP_SUCCESS(result) )
625         result = m_File.Writev(Overhead.Data(), Overhead.Length());
626  
627       if ( ASDCP_SUCCESS(result) )
628         result = m_File.Writev((byte_t*)FrameBuf.RoData(), FrameBuf.Size());
629
630       if ( ASDCP_SUCCESS(result) )
631         m_StreamOffset += Overhead.Length() + FrameBuf.Size();
632     }
633
634   if ( ASDCP_SUCCESS(result) )
635     result = m_File.Writev();
636
637   return result;
638 }
639
640
641 // standard method of writing the header and footer of a completed MXF file
642 //
643 Result_t
644 ASDCP::h__Writer::WriteMXFFooter()
645 {
646   // Set top-level file package correctly for OP-Atom
647
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 = 
650
651   DurationElementList_t::iterator dli = m_DurationUpdateList.begin();
652
653   for (; dli != m_DurationUpdateList.end(); dli++ )
654     **dli = m_FramesWritten;
655
656   m_EssenceDescriptor->ContainerDuration = m_FramesWritten;
657   m_FooterPart.PreviousPartition = m_HeaderPart.m_RIP.PairArray.back().ByteOffset;
658
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;
662
663   assert(m_Dict);
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;
668
669   m_FooterPart.OperationalPattern = m_HeaderPart.OperationalPattern;
670   m_FooterPart.EssenceContainers = m_HeaderPart.EssenceContainers;
671   m_FooterPart.FooterPartition = here;
672   m_FooterPart.ThisPartition = here;
673
674   Result_t result = m_FooterPart.WriteToFile(m_File, m_FramesWritten);
675
676   if ( ASDCP_SUCCESS(result) )
677     result = m_HeaderPart.m_RIP.WriteToFile(m_File);
678
679   if ( ASDCP_SUCCESS(result) )
680     result = m_File.Seek(0);
681
682   if ( ASDCP_SUCCESS(result) )
683     result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
684
685   m_File.Close();
686   return result;
687 }
688
689 //
690 // end h__Writer.cpp
691 //