version roll
[asdcplib.git] / src / AS_DCP_ATMOS.cpp
1 /*
2 Copyright (c) 2004-2016, 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_ATMOS.cpp
28     \version $Id$
29     \brief   AS-DCP library, Dolby Atmos essence reader and writer implementation
30 */
31
32
33 #include <iostream>
34
35 #include "AS_DCP.h"
36 #include "AS_DCP_internal.h"
37
38 namespace ASDCP
39 {
40 namespace ATMOS
41 {
42   static std::string ATMOS_PACKAGE_LABEL = "File Package: SMPTE-GC frame wrapping of Dolby ATMOS data";
43   static std::string ATMOS_DEF_LABEL = "Dolby ATMOS Data Track";
44   static byte_t ATMOS_ESSENCE_CODING[SMPTE_UL_LENGTH] = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x05,
45                                                           0x0e, 0x09, 0x06, 0x04, 0x00, 0x00, 0x00, 0x00 };
46 } // namespace ATMOS
47 } // namespace ASDCP
48
49 //
50 std::ostream&
51 ASDCP::ATMOS::operator << (std::ostream& strm, const AtmosDescriptor& ADesc)
52 {
53   char str_buf[40];
54   strm << "        EditRate: " << ADesc.EditRate.Numerator << "/" << ADesc.EditRate.Denominator << std::endl;
55   strm << " ContainerDuration: " << (unsigned) ADesc.ContainerDuration << std::endl;
56   strm << " DataEssenceCoding: " << UL(ADesc.DataEssenceCoding).EncodeString(str_buf, 40) << std::endl;
57   strm << "      AtmosVersion: " << (unsigned) ADesc.AtmosVersion << std::endl;
58   strm << "   MaxChannelCount: " << (unsigned) ADesc.MaxChannelCount << std::endl;
59   strm << "    MaxObjectCount: " << (unsigned) ADesc.MaxObjectCount << std::endl;
60   strm << "           AtmosID: " << UUID(ADesc.AtmosID).EncodeString(str_buf, 40) << std::endl;
61   strm << "        FirstFrame: " << (unsigned) ADesc.FirstFrame << std::endl;
62   return strm;
63 }
64
65 //
66 void
67 ASDCP::ATMOS::AtmosDescriptorDump(const AtmosDescriptor& ADesc, FILE* stream)
68 {
69   char str_buf[40];
70   char atmosID_buf[40];
71   if ( stream == 0 )
72     stream = stderr;
73
74   fprintf(stream, "\
75           EditRate: %d/%d\n\
76    ContainerDuration: %u\n\
77    DataEssenceCoding: %s\n\
78         AtmosVersion: %u\n\
79      MaxChannelCount: %u\n\
80       MaxObjectCount: %u\n\
81              AtmosID: %s\n\
82            FirsFrame: %u\n",
83           ADesc.EditRate.Numerator, ADesc.EditRate.Denominator,
84           ADesc.ContainerDuration,
85           UL(ADesc.DataEssenceCoding).EncodeString(str_buf, 40),
86           ADesc.AtmosVersion,
87           ADesc.MaxChannelCount,
88           ADesc.MaxObjectCount,
89           UUID(ADesc.AtmosID).EncodeString(atmosID_buf, 40),
90           ADesc.FirstFrame);
91 }
92
93 //
94 bool
95 ASDCP::ATMOS::IsDolbyAtmos(const std::string& filename)
96 {
97     // TODO
98     // For now use an atmos extension
99     bool result = ( 0 == (std::string("atmos").compare(Kumu::PathGetExtension(filename))) );
100     return result;
101 }
102
103
104 //------------------------------------------------------------------------------------------
105
106 typedef std::list<MXF::InterchangeObject*> SubDescriptorList_t;
107
108 class ASDCP::ATMOS::MXFReader::h__Reader : public ASDCP::h__ASDCPReader
109 {
110   MXF::PrivateDCDataDescriptor* m_EssenceDescriptor;
111   MXF::DolbyAtmosSubDescriptor* m_EssenceSubDescriptor;
112
113   KM_NO_COPY_CONSTRUCT(h__Reader);
114   h__Reader();
115
116  public:
117   ASDCP::DCData::DCDataDescriptor m_DDesc;
118   AtmosDescriptor m_ADesc;
119
120   h__Reader(const Dictionary& d) :
121     ASDCP::h__ASDCPReader(d),  m_EssenceDescriptor(0), m_EssenceSubDescriptor(0) {}
122   virtual ~h__Reader() {}
123   Result_t    OpenRead(const std::string&);
124   Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
125   Result_t    MD_to_DCData_DDesc(ASDCP::DCData::DCDataDescriptor& DDesc);
126   Result_t    MD_to_Atmos_ADesc(ATMOS::AtmosDescriptor& ADesc);
127 };
128
129 ASDCP::Result_t
130 ASDCP::ATMOS::MXFReader::h__Reader::MD_to_DCData_DDesc(ASDCP::DCData::DCDataDescriptor& DDesc)
131 {
132   ASDCP_TEST_NULL(m_EssenceDescriptor);
133   MXF::PrivateDCDataDescriptor* DDescObj = m_EssenceDescriptor;
134   DDesc.EditRate = DDescObj->SampleRate;
135   assert(DDescObj->ContainerDuration <= 0xFFFFFFFFL);
136   DDesc.ContainerDuration = static_cast<ui32_t>(DDescObj->ContainerDuration);
137   memcpy(DDesc.DataEssenceCoding, DDescObj->DataEssenceCoding.Value(), SMPTE_UL_LENGTH);
138   return RESULT_OK;
139 }
140
141 ASDCP::Result_t
142 ASDCP::ATMOS::MXFReader::h__Reader::MD_to_Atmos_ADesc(ATMOS::AtmosDescriptor& ADesc)
143 {
144   ASDCP_TEST_NULL(m_EssenceSubDescriptor);
145   Result_t result = MD_to_DCData_DDesc(ADesc);
146   if( ASDCP_SUCCESS(result) )
147   {
148     MXF::DolbyAtmosSubDescriptor* ADescObj = m_EssenceSubDescriptor;
149     ADesc.MaxChannelCount = ADescObj->MaxChannelCount;
150     ADesc.MaxObjectCount = ADescObj->MaxObjectCount;
151     ::memcpy(ADesc.AtmosID, ADescObj->AtmosID.Value(), UUIDlen);
152     ADesc.AtmosVersion = ADescObj->AtmosVersion;
153     ADesc.FirstFrame = ADescObj->FirstFrame;
154   }
155   return result;
156 }
157
158 //
159 //
160 ASDCP::Result_t
161 ASDCP::ATMOS::MXFReader::h__Reader::OpenRead(const std::string& filename)
162 {
163   Result_t result = OpenMXFRead(filename);
164   m_EssenceDescriptor = 0;
165
166   if ( KM_SUCCESS(result) )
167     {
168       InterchangeObject* iObj = 0;
169       result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(PrivateDCDataDescriptor), &iObj);
170
171       if ( KM_SUCCESS(result) )
172         {
173           m_EssenceDescriptor = static_cast<MXF::PrivateDCDataDescriptor*>(iObj);
174         }
175     }
176
177   if ( m_EssenceDescriptor == 0 )
178     {
179       DefaultLogSink().Error("DCDataDescriptor object not found in Atmos file.\n");
180       result = RESULT_FORMAT;
181     }
182
183   if ( KM_SUCCESS(result) )
184     {
185       result = MD_to_DCData_DDesc(m_DDesc);
186     }
187
188   // check for sample/frame rate sanity
189   if ( ASDCP_SUCCESS(result)
190                 && m_DDesc.EditRate != EditRate_24
191                 && m_DDesc.EditRate != EditRate_25
192                 && m_DDesc.EditRate != EditRate_30
193                 && m_DDesc.EditRate != EditRate_48
194                 && m_DDesc.EditRate != EditRate_50
195                 && m_DDesc.EditRate != EditRate_60
196                 && m_DDesc.EditRate != EditRate_96
197                 && m_DDesc.EditRate != EditRate_100
198        && m_DDesc.EditRate != EditRate_120 )
199   {
200     DefaultLogSink().Error("DC Data file EditRate is not a supported value: %d/%d\n", // lu
201                            m_DDesc.EditRate.Numerator, m_DDesc.EditRate.Denominator);
202
203     return RESULT_FORMAT;
204   }
205
206   if( ASDCP_SUCCESS(result) )
207     {
208       
209       if (NULL == m_EssenceSubDescriptor)
210         {
211           InterchangeObject* iObj = NULL;
212           result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor), &iObj);
213           m_EssenceSubDescriptor = static_cast<MXF::DolbyAtmosSubDescriptor*>(iObj);
214           
215           if ( iObj == 0 )
216             {
217               DefaultLogSink().Error("DolbyAtmosSubDescriptor object not found.\n");
218               return RESULT_FORMAT;
219             }
220         }
221
222       if ( ASDCP_SUCCESS(result) )
223         {
224           result = MD_to_Atmos_ADesc(m_ADesc);
225         }
226     }
227
228   return result;
229 }
230
231 //
232 ASDCP::Result_t
233 ASDCP::ATMOS::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
234                                               AESDecContext* Ctx, HMACContext* HMAC)
235 {
236   if ( ! m_File.IsOpen() )
237     return RESULT_INIT;
238
239   assert(m_Dict);
240   return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_PrivateDCDataEssence), Ctx, HMAC);
241 }
242
243
244 //------------------------------------------------------------------------------------------
245
246 ASDCP::ATMOS::MXFReader::MXFReader()
247 {
248   m_Reader = new h__Reader(DefaultSMPTEDict());
249 }
250
251
252 ASDCP::ATMOS::MXFReader::~MXFReader()
253 {
254   if ( m_Reader && m_Reader->m_File.IsOpen() )
255     m_Reader->Close();
256 }
257
258 // Warning: direct manipulation of MXF structures can interfere
259 // with the normal operation of the wrapper.  Caveat emptor!
260 //
261 ASDCP::MXF::OP1aHeader&
262 ASDCP::ATMOS::MXFReader::OP1aHeader()
263 {
264   if ( m_Reader.empty() )
265   {
266     assert(g_OP1aHeader);
267     return *g_OP1aHeader;
268   }
269
270   return m_Reader->m_HeaderPart;
271 }
272
273 // Warning: direct manipulation of MXF structures can interfere
274 // with the normal operation of the wrapper.  Caveat emptor!
275 //
276 ASDCP::MXF::OPAtomIndexFooter&
277 ASDCP::ATMOS::MXFReader::OPAtomIndexFooter()
278 {
279   if ( m_Reader.empty() )
280   {
281     assert(g_OPAtomIndexFooter);
282     return *g_OPAtomIndexFooter;
283   }
284
285   return m_Reader->m_IndexAccess;
286 }
287
288 // Warning: direct manipulation of MXF structures can interfere
289 // with the normal operation of the wrapper.  Caveat emptor!
290 //
291 ASDCP::MXF::RIP&
292 ASDCP::ATMOS::MXFReader::RIP()
293 {
294   if ( m_Reader.empty() )
295     {
296       assert(g_RIP);
297       return *g_RIP;
298     }
299
300   return m_Reader->m_RIP;
301 }
302
303 // Open the file for reading. The file must exist. Returns error if the
304 // operation cannot be completed.
305 ASDCP::Result_t
306 ASDCP::ATMOS::MXFReader::OpenRead(const std::string& filename) const
307 {
308   return m_Reader->OpenRead(filename);
309 }
310
311 //
312 ASDCP::Result_t
313 ASDCP::ATMOS::MXFReader::ReadFrame(ui32_t FrameNum, DCData::FrameBuffer& FrameBuf,
314                                     AESDecContext* Ctx, HMACContext* HMAC) const
315 {
316   if ( m_Reader && m_Reader->m_File.IsOpen() )
317     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
318
319   return RESULT_INIT;
320 }
321
322 ASDCP::Result_t
323 ASDCP::ATMOS::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
324 {
325     return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
326 }
327
328
329 // Fill the struct with the values from the file's header.
330 // Returns RESULT_INIT if the file is not open.
331 ASDCP::Result_t
332 ASDCP::ATMOS::MXFReader::FillAtmosDescriptor(AtmosDescriptor& ADesc) const
333 {
334   if ( m_Reader && m_Reader->m_File.IsOpen() )
335   {
336     ADesc = m_Reader->m_ADesc;
337     return RESULT_OK;
338   }
339
340   return RESULT_INIT;
341 }
342
343
344 // Fill the struct with the values from the file's header.
345 // Returns RESULT_INIT if the file is not open.
346 ASDCP::Result_t
347 ASDCP::ATMOS::MXFReader::FillWriterInfo(WriterInfo& Info) const
348 {
349   if ( m_Reader && m_Reader->m_File.IsOpen() )
350   {
351     Info = m_Reader->m_Info;
352     return RESULT_OK;
353   }
354
355   return RESULT_INIT;
356 }
357
358 //
359 void
360 ASDCP::ATMOS::MXFReader::DumpHeaderMetadata(FILE* stream) const
361 {
362   if ( m_Reader->m_File.IsOpen() )
363     m_Reader->m_HeaderPart.Dump(stream);
364 }
365
366 //
367 void
368 ASDCP::ATMOS::MXFReader::DumpIndex(FILE* stream) const
369 {
370   if ( m_Reader->m_File.IsOpen() )
371     m_Reader->m_IndexAccess.Dump(stream);
372 }
373
374 //
375 ASDCP::Result_t
376 ASDCP::ATMOS::MXFReader::Close() const
377 {
378   if ( m_Reader && m_Reader->m_File.IsOpen() )
379     {
380       m_Reader->Close();
381       return RESULT_OK;
382     }
383
384   return RESULT_INIT;
385 }
386
387
388 //------------------------------------------------------------------------------------------
389
390 //
391 class ASDCP::ATMOS::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter
392 {
393   ASDCP::DCData::DCDataDescriptor m_DDesc;
394   byte_t  m_EssenceUL[SMPTE_UL_LENGTH];
395   MXF::DolbyAtmosSubDescriptor* m_EssenceSubDescriptor;
396
397   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
398   h__Writer();
399
400  public:
401   AtmosDescriptor m_ADesc;
402
403   h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d),
404                                    m_EssenceSubDescriptor(0), m_ADesc() {
405     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
406   }
407
408   virtual ~h__Writer(){}
409
410   Result_t OpenWrite(const std::string&, ui32_t HeaderSize, const AtmosDescriptor& ADesc);
411   Result_t SetSourceStream(const DCData::DCDataDescriptor&, const byte_t*, const std::string&, const std::string&);
412   Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
413   Result_t Finalize();
414   Result_t DCData_DDesc_to_MD(ASDCP::DCData::DCDataDescriptor& DDesc);
415   Result_t Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc);
416 };
417
418 //
419 ASDCP::Result_t
420 ASDCP::ATMOS::MXFWriter::h__Writer::DCData_DDesc_to_MD(ASDCP::DCData::DCDataDescriptor& DDesc)
421 {
422   ASDCP_TEST_NULL(m_EssenceDescriptor);
423   MXF::PrivateDCDataDescriptor* DDescObj = static_cast<MXF::PrivateDCDataDescriptor *>(m_EssenceDescriptor);
424
425   DDescObj->SampleRate = DDesc.EditRate;
426   DDescObj->ContainerDuration = DDesc.ContainerDuration;
427   DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);
428
429   return RESULT_OK;
430 }
431
432 //
433 ASDCP::Result_t
434 ASDCP::ATMOS::MXFWriter::h__Writer::Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc)
435 {
436   ASDCP_TEST_NULL(m_EssenceDescriptor);
437   ASDCP_TEST_NULL(m_EssenceSubDescriptor);
438   MXF::DolbyAtmosSubDescriptor * ADescObj = m_EssenceSubDescriptor;
439   ADescObj->MaxChannelCount = ADesc.MaxChannelCount;
440   ADescObj->MaxObjectCount = ADesc.MaxObjectCount;
441   ADescObj->AtmosID.Set(ADesc.AtmosID);
442   ADescObj->AtmosVersion = ADesc.AtmosVersion;
443   ADescObj->FirstFrame = ADesc.FirstFrame;
444   return RESULT_OK;
445 }
446
447 //
448 ASDCP::Result_t
449 ASDCP::ATMOS::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize, const AtmosDescriptor& ADesc)
450 {
451   if ( ! m_State.Test_BEGIN() )
452     return RESULT_STATE;
453
454   Result_t result = m_File.OpenWrite(filename);
455
456   if ( ASDCP_SUCCESS(result) )
457     {
458       m_HeaderSize = HeaderSize;
459       m_EssenceDescriptor = new MXF::PrivateDCDataDescriptor(m_Dict);
460       m_EssenceSubDescriptor = new DolbyAtmosSubDescriptor(m_Dict);
461       SubDescriptorList_t subDescriptors;
462       subDescriptors.push_back(m_EssenceSubDescriptor);
463
464       SubDescriptorList_t::const_iterator sDObj;
465       SubDescriptorList_t::const_iterator lastDescriptor = subDescriptors.end();
466       for (sDObj = subDescriptors.begin(); sDObj != lastDescriptor; ++sDObj)
467       {
468           m_EssenceSubDescriptorList.push_back(*sDObj);
469           GenRandomValue((*sDObj)->InstanceUID);
470           m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
471       }
472       result = m_State.Goto_INIT();
473     }
474
475   if ( ASDCP_FAILURE(result) )
476     delete m_EssenceSubDescriptor;
477
478   if ( ASDCP_SUCCESS(result) )
479   {
480       m_ADesc = ADesc;
481       memcpy(m_ADesc.DataEssenceCoding, ATMOS_ESSENCE_CODING, SMPTE_UL_LENGTH);
482       result = Atmos_ADesc_to_MD(m_ADesc);
483   }
484
485   return result;
486 }
487
488 //
489 ASDCP::Result_t
490 ASDCP::ATMOS::MXFWriter::h__Writer::SetSourceStream(ASDCP::DCData::DCDataDescriptor const& DDesc,
491                                                     const byte_t * essenceCoding,
492                                                     const std::string& packageLabel,
493                                                     const std::string& defLabel)
494 {
495   if ( ! m_State.Test_INIT() )
496     return RESULT_STATE;
497
498   if ( DDesc.EditRate != EditRate_24
499        && DDesc.EditRate != EditRate_25
500        && DDesc.EditRate != EditRate_30
501        && DDesc.EditRate != EditRate_48
502        && DDesc.EditRate != EditRate_50
503        && DDesc.EditRate != EditRate_60
504        && DDesc.EditRate != EditRate_96
505        && DDesc.EditRate != EditRate_100
506        && DDesc.EditRate != EditRate_120 )
507   {
508     DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
509                            DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
510     return RESULT_RAW_FORMAT;
511   }
512
513   assert(m_Dict);
514   m_DDesc = DDesc;
515   if (NULL != essenceCoding)
516       memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
517   Result_t result = DCData_DDesc_to_MD(m_DDesc);
518
519   if ( ASDCP_SUCCESS(result) )
520   {
521     memcpy(m_EssenceUL, m_Dict->ul(MDD_PrivateDCDataEssence), SMPTE_UL_LENGTH);
522     m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
523     result = m_State.Goto_READY();
524   }
525
526   if ( ASDCP_SUCCESS(result) )
527   {
528     ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
529
530     result = WriteASDCPHeader(packageLabel, UL(m_Dict->ul(MDD_PrivateDCDataWrappingFrame)),
531                               defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
532                               m_DDesc.EditRate, TCFrameRate);
533   }
534
535   return result;
536 }
537
538 //
539 ASDCP::Result_t
540 ASDCP::ATMOS::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
541                                                ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
542 {
543   Result_t result = RESULT_OK;
544
545   if ( m_State.Test_READY() )
546     result = m_State.Goto_RUNNING(); // first time through
547
548   ui64_t StreamOffset = m_StreamOffset;
549
550   if ( ASDCP_SUCCESS(result) )
551     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
552
553   if ( ASDCP_SUCCESS(result) )
554   {
555     IndexTableSegment::IndexEntry Entry;
556     Entry.StreamOffset = StreamOffset;
557     m_FooterPart.PushIndexEntry(Entry);
558     m_FramesWritten++;
559   }
560   return result;
561 }
562
563 // Closes the MXF file, writing the index and other closing information.
564 //
565 ASDCP::Result_t
566 ASDCP::ATMOS::MXFWriter::h__Writer::Finalize()
567 {
568   if ( ! m_State.Test_RUNNING() )
569     return RESULT_STATE;
570
571   m_State.Goto_FINAL();
572
573   return WriteASDCPFooter();
574 }
575
576
577
578 //------------------------------------------------------------------------------------------
579
580 ASDCP::ATMOS::MXFWriter::MXFWriter()
581 {
582 }
583
584 ASDCP::ATMOS::MXFWriter::~MXFWriter()
585 {
586 }
587
588 // Warning: direct manipulation of MXF structures can interfere
589 // with the normal operation of the wrapper.  Caveat emptor!
590 //
591 ASDCP::MXF::OP1aHeader&
592 ASDCP::ATMOS::MXFWriter::OP1aHeader()
593 {
594   if ( m_Writer.empty() )
595   {
596     assert(g_OP1aHeader);
597     return *g_OP1aHeader;
598     }
599
600   return m_Writer->m_HeaderPart;
601 }
602
603 // Warning: direct manipulation of MXF structures can interfere
604 // with the normal operation of the wrapper.  Caveat emptor!
605 //
606 ASDCP::MXF::OPAtomIndexFooter&
607 ASDCP::ATMOS::MXFWriter::OPAtomIndexFooter()
608 {
609   if ( m_Writer.empty() )
610   {
611     assert(g_OPAtomIndexFooter);
612     return *g_OPAtomIndexFooter;
613   }
614
615   return m_Writer->m_FooterPart;
616 }
617
618 // Warning: direct manipulation of MXF structures can interfere
619 // with the normal operation of the wrapper.  Caveat emptor!
620 //
621 ASDCP::MXF::RIP&
622 ASDCP::ATMOS::MXFWriter::RIP()
623 {
624   if ( m_Writer.empty() )
625     {
626       assert(g_RIP);
627       return *g_RIP;
628     }
629
630   return m_Writer->m_RIP;
631 }
632
633 // Open the file for writing. The file must not exist. Returns error if
634 // the operation cannot be completed.
635 ASDCP::Result_t
636 ASDCP::ATMOS::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
637                                        const AtmosDescriptor& ADesc, ui32_t HeaderSize)
638 {
639   if ( Info.LabelSetType != LS_MXF_SMPTE )
640   {
641     DefaultLogSink().Error("Atmos support requires LS_MXF_SMPTE\n");
642     return RESULT_FORMAT;
643   }
644
645   m_Writer = new h__Writer(DefaultSMPTEDict());
646   m_Writer->m_Info = Info;
647
648   Result_t result = m_Writer->OpenWrite(filename, HeaderSize, ADesc);
649
650   if ( ASDCP_SUCCESS(result) )
651       result = m_Writer->SetSourceStream(ADesc, ATMOS_ESSENCE_CODING, ATMOS_PACKAGE_LABEL,
652                                          ATMOS_DEF_LABEL);
653   
654   if ( ASDCP_FAILURE(result) )
655     m_Writer.release();
656
657   return result;
658 }
659
660 // Writes a frame of essence to the MXF file. If the optional AESEncContext
661 // argument is present, the essence is encrypted prior to writing.
662 // Fails if the file is not open, is finalized, or an operating system
663 // error occurs.
664 ASDCP::Result_t
665 ASDCP::ATMOS::MXFWriter::WriteFrame(const DCData::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
666 {
667   if ( m_Writer.empty() )
668     return RESULT_INIT;
669
670   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
671 }
672
673 // Closes the MXF file, writing the index and other closing information.
674 ASDCP::Result_t
675 ASDCP::ATMOS::MXFWriter::Finalize()
676 {
677   if ( m_Writer.empty() )
678     return RESULT_INIT;
679
680   return m_Writer->Finalize();
681 }
682
683
684 //
685 // end AS_DCP_ATMOS.cpp
686 //
687
688