2 Copyright (c) 2004-2013, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
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.
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.
27 /*! \file AS_DCP_DCData.cpp
29 \brief AS-DCP library, Dcinema generic data essence reader and writer implementation
35 #include "AS_DCP_DCData_internal.h"
36 #include "AS_DCP_internal.h"
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";
49 ASDCP::DCData::operator << (std::ostream& strm, const DCDataDescriptor& DDesc)
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;
60 ASDCP::DCData::DCDataDescriptorDump(const DCDataDescriptor& DDesc, FILE* stream)
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));
76 //------------------------------------------------------------------------------------------
80 ASDCP::DCData::h__Reader::MD_to_DCData_DDesc(DCData::DCDataDescriptor& DDesc)
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);
94 ASDCP::DCData::h__Reader::OpenRead(const char* filename)
96 Result_t result = OpenMXFRead(filename);
98 if( ASDCP_SUCCESS(result) )
100 if (NULL == m_EssenceDescriptor)
102 InterchangeObject* iObj = NULL;
103 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor), &iObj);
104 m_EssenceDescriptor = static_cast<MXF::DCDataDescriptor*>(iObj);
107 if ( ASDCP_SUCCESS(result) )
109 result = MD_to_DCData_DDesc(m_DDesc);
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 )
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);
128 return RESULT_FORMAT;
137 ASDCP::DCData::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
138 AESDecContext* Ctx, HMACContext* HMAC)
140 if ( ! m_File.IsOpen() )
144 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_DCDataEssence), Ctx, HMAC);
149 //------------------------------------------------------------------------------------------
151 class ASDCP::DCData::MXFReader::h__Reader : public DCData::h__Reader
153 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
157 h__Reader(const Dictionary& d) : DCData::h__Reader(d) {}
158 virtual ~h__Reader() {}
162 //------------------------------------------------------------------------------------------
167 ASDCP::DCData::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
172 fprintf(stream, "Frame: %06u, %7u bytes\n", m_FrameNumber, m_Size);
175 Kumu::hexdump(m_Data, dump_len, stream);
179 //------------------------------------------------------------------------------------------
181 ASDCP::DCData::MXFReader::MXFReader()
183 m_Reader = new h__Reader(DefaultSMPTEDict());
187 ASDCP::DCData::MXFReader::~MXFReader()
189 if ( m_Reader && m_Reader->m_File.IsOpen() )
193 // Warning: direct manipulation of MXF structures can interfere
194 // with the normal operation of the wrapper. Caveat emptor!
196 ASDCP::MXF::OP1aHeader&
197 ASDCP::DCData::MXFReader::OP1aHeader()
199 if ( m_Reader.empty() )
201 assert(g_OP1aHeader);
202 return *g_OP1aHeader;
205 return m_Reader->m_HeaderPart;
208 // Warning: direct manipulation of MXF structures can interfere
209 // with the normal operation of the wrapper. Caveat emptor!
211 ASDCP::MXF::OPAtomIndexFooter&
212 ASDCP::DCData::MXFReader::OPAtomIndexFooter()
214 if ( m_Reader.empty() )
216 assert(g_OPAtomIndexFooter);
217 return *g_OPAtomIndexFooter;
220 return m_Reader->m_IndexAccess;
223 // Warning: direct manipulation of MXF structures can interfere
224 // with the normal operation of the wrapper. Caveat emptor!
227 ASDCP::DCData::MXFReader::RIP()
229 if ( m_Reader.empty() )
235 return m_Reader->m_RIP;
238 // Open the file for reading. The file must exist. Returns error if the
239 // operation cannot be completed.
241 ASDCP::DCData::MXFReader::OpenRead(const char* filename) const
243 return m_Reader->OpenRead(filename);
248 ASDCP::DCData::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
249 AESDecContext* Ctx, HMACContext* HMAC) const
251 if ( m_Reader && m_Reader->m_File.IsOpen() )
252 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
258 ASDCP::DCData::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
260 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
264 // Fill the struct with the values from the file's header.
265 // Returns RESULT_INIT if the file is not open.
267 ASDCP::DCData::MXFReader::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
269 if ( m_Reader && m_Reader->m_File.IsOpen() )
271 DDesc = m_Reader->m_DDesc;
279 // Fill the struct with the values from the file's header.
280 // Returns RESULT_INIT if the file is not open.
282 ASDCP::DCData::MXFReader::FillWriterInfo(WriterInfo& Info) const
284 if ( m_Reader && m_Reader->m_File.IsOpen() )
286 Info = m_Reader->m_Info;
295 ASDCP::DCData::MXFReader::DumpHeaderMetadata(FILE* stream) const
297 if ( m_Reader->m_File.IsOpen() )
298 m_Reader->m_HeaderPart.Dump(stream);
304 ASDCP::DCData::MXFReader::DumpIndex(FILE* stream) const
306 if ( m_Reader->m_File.IsOpen() )
307 m_Reader->m_IndexAccess.Dump(stream);
312 ASDCP::DCData::MXFReader::Close() const
314 if ( m_Reader && m_Reader->m_File.IsOpen() )
324 //------------------------------------------------------------------------------------------
329 ASDCP::DCData::h__Writer::DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc)
331 ASDCP_TEST_NULL(m_EssenceDescriptor);
332 MXF::DCDataDescriptor* DDescObj = static_cast<MXF::DCDataDescriptor *>(m_EssenceDescriptor);
334 DDescObj->SampleRate = DDesc.EditRate;
335 DDescObj->ContainerDuration = DDesc.ContainerDuration;
336 DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);
343 ASDCP::DCData::h__Writer::OpenWrite(char const* filename, ui32_t HeaderSize,
344 const SubDescriptorList_t& subDescriptors)
346 if ( ! m_State.Test_BEGIN() )
349 Result_t result = m_File.OpenWrite(filename);
351 if ( ASDCP_SUCCESS(result) )
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)
359 m_EssenceSubDescriptorList.push_back(*sDObj);
360 GenRandomValue((*sDObj)->InstanceUID);
361 m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
363 result = m_State.Goto_INIT();
371 ASDCP::DCData::h__Writer::SetSourceStream(DCDataDescriptor const& DDesc,
372 const byte_t * essenceCoding,
373 const std::string& packageLabel,
374 const std::string& defLabel)
376 if ( ! m_State.Test_INIT() )
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 )
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;
396 if (NULL != essenceCoding)
397 memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
398 Result_t result = DCData_DDesc_to_MD(m_DDesc);
400 if ( ASDCP_SUCCESS(result) )
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();
407 if ( ASDCP_SUCCESS(result) )
409 ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
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);
421 ASDCP::DCData::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
422 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
424 Result_t result = RESULT_OK;
426 if ( m_State.Test_READY() )
427 result = m_State.Goto_RUNNING(); // first time through
429 ui64_t StreamOffset = m_StreamOffset;
431 if ( ASDCP_SUCCESS(result) )
432 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
434 if ( ASDCP_SUCCESS(result) )
436 IndexTableSegment::IndexEntry Entry;
437 Entry.StreamOffset = StreamOffset;
438 m_FooterPart.PushIndexEntry(Entry);
444 // Closes the MXF file, writing the index and other closing information.
447 ASDCP::DCData::h__Writer::Finalize()
449 if ( ! m_State.Test_RUNNING() )
452 m_State.Goto_FINAL();
454 return WriteASDCPFooter();
459 //------------------------------------------------------------------------------------------
462 class ASDCP::DCData::MXFWriter::h__Writer : public DCData::h__Writer
464 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
468 h__Writer(const Dictionary& d) : DCData::h__Writer(d) {}
469 virtual ~h__Writer() {}
473 //------------------------------------------------------------------------------------------
475 ASDCP::DCData::MXFWriter::MXFWriter()
479 ASDCP::DCData::MXFWriter::~MXFWriter()
483 // Warning: direct manipulation of MXF structures can interfere
484 // with the normal operation of the wrapper. Caveat emptor!
486 ASDCP::MXF::OP1aHeader&
487 ASDCP::DCData::MXFWriter::OP1aHeader()
489 if ( m_Writer.empty() )
491 assert(g_OP1aHeader);
492 return *g_OP1aHeader;
495 return m_Writer->m_HeaderPart;
498 // Warning: direct manipulation of MXF structures can interfere
499 // with the normal operation of the wrapper. Caveat emptor!
501 ASDCP::MXF::OPAtomIndexFooter&
502 ASDCP::DCData::MXFWriter::OPAtomIndexFooter()
504 if ( m_Writer.empty() )
506 assert(g_OPAtomIndexFooter);
507 return *g_OPAtomIndexFooter;
510 return m_Writer->m_FooterPart;
513 // Warning: direct manipulation of MXF structures can interfere
514 // with the normal operation of the wrapper. Caveat emptor!
517 ASDCP::DCData::MXFWriter::RIP()
519 if ( m_Writer.empty() )
525 return m_Writer->m_RIP;
528 // Open the file for writing. The file must not exist. Returns error if
529 // the operation cannot be completed.
531 ASDCP::DCData::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
532 const DCDataDescriptor& DDesc, ui32_t HeaderSize)
534 if ( Info.LabelSetType != LS_MXF_SMPTE )
536 DefaultLogSink().Error("DC Data support requires LS_MXF_SMPTE\n");
537 return RESULT_FORMAT;
540 m_Writer = new h__Writer(DefaultSMPTEDict());
541 m_Writer->m_Info = Info;
543 Result_t result = m_Writer->OpenWrite(filename, HeaderSize, SubDescriptorList_t());
545 if ( ASDCP_SUCCESS(result) )
546 result = m_Writer->SetSourceStream(DDesc, NULL, DC_DATA_PACKAGE_LABEL, DC_DATA_DEF_LABEL);
548 if ( ASDCP_FAILURE(result) )
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
559 ASDCP::DCData::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
561 if ( m_Writer.empty() )
564 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
567 // Closes the MXF file, writing the index and other closing information.
569 ASDCP::DCData::MXFWriter::Finalize()
571 if ( m_Writer.empty() )
574 return m_Writer->Finalize();
579 // end AS_DCP_DCData.cpp