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