o Fixed soundfield split-syntax fault (was tagging out-of-group channels with the...
[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(DefaultSMPTEDict());
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
432   return RESULT_OK;
433 }
434
435 //
436 ASDCP::Result_t
437 ASDCP::ATMOS::MXFWriter::h__Writer::Atmos_ADesc_to_MD(const AtmosDescriptor& ADesc)
438 {
439   ASDCP_TEST_NULL(m_EssenceDescriptor);
440   ASDCP_TEST_NULL(m_EssenceSubDescriptor);
441   MXF::DolbyAtmosSubDescriptor * ADescObj = m_EssenceSubDescriptor;
442   ADescObj->MaxChannelCount = ADesc.MaxChannelCount;
443   ADescObj->MaxObjectCount = ADesc.MaxObjectCount;
444   ADescObj->AtmosID.Set(ADesc.AtmosID);
445   ADescObj->AtmosVersion = ADesc.AtmosVersion;
446   ADescObj->FirstFrame = ADesc.FirstFrame;
447   return RESULT_OK;
448 }
449
450 //
451 ASDCP::Result_t
452 ASDCP::ATMOS::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize, const AtmosDescriptor& ADesc)
453 {
454   if ( ! m_State.Test_BEGIN() )
455     return RESULT_STATE;
456
457   Result_t result = m_File.OpenWrite(filename);
458
459   if ( ASDCP_SUCCESS(result) )
460     {
461       m_HeaderSize = HeaderSize;
462       m_EssenceDescriptor = new MXF::PrivateDCDataDescriptor(m_Dict);
463       m_EssenceSubDescriptor = new DolbyAtmosSubDescriptor(m_Dict);
464       SubDescriptorList_t subDescriptors;
465       subDescriptors.push_back(m_EssenceSubDescriptor);
466
467       SubDescriptorList_t::const_iterator sDObj;
468       SubDescriptorList_t::const_iterator lastDescriptor = subDescriptors.end();
469       for (sDObj = subDescriptors.begin(); sDObj != lastDescriptor; ++sDObj)
470       {
471           m_EssenceSubDescriptorList.push_back(*sDObj);
472           GenRandomValue((*sDObj)->InstanceUID);
473           m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
474       }
475       result = m_State.Goto_INIT();
476     }
477
478   if ( ASDCP_FAILURE(result) )
479     delete m_EssenceSubDescriptor;
480
481   if ( ASDCP_SUCCESS(result) )
482   {
483       m_ADesc = ADesc;
484       memcpy(m_ADesc.DataEssenceCoding, ATMOS_ESSENCE_CODING, SMPTE_UL_LENGTH);
485       result = Atmos_ADesc_to_MD(m_ADesc);
486   }
487
488   return result;
489 }
490
491 //
492 ASDCP::Result_t
493 ASDCP::ATMOS::MXFWriter::h__Writer::SetSourceStream(ASDCP::DCData::DCDataDescriptor const& DDesc,
494                                                     const byte_t * essenceCoding,
495                                                     const std::string& packageLabel,
496                                                     const std::string& defLabel)
497 {
498   if ( ! m_State.Test_INIT() )
499     return RESULT_STATE;
500
501   if ( DDesc.EditRate != EditRate_24
502        && DDesc.EditRate != EditRate_25
503        && DDesc.EditRate != EditRate_30
504        && DDesc.EditRate != EditRate_48
505        && DDesc.EditRate != EditRate_50
506        && DDesc.EditRate != EditRate_60
507        && DDesc.EditRate != EditRate_96
508        && DDesc.EditRate != EditRate_100
509        && DDesc.EditRate != EditRate_120
510        && DDesc.EditRate != EditRate_192
511        && DDesc.EditRate != EditRate_200
512        && DDesc.EditRate != EditRate_240 )
513   {
514     DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
515                            DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
516     return RESULT_RAW_FORMAT;
517   }
518
519   assert(m_Dict);
520   m_DDesc = DDesc;
521   if (NULL != essenceCoding)
522       memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
523   Result_t result = DCData_DDesc_to_MD(m_DDesc);
524
525   if ( ASDCP_SUCCESS(result) )
526   {
527     memcpy(m_EssenceUL, m_Dict->ul(MDD_PrivateDCDataEssence), SMPTE_UL_LENGTH);
528     m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
529     result = m_State.Goto_READY();
530   }
531
532   if ( ASDCP_SUCCESS(result) )
533   {
534     ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
535
536     result = WriteASDCPHeader(packageLabel, UL(m_Dict->ul(MDD_PrivateDCDataWrappingFrame)),
537                               defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
538                               m_DDesc.EditRate, TCFrameRate);
539   }
540
541   return result;
542 }
543
544 //
545 ASDCP::Result_t
546 ASDCP::ATMOS::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
547                                                ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
548 {
549   Result_t result = RESULT_OK;
550
551   if ( m_State.Test_READY() )
552     result = m_State.Goto_RUNNING(); // first time through
553
554   ui64_t StreamOffset = m_StreamOffset;
555
556   if ( ASDCP_SUCCESS(result) )
557     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
558
559   if ( ASDCP_SUCCESS(result) )
560   {
561     IndexTableSegment::IndexEntry Entry;
562     Entry.StreamOffset = StreamOffset;
563     m_FooterPart.PushIndexEntry(Entry);
564     m_FramesWritten++;
565   }
566   return result;
567 }
568
569 // Closes the MXF file, writing the index and other closing information.
570 //
571 ASDCP::Result_t
572 ASDCP::ATMOS::MXFWriter::h__Writer::Finalize()
573 {
574   if ( ! m_State.Test_RUNNING() )
575     return RESULT_STATE;
576
577   m_State.Goto_FINAL();
578
579   return WriteASDCPFooter();
580 }
581
582
583
584 //------------------------------------------------------------------------------------------
585
586 ASDCP::ATMOS::MXFWriter::MXFWriter()
587 {
588 }
589
590 ASDCP::ATMOS::MXFWriter::~MXFWriter()
591 {
592 }
593
594 // Warning: direct manipulation of MXF structures can interfere
595 // with the normal operation of the wrapper.  Caveat emptor!
596 //
597 ASDCP::MXF::OP1aHeader&
598 ASDCP::ATMOS::MXFWriter::OP1aHeader()
599 {
600   if ( m_Writer.empty() )
601   {
602     assert(g_OP1aHeader);
603     return *g_OP1aHeader;
604     }
605
606   return m_Writer->m_HeaderPart;
607 }
608
609 // Warning: direct manipulation of MXF structures can interfere
610 // with the normal operation of the wrapper.  Caveat emptor!
611 //
612 ASDCP::MXF::OPAtomIndexFooter&
613 ASDCP::ATMOS::MXFWriter::OPAtomIndexFooter()
614 {
615   if ( m_Writer.empty() )
616   {
617     assert(g_OPAtomIndexFooter);
618     return *g_OPAtomIndexFooter;
619   }
620
621   return m_Writer->m_FooterPart;
622 }
623
624 // Warning: direct manipulation of MXF structures can interfere
625 // with the normal operation of the wrapper.  Caveat emptor!
626 //
627 ASDCP::MXF::RIP&
628 ASDCP::ATMOS::MXFWriter::RIP()
629 {
630   if ( m_Writer.empty() )
631     {
632       assert(g_RIP);
633       return *g_RIP;
634     }
635
636   return m_Writer->m_RIP;
637 }
638
639 // Open the file for writing. The file must not exist. Returns error if
640 // the operation cannot be completed.
641 ASDCP::Result_t
642 ASDCP::ATMOS::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
643                                        const AtmosDescriptor& ADesc, ui32_t HeaderSize)
644 {
645   if ( Info.LabelSetType != LS_MXF_SMPTE )
646   {
647     DefaultLogSink().Error("Atmos support requires LS_MXF_SMPTE\n");
648     return RESULT_FORMAT;
649   }
650
651   m_Writer = new h__Writer(DefaultSMPTEDict());
652   m_Writer->m_Info = Info;
653
654   Result_t result = m_Writer->OpenWrite(filename, HeaderSize, ADesc);
655
656   if ( ASDCP_SUCCESS(result) )
657       result = m_Writer->SetSourceStream(ADesc, ATMOS_ESSENCE_CODING, ATMOS_PACKAGE_LABEL,
658                                          ATMOS_DEF_LABEL);
659   
660   if ( ASDCP_FAILURE(result) )
661     m_Writer.release();
662
663   return result;
664 }
665
666 // Writes a frame of essence to the MXF file. If the optional AESEncContext
667 // argument is present, the essence is encrypted prior to writing.
668 // Fails if the file is not open, is finalized, or an operating system
669 // error occurs.
670 ASDCP::Result_t
671 ASDCP::ATMOS::MXFWriter::WriteFrame(const DCData::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
672 {
673   if ( m_Writer.empty() )
674     return RESULT_INIT;
675
676   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
677 }
678
679 // Closes the MXF file, writing the index and other closing information.
680 ASDCP::Result_t
681 ASDCP::ATMOS::MXFWriter::Finalize()
682 {
683   if ( m_Writer.empty() )
684     return RESULT_INIT;
685
686   return m_Writer->Finalize();
687 }
688
689
690 //
691 // end AS_DCP_ATMOS.cpp
692 //
693
694