2 Copyright (c) 2004-2018, 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 in ST 429-14 file.\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
169 && m_DDesc.EditRate != EditRate_192
170 && m_DDesc.EditRate != EditRate_200
171 && m_DDesc.EditRate != EditRate_240 )
173 DefaultLogSink().Error("DC Data file EditRate is not a supported value: %d/%d\n", // lu
174 m_DDesc.EditRate.Numerator, m_DDesc.EditRate.Denominator);
176 return RESULT_FORMAT;
185 ASDCP::DCData::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
186 AESDecContext* Ctx, HMACContext* HMAC)
188 if ( ! m_File.IsOpen() )
192 if ( m_PrivateLabelCompatibilityMode )
194 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_PrivateDCDataEssence), Ctx, HMAC);
197 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_DCDataEssence), Ctx, HMAC);
202 //------------------------------------------------------------------------------------------
207 ASDCP::DCData::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
212 fprintf(stream, "Frame: %06u, %7u bytes\n", m_FrameNumber, m_Size);
215 Kumu::hexdump(m_Data, dump_len, stream);
219 //------------------------------------------------------------------------------------------
221 ASDCP::DCData::MXFReader::MXFReader()
223 m_Reader = new h__Reader(DefaultSMPTEDict());
227 ASDCP::DCData::MXFReader::~MXFReader()
229 if ( m_Reader && m_Reader->m_File.IsOpen() )
233 // Warning: direct manipulation of MXF structures can interfere
234 // with the normal operation of the wrapper. Caveat emptor!
236 ASDCP::MXF::OP1aHeader&
237 ASDCP::DCData::MXFReader::OP1aHeader()
239 if ( m_Reader.empty() )
241 assert(g_OP1aHeader);
242 return *g_OP1aHeader;
245 return m_Reader->m_HeaderPart;
248 // Warning: direct manipulation of MXF structures can interfere
249 // with the normal operation of the wrapper. Caveat emptor!
251 ASDCP::MXF::OPAtomIndexFooter&
252 ASDCP::DCData::MXFReader::OPAtomIndexFooter()
254 if ( m_Reader.empty() )
256 assert(g_OPAtomIndexFooter);
257 return *g_OPAtomIndexFooter;
260 return m_Reader->m_IndexAccess;
263 // Warning: direct manipulation of MXF structures can interfere
264 // with the normal operation of the wrapper. Caveat emptor!
267 ASDCP::DCData::MXFReader::RIP()
269 if ( m_Reader.empty() )
275 return m_Reader->m_RIP;
278 // Open the file for reading. The file must exist. Returns error if the
279 // operation cannot be completed.
281 ASDCP::DCData::MXFReader::OpenRead(const std::string& filename) const
283 return m_Reader->OpenRead(filename);
288 ASDCP::DCData::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
289 AESDecContext* Ctx, HMACContext* HMAC) const
291 if ( m_Reader && m_Reader->m_File.IsOpen() )
292 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
298 ASDCP::DCData::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
300 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
304 // Fill the struct with the values from the file's header.
305 // Returns RESULT_INIT if the file is not open.
307 ASDCP::DCData::MXFReader::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
309 if ( m_Reader && m_Reader->m_File.IsOpen() )
311 DDesc = m_Reader->m_DDesc;
319 // Fill the struct with the values from the file's header.
320 // Returns RESULT_INIT if the file is not open.
322 ASDCP::DCData::MXFReader::FillWriterInfo(WriterInfo& Info) const
324 if ( m_Reader && m_Reader->m_File.IsOpen() )
326 Info = m_Reader->m_Info;
335 ASDCP::DCData::MXFReader::DumpHeaderMetadata(FILE* stream) const
337 if ( m_Reader->m_File.IsOpen() )
338 m_Reader->m_HeaderPart.Dump(stream);
344 ASDCP::DCData::MXFReader::DumpIndex(FILE* stream) const
346 if ( m_Reader->m_File.IsOpen() )
347 m_Reader->m_IndexAccess.Dump(stream);
352 ASDCP::DCData::MXFReader::Close() const
354 if ( m_Reader && m_Reader->m_File.IsOpen() )
364 //------------------------------------------------------------------------------------------
367 class ASDCP::DCData::MXFWriter::h__Writer : public ASDCP::h__ASDCPWriter
369 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
373 DCDataDescriptor m_DDesc;
374 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
376 h__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d) {
377 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
382 Result_t OpenWrite(const std::string&, ui32_t HeaderSize, const SubDescriptorList_t& subDescriptors);
383 Result_t SetSourceStream(const DCDataDescriptor&, const byte_t*, const std::string&, const std::string&);
384 Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
386 Result_t DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc);
392 ASDCP::DCData::MXFWriter::h__Writer::DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc)
394 ASDCP_TEST_NULL(m_EssenceDescriptor);
395 MXF::DCDataDescriptor* DDescObj = static_cast<MXF::DCDataDescriptor *>(m_EssenceDescriptor);
397 DDescObj->SampleRate = DDesc.EditRate;
398 DDescObj->ContainerDuration = DDesc.ContainerDuration;
399 DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);
406 ASDCP::DCData::MXFWriter::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize,
407 const SubDescriptorList_t& subDescriptors)
409 if ( ! m_State.Test_BEGIN() )
412 Result_t result = m_File.OpenWrite(filename);
414 if ( ASDCP_SUCCESS(result) )
416 m_HeaderSize = HeaderSize;
417 m_EssenceDescriptor = new MXF::DCDataDescriptor(m_Dict);
418 SubDescriptorList_t::const_iterator sDObj;
419 SubDescriptorList_t::const_iterator lastDescriptor = subDescriptors.end();
420 for (sDObj = subDescriptors.begin(); sDObj != lastDescriptor; ++sDObj)
422 m_EssenceSubDescriptorList.push_back(*sDObj);
423 GenRandomValue((*sDObj)->InstanceUID);
424 m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
426 result = m_State.Goto_INIT();
434 ASDCP::DCData::MXFWriter::h__Writer::SetSourceStream(DCDataDescriptor const& DDesc,
435 const byte_t * essenceCoding,
436 const std::string& packageLabel,
437 const std::string& defLabel)
439 if ( ! m_State.Test_INIT() )
442 if ( DDesc.EditRate != EditRate_24
443 && DDesc.EditRate != EditRate_25
444 && DDesc.EditRate != EditRate_30
445 && DDesc.EditRate != EditRate_48
446 && DDesc.EditRate != EditRate_50
447 && DDesc.EditRate != EditRate_60
448 && DDesc.EditRate != EditRate_96
449 && DDesc.EditRate != EditRate_100
450 && DDesc.EditRate != EditRate_120
451 && DDesc.EditRate != EditRate_192
452 && DDesc.EditRate != EditRate_200
453 && DDesc.EditRate != EditRate_240 )
455 DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
456 DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
457 return RESULT_RAW_FORMAT;
462 if (NULL != essenceCoding)
463 memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
464 Result_t result = DCData_DDesc_to_MD(m_DDesc);
466 if ( ASDCP_SUCCESS(result) )
468 memcpy(m_EssenceUL, m_Dict->ul(MDD_DCDataEssence), SMPTE_UL_LENGTH);
469 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
470 result = m_State.Goto_READY();
473 if ( ASDCP_SUCCESS(result) )
475 ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
477 result = WriteASDCPHeader(packageLabel, UL(m_Dict->ul(MDD_DCDataWrappingFrame)),
478 defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
479 m_DDesc.EditRate, TCFrameRate);
487 ASDCP::DCData::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
488 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
490 Result_t result = RESULT_OK;
492 if ( m_State.Test_READY() )
493 result = m_State.Goto_RUNNING(); // first time through
495 ui64_t StreamOffset = m_StreamOffset;
497 if ( ASDCP_SUCCESS(result) )
498 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, MXF_BER_LENGTH, Ctx, HMAC);
500 if ( ASDCP_SUCCESS(result) )
502 IndexTableSegment::IndexEntry Entry;
503 Entry.StreamOffset = StreamOffset;
504 m_FooterPart.PushIndexEntry(Entry);
510 // Closes the MXF file, writing the index and other closing information.
513 ASDCP::DCData::MXFWriter::h__Writer::Finalize()
515 if ( ! m_State.Test_RUNNING() )
518 m_State.Goto_FINAL();
520 return WriteASDCPFooter();
525 //------------------------------------------------------------------------------------------
527 ASDCP::DCData::MXFWriter::MXFWriter()
531 ASDCP::DCData::MXFWriter::~MXFWriter()
535 // Warning: direct manipulation of MXF structures can interfere
536 // with the normal operation of the wrapper. Caveat emptor!
538 ASDCP::MXF::OP1aHeader&
539 ASDCP::DCData::MXFWriter::OP1aHeader()
541 if ( m_Writer.empty() )
543 assert(g_OP1aHeader);
544 return *g_OP1aHeader;
547 return m_Writer->m_HeaderPart;
550 // Warning: direct manipulation of MXF structures can interfere
551 // with the normal operation of the wrapper. Caveat emptor!
553 ASDCP::MXF::OPAtomIndexFooter&
554 ASDCP::DCData::MXFWriter::OPAtomIndexFooter()
556 if ( m_Writer.empty() )
558 assert(g_OPAtomIndexFooter);
559 return *g_OPAtomIndexFooter;
562 return m_Writer->m_FooterPart;
565 // Warning: direct manipulation of MXF structures can interfere
566 // with the normal operation of the wrapper. Caveat emptor!
569 ASDCP::DCData::MXFWriter::RIP()
571 if ( m_Writer.empty() )
577 return m_Writer->m_RIP;
580 // Open the file for writing. The file must not exist. Returns error if
581 // the operation cannot be completed.
583 ASDCP::DCData::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
584 const DCDataDescriptor& DDesc, ui32_t HeaderSize)
586 if ( Info.LabelSetType != LS_MXF_SMPTE )
588 DefaultLogSink().Error("DC Data support requires LS_MXF_SMPTE\n");
589 return RESULT_FORMAT;
592 m_Writer = new h__Writer(DefaultSMPTEDict());
593 m_Writer->m_Info = Info;
595 Result_t result = m_Writer->OpenWrite(filename, HeaderSize, SubDescriptorList_t());
597 if ( ASDCP_SUCCESS(result) )
598 result = m_Writer->SetSourceStream(DDesc, NULL, DC_DATA_PACKAGE_LABEL, DC_DATA_DEF_LABEL);
600 if ( ASDCP_FAILURE(result) )
606 // Writes a frame of essence to the MXF file. If the optional AESEncContext
607 // argument is present, the essence is encrypted prior to writing.
608 // Fails if the file is not open, is finalized, or an operating system
611 ASDCP::DCData::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
613 if ( m_Writer.empty() )
616 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
619 // Closes the MXF file, writing the index and other closing information.
621 ASDCP::DCData::MXFWriter::Finalize()
623 if ( m_Writer.empty() )
626 return m_Writer->Finalize();
631 // end AS_DCP_DCData.cpp