2 Copyright (c) 2004-2016, 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_internal.h"
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";
48 ASDCP::DCData::operator << (std::ostream& strm, const DCDataDescriptor& DDesc)
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;
59 ASDCP::DCData::DCDataDescriptorDump(const DCDataDescriptor& DDesc, FILE* stream)
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));
75 //------------------------------------------------------------------------------------------
77 typedef std::list<MXF::InterchangeObject*> SubDescriptorList_t;
79 class ASDCP::DCData::MXFReader::h__Reader : public ASDCP::h__ASDCPReader
81 bool m_PrivateLabelCompatibilityMode;
82 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
86 DCDataDescriptor m_DDesc;
88 h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d), m_PrivateLabelCompatibilityMode(false), m_DDesc() {}
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);
98 ASDCP::DCData::MXFReader::h__Reader::MD_to_DCData_DDesc(const MXF::DCDataDescriptor& descriptor_object,
99 DCData::DCDataDescriptor& DDesc)
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);
110 ASDCP::DCData::MXFReader::h__Reader::MD_to_DCData_DDesc(const MXF::PrivateDCDataDescriptor& descriptor_object,
111 DCData::DCDataDescriptor& DDesc)
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);
123 ASDCP::DCData::MXFReader::h__Reader::OpenRead(const std::string& filename)
125 Result_t result = OpenMXFRead(filename);
127 if( KM_SUCCESS(result) )
129 InterchangeObject* iObj = 0;
130 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor), &iObj);
132 if ( KM_SUCCESS(result) )
134 const MXF::DCDataDescriptor* p = dynamic_cast<const MXF::DCDataDescriptor*>(iObj);
136 result = MD_to_DCData_DDesc(*p, m_DDesc);
140 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(PrivateDCDataDescriptor), &iObj);
142 if ( KM_SUCCESS(result) )
144 m_PrivateLabelCompatibilityMode = true;
145 const MXF::PrivateDCDataDescriptor* p = dynamic_cast<const MXF::PrivateDCDataDescriptor*>(iObj);
147 result = MD_to_DCData_DDesc(*p, m_DDesc);
151 if ( KM_FAILURE(result) )
153 DefaultLogSink().Error("DCDataDescriptor object not found.\n");
154 result = RESULT_FORMAT;
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 )
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);
173 return RESULT_FORMAT;
182 ASDCP::DCData::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
183 AESDecContext* Ctx, HMACContext* HMAC)
185 if ( ! m_File.IsOpen() )
189 if ( m_PrivateLabelCompatibilityMode )
191 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_PrivateDCDataEssence), Ctx, HMAC);
194 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_DCDataEssence), Ctx, HMAC);
199 //------------------------------------------------------------------------------------------
204 ASDCP::DCData::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
209 fprintf(stream, "Frame: %06u, %7u bytes\n", m_FrameNumber, m_Size);
212 Kumu::hexdump(m_Data, dump_len, stream);
216 //------------------------------------------------------------------------------------------
218 ASDCP::DCData::MXFReader::MXFReader()
220 m_Reader = new h__Reader(DefaultSMPTEDict());
224 ASDCP::DCData::MXFReader::~MXFReader()
226 if ( m_Reader && m_Reader->m_File.IsOpen() )
230 // Warning: direct manipulation of MXF structures can interfere
231 // with the normal operation of the wrapper. Caveat emptor!
233 ASDCP::MXF::OP1aHeader&
234 ASDCP::DCData::MXFReader::OP1aHeader()
236 if ( m_Reader.empty() )
238 assert(g_OP1aHeader);
239 return *g_OP1aHeader;
242 return m_Reader->m_HeaderPart;
245 // Warning: direct manipulation of MXF structures can interfere
246 // with the normal operation of the wrapper. Caveat emptor!
248 ASDCP::MXF::OPAtomIndexFooter&
249 ASDCP::DCData::MXFReader::OPAtomIndexFooter()
251 if ( m_Reader.empty() )
253 assert(g_OPAtomIndexFooter);
254 return *g_OPAtomIndexFooter;
257 return m_Reader->m_IndexAccess;
260 // Warning: direct manipulation of MXF structures can interfere
261 // with the normal operation of the wrapper. Caveat emptor!
264 ASDCP::DCData::MXFReader::RIP()
266 if ( m_Reader.empty() )
272 return m_Reader->m_RIP;
275 // Open the file for reading. The file must exist. Returns error if the
276 // operation cannot be completed.
278 ASDCP::DCData::MXFReader::OpenRead(const std::string& filename) const
280 return m_Reader->OpenRead(filename);
285 ASDCP::DCData::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
286 AESDecContext* Ctx, HMACContext* HMAC) const
288 if ( m_Reader && m_Reader->m_File.IsOpen() )
289 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
295 ASDCP::DCData::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
297 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
301 // Fill the struct with the values from the file's header.
302 // Returns RESULT_INIT if the file is not open.
304 ASDCP::DCData::MXFReader::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
306 if ( m_Reader && m_Reader->m_File.IsOpen() )
308 DDesc = m_Reader->m_DDesc;
316 // Fill the struct with the values from the file's header.
317 // Returns RESULT_INIT if the file is not open.
319 ASDCP::DCData::MXFReader::FillWriterInfo(WriterInfo& Info) const
321 if ( m_Reader && m_Reader->m_File.IsOpen() )
323 Info = m_Reader->m_Info;
332 ASDCP::DCData::MXFReader::DumpHeaderMetadata(FILE* stream) const
334 if ( m_Reader->m_File.IsOpen() )
335 m_Reader->m_HeaderPart.Dump(stream);
341 ASDCP::DCData::MXFReader::DumpIndex(FILE* stream) const
343 if ( m_Reader->m_File.IsOpen() )
344 m_Reader->m_IndexAccess.Dump(stream);
349 ASDCP::DCData::MXFReader::Close() const
351 if ( m_Reader && m_Reader->m_File.IsOpen() )
361 //------------------------------------------------------------------------------------------
364 class ASDCP::DCData::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter
366 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
370 DCDataDescriptor m_DDesc;
371 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
373 h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d) {
374 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
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);
383 Result_t DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc);
389 ASDCP::DCData::MXFWriter::h__Writer::DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc)
391 ASDCP_TEST_NULL(m_EssenceDescriptor);
392 MXF::DCDataDescriptor* DDescObj = static_cast<MXF::DCDataDescriptor *>(m_EssenceDescriptor);
394 DDescObj->SampleRate = DDesc.EditRate;
395 DDescObj->ContainerDuration = DDesc.ContainerDuration;
396 DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);
403 ASDCP::DCData::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize,
404 const SubDescriptorList_t& subDescriptors)
406 if ( ! m_State.Test_BEGIN() )
409 Result_t result = m_File.OpenWrite(filename);
411 if ( ASDCP_SUCCESS(result) )
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)
419 m_EssenceSubDescriptorList.push_back(*sDObj);
420 GenRandomValue((*sDObj)->InstanceUID);
421 m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
423 result = m_State.Goto_INIT();
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)
436 if ( ! m_State.Test_INIT() )
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 )
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;
456 if (NULL != essenceCoding)
457 memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
458 Result_t result = DCData_DDesc_to_MD(m_DDesc);
460 if ( ASDCP_SUCCESS(result) )
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();
467 if ( ASDCP_SUCCESS(result) )
469 ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
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);
481 ASDCP::DCData::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
482 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
484 Result_t result = RESULT_OK;
486 if ( m_State.Test_READY() )
487 result = m_State.Goto_RUNNING(); // first time through
489 ui64_t StreamOffset = m_StreamOffset;
491 if ( ASDCP_SUCCESS(result) )
492 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
494 if ( ASDCP_SUCCESS(result) )
496 IndexTableSegment::IndexEntry Entry;
497 Entry.StreamOffset = StreamOffset;
498 m_FooterPart.PushIndexEntry(Entry);
504 // Closes the MXF file, writing the index and other closing information.
507 ASDCP::DCData::MXFWriter::h__Writer::Finalize()
509 if ( ! m_State.Test_RUNNING() )
512 m_State.Goto_FINAL();
514 return WriteASDCPFooter();
519 //------------------------------------------------------------------------------------------
521 ASDCP::DCData::MXFWriter::MXFWriter()
525 ASDCP::DCData::MXFWriter::~MXFWriter()
529 // Warning: direct manipulation of MXF structures can interfere
530 // with the normal operation of the wrapper. Caveat emptor!
532 ASDCP::MXF::OP1aHeader&
533 ASDCP::DCData::MXFWriter::OP1aHeader()
535 if ( m_Writer.empty() )
537 assert(g_OP1aHeader);
538 return *g_OP1aHeader;
541 return m_Writer->m_HeaderPart;
544 // Warning: direct manipulation of MXF structures can interfere
545 // with the normal operation of the wrapper. Caveat emptor!
547 ASDCP::MXF::OPAtomIndexFooter&
548 ASDCP::DCData::MXFWriter::OPAtomIndexFooter()
550 if ( m_Writer.empty() )
552 assert(g_OPAtomIndexFooter);
553 return *g_OPAtomIndexFooter;
556 return m_Writer->m_FooterPart;
559 // Warning: direct manipulation of MXF structures can interfere
560 // with the normal operation of the wrapper. Caveat emptor!
563 ASDCP::DCData::MXFWriter::RIP()
565 if ( m_Writer.empty() )
571 return m_Writer->m_RIP;
574 // Open the file for writing. The file must not exist. Returns error if
575 // the operation cannot be completed.
577 ASDCP::DCData::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
578 const DCDataDescriptor& DDesc, ui32_t HeaderSize)
580 if ( Info.LabelSetType != LS_MXF_SMPTE )
582 DefaultLogSink().Error("DC Data support requires LS_MXF_SMPTE\n");
583 return RESULT_FORMAT;
586 m_Writer = new h__Writer(DefaultSMPTEDict());
587 m_Writer->m_Info = Info;
589 Result_t result = m_Writer->OpenWrite(filename, HeaderSize, SubDescriptorList_t());
591 if ( ASDCP_SUCCESS(result) )
592 result = m_Writer->SetSourceStream(DDesc, NULL, DC_DATA_PACKAGE_LABEL, DC_DATA_DEF_LABEL);
594 if ( ASDCP_FAILURE(result) )
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
605 ASDCP::DCData::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
607 if ( m_Writer.empty() )
610 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
613 // Closes the MXF file, writing the index and other closing information.
615 ASDCP::DCData::MXFWriter::Finalize()
617 if ( m_Writer.empty() )
620 return m_Writer->Finalize();
625 // end AS_DCP_DCData.cpp