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