Fix enum switch/case statements with unhandled values.
[asdcplib-cth.git] / src / AS_02_PHDR.cpp
1 /*
2 Copyright (c) 2011-2015, John Hurst
3
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 1. Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12    notice, this list of conditions and the following disclaimer in the
13    documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15    derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */ 
28 /*! \file    AS_02_PHDR.cpp
29   \version $Id: AS_02_PHDR.cpp,v 1.7 2015/10/09 23:41:11 jhurst Exp $
30   \brief   AS-02 library, JPEG 2000 P-HDR essence reader and writer implementation
31 */
32
33 #include "AS_02_internal.h"
34 #include "AS_02_PHDR.h"
35
36 #include <iostream>
37 #include <iomanip>
38
39 using namespace ASDCP;
40 using namespace ASDCP::JP2K;
41 using Kumu::GenRandomValue;
42
43 //------------------------------------------------------------------------------------------
44
45 static std::string JP2K_PACKAGE_LABEL = "File Package: PROTOTYPE SMPTE ST 422 / ST 2067-5 frame wrapping of JPEG 2000 codestreams with HDR metadata";
46 static std::string PICT_DEF_LABEL = "PHDR Image Track";
47 static std::string MD_DEF_LABEL = "PHDR Metadata Track";
48
49
50
51 //------------------------------------------------------------------------------------------
52
53 //
54 void
55 AS_02::PHDR::FrameBuffer::Dump(FILE* stream, ui32_t dump_bytes) const
56 {
57   if ( stream == 0 )
58     stream = stderr;
59
60   fprintf(stream, "Frame %d, %d bytes (metadata: %zd bytes)\n", FrameNumber(), Size(), OpaqueMetadata.size());
61
62   if ( dump_bytes > 0 )
63     {
64       Kumu::hexdump(RoData(), Kumu::xmin(dump_bytes, Size()), stream);
65     }
66 }
67
68
69 //------------------------------------------------------------------------------------------
70 //
71 // hidden, internal implementation of JPEG 2000 reader
72
73
74 class AS_02::PHDR::MXFReader::h__Reader : public AS_02::h__AS02Reader
75 {
76   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
77
78 public:
79   h__Reader(const Dictionary& d) :
80     AS_02::h__AS02Reader(d) {}
81
82   virtual ~h__Reader() {}
83
84   Result_t    OpenRead(const std::string& filename, std::string& PHDR_master_metadata);
85   Result_t    ReadFrame(ui32_t, AS_02::PHDR::FrameBuffer&, AESDecContext*, HMACContext*);
86 };
87
88 //
89 Result_t
90 AS_02::PHDR::MXFReader::h__Reader::OpenRead(const std::string& filename, std::string& PHDR_master_metadata)
91 {
92   Result_t result = OpenMXFRead(filename.c_str());
93   ui32_t SimplePayloadSID = 0;
94
95   if( KM_SUCCESS(result) )
96     {
97       InterchangeObject* tmp_iobj = 0;
98
99       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CDCIEssenceDescriptor), &tmp_iobj);
100
101       if ( tmp_iobj == 0 )
102         {
103           m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
104         }
105
106       if ( tmp_iobj == 0 )
107         {
108           DefaultLogSink().Error("RGBAEssenceDescriptor nor CDCIEssenceDescriptor found.\n");
109           return RESULT_AS02_FORMAT;
110         }
111
112       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
113
114       if ( tmp_iobj == 0 )
115         {
116           DefaultLogSink().Error("JPEG2000PictureSubDescriptor not found.\n");
117           return RESULT_AS02_FORMAT;
118         }
119
120       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(PHDRMetadataTrackSubDescriptor), &tmp_iobj);
121
122       if ( tmp_iobj == 0 )
123         {
124           DefaultLogSink().Error("PHDRMetadataTrackSubDescriptor not found.\n");
125           return RESULT_AS02_FORMAT;
126         }
127       else
128         {
129           PHDRMetadataTrackSubDescriptor *tmp_desc = dynamic_cast<PHDRMetadataTrackSubDescriptor*>(tmp_iobj);
130           assert(tmp_desc);
131           SimplePayloadSID = tmp_desc->SimplePayloadSID;
132         }
133
134       std::list<InterchangeObject*> ObjectList;
135       m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
136
137       if ( ObjectList.empty() )
138         {
139           DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
140           return RESULT_AS02_FORMAT;
141         }
142     }
143
144   // if PHDRSimplePayload exists, go get it
145   if ( KM_SUCCESS(result) && SimplePayloadSID )
146     {
147       RIP::const_pair_iterator pi;
148       RIP::PartitionPair TmpPair;
149       
150       // Look up the partition start in the RIP using the SID.
151       for ( pi = m_RIP.PairArray.begin(); pi != m_RIP.PairArray.end(); ++pi )
152         {
153           if ( (*pi).BodySID == SimplePayloadSID )
154             {
155               TmpPair = *pi;
156               break;
157             }
158         }
159
160       if ( TmpPair.ByteOffset == 0 )
161         {
162           DefaultLogSink().Error("Body SID not found in RIP set: %d\n", SimplePayloadSID);
163           return RESULT_AS02_FORMAT;
164         }
165
166       // seek to the start of the partition
167       if ( (Kumu::fpos_t)TmpPair.ByteOffset != m_LastPosition )
168         {
169           m_LastPosition = TmpPair.ByteOffset;
170           result = m_File.Seek(TmpPair.ByteOffset);
171         }
172
173       // read the partition header
174       ASDCP::MXF::Partition GSPart(m_Dict);
175       result = GSPart.InitFromFile(m_File);
176
177       if ( KM_SUCCESS(result) )
178         {
179           // read the generic stream packet
180           if ( KM_SUCCESS(result) )
181             {
182               ASDCP::FrameBuffer tmp_buf;
183               tmp_buf.Capacity(Kumu::Megabyte);
184
185               result = Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
186                                         0, 0, tmp_buf, m_Dict->ul(MDD_GenericStream_DataElement), 0, 0);
187
188               if ( KM_SUCCESS(result) )
189                 {
190                   PHDR_master_metadata.assign((const char*)tmp_buf.RoData(), tmp_buf.Size());
191                 }
192             }
193         }
194     }
195
196   return result;
197 }
198
199 //
200 //
201 Result_t
202 AS_02::PHDR::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, AS_02::PHDR::FrameBuffer& FrameBuf,
203                       ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC)
204 {
205   if ( ! m_File.IsOpen() )
206     return RESULT_INIT;
207
208   assert(m_Dict);
209   Result_t result = ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
210
211   if ( KM_SUCCESS(result) )
212     {
213       ASDCP::FrameBuffer tmp_metadata_buffer;
214       tmp_metadata_buffer.Capacity(8192);
215
216       result = Read_EKLV_Packet(m_File, *m_Dict, m_Info, m_LastPosition, m_CtFrameBuf,
217                                 FrameNum, FrameNum + 1, tmp_metadata_buffer, m_Dict->ul(MDD_PHDRImageMetadataItem), Ctx, HMAC);
218
219       if ( KM_SUCCESS(result) )
220         {
221           FrameBuf.OpaqueMetadata.assign((const char*)tmp_metadata_buffer.RoData(), tmp_metadata_buffer.Size());
222         }
223       else
224         {
225           DefaultLogSink().Error("Metadata packet not found at frame %d.\n", FrameNum);
226           result = RESULT_OK;
227         }
228     }
229
230   return result;
231 }
232
233 //------------------------------------------------------------------------------------------
234 //
235
236 AS_02::PHDR::MXFReader::MXFReader()
237 {
238   m_Reader = new h__Reader(DefaultCompositeDict());
239 }
240
241
242 AS_02::PHDR::MXFReader::~MXFReader()
243 {
244 }
245
246 // Warning: direct manipulation of MXF structures can interfere
247 // with the normal operation of the wrapper.  Caveat emptor!
248 //
249 ASDCP::MXF::OP1aHeader&
250 AS_02::PHDR::MXFReader::OP1aHeader()
251 {
252   if ( m_Reader.empty() )
253     {
254       assert(g_OP1aHeader);
255       return *g_OP1aHeader;
256     }
257
258   return m_Reader->m_HeaderPart;
259 }
260
261 // Warning: direct manipulation of MXF structures can interfere
262 // with the normal operation of the wrapper.  Caveat emptor!
263 //
264 AS_02::MXF::AS02IndexReader&
265 AS_02::PHDR::MXFReader::AS02IndexReader()
266 {
267   if ( m_Reader.empty() )
268     {
269       assert(g_AS02IndexReader);
270       return *g_AS02IndexReader;
271     }
272
273   return m_Reader->m_IndexAccess;
274 }
275
276 // Warning: direct manipulation of MXF structures can interfere
277 // with the normal operation of the wrapper.  Caveat emptor!
278 //
279 ASDCP::MXF::RIP&
280 AS_02::PHDR::MXFReader::RIP()
281 {
282   if ( m_Reader.empty() )
283     {
284       assert(g_RIP);
285       return *g_RIP;
286     }
287
288   return m_Reader->m_RIP;
289 }
290
291 // Open the file for reading. The file must exist. Returns error if the
292 // operation cannot be completed.
293 Result_t
294 AS_02::PHDR::MXFReader::OpenRead(const std::string& filename, std::string& PHDR_master_metadata) const
295 {
296   return m_Reader->OpenRead(filename, PHDR_master_metadata);
297 }
298
299 //
300 Result_t
301 AS_02::PHDR::MXFReader::Close() const
302 {
303   if ( m_Reader && m_Reader->m_File.IsOpen() )
304     {
305       m_Reader->Close();
306       return RESULT_OK;
307     }
308
309   return RESULT_INIT;
310 }
311
312 //
313 Result_t
314 AS_02::PHDR::MXFReader::ReadFrame(ui32_t FrameNum, AS_02::PHDR::FrameBuffer& FrameBuf,
315                                            ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC) const
316 {
317   if ( m_Reader && m_Reader->m_File.IsOpen() )
318     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
319
320   return RESULT_INIT;
321 }
322
323 // Fill the struct with the values from the file's header.
324 // Returns RESULT_INIT if the file is not open.
325 Result_t
326 AS_02::PHDR::MXFReader::FillWriterInfo(WriterInfo& Info) const
327 {
328   if ( m_Reader && m_Reader->m_File.IsOpen() )
329     {
330       Info = m_Reader->m_Info;
331       return RESULT_OK;
332     }
333
334   return RESULT_INIT;
335 }
336
337
338 //------------------------------------------------------------------------------------------
339
340 //
341 class AS_02::PHDR::MXFWriter::h__Writer : public AS_02::h__AS02WriterFrame
342 {
343   PHDRMetadataTrackSubDescriptor *m_MetadataTrackSubDescriptor;
344
345   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
346   h__Writer();
347
348   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
349
350   Result_t WritePHDRHeader(const std::string& PackageLabel, const ASDCP::UL& WrappingUL,
351                            const std::string& TrackName, const ASDCP::UL& EssenceUL,
352                            const ASDCP::UL& DataDefinition, const ASDCP::Rational& EditRate,
353                            const ui32_t& TCFrameRate);
354
355 public:
356   byte_t            m_EssenceUL[SMPTE_UL_LENGTH];
357   byte_t            m_MetadataUL[SMPTE_UL_LENGTH];
358
359   h__Writer(const Dictionary& d) : h__AS02WriterFrame(d), m_EssenceSubDescriptor(0), m_MetadataTrackSubDescriptor(0) {
360     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
361     memset(m_MetadataUL, 0, SMPTE_UL_LENGTH);
362   }
363
364   virtual ~h__Writer(){}
365
366   Result_t OpenWrite(const std::string&, ASDCP::MXF::FileDescriptor* essence_descriptor,
367                      ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
368                      const AS_02::IndexStrategy_t& IndexStrategy,
369                      const ui32_t& PartitionSpace, const ui32_t& HeaderSize);
370   Result_t SetSourceStream(const std::string& label, const ASDCP::Rational& edit_rate);
371   Result_t WriteFrame(const AS_02::PHDR::FrameBuffer&, ASDCP::AESEncContext*, ASDCP::HMACContext*);
372   Result_t Finalize(const std::string& PHDR_master_metadata);
373 };
374
375
376 // Open the file for writing. The file must not exist. Returns error if
377 // the operation cannot be completed.
378 Result_t
379 AS_02::PHDR::MXFWriter::h__Writer::OpenWrite(const std::string& filename,
380                                              ASDCP::MXF::FileDescriptor* essence_descriptor,
381                                              ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
382                                              const AS_02::IndexStrategy_t& IndexStrategy,
383                                              const ui32_t& PartitionSpace_sec, const ui32_t& HeaderSize)
384 {
385   if ( ! m_State.Test_BEGIN() )
386     {
387       return RESULT_STATE;
388     }
389
390   if ( m_IndexStrategy != AS_02::IS_FOLLOW )
391     {
392       DefaultLogSink().Error("Only strategy IS_FOLLOW is supported at this time.\n");
393       return Kumu::RESULT_NOTIMPL;
394     }
395
396   Result_t result = m_File.OpenWrite(filename);
397
398   if ( KM_SUCCESS(result) )
399     {
400       m_IndexStrategy = IndexStrategy;
401       m_PartitionSpace = PartitionSpace_sec; // later converted to edit units by WritePHDRHeader()
402       m_HeaderSize = HeaderSize;
403
404       if ( essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_RGBAEssenceDescriptor))
405            && essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_CDCIEssenceDescriptor)) )
406         {
407           DefaultLogSink().Error("Essence descriptor is not a RGBAEssenceDescriptor or CDCIEssenceDescriptor.\n");
408           essence_descriptor->Dump();
409           return RESULT_AS02_FORMAT;
410         }
411
412       m_EssenceDescriptor = essence_descriptor;
413
414       ASDCP::MXF::InterchangeObject_list_t::iterator i;
415       for ( i = essence_sub_descriptor_list.begin(); i != essence_sub_descriptor_list.end(); ++i )
416         {
417           if ( (*i)->GetUL() != UL(m_Dict->ul(MDD_JPEG2000PictureSubDescriptor)) )
418             {
419               DefaultLogSink().Error("Essence sub-descriptor is not a JPEG2000PictureSubDescriptor.\n");
420               (*i)->Dump();
421             }
422
423           m_EssenceSubDescriptorList.push_back(*i);
424           GenRandomValue((*i)->InstanceUID);
425           m_EssenceDescriptor->SubDescriptors.push_back((*i)->InstanceUID);
426           *i = 0; // parent will only free the ones we don't keep
427         }
428
429       result = m_State.Goto_INIT();
430     }
431
432   return result;
433 }
434
435 // all the above for a single source clip
436 Result_t
437 AS_02::PHDR::MXFWriter::h__Writer::WritePHDRHeader(const std::string& PackageLabel, const ASDCP::UL& WrappingUL,
438                                                    const std::string& TrackName, const ASDCP::UL& EssenceUL,
439                                                    const ASDCP::UL& DataDefinition, const ASDCP::Rational& EditRate,
440                                                    const ui32_t& TCFrameRate)
441 {
442   if ( EditRate.Numerator == 0 || EditRate.Denominator == 0 )
443     {
444       DefaultLogSink().Error("Non-zero edit-rate reqired.\n");
445       return RESULT_PARAM;
446     }
447   
448   InitHeader();
449   
450   AddSourceClip(EditRate, EditRate/*TODO: for a moment*/, TCFrameRate, TrackName, EssenceUL, DataDefinition, PackageLabel);
451
452   // add metadata track
453   TrackSet<SourceClip> metdata_track =
454     CreateTrackAndSequence<SourcePackage, SourceClip>(m_HeaderPart, *m_FilePackage,
455                                                       MD_DEF_LABEL, EditRate,
456                                                       UL(m_Dict->ul(MDD_PHDRImageMetadataItem)),
457                                                       3 /* track id */, m_Dict);
458
459   metdata_track.Sequence->Duration.set_has_value();
460   m_DurationUpdateList.push_back(&(metdata_track.Sequence->Duration.get()));
461   // Consult ST 379:2004 Sec. 6.3, "Element to track relationship" to see where "12" comes from.
462   metdata_track.Track->TrackNumber = KM_i32_BE(Kumu::cp2i<ui32_t>((UL(m_MetadataUL).Value() + 12)));
463
464   metdata_track.Clip = new SourceClip(m_Dict);
465   m_HeaderPart.AddChildObject(metdata_track.Clip);
466   metdata_track.Sequence->StructuralComponents.push_back(metdata_track.Clip->InstanceUID);
467   metdata_track.Clip->DataDefinition = UL(m_Dict->ul(MDD_PHDRImageMetadataWrappingFrame));
468
469   // for now we do not allow setting this value, so all files will be 'original'
470   metdata_track.Clip->SourceTrackID = 0;
471   metdata_track.Clip->SourcePackageID = NilUMID;
472   
473   metdata_track.Clip->Duration.set_has_value();
474   m_DurationUpdateList.push_back(&(metdata_track.Clip->Duration.get()));
475
476   // add PHDR subdescriptor
477   m_MetadataTrackSubDescriptor = new PHDRMetadataTrackSubDescriptor(m_Dict);
478   m_EssenceSubDescriptorList.push_back(m_MetadataTrackSubDescriptor);
479   GenRandomValue(m_MetadataTrackSubDescriptor->InstanceUID);
480   m_EssenceDescriptor->SubDescriptors.push_back(m_MetadataTrackSubDescriptor->InstanceUID);
481   m_MetadataTrackSubDescriptor->DataDefinition = UL(m_Dict->ul(MDD_PHDRImageMetadataWrappingFrame));
482   m_MetadataTrackSubDescriptor->SourceTrackID = 3;
483   m_MetadataTrackSubDescriptor->SimplePayloadSID = 0;
484
485   AddEssenceDescriptor(WrappingUL);
486
487   m_IndexWriter.SetPrimerLookup(&m_HeaderPart.m_Primer);
488   m_RIP.PairArray.push_back(RIP::PartitionPair(0, 0)); // Header partition RIP entry
489   m_IndexWriter.OperationalPattern = m_HeaderPart.OperationalPattern;
490   m_IndexWriter.EssenceContainers = m_HeaderPart.EssenceContainers;
491
492   Result_t result = m_HeaderPart.WriteToFile(m_File, m_HeaderSize);
493
494   if ( KM_SUCCESS(result) )
495     {
496       m_PartitionSpace *= floor( EditRate.Quotient() + 0.5 );  // convert seconds to edit units
497       m_ECStart = m_File.Tell();
498       m_IndexWriter.IndexSID = 129;
499
500       UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
501       Partition body_part(m_Dict);
502       body_part.BodySID = 1;
503       body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
504       body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
505       body_part.ThisPartition = m_ECStart;
506       result = body_part.WriteToFile(m_File, body_ul);
507       m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition)); // Second RIP Entry
508     }
509
510   return result;
511 }
512
513 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
514 Result_t
515 AS_02::PHDR::MXFWriter::h__Writer::SetSourceStream(const std::string& label, const ASDCP::Rational& edit_rate)
516 {
517   assert(m_Dict);
518   if ( ! m_State.Test_INIT() )
519     {
520       return RESULT_STATE;
521     }
522
523   memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
524   m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first track of the essence container
525
526   memcpy(m_MetadataUL, m_Dict->ul(MDD_PHDRImageMetadataItem), SMPTE_UL_LENGTH);
527   m_MetadataUL[SMPTE_UL_LENGTH-1] = 3; // third track of the essence container
528
529   Result_t result = m_State.Goto_READY();
530
531   if ( KM_SUCCESS(result) )
532     {
533       result = WritePHDRHeader(label, UL(m_Dict->ul(MDD_JPEG_2000WrappingFrame)),
534                                PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
535                                edit_rate, derive_timecode_rate_from_edit_rate(edit_rate));
536
537       if ( KM_SUCCESS(result) )
538         {
539           this->m_IndexWriter.SetPrimerLookup(&this->m_HeaderPart.m_Primer);
540         }
541     }
542
543   return result;
544 }
545
546 // Writes a frame of essence to the MXF file. If the optional AESEncContext
547 // argument is present, the essence is encrypted prior to writing.
548 // Fails if the file is not open, is finalized, or an operating system
549 // error occurs.
550 //
551 Result_t
552 AS_02::PHDR::MXFWriter::h__Writer::WriteFrame(const AS_02::PHDR::FrameBuffer& FrameBuf,
553                                               AESEncContext* Ctx, HMACContext* HMAC)
554 {
555   if ( FrameBuf.Size() == 0 )
556     {
557       DefaultLogSink().Error("The frame buffer size is zero.\n");
558       return RESULT_PARAM;
559     }
560
561   Result_t result = RESULT_OK;
562
563   if ( m_State.Test_READY() )
564     {
565       result = m_State.Goto_RUNNING(); // first time through
566     }
567
568   if ( KM_SUCCESS(result) )
569     {
570       ui64_t this_stream_offset = m_StreamOffset; // m_StreamOffset will be changed by the call to Write_EKLV_Packet
571
572       result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
573                                  m_StreamOffset, FrameBuf, m_EssenceUL, Ctx, HMAC);
574       
575       if ( KM_SUCCESS(result) )
576         {
577           ASDCP::FrameBuffer metadata_buffer_wrapper;
578           metadata_buffer_wrapper.SetData((byte_t*)(FrameBuf.OpaqueMetadata.c_str()), FrameBuf.OpaqueMetadata.size());
579           metadata_buffer_wrapper.Size(FrameBuf.OpaqueMetadata.size());
580           
581           
582           result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
583                                      m_StreamOffset, metadata_buffer_wrapper, m_MetadataUL, Ctx, HMAC);
584         }
585       
586       if ( KM_SUCCESS(result) )
587         {  
588           IndexTableSegment::IndexEntry Entry;
589           Entry.StreamOffset = this_stream_offset;
590           m_IndexWriter.PushIndexEntry(Entry);
591         }
592
593       if ( m_FramesWritten > 1 && ( ( m_FramesWritten + 1 ) % m_PartitionSpace ) == 0 )
594         {
595           m_IndexWriter.ThisPartition = m_File.Tell();
596           m_IndexWriter.WriteToFile(m_File);
597           m_RIP.PairArray.push_back(RIP::PartitionPair(0, m_IndexWriter.ThisPartition));
598
599           UL body_ul(m_Dict->ul(MDD_ClosedCompleteBodyPartition));
600           Partition body_part(m_Dict);
601           body_part.BodySID = 1;
602           body_part.OperationalPattern = m_HeaderPart.OperationalPattern;
603           body_part.EssenceContainers = m_HeaderPart.EssenceContainers;
604           body_part.ThisPartition = m_File.Tell();
605
606           body_part.BodyOffset = m_StreamOffset;
607           result = body_part.WriteToFile(m_File, body_ul);
608           m_RIP.PairArray.push_back(RIP::PartitionPair(1, body_part.ThisPartition));
609         }
610     }
611
612   if ( KM_SUCCESS(result) )
613     {
614       m_FramesWritten++;
615     }
616
617   return result;
618 }
619
620 // Closes the MXF file, writing the index and other closing information.
621 //
622 Result_t
623 AS_02::PHDR::MXFWriter::h__Writer::Finalize(const std::string& PHDR_master_metadata)
624 {
625   if ( ! m_State.Test_RUNNING() )
626     return RESULT_STATE;
627
628   Result_t result = m_State.Goto_FINAL();
629
630   if ( KM_SUCCESS(result) )
631     {
632       if ( m_IndexWriter.GetDuration() > 0 )
633         {
634           m_IndexWriter.ThisPartition = this->m_File.Tell();
635           m_IndexWriter.WriteToFile(this->m_File);
636           m_RIP.PairArray.push_back(RIP::PartitionPair(0, this->m_IndexWriter.ThisPartition));
637         }
638
639       if ( ! PHDR_master_metadata.empty() )
640         {
641           // write PHDRSimplePayload
642           Kumu::fpos_t here = m_File.Tell();
643
644           // create generic stream partition header
645           static UL GenericStream_DataElement(m_Dict->ul(MDD_GenericStream_DataElement));
646           ASDCP::MXF::Partition GSPart(m_Dict);
647
648           GSPart.ThisPartition = here;
649           GSPart.PreviousPartition = m_RIP.PairArray.back().ByteOffset;
650           GSPart.OperationalPattern = m_HeaderPart.OperationalPattern;
651           GSPart.BodySID = 2;
652           m_MetadataTrackSubDescriptor->SimplePayloadSID = 2;
653
654           m_RIP.PairArray.push_back(RIP::PartitionPair(2, here));
655           GSPart.EssenceContainers = m_HeaderPart.EssenceContainers;
656
657           static UL gs_part_ul(m_Dict->ul(MDD_GenericStreamPartition));
658           Result_t result = GSPart.WriteToFile(m_File, gs_part_ul);
659
660           if ( KM_SUCCESS(result) )
661             {
662               ASDCP::FrameBuffer tmp_buf;
663               tmp_buf.SetData((byte_t*)PHDR_master_metadata.c_str(), PHDR_master_metadata.size());
664               tmp_buf.Size(PHDR_master_metadata.size());
665
666               result = Write_EKLV_Packet(m_File, *m_Dict, m_HeaderPart, m_Info, m_CtFrameBuf, m_FramesWritten,
667                                          m_StreamOffset, tmp_buf, GenericStream_DataElement.Value(), 0, 0);
668             }
669         }
670
671       result = WriteAS02Footer();
672     }
673
674   return result;
675 }
676
677
678 //------------------------------------------------------------------------------------------
679
680
681
682 AS_02::PHDR::MXFWriter::MXFWriter()
683 {
684 }
685
686 AS_02::PHDR::MXFWriter::~MXFWriter()
687 {
688 }
689
690 // Warning: direct manipulation of MXF structures can interfere
691 // with the normal operation of the wrapper.  Caveat emptor!
692 //
693 ASDCP::MXF::OP1aHeader&
694 AS_02::PHDR::MXFWriter::OP1aHeader()
695 {
696   if ( m_Writer.empty() )
697     {
698       assert(g_OP1aHeader);
699       return *g_OP1aHeader;
700     }
701
702   return m_Writer->m_HeaderPart;
703 }
704
705 // Warning: direct manipulation of MXF structures can interfere
706 // with the normal operation of the wrapper.  Caveat emptor!
707 //
708 ASDCP::MXF::RIP&
709 AS_02::PHDR::MXFWriter::RIP()
710 {
711   if ( m_Writer.empty() )
712     {
713       assert(g_RIP);
714       return *g_RIP;
715     }
716
717   return m_Writer->m_RIP;
718 }
719
720 // Open the file for writing. The file must not exist. Returns error if
721 // the operation cannot be completed.
722 Result_t
723 AS_02::PHDR::MXFWriter::OpenWrite(const std::string& filename, const ASDCP::WriterInfo& Info,
724                                   ASDCP::MXF::FileDescriptor* essence_descriptor,
725                                   ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
726                                   const ASDCP::Rational& edit_rate, const ui32_t& header_size,
727                                   const IndexStrategy_t& strategy, const ui32_t& partition_space)
728 {
729   if ( essence_descriptor == 0 )
730     {
731       DefaultLogSink().Error("Essence descriptor object required.\n");
732       return RESULT_PARAM;
733     }
734
735   m_Writer = new AS_02::PHDR::MXFWriter::h__Writer(DefaultSMPTEDict());
736   m_Writer->m_Info = Info;
737
738   Result_t result = m_Writer->OpenWrite(filename, essence_descriptor, essence_sub_descriptor_list,
739                                         strategy, partition_space, header_size);
740
741   if ( KM_SUCCESS(result) )
742     result = m_Writer->SetSourceStream(JP2K_PACKAGE_LABEL, edit_rate);
743
744   if ( KM_FAILURE(result) )
745     m_Writer.release();
746
747   return result;
748 }
749
750 // Writes a frame of essence to the MXF file. If the optional AESEncContext
751 // argument is present, the essence is encrypted prior to writing.
752 // Fails if the file is not open, is finalized, or an operating system
753 // error occurs.
754 Result_t 
755 AS_02::PHDR::MXFWriter::WriteFrame(const AS_02::PHDR::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
756 {
757   if ( m_Writer.empty() )
758     return RESULT_INIT;
759
760   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
761 }
762
763 // Closes the MXF file, writing the index and other closing information.
764 Result_t
765 AS_02::PHDR::MXFWriter::Finalize(const std::string& PHDR_master_metadata)
766 {
767   if ( m_Writer.empty() )
768     return RESULT_INIT;
769
770   return m_Writer->Finalize(PHDR_master_metadata);
771 }
772
773
774 //
775 // end AS_02_PHDR.cpp
776 //