Reverting const accessor for class optional_property
[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        && m_DDesc.EditRate != EditRate_192
200        && m_DDesc.EditRate != EditRate_200
201        && m_DDesc.EditRate != EditRate_240 )
202   {
203     DefaultLogSink().Error("DC Data file EditRate is not a supported value: %d/%d\n", // lu
204                            m_DDesc.EditRate.Numerator, m_DDesc.EditRate.Denominator);
205
206     return RESULT_FORMAT;
207   }
208
209   if( ASDCP_SUCCESS(result) )
210     {
211       
212       if (NULL == m_EssenceSubDescriptor)
213         {
214           InterchangeObject* iObj = NULL;
215           result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosSubDescriptor), &iObj);
216           m_EssenceSubDescriptor = static_cast<MXF::DolbyAtmosSubDescriptor*>(iObj);
217           
218           if ( iObj == 0 )
219             {
220               DefaultLogSink().Error("DolbyAtmosSubDescriptor object not found.\n");
221               return RESULT_FORMAT;
222             }
223         }
224
225       if ( ASDCP_SUCCESS(result) )
226         {
227           result = MD_to_Atmos_ADesc(m_ADesc);
228         }
229     }
230
231   return result;
232 }
233
234 //
235 ASDCP::Result_t
236 ASDCP::ATMOS::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
237                                               AESDecContext* Ctx, HMACContext* HMAC)
238 {
239   if ( ! m_File.IsOpen() )
240     return RESULT_INIT;
241
242   assert(m_Dict);
243   return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_PrivateDCDataEssence), Ctx, HMAC);
244 }
245
246
247 //------------------------------------------------------------------------------------------
248
249 ASDCP::ATMOS::MXFReader::MXFReader()
250 {
251   m_Reader = new h__Reader(AtmosSMPTEDict());
252 }
253
254
255 ASDCP::ATMOS::MXFReader::~MXFReader()
256 {
257   if ( m_Reader && m_Reader->m_File.IsOpen() )
258     m_Reader->Close();
259 }
260
261 // Warning: direct manipulation of MXF structures can interfere
262 // with the normal operation of the wrapper.  Caveat emptor!
263 //
264 ASDCP::MXF::OP1aHeader&
265 ASDCP::ATMOS::MXFReader::OP1aHeader()
266 {
267   if ( m_Reader.empty() )
268   {
269     assert(g_OP1aHeader);
270     return *g_OP1aHeader;
271   }
272
273   return m_Reader->m_HeaderPart;
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::OPAtomIndexFooter&
280 ASDCP::ATMOS::MXFReader::OPAtomIndexFooter()
281 {
282   if ( m_Reader.empty() )
283   {
284     assert(g_OPAtomIndexFooter);
285     return *g_OPAtomIndexFooter;
286   }
287
288   return m_Reader->m_IndexAccess;
289 }
290
291 // Warning: direct manipulation of MXF structures can interfere
292 // with the normal operation of the wrapper.  Caveat emptor!
293 //
294 ASDCP::MXF::RIP&
295 ASDCP::ATMOS::MXFReader::RIP()
296 {
297   if ( m_Reader.empty() )
298     {
299       assert(g_RIP);
300       return *g_RIP;
301     }
302
303   return m_Reader->m_RIP;
304 }
305
306 // Open the file for reading. The file must exist. Returns error if the
307 // operation cannot be completed.
308 ASDCP::Result_t
309 ASDCP::ATMOS::MXFReader::OpenRead(const std::string& filename) const
310 {
311   return m_Reader->OpenRead(filename);
312 }
313
314 //
315 ASDCP::Result_t
316 ASDCP::ATMOS::MXFReader::ReadFrame(ui32_t FrameNum, DCData::FrameBuffer& FrameBuf,
317                                     AESDecContext* Ctx, HMACContext* HMAC) const
318 {
319   if ( m_Reader && m_Reader->m_File.IsOpen() )
320     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
321
322   return RESULT_INIT;
323 }
324
325 ASDCP::Result_t
326 ASDCP::ATMOS::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
327 {
328     return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
329 }
330
331
332 // Fill the struct with the values from the file's header.
333 // Returns RESULT_INIT if the file is not open.
334 ASDCP::Result_t
335 ASDCP::ATMOS::MXFReader::FillAtmosDescriptor(AtmosDescriptor& ADesc) const
336 {
337   if ( m_Reader && m_Reader->m_File.IsOpen() )
338   {
339     ADesc = m_Reader->m_ADesc;
340     return RESULT_OK;
341   }
342
343   return RESULT_INIT;
344 }
345
346
347 // Fill the struct with the values from the file's header.
348 // Returns RESULT_INIT if the file is not open.
349 ASDCP::Result_t
350 ASDCP::ATMOS::MXFReader::FillWriterInfo(WriterInfo& Info) const
351 {
352   if ( m_Reader && m_Reader->m_File.IsOpen() )
353   {
354     Info = m_Reader->m_Info;
355     return RESULT_OK;
356   }
357
358   return RESULT_INIT;
359 }
360
361 //
362 void
363 ASDCP::ATMOS::MXFReader::DumpHeaderMetadata(FILE* stream) const
364 {
365   if ( m_Reader->m_File.IsOpen() )
366     m_Reader->m_HeaderPart.Dump(stream);
367 }
368
369 //
370 void
371 ASDCP::ATMOS::MXFReader::DumpIndex(FILE* stream) const
372 {
373   if ( m_Reader->m_File.IsOpen() )
374     m_Reader->m_IndexAccess.Dump(stream);
375 }
376
377 //
378 ASDCP::Result_t
379 ASDCP::ATMOS::MXFReader::Close() const
380 {
381   if ( m_Reader && m_Reader->m_File.IsOpen() )
382     {
383       m_Reader->Close();
384       return RESULT_OK;
385     }
386
387   return RESULT_INIT;
388 }
389
390
391 //------------------------------------------------------------------------------------------
392
393 //
394 class ASDCP::ATMOS::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter
395 {
396   ASDCP::DCData::DCDataDescriptor m_DDesc;
397   byte_t  m_EssenceUL[SMPTE_UL_LENGTH];
398   MXF::DolbyAtmosSubDescriptor* m_EssenceSubDescriptor;
399
400   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
401   h__Writer();
402
403  public:
404   AtmosDescriptor m_ADesc;
405
406   h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d),
407                                    m_EssenceSubDescriptor(0), m_ADesc() {
408     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
409   }
410
411   virtual ~h__Writer(){}
412
413   Result_t OpenWrite(const std::string&, ui32_t HeaderSize, const AtmosDescriptor& ADesc);
414   Result_t SetSourceStream(const DCData::DCDataDescriptor&, const byte_t*, const std::string&, const std::string&);
415   Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
416   Result_t Finalize();
417   Result_t DCData_DDesc_to_MD(ASDCP::DCData::DCDataDescriptor& DDesc);
418   Result_t Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc);
419 };
420
421 //
422 ASDCP::Result_t
423 ASDCP::ATMOS::MXFWriter::h__Writer::DCData_DDesc_to_MD(ASDCP::DCData::DCDataDescriptor& DDesc)
424 {
425   ASDCP_TEST_NULL(m_EssenceDescriptor);
426   MXF::PrivateDCDataDescriptor* DDescObj = static_cast<MXF::PrivateDCDataDescriptor *>(m_EssenceDescriptor);
427
428   DDescObj->SampleRate = DDesc.EditRate;
429   DDescObj->ContainerDuration = DDesc.ContainerDuration;
430   DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);  
431   return RESULT_OK;
432 }
433
434 //
435 ASDCP::Result_t
436 ASDCP::ATMOS::MXFWriter::h__Writer::Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc)
437 {
438   ASDCP_TEST_NULL(m_EssenceDescriptor);
439   ASDCP_TEST_NULL(m_EssenceSubDescriptor);
440   MXF::DolbyAtmosSubDescriptor * ADescObj = m_EssenceSubDescriptor;
441   ADescObj->MaxChannelCount = ADesc.MaxChannelCount;
442   ADescObj->MaxObjectCount = ADesc.MaxObjectCount;
443   ADescObj->AtmosID.Set(ADesc.AtmosID);
444   ADescObj->AtmosVersion = ADesc.AtmosVersion;
445   ADescObj->FirstFrame = ADesc.FirstFrame;
446   return RESULT_OK;
447 }
448
449 //
450 ASDCP::Result_t
451 ASDCP::ATMOS::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize, const AtmosDescriptor& ADesc)
452 {
453   if ( ! m_State.Test_BEGIN() )
454     return RESULT_STATE;
455
456   Result_t result = m_File.OpenWrite(filename);
457
458   if ( ASDCP_SUCCESS(result) )
459     {
460       m_HeaderSize = HeaderSize;
461       m_EssenceDescriptor = new MXF::PrivateDCDataDescriptor(m_Dict);
462       m_EssenceSubDescriptor = new DolbyAtmosSubDescriptor(m_Dict);
463       SubDescriptorList_t subDescriptors;
464       subDescriptors.push_back(m_EssenceSubDescriptor);
465
466       SubDescriptorList_t::const_iterator sDObj;
467       SubDescriptorList_t::const_iterator lastDescriptor = subDescriptors.end();
468       for (sDObj = subDescriptors.begin(); sDObj != lastDescriptor; ++sDObj)
469       {
470           m_EssenceSubDescriptorList.push_back(*sDObj);
471           GenRandomValue((*sDObj)->InstanceUID);
472           m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
473       }
474       result = m_State.Goto_INIT();
475     }
476
477   if ( ASDCP_FAILURE(result) )
478     delete m_EssenceSubDescriptor;
479
480   if ( ASDCP_SUCCESS(result) )
481   {
482       m_ADesc = ADesc;
483       memcpy(m_ADesc.DataEssenceCoding, ATMOS_ESSENCE_CODING, SMPTE_UL_LENGTH);
484       result = Atmos_ADesc_to_MD(m_ADesc);
485   }
486
487   return result;
488 }
489
490 //
491 ASDCP::Result_t
492 ASDCP::ATMOS::MXFWriter::h__Writer::SetSourceStream(ASDCP::DCData::DCDataDescriptor const& DDesc,
493                                                     const byte_t * essenceCoding,
494                                                     const std::string& packageLabel,
495                                                     const std::string& defLabel)
496 {
497   if ( ! m_State.Test_INIT() )
498     return RESULT_STATE;
499
500   if ( DDesc.EditRate != EditRate_24
501        && DDesc.EditRate != EditRate_25
502        && DDesc.EditRate != EditRate_30
503        && DDesc.EditRate != EditRate_48
504        && DDesc.EditRate != EditRate_50
505        && DDesc.EditRate != EditRate_60
506        && DDesc.EditRate != EditRate_96
507        && DDesc.EditRate != EditRate_100
508        && DDesc.EditRate != EditRate_120
509        && DDesc.EditRate != EditRate_192
510        && DDesc.EditRate != EditRate_200
511        && DDesc.EditRate != EditRate_240 )
512   {
513     DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
514                            DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
515     return RESULT_RAW_FORMAT;
516   }
517
518   assert(m_Dict);
519   m_DDesc = DDesc;
520   if (NULL != essenceCoding)
521       memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
522   Result_t result = DCData_DDesc_to_MD(m_DDesc);
523
524   if ( ASDCP_SUCCESS(result) )
525   {
526     memcpy(m_EssenceUL, m_Dict->ul(MDD_PrivateDCDataEssence), SMPTE_UL_LENGTH);
527     m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
528     result = m_State.Goto_READY();
529   }
530
531   if ( ASDCP_SUCCESS(result) )
532   {
533     ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
534
535     result = WriteASDCPHeader(packageLabel, UL(m_Dict->ul(MDD_PrivateDCDataWrappingFrame)),
536                               defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
537                               m_DDesc.EditRate, TCFrameRate);
538   }
539
540   return result;
541 }
542
543 //
544 ASDCP::Result_t
545 ASDCP::ATMOS::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
546                                                ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
547 {
548   Result_t result = RESULT_OK;
549
550   if ( m_State.Test_READY() )
551     result = m_State.Goto_RUNNING(); // first time through
552
553   ui64_t StreamOffset = m_StreamOffset;
554
555   if ( ASDCP_SUCCESS(result) )
556     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, MXF_BER_LENGTH, Ctx, HMAC);
557
558   if ( ASDCP_SUCCESS(result) )
559   {
560     IndexTableSegment::IndexEntry Entry;
561     Entry.StreamOffset = StreamOffset;
562     m_FooterPart.PushIndexEntry(Entry);
563     m_FramesWritten++;
564   }
565   return result;
566 }
567
568 // Closes the MXF file, writing the index and other closing information.
569 //
570 ASDCP::Result_t
571 ASDCP::ATMOS::MXFWriter::h__Writer::Finalize()
572 {
573   if ( ! m_State.Test_RUNNING() )
574     return RESULT_STATE;
575
576   m_State.Goto_FINAL();
577
578   return WriteASDCPFooter();
579 }
580
581
582
583 //------------------------------------------------------------------------------------------
584
585 ASDCP::ATMOS::MXFWriter::MXFWriter()
586 {
587 }
588
589 ASDCP::ATMOS::MXFWriter::~MXFWriter()
590 {
591 }
592
593 // Warning: direct manipulation of MXF structures can interfere
594 // with the normal operation of the wrapper.  Caveat emptor!
595 //
596 ASDCP::MXF::OP1aHeader&
597 ASDCP::ATMOS::MXFWriter::OP1aHeader()
598 {
599   if ( m_Writer.empty() )
600   {
601     assert(g_OP1aHeader);
602     return *g_OP1aHeader;
603     }
604
605   return m_Writer->m_HeaderPart;
606 }
607
608 // Warning: direct manipulation of MXF structures can interfere
609 // with the normal operation of the wrapper.  Caveat emptor!
610 //
611 ASDCP::MXF::OPAtomIndexFooter&
612 ASDCP::ATMOS::MXFWriter::OPAtomIndexFooter()
613 {
614   if ( m_Writer.empty() )
615   {
616     assert(g_OPAtomIndexFooter);
617     return *g_OPAtomIndexFooter;
618   }
619
620   return m_Writer->m_FooterPart;
621 }
622
623 // Warning: direct manipulation of MXF structures can interfere
624 // with the normal operation of the wrapper.  Caveat emptor!
625 //
626 ASDCP::MXF::RIP&
627 ASDCP::ATMOS::MXFWriter::RIP()
628 {
629   if ( m_Writer.empty() )
630     {
631       assert(g_RIP);
632       return *g_RIP;
633     }
634
635   return m_Writer->m_RIP;
636 }
637
638 // Open the file for writing. The file must not exist. Returns error if
639 // the operation cannot be completed.
640 ASDCP::Result_t
641 ASDCP::ATMOS::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
642                                        const AtmosDescriptor& ADesc, ui32_t HeaderSize)
643 {
644   if ( Info.LabelSetType != LS_MXF_SMPTE )
645   {
646     DefaultLogSink().Error("Atmos support requires LS_MXF_SMPTE\n");
647     return RESULT_FORMAT;
648   }
649
650   m_Writer = new h__Writer(AtmosSMPTEDict());
651   m_Writer->m_Info = Info;
652
653   Result_t result = m_Writer->OpenWrite(filename, HeaderSize, ADesc);
654
655   if ( ASDCP_SUCCESS(result) )
656       result = m_Writer->SetSourceStream(ADesc, ATMOS_ESSENCE_CODING, ATMOS_PACKAGE_LABEL,
657                                          ATMOS_DEF_LABEL);
658   
659   if ( ASDCP_FAILURE(result) )
660     m_Writer.release();
661
662   return result;
663 }
664
665 // Writes a frame of essence to the MXF file. If the optional AESEncContext
666 // argument is present, the essence is encrypted prior to writing.
667 // Fails if the file is not open, is finalized, or an operating system
668 // error occurs.
669 ASDCP::Result_t
670 ASDCP::ATMOS::MXFWriter::WriteFrame(const DCData::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
671 {
672   if ( m_Writer.empty() )
673     return RESULT_INIT;
674
675   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
676 }
677
678 // Closes the MXF file, writing the index and other closing information.
679 ASDCP::Result_t
680 ASDCP::ATMOS::MXFWriter::Finalize()
681 {
682   if ( m_Writer.empty() )
683     return RESULT_INIT;
684
685   return m_Writer->Finalize();
686 }
687
688
689 //
690 // end AS_DCP_ATMOS.cpp
691 //
692
693