Updating version info in Win32 portions
[asdcplib.git] / src / AS_DCP_MPEG2.cpp
1 /*
2 Copyright (c) 2004-2011, 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    AS_DCP_MPEG2.cpp
28     \version $Id$       
29     \brief   AS-DCP library, MPEG2 essence reader and writer implementation
30 */
31
32 #include "AS_DCP_internal.h"
33 #include <iostream>
34 #include <iomanip>
35
36
37 //------------------------------------------------------------------------------------------
38
39 static std::string MPEG_PACKAGE_LABEL = "File Package: SMPTE 381M frame wrapping of MPEG2 video elementary stream";
40 static std::string PICT_DEF_LABEL = "Picture Track";
41
42 //
43 ASDCP::Result_t
44 MD_to_MPEG2_VDesc(MXF::MPEG2VideoDescriptor* VDescObj, MPEG2::VideoDescriptor& VDesc)
45 {
46   ASDCP_TEST_NULL(VDescObj);
47
48   VDesc.SampleRate             = VDescObj->SampleRate;
49   VDesc.EditRate               = VDescObj->SampleRate;
50   VDesc.FrameRate              = VDescObj->SampleRate.Numerator;
51   assert(VDescObj->ContainerDuration <= 0xFFFFFFFFL);
52   VDesc.ContainerDuration      = (ui32_t) VDescObj->ContainerDuration;
53
54   VDesc.FrameLayout            = VDescObj->FrameLayout;
55   VDesc.StoredWidth            = VDescObj->StoredWidth;
56   VDesc.StoredHeight           = VDescObj->StoredHeight;
57   VDesc.AspectRatio            = VDescObj->AspectRatio;
58
59   VDesc.ComponentDepth         = VDescObj->ComponentDepth;
60   VDesc.HorizontalSubsampling  = VDescObj->HorizontalSubsampling;
61   VDesc.VerticalSubsampling    = VDescObj->VerticalSubsampling;
62   VDesc.ColorSiting            = VDescObj->ColorSiting;
63   VDesc.CodedContentType       = VDescObj->CodedContentType;
64
65   VDesc.LowDelay               = VDescObj->LowDelay == 0 ? false : true;
66   VDesc.BitRate                = VDescObj->BitRate;
67   VDesc.ProfileAndLevel        = VDescObj->ProfileAndLevel;
68   return RESULT_OK;
69 }
70
71
72 //
73 ASDCP::Result_t
74 MPEG2_VDesc_to_MD(MPEG2::VideoDescriptor& VDesc, MXF::MPEG2VideoDescriptor* VDescObj)
75 {
76   ASDCP_TEST_NULL(VDescObj);
77
78   VDescObj->SampleRate = VDesc.SampleRate;
79   VDescObj->ContainerDuration = VDesc.ContainerDuration;
80
81   VDescObj->FrameLayout = VDesc.FrameLayout;
82   VDescObj->StoredWidth = VDesc.StoredWidth;
83   VDescObj->StoredHeight = VDesc.StoredHeight;
84   VDescObj->AspectRatio = VDesc.AspectRatio;
85
86   VDescObj->ComponentDepth = VDesc.ComponentDepth;
87   VDescObj->HorizontalSubsampling = VDesc.HorizontalSubsampling;
88   VDescObj->VerticalSubsampling = VDesc.VerticalSubsampling;
89   VDescObj->ColorSiting = VDesc.ColorSiting;
90   VDescObj->CodedContentType = VDesc.CodedContentType;
91
92   VDescObj->LowDelay = VDesc.LowDelay ? 1 : 0;
93   VDescObj->BitRate = VDesc.BitRate;
94   VDescObj->ProfileAndLevel = VDesc.ProfileAndLevel;
95   return RESULT_OK;
96 }
97
98 //
99 std::ostream&
100 ASDCP::MPEG2::operator << (std::ostream& strm, const VideoDescriptor& VDesc)
101 {
102   strm << "        SampleRate: " << VDesc.SampleRate.Numerator << "/" << VDesc.SampleRate.Denominator << std::endl;
103   strm << "       FrameLayout: " << (unsigned) VDesc.FrameLayout << std::endl;
104   strm << "       StoredWidth: " << (unsigned) VDesc.StoredWidth << std::endl;
105   strm << "      StoredHeight: " << (unsigned) VDesc.StoredHeight << std::endl;
106   strm << "       AspectRatio: " << VDesc.AspectRatio.Numerator << "/" << VDesc.AspectRatio.Denominator << std::endl;
107   strm << "    ComponentDepth: " << (unsigned) VDesc.ComponentDepth << std::endl;
108   strm << " HorizontalSubsmpl: " << (unsigned) VDesc.HorizontalSubsampling << std::endl;
109   strm << "   VerticalSubsmpl: " << (unsigned) VDesc.VerticalSubsampling << std::endl;
110   strm << "       ColorSiting: " << (unsigned) VDesc.ColorSiting << std::endl;
111   strm << "  CodedContentType: " << (unsigned) VDesc.CodedContentType << std::endl;
112   strm << "          LowDelay: " << (unsigned) VDesc.LowDelay << std::endl;
113   strm << "           BitRate: " << (unsigned) VDesc.BitRate << std::endl;
114   strm << "   ProfileAndLevel: " << (unsigned) VDesc.ProfileAndLevel << std::endl;
115   strm << " ContainerDuration: " << (unsigned) VDesc.ContainerDuration << std::endl;
116
117   return strm;
118 }
119
120 //
121 void
122 ASDCP::MPEG2::VideoDescriptorDump(const VideoDescriptor& VDesc, FILE* stream)
123 {
124   if ( stream == 0 )
125     stream = stderr;
126
127   fprintf(stream, "\
128         SampleRate: %d/%d\n\
129        FrameLayout: %u\n\
130        StoredWidth: %u\n\
131       StoredHeight: %u\n\
132        AspectRatio: %d/%d\n\
133     ComponentDepth: %u\n\
134  HorizontalSubsmpl: %u\n\
135    VerticalSubsmpl: %u\n\
136        ColorSiting: %u\n\
137   CodedContentType: %u\n\
138           LowDelay: %u\n\
139            BitRate: %u\n\
140    ProfileAndLevel: %u\n\
141  ContainerDuration: %u\n",
142           VDesc.SampleRate.Numerator ,VDesc.SampleRate.Denominator,
143           VDesc.FrameLayout,
144           VDesc.StoredWidth,
145           VDesc.StoredHeight,
146           VDesc.AspectRatio.Numerator ,VDesc.AspectRatio.Denominator,
147           VDesc.ComponentDepth,
148           VDesc.HorizontalSubsampling,
149           VDesc.VerticalSubsampling,
150           VDesc.ColorSiting,
151           VDesc.CodedContentType,
152           VDesc.LowDelay,
153           VDesc.BitRate,
154           VDesc.ProfileAndLevel,
155           VDesc.ContainerDuration
156           );
157 }
158
159 //------------------------------------------------------------------------------------------
160 //
161 // hidden, internal implementation of MPEG2 reader
162
163 class ASDCP::MPEG2::MXFReader::h__Reader : public ASDCP::h__Reader
164 {
165   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
166   h__Reader();
167
168 public:
169   VideoDescriptor m_VDesc;        // video parameter list
170
171   h__Reader(const Dictionary& d) : ASDCP::h__Reader(d) {}
172   ~h__Reader() {}
173   Result_t    OpenRead(const char*);
174   Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
175   Result_t    ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
176   Result_t    FindFrameGOPStart(ui32_t, ui32_t&);
177   Result_t    FrameType(ui32_t FrameNum, FrameType_t& type);
178 };
179
180
181 //
182 //
183 ASDCP::Result_t
184 ASDCP::MPEG2::MXFReader::h__Reader::OpenRead(const char* filename)
185 {
186   Result_t result = OpenMXFRead(filename);
187
188   if( ASDCP_SUCCESS(result) )
189     {
190       InterchangeObject* Object;
191       if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(MPEG2VideoDescriptor), &Object)) )
192         {
193           assert(Object);
194           result = MD_to_MPEG2_VDesc((MXF::MPEG2VideoDescriptor*)Object, m_VDesc);
195         }
196     }
197
198   if( ASDCP_SUCCESS(result) )
199     result = InitMXFIndex();
200
201   if( ASDCP_SUCCESS(result) )
202     result = InitInfo();
203
204   return result;
205 }
206
207
208 //
209 //
210 ASDCP::Result_t
211 ASDCP::MPEG2::MXFReader::h__Reader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf,
212                                                       AESDecContext* Ctx, HMACContext* HMAC)
213 {
214   ui32_t KeyFrameNum;
215
216   Result_t result = FindFrameGOPStart(FrameNum, KeyFrameNum);
217
218   if ( ASDCP_SUCCESS(result) )
219     result = ReadFrame(KeyFrameNum, FrameBuf, Ctx, HMAC);
220
221   return result;
222 }
223
224
225 //
226 //
227 ASDCP::Result_t
228 ASDCP::MPEG2::MXFReader::h__Reader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& KeyFrameNum)
229 {
230   KeyFrameNum = 0;
231
232   if ( ! m_File.IsOpen() )
233     return RESULT_INIT;
234
235   // look up frame index node
236   IndexTableSegment::IndexEntry TmpEntry;
237
238   if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
239     {
240       DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
241       return RESULT_RANGE;
242     }
243
244   KeyFrameNum = FrameNum - TmpEntry.KeyFrameOffset;
245
246   return RESULT_OK;
247 }
248
249 //
250 ASDCP::Result_t
251 ASDCP::MPEG2::MXFReader::h__Reader::FrameType(ui32_t FrameNum, FrameType_t& type)
252 {
253   if ( ! m_File.IsOpen() )
254     return RESULT_INIT;
255
256   // look up frame index node
257   IndexTableSegment::IndexEntry TmpEntry;
258
259   if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
260     {
261       DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
262       return RESULT_RANGE;
263     }
264
265   type = ( (TmpEntry.Flags & 0x0f) == 3 ) ? FRAME_B : ( (TmpEntry.Flags & 0x0f) == 2 ) ? FRAME_P : FRAME_I;
266   return RESULT_OK;
267 }
268
269
270 //
271 //
272 ASDCP::Result_t
273 ASDCP::MPEG2::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
274                                               AESDecContext* Ctx, HMACContext* HMAC)
275 {
276   assert(m_Dict);
277   if ( ! m_File.IsOpen() )
278     return RESULT_INIT;
279
280   Result_t result = ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_MPEG2Essence), Ctx, HMAC);
281
282   if ( ASDCP_FAILURE(result) )
283     return result;
284
285   IndexTableSegment::IndexEntry TmpEntry;
286   m_FooterPart.Lookup(FrameNum, TmpEntry);
287
288   switch ( ( TmpEntry.Flags >> 4 ) & 0x03 )
289     {
290     case 0:  FrameBuf.FrameType(FRAME_I); break;
291     case 2:  FrameBuf.FrameType(FRAME_P); break;
292     case 3:  FrameBuf.FrameType(FRAME_B); break;
293     default: FrameBuf.FrameType(FRAME_U);
294     }
295
296   FrameBuf.TemporalOffset(TmpEntry.TemporalOffset);
297   FrameBuf.GOPStart(TmpEntry.Flags & 0x40 ? true : false);
298   FrameBuf.ClosedGOP(TmpEntry.Flags & 0x80 ? true : false);
299
300   return RESULT_OK;
301 }
302
303 //------------------------------------------------------------------------------------------
304
305
306 //
307 void
308 ASDCP::MPEG2::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
309 {
310   if ( stream == 0 )
311     stream = stderr;
312
313   fprintf(stream, "Frame: %06u, %c%-2hu, %7u bytes",
314           m_FrameNumber, FrameTypeChar(m_FrameType), m_TemporalOffset, m_Size);
315
316   if ( m_GOPStart )
317     fprintf(stream, " (start %s GOP)", ( m_ClosedGOP ? "closed" : "open"));
318   
319   fputc('\n', stream);
320
321   if ( dump_len > 0 )
322     Kumu::hexdump(m_Data, dump_len, stream);
323 }
324
325
326 //------------------------------------------------------------------------------------------
327
328 ASDCP::MPEG2::MXFReader::MXFReader()
329 {
330   m_Reader = new h__Reader(DefaultCompositeDict());
331 }
332
333
334 ASDCP::MPEG2::MXFReader::~MXFReader()
335 {
336 }
337
338 // Open the file for reading. The file must exist. Returns error if the
339 // operation cannot be completed.
340 ASDCP::Result_t
341 ASDCP::MPEG2::MXFReader::OpenRead(const char* filename) const
342 {
343   return m_Reader->OpenRead(filename);
344 }
345
346 //
347 ASDCP::Result_t
348 ASDCP::MPEG2::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
349                                    AESDecContext* Ctx, HMACContext* HMAC) const
350 {
351   if ( m_Reader && m_Reader->m_File.IsOpen() )
352     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
353
354   return RESULT_INIT;
355 }
356
357
358 //
359 ASDCP::Result_t
360 ASDCP::MPEG2::MXFReader::ReadFrameGOPStart(ui32_t FrameNum, FrameBuffer& FrameBuf,
361                                            AESDecContext* Ctx, HMACContext* HMAC) const
362 {
363   if ( m_Reader && m_Reader->m_File.IsOpen() )
364     return m_Reader->ReadFrameGOPStart(FrameNum, FrameBuf, Ctx, HMAC);
365
366   return RESULT_INIT;
367 }
368
369
370 //
371 ASDCP::Result_t
372 ASDCP::MPEG2::MXFReader::FindFrameGOPStart(ui32_t FrameNum, ui32_t& KeyFrameNum) const
373 {
374   if ( m_Reader && m_Reader->m_File.IsOpen() )
375     return m_Reader->FindFrameGOPStart(FrameNum, KeyFrameNum);
376
377   return RESULT_INIT;
378 }
379
380
381 // Fill the struct with the values from the file's header.
382 // Returns RESULT_INIT if the file is not open.
383 ASDCP::Result_t
384 ASDCP::MPEG2::MXFReader::FillVideoDescriptor(VideoDescriptor& VDesc) const
385 {
386   if ( m_Reader && m_Reader->m_File.IsOpen() )
387     {
388       VDesc = m_Reader->m_VDesc;
389       return RESULT_OK;
390     }
391
392   return RESULT_INIT;
393 }
394
395
396 // Fill the struct with the values from the file's header.
397 // Returns RESULT_INIT if the file is not open.
398 ASDCP::Result_t
399 ASDCP::MPEG2::MXFReader::FillWriterInfo(WriterInfo& Info) const
400 {
401   if ( m_Reader && m_Reader->m_File.IsOpen() )
402     {
403       Info = m_Reader->m_Info;
404       return RESULT_OK;
405     }
406
407   return RESULT_INIT;
408 }
409
410 //
411 void
412 ASDCP::MPEG2::MXFReader::DumpHeaderMetadata(FILE* stream) const
413 {
414   if ( m_Reader->m_File.IsOpen() )
415     m_Reader->m_HeaderPart.Dump(stream);
416 }
417
418
419 //
420 void
421 ASDCP::MPEG2::MXFReader::DumpIndex(FILE* stream) const
422 {
423   if ( m_Reader->m_File.IsOpen() )
424     m_Reader->m_FooterPart.Dump(stream);
425 }
426
427 //
428 ASDCP::Result_t
429 ASDCP::MPEG2::MXFReader::Close() const
430 {
431   if ( m_Reader && m_Reader->m_File.IsOpen() )
432     {
433       m_Reader->Close();
434       return RESULT_OK;
435     }
436
437   return RESULT_INIT;
438 }
439
440 //
441 ASDCP::Result_t
442 ASDCP::MPEG2::MXFReader::FrameType(ui32_t FrameNum, FrameType_t& type) const
443 {
444   if ( ! m_Reader )
445     return RESULT_INIT;
446
447   return m_Reader->FrameType(FrameNum, type);
448 }
449
450
451 //------------------------------------------------------------------------------------------
452
453 //
454 class ASDCP::MPEG2::MXFWriter::h__Writer : public ASDCP::h__Writer
455 {
456   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
457   h__Writer();
458
459 public:
460   VideoDescriptor m_VDesc;
461   ui32_t          m_GOPOffset;
462   byte_t          m_EssenceUL[SMPTE_UL_LENGTH];
463
464   h__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_GOPOffset(0) {
465     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
466   }
467
468   ~h__Writer(){}
469
470   Result_t OpenWrite(const char*, ui32_t HeaderSize);
471   Result_t SetSourceStream(const VideoDescriptor&);
472   Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
473   Result_t Finalize();
474 };
475
476
477 // Open the file for writing. The file must not exist. Returns error if
478 // the operation cannot be completed.
479 ASDCP::Result_t
480 ASDCP::MPEG2::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
481 {
482   if ( ! m_State.Test_BEGIN() )
483     return RESULT_STATE;
484
485   Result_t result = m_File.OpenWrite(filename);
486
487   if ( ASDCP_SUCCESS(result) )
488     {
489       m_HeaderSize = HeaderSize;
490       m_EssenceDescriptor = new MPEG2VideoDescriptor(m_Dict);
491       result = m_State.Goto_INIT();
492     }
493
494   return result;
495 }
496
497 // Automatically sets the MXF file's metadata from the MPEG stream.
498 ASDCP::Result_t
499 ASDCP::MPEG2::MXFWriter::h__Writer::SetSourceStream(const VideoDescriptor& VDesc)
500 {
501   assert(m_Dict);
502   if ( ! m_State.Test_INIT() )
503     return RESULT_STATE;
504
505   m_VDesc = VDesc;
506   Result_t result = MPEG2_VDesc_to_MD(m_VDesc, (MPEG2VideoDescriptor*)m_EssenceDescriptor);
507
508   if ( ASDCP_SUCCESS(result) )
509     {
510       memcpy(m_EssenceUL, m_Dict->ul(MDD_MPEG2Essence), SMPTE_UL_LENGTH);
511       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
512       result = m_State.Goto_READY();
513     }
514
515   if ( ASDCP_SUCCESS(result) )
516     {
517       ui32_t TCFrameRate = ( m_VDesc.EditRate == EditRate_23_98  ) ? 24 : m_VDesc.EditRate.Numerator;
518
519       result = WriteMXFHeader(MPEG_PACKAGE_LABEL, UL(m_Dict->ul(MDD_MPEG2_VESWrapping)), 
520                               PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
521                               m_VDesc.EditRate, TCFrameRate);
522     }
523
524   return result;
525 }
526
527 // Writes a frame of essence to the MXF file. If the optional AESEncContext
528 // argument is present, the essence is encrypted prior to writing.
529 // Fails if the file is not open, is finalized, or an operating system
530 // error occurs.
531 //
532 ASDCP::Result_t
533 ASDCP::MPEG2::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
534                                                HMACContext* HMAC)
535 {
536   Result_t result = RESULT_OK;
537
538   if ( m_State.Test_READY() )
539     result = m_State.Goto_RUNNING(); // first time through, get the body location
540
541   IndexTableSegment::IndexEntry Entry;
542   Entry.StreamOffset = m_StreamOffset;
543
544   if ( ASDCP_SUCCESS(result) )
545     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
546
547   if ( ASDCP_FAILURE(result) )
548     return result;
549
550   // create mxflib flags
551   int Flags = 0;
552
553   switch ( FrameBuf.FrameType() )
554     {
555     case FRAME_I: Flags = 0x00; break;
556     case FRAME_P: Flags = 0x22; break;
557     case FRAME_B: Flags = 0x33; break;
558     }
559
560   if ( FrameBuf.GOPStart() )
561     {
562       m_GOPOffset = 0;
563       Flags |= 0x40;
564
565       if ( FrameBuf.ClosedGOP() )
566         Flags |= 0x80;
567     }
568
569   // update the index manager
570   Entry.TemporalOffset = - FrameBuf.TemporalOffset();
571   Entry.KeyFrameOffset = 0 - m_GOPOffset;
572   Entry.Flags = Flags;
573   /*
574   fprintf(stderr, "to: %4hd   ko: %4hd   c1: %4hd   c2: %4hd   fl: 0x%02x\n",
575           Entry.TemporalOffset, Entry.KeyFrameOffset,
576           m_GOPOffset + Entry.TemporalOffset,
577           Entry.KeyFrameOffset - Entry.TemporalOffset,
578           Entry.Flags);
579   */
580   m_FooterPart.PushIndexEntry(Entry);
581   m_FramesWritten++;
582   m_GOPOffset++;
583
584   return RESULT_OK;
585 }
586
587
588 // Closes the MXF file, writing the index and other closing information.
589 //
590 ASDCP::Result_t
591 ASDCP::MPEG2::MXFWriter::h__Writer::Finalize()
592 {
593   if ( ! m_State.Test_RUNNING() )
594     return RESULT_STATE;
595
596   m_State.Goto_FINAL();
597
598   return WriteMXFFooter();
599 }
600
601
602 //------------------------------------------------------------------------------------------
603
604
605
606 ASDCP::MPEG2::MXFWriter::MXFWriter()
607 {
608 }
609
610 ASDCP::MPEG2::MXFWriter::~MXFWriter()
611 {
612 }
613
614
615 // Open the file for writing. The file must not exist. Returns error if
616 // the operation cannot be completed.
617 ASDCP::Result_t
618 ASDCP::MPEG2::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
619                                    const VideoDescriptor& VDesc, ui32_t HeaderSize)
620 {
621   if ( Info.LabelSetType == LS_MXF_SMPTE )
622     m_Writer = new h__Writer(DefaultSMPTEDict());
623   else
624     m_Writer = new h__Writer(DefaultInteropDict());
625
626   m_Writer->m_Info = Info;
627   
628   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
629
630   if ( ASDCP_SUCCESS(result) )
631     result = m_Writer->SetSourceStream(VDesc);
632
633   if ( ASDCP_FAILURE(result) )
634     m_Writer.release();
635
636   return result;
637 }
638
639
640 // Writes a frame of essence to the MXF file. If the optional AESEncContext
641 // argument is present, the essence is encrypted prior to writing.
642 // Fails if the file is not open, is finalized, or an operating system
643 // error occurs.
644 ASDCP::Result_t
645 ASDCP::MPEG2::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
646 {
647   if ( m_Writer.empty() )
648     return RESULT_INIT;
649
650   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
651 }
652
653 // Closes the MXF file, writing the index and other closing information.
654 ASDCP::Result_t
655 ASDCP::MPEG2::MXFWriter::Finalize()
656 {
657   if ( m_Writer.empty() )
658     return RESULT_INIT;
659
660   return m_Writer->Finalize();
661 }
662
663
664 //
665 // end AS_DCP_MPEG2.cpp
666 //