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