working j2c as-02
[asdcplib.git] / src / AS_DCP_PCM.cpp
1 /*
2 Copyright (c) 2004-2013, 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_PCM.cpp
28     \version $Id$       
29     \brief   AS-DCP library, PCM essence reader and writer implementation
30 */
31
32 #include "AS_DCP_internal.h"
33 #include <map>
34 #include <iostream>
35 #include <iomanip>
36
37 //------------------------------------------------------------------------------------------
38
39 static std::string PCM_PACKAGE_LABEL = "File Package: SMPTE 382M frame wrapping of wave audio";
40 static std::string SOUND_DEF_LABEL = "Sound Track";
41
42 //
43 Result_t
44 ASDCP::PCM_ADesc_to_MD(PCM::AudioDescriptor& ADesc, MXF::WaveAudioDescriptor* ADescObj)
45 {
46   ASDCP_TEST_NULL(ADescObj);
47   ADescObj->SampleRate = ADesc.EditRate;
48   ADescObj->AudioSamplingRate = ADesc.AudioSamplingRate;
49   ADescObj->Locked = ADesc.Locked;
50   ADescObj->ChannelCount = ADesc.ChannelCount;
51   ADescObj->QuantizationBits = ADesc.QuantizationBits;
52   ADescObj->BlockAlign = ADesc.BlockAlign;
53   ADescObj->AvgBps = ADesc.AvgBps;
54   ADescObj->LinkedTrackID = ADesc.LinkedTrackID;
55   ADescObj->ContainerDuration = ADesc.ContainerDuration;
56
57   ADescObj->ChannelAssignment.Reset();
58
59   switch ( ADesc.ChannelFormat )
60     {
61       case PCM::CF_CFG_1:
62         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_1_5p1).ul;
63         break;
64
65       case PCM::CF_CFG_2:
66         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_2_6p1).ul;
67         break;
68
69       case PCM::CF_CFG_3:
70         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_3_7p1).ul;
71         break;
72
73       case PCM::CF_CFG_4:
74         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_4_WTF).ul;
75         break;
76
77       case PCM::CF_CFG_5:
78         ADescObj->ChannelAssignment = DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_5_7p1_DS).ul;
79         break;
80     }
81
82   return RESULT_OK;
83 }
84
85 //
86 ASDCP::Result_t
87 ASDCP::MD_to_PCM_ADesc(MXF::WaveAudioDescriptor* ADescObj, PCM::AudioDescriptor& ADesc)
88 {
89   ASDCP_TEST_NULL(ADescObj);
90   ADesc.EditRate = ADescObj->SampleRate;
91   ADesc.AudioSamplingRate = ADescObj->AudioSamplingRate;
92   ADesc.Locked = ADescObj->Locked;
93   ADesc.ChannelCount = ADescObj->ChannelCount;
94   ADesc.QuantizationBits = ADescObj->QuantizationBits;
95   ADesc.BlockAlign = ADescObj->BlockAlign;
96   ADesc.AvgBps = ADescObj->AvgBps;
97   ADesc.LinkedTrackID = ADescObj->LinkedTrackID;
98   assert(ADescObj->ContainerDuration <= 0xFFFFFFFFL);
99   ADesc.ContainerDuration = (ui32_t) ADescObj->ContainerDuration;
100
101   ADesc.ChannelFormat = PCM::CF_NONE;
102
103   if ( ADescObj->ChannelAssignment.HasValue() )
104     {
105       if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_1_5p1).ul )
106         ADesc.ChannelFormat = PCM::CF_CFG_1;
107
108       else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_2_6p1).ul )
109         ADesc.ChannelFormat = PCM::CF_CFG_2;
110
111       else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_3_7p1).ul )
112         ADesc.ChannelFormat = PCM::CF_CFG_3;
113
114       else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_4_WTF).ul )
115         ADesc.ChannelFormat = PCM::CF_CFG_4;
116
117       else if ( ADescObj->ChannelAssignment == DefaultSMPTEDict().Type(MDD_DCAudioChannelCfg_5_7p1_DS).ul )
118         ADesc.ChannelFormat = PCM::CF_CFG_5;
119     }
120
121   return RESULT_OK;
122 }
123
124 //
125 std::ostream&
126 ASDCP::PCM::operator << (std::ostream& strm, const AudioDescriptor& ADesc)
127 {
128   strm << "        SampleRate: " << ADesc.EditRate.Numerator << "/" << ADesc.EditRate.Denominator << std::endl;
129   strm << " AudioSamplingRate: " << ADesc.AudioSamplingRate.Numerator << "/" << ADesc.AudioSamplingRate.Denominator << std::endl;
130   strm << "            Locked: " << (unsigned) ADesc.Locked << std::endl;
131   strm << "      ChannelCount: " << (unsigned) ADesc.ChannelCount << std::endl;
132   strm << "  QuantizationBits: " << (unsigned) ADesc.QuantizationBits << std::endl;
133   strm << "        BlockAlign: " << (unsigned) ADesc.BlockAlign << std::endl;
134   strm << "            AvgBps: " << (unsigned) ADesc.AvgBps << std::endl;
135   strm << "     LinkedTrackID: " << (unsigned) ADesc.LinkedTrackID << std::endl;
136   strm << " ContainerDuration: " << (unsigned) ADesc.ContainerDuration << std::endl;
137   strm << "     ChannelFormat: ";
138   switch (ADesc.ChannelFormat)
139   {
140     case CF_NONE:
141     default:
142       strm << "No Channel Format";
143       break;
144
145     case CF_CFG_1:
146       strm << "Config 1 (5.1 with optional HI/VI)";
147       break;
148
149     case CF_CFG_2:
150       strm << "Config 2 (5.1 + center surround with optional HI/VI)";
151       break;
152
153     case CF_CFG_3:
154       strm << "Config 3 (7.1 with optional HI/VI)";
155       break;
156
157     case CF_CFG_4:
158       strm << "Config 4";
159       break;
160
161     case CF_CFG_5:
162       strm << "Config 5 (7.1 DS with optional HI/VI)";
163       break;
164   }
165   strm << std::endl;
166
167   return strm;
168 }
169
170 //
171 void
172 ASDCP::PCM::AudioDescriptorDump(const AudioDescriptor& ADesc, FILE* stream)
173 {
174   if ( stream == 0 )
175     stream = stderr;
176
177   fprintf(stream, "\
178         EditRate: %d/%d\n\
179  AudioSamplingRate: %d/%d\n\
180             Locked: %u\n\
181       ChannelCount: %u\n\
182   QuantizationBits: %u\n\
183         BlockAlign: %u\n\
184             AvgBps: %u\n\
185      LinkedTrackID: %u\n\
186  ContainerDuration: %u\n\
187      ChannelFormat: %u\n",
188           ADesc.EditRate.Numerator, ADesc.EditRate.Denominator,
189           ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator,
190           ADesc.Locked,
191           ADesc.ChannelCount,
192           ADesc.QuantizationBits,
193           ADesc.BlockAlign,
194           ADesc.AvgBps,
195           ADesc.LinkedTrackID,
196           ADesc.ContainerDuration,
197           ADesc.ChannelFormat
198           );
199 }
200
201
202 //
203 //
204 static ui32_t
205 calc_CBR_frame_size(ASDCP::WriterInfo& Info, const ASDCP::PCM::AudioDescriptor& ADesc)
206 {
207   ui32_t CBR_frame_size = 0;
208
209   if ( Info.EncryptedEssence )
210     {
211       CBR_frame_size =
212         SMPTE_UL_LENGTH
213         + MXF_BER_LENGTH
214         + klv_cryptinfo_size
215         + calc_esv_length(ASDCP::PCM::CalcFrameBufferSize(ADesc), 0)
216         + ( Info.UsesHMAC ? klv_intpack_size : (MXF_BER_LENGTH * 3) );
217     }
218   else
219     {
220       CBR_frame_size = ASDCP::PCM::CalcFrameBufferSize(ADesc) + SMPTE_UL_LENGTH + MXF_BER_LENGTH;
221     }
222
223   return CBR_frame_size;
224 }
225
226
227 //------------------------------------------------------------------------------------------
228
229
230 class ASDCP::PCM::MXFReader::h__Reader : public ASDCP::h__ASDCPReader
231 {
232   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
233   h__Reader();
234
235 public:
236   AudioDescriptor m_ADesc;
237
238   h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d) {}
239   virtual ~h__Reader() {}
240   Result_t    OpenRead(const char*);
241   Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
242 };
243
244
245 //
246 //
247 ASDCP::Result_t
248 ASDCP::PCM::MXFReader::h__Reader::OpenRead(const char* filename)
249 {
250   Result_t result = OpenMXFRead(filename);
251
252   if( ASDCP_SUCCESS(result) )
253     {
254       InterchangeObject* Object = 0
255 ;
256       if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &Object)) )
257         {
258           if ( Object == 0 )
259             {
260               DefaultLogSink().Error("WaveAudioDescriptor object not found.\n");
261               return RESULT_FORMAT;
262             }
263
264           result = MD_to_PCM_ADesc((MXF::WaveAudioDescriptor*)Object, m_ADesc);
265         }
266     }
267
268   // check for sample/frame rate sanity
269   if ( ASDCP_SUCCESS(result)
270        && m_ADesc.EditRate != EditRate_24
271        && m_ADesc.EditRate != EditRate_25
272        && m_ADesc.EditRate != EditRate_30
273        && m_ADesc.EditRate != EditRate_48
274        && m_ADesc.EditRate != EditRate_50
275        && m_ADesc.EditRate != EditRate_60
276        && m_ADesc.EditRate != EditRate_96
277        && m_ADesc.EditRate != EditRate_100
278        && m_ADesc.EditRate != EditRate_120
279        && m_ADesc.EditRate != EditRate_16
280        && m_ADesc.EditRate != EditRate_18
281        && m_ADesc.EditRate != EditRate_20
282        && m_ADesc.EditRate != EditRate_22
283        && m_ADesc.EditRate != EditRate_23_98 )
284     {
285       DefaultLogSink().Error("PCM file EditRate is not a supported value: %d/%d\n", // lu
286                              m_ADesc.EditRate.Numerator, m_ADesc.EditRate.Denominator);
287
288       // oh, they gave us the audio sampling rate instead, assume 24/1
289       if ( m_ADesc.EditRate == SampleRate_48k )
290         {
291           DefaultLogSink().Warn("adjusting EditRate to 24/1\n"); 
292           m_ADesc.EditRate = EditRate_24;
293         }
294       else
295         {
296       DefaultLogSink().Error("PCM EditRate not in expected value range.\n");
297           // or we just drop the hammer
298           return RESULT_FORMAT;
299         }
300     }
301
302   // TODO: test file for sane CBR index BytesPerEditUnit
303
304   return result;
305 }
306
307
308 //
309 //
310 ASDCP::Result_t
311 ASDCP::PCM::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
312                                             AESDecContext* Ctx, HMACContext* HMAC)
313 {
314   if ( ! m_File.IsOpen() )
315     return RESULT_INIT;
316
317   assert(m_Dict);
318   return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_WAVEssence), Ctx, HMAC);
319 }
320
321 //------------------------------------------------------------------------------------------
322
323
324 //
325 void
326 ASDCP::PCM::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
327 {
328   if ( stream == 0 )
329     stream = stderr;
330
331   fprintf(stream, "Frame: %06u, %7u bytes\n",
332           m_FrameNumber, m_Size);
333
334   if ( dump_len )
335     Kumu::hexdump(m_Data, dump_len, stream);
336 }
337
338 //------------------------------------------------------------------------------------------
339
340 ASDCP::PCM::MXFReader::MXFReader()
341 {
342   m_Reader = new h__Reader(DefaultCompositeDict());
343 }
344
345
346 ASDCP::PCM::MXFReader::~MXFReader()
347 {
348   if ( m_Reader && m_Reader->m_File.IsOpen() )
349     m_Reader->Close();
350 }
351
352 // Warning: direct manipulation of MXF structures can interfere
353 // with the normal operation of the wrapper.  Caveat emptor!
354 //
355 ASDCP::MXF::OP1aHeader&
356 ASDCP::PCM::MXFReader::OP1aHeader()
357 {
358   if ( m_Reader.empty() )
359     {
360       assert(g_OP1aHeader);
361       return *g_OP1aHeader;
362     }
363
364   return m_Reader->m_HeaderPart;
365 }
366
367 // Warning: direct manipulation of MXF structures can interfere
368 // with the normal operation of the wrapper.  Caveat emptor!
369 //
370 ASDCP::MXF::OPAtomIndexFooter&
371 ASDCP::PCM::MXFReader::OPAtomIndexFooter()
372 {
373   if ( m_Reader.empty() )
374     {
375       assert(g_OPAtomIndexFooter);
376       return *g_OPAtomIndexFooter;
377     }
378
379   return m_Reader->m_IndexAccess;
380 }
381
382 // Warning: direct manipulation of MXF structures can interfere
383 // with the normal operation of the wrapper.  Caveat emptor!
384 //
385 ASDCP::MXF::RIP&
386 ASDCP::PCM::MXFReader::RIP()
387 {
388   if ( m_Reader.empty() )
389     {
390       assert(g_RIP);
391       return *g_RIP;
392     }
393
394   return m_Reader->m_RIP;
395 }
396
397 // Open the file for reading. The file must exist. Returns error if the
398 // operation cannot be completed.
399 ASDCP::Result_t
400 ASDCP::PCM::MXFReader::OpenRead(const char* filename) const
401 {
402   return m_Reader->OpenRead(filename);
403 }
404
405 // Reads a frame of essence from the MXF file. If the optional AESEncContext
406 // argument is present, the essence is decrypted after reading. If the MXF
407 // file is encrypted and the AESDecContext argument is NULL, the frame buffer
408 // will contain the ciphertext frame data.
409 ASDCP::Result_t
410 ASDCP::PCM::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
411                                  AESDecContext* Ctx, HMACContext* HMAC) const
412 {
413   if ( m_Reader && m_Reader->m_File.IsOpen() )
414     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
415
416   return RESULT_INIT;
417 }
418
419
420 ASDCP::Result_t
421 ASDCP::PCM::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
422 {
423     return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
424 }
425
426 // Fill the struct with the values from the file's header.
427 // Returns RESULT_INIT if the file is not open.
428 ASDCP::Result_t
429 ASDCP::PCM::MXFReader::FillAudioDescriptor(AudioDescriptor& ADesc) const
430 {
431   if ( m_Reader && m_Reader->m_File.IsOpen() )
432     {
433       ADesc = m_Reader->m_ADesc;
434       return RESULT_OK;
435     }
436
437   return RESULT_INIT;
438 }
439
440 // Fill the struct with the values from the file's header.
441 // Returns RESULT_INIT if the file is not open.
442 ASDCP::Result_t
443 ASDCP::PCM::MXFReader::FillWriterInfo(WriterInfo& Info) const
444 {
445   if ( m_Reader && m_Reader->m_File.IsOpen() )
446     {
447       Info = m_Reader->m_Info;
448       return RESULT_OK;
449     }
450
451   return RESULT_INIT;
452 }
453
454 //
455 void
456 ASDCP::PCM::MXFReader::DumpHeaderMetadata(FILE* stream) const
457 {
458   if ( m_Reader && m_Reader->m_File.IsOpen() )
459     m_Reader->m_HeaderPart.Dump(stream);
460 }
461
462
463 //
464 void
465 ASDCP::PCM::MXFReader::DumpIndex(FILE* stream) const
466 {
467   if ( m_Reader->m_File.IsOpen() )
468     m_Reader->m_IndexAccess.Dump(stream);
469 }
470
471 //
472 ASDCP::Result_t
473 ASDCP::PCM::MXFReader::Close() const
474 {
475   if ( m_Reader && m_Reader->m_File.IsOpen() )
476     {
477       m_Reader->Close();
478       return RESULT_OK;
479     }
480
481   return RESULT_INIT;
482 }
483
484
485 //------------------------------------------------------------------------------------------
486
487 //
488 class ASDCP::PCM::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter
489 {
490   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
491   h__Writer();
492
493 public:
494   AudioDescriptor m_ADesc;
495   byte_t          m_EssenceUL[SMPTE_UL_LENGTH];
496   
497   h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d) {
498     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
499   }
500
501   virtual ~h__Writer(){}
502
503   Result_t OpenWrite(const char*, ui32_t HeaderSize);
504   Result_t SetSourceStream(const AudioDescriptor&);
505   Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
506   Result_t Finalize();
507 };
508
509
510
511 // Open the file for writing. The file must not exist. Returns error if
512 // the operation cannot be completed.
513 ASDCP::Result_t
514 ASDCP::PCM::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
515 {
516   if ( ! m_State.Test_BEGIN() )
517     return RESULT_STATE;
518
519   Result_t result = m_File.OpenWrite(filename);
520
521   if ( ASDCP_SUCCESS(result) )
522     {
523       m_HeaderSize = HeaderSize;
524       m_EssenceDescriptor = new WaveAudioDescriptor(m_Dict);
525       result = m_State.Goto_INIT();
526     }
527
528   return result;
529 }
530
531
532 // Automatically sets the MXF file's metadata from the WAV parser info.
533 ASDCP::Result_t
534 ASDCP::PCM::MXFWriter::h__Writer::SetSourceStream(const AudioDescriptor& ADesc)
535 {
536   if ( ! m_State.Test_INIT() )
537     return RESULT_STATE;
538
539   if ( ADesc.EditRate != EditRate_24
540        && ADesc.EditRate != EditRate_25
541        && ADesc.EditRate != EditRate_30
542        && ADesc.EditRate != EditRate_48
543        && ADesc.EditRate != EditRate_50
544        && ADesc.EditRate != EditRate_60
545        && ADesc.EditRate != EditRate_96
546        && ADesc.EditRate != EditRate_100
547        && ADesc.EditRate != EditRate_120
548        && ADesc.EditRate != EditRate_16
549        && ADesc.EditRate != EditRate_18
550        && ADesc.EditRate != EditRate_20
551        && ADesc.EditRate != EditRate_22
552        && ADesc.EditRate != EditRate_23_98 )
553     {
554       DefaultLogSink().Error("AudioDescriptor.EditRate is not a supported value: %d/%d\n",
555                              ADesc.EditRate.Numerator, ADesc.EditRate.Denominator);
556       return RESULT_RAW_FORMAT;
557     }
558
559   if ( ADesc.AudioSamplingRate != SampleRate_48k && ADesc.AudioSamplingRate != SampleRate_96k )
560     {
561       DefaultLogSink().Error("AudioDescriptor.AudioSamplingRate is not 48000/1 or 96000/1: %d/%d\n",
562                              ADesc.AudioSamplingRate.Numerator, ADesc.AudioSamplingRate.Denominator);
563       return RESULT_RAW_FORMAT;
564     }
565
566   assert(m_Dict);
567   m_ADesc = ADesc;
568
569   Result_t result = PCM_ADesc_to_MD(m_ADesc, (WaveAudioDescriptor*)m_EssenceDescriptor);
570   
571   if ( ASDCP_SUCCESS(result) )
572     {
573       memcpy(m_EssenceUL, m_Dict->ul(MDD_WAVEssence), SMPTE_UL_LENGTH);
574       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
575       result = m_State.Goto_READY();
576     }
577
578   if ( ASDCP_SUCCESS(result) )
579     {
580       ui32_t TCFrameRate = m_ADesc.EditRate.Numerator;
581
582       if ( m_ADesc.EditRate == EditRate_23_98  )
583         TCFrameRate = 24;
584       else if ( m_ADesc.EditRate == EditRate_18  )
585         TCFrameRate = 18;
586       else if ( m_ADesc.EditRate == EditRate_22  )
587         TCFrameRate = 22;
588       
589       result = WriteASDCPHeader(PCM_PACKAGE_LABEL, UL(m_Dict->ul(MDD_WAVWrapping)),
590                                 SOUND_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_SoundDataDef)),
591                                 m_ADesc.EditRate, TCFrameRate, calc_CBR_frame_size(m_Info, m_ADesc));
592     }
593
594   return result;
595 }
596
597
598 //
599 //
600 ASDCP::Result_t
601 ASDCP::PCM::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
602                                              HMACContext* HMAC)
603 {
604   Result_t result = RESULT_OK;
605
606   if ( m_State.Test_READY() )
607     result = m_State.Goto_RUNNING(); // first time through
608
609   if ( ASDCP_SUCCESS(result) )
610     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
611
612   if ( ASDCP_SUCCESS(result) )
613     m_FramesWritten++;
614
615   return result;
616 }
617
618 // Closes the MXF file, writing the index and other closing information.
619 //
620 ASDCP::Result_t
621 ASDCP::PCM::MXFWriter::h__Writer::Finalize()
622 {
623   if ( ! m_State.Test_RUNNING() )
624     return RESULT_STATE;
625
626   m_State.Goto_FINAL();
627
628   return WriteASDCPFooter();
629 }
630
631
632 //------------------------------------------------------------------------------------------
633 //
634
635
636
637 ASDCP::PCM::MXFWriter::MXFWriter()
638 {
639 }
640
641 ASDCP::PCM::MXFWriter::~MXFWriter()
642 {
643 }
644
645 // Warning: direct manipulation of MXF structures can interfere
646 // with the normal operation of the wrapper.  Caveat emptor!
647 //
648 ASDCP::MXF::OP1aHeader&
649 ASDCP::PCM::MXFWriter::OP1aHeader()
650 {
651   if ( m_Writer.empty() )
652     {
653       assert(g_OP1aHeader);
654       return *g_OP1aHeader;
655     }
656
657   return m_Writer->m_HeaderPart;
658 }
659
660 // Warning: direct manipulation of MXF structures can interfere
661 // with the normal operation of the wrapper.  Caveat emptor!
662 //
663 ASDCP::MXF::OPAtomIndexFooter&
664 ASDCP::PCM::MXFWriter::OPAtomIndexFooter()
665 {
666   if ( m_Writer.empty() )
667     {
668       assert(g_OPAtomIndexFooter);
669       return *g_OPAtomIndexFooter;
670     }
671
672   return m_Writer->m_FooterPart;
673 }
674
675 // Warning: direct manipulation of MXF structures can interfere
676 // with the normal operation of the wrapper.  Caveat emptor!
677 //
678 ASDCP::MXF::RIP&
679 ASDCP::PCM::MXFWriter::RIP()
680 {
681   if ( m_Writer.empty() )
682     {
683       assert(g_RIP);
684       return *g_RIP;
685     }
686
687   return m_Writer->m_RIP;
688 }
689
690 // Open the file for writing. The file must not exist. Returns error if
691 // the operation cannot be completed.
692 ASDCP::Result_t
693 ASDCP::PCM::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
694                                  const AudioDescriptor& ADesc, ui32_t HeaderSize)
695 {
696   if ( Info.LabelSetType == LS_MXF_SMPTE )
697     m_Writer = new h__Writer(DefaultSMPTEDict());
698   else
699     m_Writer = new h__Writer(DefaultInteropDict());
700
701   m_Writer->m_Info = Info;
702   
703   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
704
705   if ( ASDCP_SUCCESS(result) )
706     result = m_Writer->SetSourceStream(ADesc);
707
708   if ( ASDCP_FAILURE(result) )
709     m_Writer.release();
710
711   return result;
712 }
713
714 // Writes a frame of essence to the MXF file. If the optional AESEncContext
715 // argument is present, the essence is encrypted prior to writing.
716 // Fails if the file is not open, is finalized, or an operating system
717 // error occurs.
718 ASDCP::Result_t
719 ASDCP::PCM::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
720 {
721   if ( m_Writer.empty() )
722     return RESULT_INIT;
723
724   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
725 }
726
727 // Closes the MXF file, writing the index and other closing information.
728 ASDCP::Result_t
729 ASDCP::PCM::MXFWriter::Finalize()
730 {
731   if ( m_Writer.empty() )
732     return RESULT_INIT;
733
734   return m_Writer->Finalize();
735 }
736
737 //
738 // end AS_DCP_PCM.cpp
739 //
740