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_AtmosLabelCompatibilityMode;
82 MXF::DCDataDescriptor* m_EssenceDescriptor;
83 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
87 DCDataDescriptor m_DDesc;
89 h__Reader(const Dictionary& d) : ASDCP::h__ASDCPReader(d), m_AtmosLabelCompatibilityMode(false), m_EssenceDescriptor(0), m_DDesc() {}
91 Result_t OpenRead(const std::string&);
92 Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
93 Result_t MD_to_DCData_DDesc(DCData::DCDataDescriptor& DDesc);
98 ASDCP::DCData::MXFReader::h__Reader::MD_to_DCData_DDesc(DCData::DCDataDescriptor& DDesc)
100 ASDCP_TEST_NULL(m_EssenceDescriptor);
101 MXF::DCDataDescriptor* DDescObj = m_EssenceDescriptor;
102 DDesc.EditRate = DDescObj->SampleRate;
103 assert(DDescObj->ContainerDuration <= 0xFFFFFFFFL);
104 DDesc.ContainerDuration = static_cast<ui32_t>(DDescObj->ContainerDuration);
105 memcpy(DDesc.DataEssenceCoding, DDescObj->DataEssenceCoding.Value(), SMPTE_UL_LENGTH);
112 ASDCP::DCData::MXFReader::h__Reader::OpenRead(const std::string& filename)
114 Result_t result = OpenMXFRead(filename);
115 m_EssenceDescriptor = 0;
117 if( KM_SUCCESS(result) )
119 InterchangeObject* iObj = 0;
120 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DCDataDescriptor), &iObj);
122 if ( KM_FAILURE(result) )
124 result = m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(DolbyAtmosDCDataDescriptor), &iObj);
126 if ( KM_SUCCESS(result) )
128 m_AtmosLabelCompatibilityMode = true;
132 if ( KM_SUCCESS(result) )
134 m_EssenceDescriptor = static_cast<MXF::DCDataDescriptor*>(iObj);
138 if ( m_EssenceDescriptor == 0 )
140 DefaultLogSink().Error("DCDataDescriptor object not found.\n");
141 result = RESULT_FORMAT;
144 if ( KM_SUCCESS(result) )
146 result = MD_to_DCData_DDesc(m_DDesc);
149 // check for sample/frame rate sanity
150 if ( ASDCP_SUCCESS(result)
151 && m_DDesc.EditRate != EditRate_24
152 && m_DDesc.EditRate != EditRate_25
153 && m_DDesc.EditRate != EditRate_30
154 && m_DDesc.EditRate != EditRate_48
155 && m_DDesc.EditRate != EditRate_50
156 && m_DDesc.EditRate != EditRate_60
157 && m_DDesc.EditRate != EditRate_96
158 && m_DDesc.EditRate != EditRate_100
159 && m_DDesc.EditRate != EditRate_120 )
161 DefaultLogSink().Error("DC Data file EditRate is not a supported value: %d/%d\n", // lu
162 m_DDesc.EditRate.Numerator, m_DDesc.EditRate.Denominator);
164 return RESULT_FORMAT;
173 ASDCP::DCData::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
174 AESDecContext* Ctx, HMACContext* HMAC)
176 if ( ! m_File.IsOpen() )
180 if ( m_AtmosLabelCompatibilityMode )
182 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_DolbyAtmosDCDataEssence), Ctx, HMAC);
185 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_DCDataEssence), Ctx, HMAC);
190 //------------------------------------------------------------------------------------------
195 ASDCP::DCData::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
200 fprintf(stream, "Frame: %06u, %7u bytes\n", m_FrameNumber, m_Size);
203 Kumu::hexdump(m_Data, dump_len, stream);
207 //------------------------------------------------------------------------------------------
209 ASDCP::DCData::MXFReader::MXFReader()
211 m_Reader = new h__Reader(DefaultSMPTEDict());
215 ASDCP::DCData::MXFReader::~MXFReader()
217 if ( m_Reader && m_Reader->m_File.IsOpen() )
221 // Warning: direct manipulation of MXF structures can interfere
222 // with the normal operation of the wrapper. Caveat emptor!
224 ASDCP::MXF::OP1aHeader&
225 ASDCP::DCData::MXFReader::OP1aHeader()
227 if ( m_Reader.empty() )
229 assert(g_OP1aHeader);
230 return *g_OP1aHeader;
233 return m_Reader->m_HeaderPart;
236 // Warning: direct manipulation of MXF structures can interfere
237 // with the normal operation of the wrapper. Caveat emptor!
239 ASDCP::MXF::OPAtomIndexFooter&
240 ASDCP::DCData::MXFReader::OPAtomIndexFooter()
242 if ( m_Reader.empty() )
244 assert(g_OPAtomIndexFooter);
245 return *g_OPAtomIndexFooter;
248 return m_Reader->m_IndexAccess;
251 // Warning: direct manipulation of MXF structures can interfere
252 // with the normal operation of the wrapper. Caveat emptor!
255 ASDCP::DCData::MXFReader::RIP()
257 if ( m_Reader.empty() )
263 return m_Reader->m_RIP;
266 // Open the file for reading. The file must exist. Returns error if the
267 // operation cannot be completed.
269 ASDCP::DCData::MXFReader::OpenRead(const std::string& filename) const
271 return m_Reader->OpenRead(filename);
276 ASDCP::DCData::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
277 AESDecContext* Ctx, HMACContext* HMAC) const
279 if ( m_Reader && m_Reader->m_File.IsOpen() )
280 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
286 ASDCP::DCData::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
288 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
292 // Fill the struct with the values from the file's header.
293 // Returns RESULT_INIT if the file is not open.
295 ASDCP::DCData::MXFReader::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
297 if ( m_Reader && m_Reader->m_File.IsOpen() )
299 DDesc = m_Reader->m_DDesc;
307 // Fill the struct with the values from the file's header.
308 // Returns RESULT_INIT if the file is not open.
310 ASDCP::DCData::MXFReader::FillWriterInfo(WriterInfo& Info) const
312 if ( m_Reader && m_Reader->m_File.IsOpen() )
314 Info = m_Reader->m_Info;
323 ASDCP::DCData::MXFReader::DumpHeaderMetadata(FILE* stream) const
325 if ( m_Reader->m_File.IsOpen() )
326 m_Reader->m_HeaderPart.Dump(stream);
332 ASDCP::DCData::MXFReader::DumpIndex(FILE* stream) const
334 if ( m_Reader->m_File.IsOpen() )
335 m_Reader->m_IndexAccess.Dump(stream);
340 ASDCP::DCData::MXFReader::Close() const
342 if ( m_Reader && m_Reader->m_File.IsOpen() )
352 //------------------------------------------------------------------------------------------
355 class ASDCP::DCData::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter
357 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
361 DCDataDescriptor m_DDesc;
362 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
364 h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d) {
365 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
370 Result_t OpenWrite(const std::string&, ui32_t HeaderSize, const SubDescriptorList_t& subDescriptors);
371 Result_t SetSourceStream(const DCDataDescriptor&, const byte_t*, const std::string&, const std::string&);
372 Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
374 Result_t DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc);
380 ASDCP::DCData::MXFWriter::h__Writer::DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc)
382 ASDCP_TEST_NULL(m_EssenceDescriptor);
383 MXF::DCDataDescriptor* DDescObj = static_cast<MXF::DCDataDescriptor *>(m_EssenceDescriptor);
385 DDescObj->SampleRate = DDesc.EditRate;
386 DDescObj->ContainerDuration = DDesc.ContainerDuration;
387 DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);
394 ASDCP::DCData::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize,
395 const SubDescriptorList_t& subDescriptors)
397 if ( ! m_State.Test_BEGIN() )
400 Result_t result = m_File.OpenWrite(filename);
402 if ( ASDCP_SUCCESS(result) )
404 m_HeaderSize = HeaderSize;
405 m_EssenceDescriptor = new MXF::DCDataDescriptor(m_Dict);
406 SubDescriptorList_t::const_iterator sDObj;
407 SubDescriptorList_t::const_iterator lastDescriptor = subDescriptors.end();
408 for (sDObj = subDescriptors.begin(); sDObj != lastDescriptor; ++sDObj)
410 m_EssenceSubDescriptorList.push_back(*sDObj);
411 GenRandomValue((*sDObj)->InstanceUID);
412 m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
414 result = m_State.Goto_INIT();
422 ASDCP::DCData::MXFWriter::h__Writer::SetSourceStream(DCDataDescriptor const& DDesc,
423 const byte_t * essenceCoding,
424 const std::string& packageLabel,
425 const std::string& defLabel)
427 if ( ! m_State.Test_INIT() )
430 if ( DDesc.EditRate != EditRate_24
431 && DDesc.EditRate != EditRate_25
432 && DDesc.EditRate != EditRate_30
433 && DDesc.EditRate != EditRate_48
434 && DDesc.EditRate != EditRate_50
435 && DDesc.EditRate != EditRate_60
436 && DDesc.EditRate != EditRate_96
437 && DDesc.EditRate != EditRate_100
438 && DDesc.EditRate != EditRate_120 )
440 DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
441 DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
442 return RESULT_RAW_FORMAT;
447 if (NULL != essenceCoding)
448 memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
449 Result_t result = DCData_DDesc_to_MD(m_DDesc);
451 if ( ASDCP_SUCCESS(result) )
453 memcpy(m_EssenceUL, m_Dict->ul(MDD_DCDataEssence), SMPTE_UL_LENGTH);
454 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
455 result = m_State.Goto_READY();
458 if ( ASDCP_SUCCESS(result) )
460 ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
462 result = WriteASDCPHeader(packageLabel, UL(m_Dict->ul(MDD_DCDataWrappingFrame)),
463 defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
464 m_DDesc.EditRate, TCFrameRate);
472 ASDCP::DCData::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
473 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
475 Result_t result = RESULT_OK;
477 if ( m_State.Test_READY() )
478 result = m_State.Goto_RUNNING(); // first time through
480 ui64_t StreamOffset = m_StreamOffset;
482 if ( ASDCP_SUCCESS(result) )
483 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
485 if ( ASDCP_SUCCESS(result) )
487 IndexTableSegment::IndexEntry Entry;
488 Entry.StreamOffset = StreamOffset;
489 m_FooterPart.PushIndexEntry(Entry);
495 // Closes the MXF file, writing the index and other closing information.
498 ASDCP::DCData::MXFWriter::h__Writer::Finalize()
500 if ( ! m_State.Test_RUNNING() )
503 m_State.Goto_FINAL();
505 return WriteASDCPFooter();
510 //------------------------------------------------------------------------------------------
512 ASDCP::DCData::MXFWriter::MXFWriter()
516 ASDCP::DCData::MXFWriter::~MXFWriter()
520 // Warning: direct manipulation of MXF structures can interfere
521 // with the normal operation of the wrapper. Caveat emptor!
523 ASDCP::MXF::OP1aHeader&
524 ASDCP::DCData::MXFWriter::OP1aHeader()
526 if ( m_Writer.empty() )
528 assert(g_OP1aHeader);
529 return *g_OP1aHeader;
532 return m_Writer->m_HeaderPart;
535 // Warning: direct manipulation of MXF structures can interfere
536 // with the normal operation of the wrapper. Caveat emptor!
538 ASDCP::MXF::OPAtomIndexFooter&
539 ASDCP::DCData::MXFWriter::OPAtomIndexFooter()
541 if ( m_Writer.empty() )
543 assert(g_OPAtomIndexFooter);
544 return *g_OPAtomIndexFooter;
547 return m_Writer->m_FooterPart;
550 // Warning: direct manipulation of MXF structures can interfere
551 // with the normal operation of the wrapper. Caveat emptor!
554 ASDCP::DCData::MXFWriter::RIP()
556 if ( m_Writer.empty() )
562 return m_Writer->m_RIP;
565 // Open the file for writing. The file must not exist. Returns error if
566 // the operation cannot be completed.
568 ASDCP::DCData::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
569 const DCDataDescriptor& DDesc, ui32_t HeaderSize)
571 if ( Info.LabelSetType != LS_MXF_SMPTE )
573 DefaultLogSink().Error("DC Data support requires LS_MXF_SMPTE\n");
574 return RESULT_FORMAT;
577 m_Writer = new h__Writer(DefaultSMPTEDict());
578 m_Writer->m_Info = Info;
580 Result_t result = m_Writer->OpenWrite(filename, HeaderSize, SubDescriptorList_t());
582 if ( ASDCP_SUCCESS(result) )
583 result = m_Writer->SetSourceStream(DDesc, NULL, DC_DATA_PACKAGE_LABEL, DC_DATA_DEF_LABEL);
585 if ( ASDCP_FAILURE(result) )
591 // Writes a frame of essence to the MXF file. If the optional AESEncContext
592 // argument is present, the essence is encrypted prior to writing.
593 // Fails if the file is not open, is finalized, or an operating system
596 ASDCP::DCData::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
598 if ( m_Writer.empty() )
601 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
604 // Closes the MXF file, writing the index and other closing information.
606 ASDCP::DCData::MXFWriter::Finalize()
608 if ( m_Writer.empty() )
611 return m_Writer->Finalize();
616 // end AS_DCP_DCData.cpp