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