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 std::string& 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);
106 if ( m_EssenceDescriptor == 0 )
108 DefaultLogSink().Error("DCDataDescriptor object not found.\n");
109 return RESULT_FORMAT;
113 if ( ASDCP_SUCCESS(result) )
115 result = MD_to_DCData_DDesc(m_DDesc);
119 // check for sample/frame rate sanity
120 if ( ASDCP_SUCCESS(result)
121 && m_DDesc.EditRate != EditRate_24
122 && m_DDesc.EditRate != EditRate_25
123 && m_DDesc.EditRate != EditRate_30
124 && m_DDesc.EditRate != EditRate_48
125 && m_DDesc.EditRate != EditRate_50
126 && m_DDesc.EditRate != EditRate_60
127 && m_DDesc.EditRate != EditRate_96
128 && m_DDesc.EditRate != EditRate_100
129 && m_DDesc.EditRate != EditRate_120 )
131 DefaultLogSink().Error("DC Data file EditRate is not a supported value: %d/%d\n", // lu
132 m_DDesc.EditRate.Numerator, m_DDesc.EditRate.Denominator);
134 return RESULT_FORMAT;
143 ASDCP::DCData::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
144 AESDecContext* Ctx, HMACContext* HMAC)
146 if ( ! m_File.IsOpen() )
150 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_DCDataEssence), Ctx, HMAC);
155 //------------------------------------------------------------------------------------------
157 class ASDCP::DCData::MXFReader::h__Reader : public DCData::h__Reader
159 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
163 h__Reader(const Dictionary& d) : DCData::h__Reader(d) {}
164 virtual ~h__Reader() {}
168 //------------------------------------------------------------------------------------------
173 ASDCP::DCData::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
178 fprintf(stream, "Frame: %06u, %7u bytes\n", m_FrameNumber, m_Size);
181 Kumu::hexdump(m_Data, dump_len, stream);
185 //------------------------------------------------------------------------------------------
187 ASDCP::DCData::MXFReader::MXFReader()
189 m_Reader = new h__Reader(DefaultSMPTEDict());
193 ASDCP::DCData::MXFReader::~MXFReader()
195 if ( m_Reader && m_Reader->m_File.IsOpen() )
199 // Warning: direct manipulation of MXF structures can interfere
200 // with the normal operation of the wrapper. Caveat emptor!
202 ASDCP::MXF::OP1aHeader&
203 ASDCP::DCData::MXFReader::OP1aHeader()
205 if ( m_Reader.empty() )
207 assert(g_OP1aHeader);
208 return *g_OP1aHeader;
211 return m_Reader->m_HeaderPart;
214 // Warning: direct manipulation of MXF structures can interfere
215 // with the normal operation of the wrapper. Caveat emptor!
217 ASDCP::MXF::OPAtomIndexFooter&
218 ASDCP::DCData::MXFReader::OPAtomIndexFooter()
220 if ( m_Reader.empty() )
222 assert(g_OPAtomIndexFooter);
223 return *g_OPAtomIndexFooter;
226 return m_Reader->m_IndexAccess;
229 // Warning: direct manipulation of MXF structures can interfere
230 // with the normal operation of the wrapper. Caveat emptor!
233 ASDCP::DCData::MXFReader::RIP()
235 if ( m_Reader.empty() )
241 return m_Reader->m_RIP;
244 // Open the file for reading. The file must exist. Returns error if the
245 // operation cannot be completed.
247 ASDCP::DCData::MXFReader::OpenRead(const std::string& filename) const
249 return m_Reader->OpenRead(filename);
254 ASDCP::DCData::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
255 AESDecContext* Ctx, HMACContext* HMAC) const
257 if ( m_Reader && m_Reader->m_File.IsOpen() )
258 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
264 ASDCP::DCData::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
266 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
270 // Fill the struct with the values from the file's header.
271 // Returns RESULT_INIT if the file is not open.
273 ASDCP::DCData::MXFReader::FillDCDataDescriptor(DCDataDescriptor& DDesc) const
275 if ( m_Reader && m_Reader->m_File.IsOpen() )
277 DDesc = m_Reader->m_DDesc;
285 // Fill the struct with the values from the file's header.
286 // Returns RESULT_INIT if the file is not open.
288 ASDCP::DCData::MXFReader::FillWriterInfo(WriterInfo& Info) const
290 if ( m_Reader && m_Reader->m_File.IsOpen() )
292 Info = m_Reader->m_Info;
301 ASDCP::DCData::MXFReader::DumpHeaderMetadata(FILE* stream) const
303 if ( m_Reader->m_File.IsOpen() )
304 m_Reader->m_HeaderPart.Dump(stream);
310 ASDCP::DCData::MXFReader::DumpIndex(FILE* stream) const
312 if ( m_Reader->m_File.IsOpen() )
313 m_Reader->m_IndexAccess.Dump(stream);
318 ASDCP::DCData::MXFReader::Close() const
320 if ( m_Reader && m_Reader->m_File.IsOpen() )
330 //------------------------------------------------------------------------------------------
335 ASDCP::DCData::h__Writer::DCData_DDesc_to_MD(DCData::DCDataDescriptor& DDesc)
337 ASDCP_TEST_NULL(m_EssenceDescriptor);
338 MXF::DCDataDescriptor* DDescObj = static_cast<MXF::DCDataDescriptor *>(m_EssenceDescriptor);
340 DDescObj->SampleRate = DDesc.EditRate;
341 DDescObj->ContainerDuration = DDesc.ContainerDuration;
342 DDescObj->DataEssenceCoding.Set(DDesc.DataEssenceCoding);
349 ASDCP::DCData::h__Writer::OpenWrite(const std::string& filename, ui32_t HeaderSize,
350 const SubDescriptorList_t& subDescriptors)
352 if ( ! m_State.Test_BEGIN() )
355 Result_t result = m_File.OpenWrite(filename);
357 if ( ASDCP_SUCCESS(result) )
359 m_HeaderSize = HeaderSize;
360 m_EssenceDescriptor = new MXF::DCDataDescriptor(m_Dict);
361 SubDescriptorList_t::const_iterator sDObj;
362 SubDescriptorList_t::const_iterator lastDescriptor = subDescriptors.end();
363 for (sDObj = subDescriptors.begin(); sDObj != lastDescriptor; ++sDObj)
365 m_EssenceSubDescriptorList.push_back(*sDObj);
366 GenRandomValue((*sDObj)->InstanceUID);
367 m_EssenceDescriptor->SubDescriptors.push_back((*sDObj)->InstanceUID);
369 result = m_State.Goto_INIT();
377 ASDCP::DCData::h__Writer::SetSourceStream(DCDataDescriptor const& DDesc,
378 const byte_t * essenceCoding,
379 const std::string& packageLabel,
380 const std::string& defLabel)
382 if ( ! m_State.Test_INIT() )
385 if ( DDesc.EditRate != EditRate_24
386 && DDesc.EditRate != EditRate_25
387 && DDesc.EditRate != EditRate_30
388 && DDesc.EditRate != EditRate_48
389 && DDesc.EditRate != EditRate_50
390 && DDesc.EditRate != EditRate_60
391 && DDesc.EditRate != EditRate_96
392 && DDesc.EditRate != EditRate_100
393 && DDesc.EditRate != EditRate_120 )
395 DefaultLogSink().Error("DCDataDescriptor.EditRate is not a supported value: %d/%d\n",
396 DDesc.EditRate.Numerator, DDesc.EditRate.Denominator);
397 return RESULT_RAW_FORMAT;
402 if (NULL != essenceCoding)
403 memcpy(m_DDesc.DataEssenceCoding, essenceCoding, SMPTE_UL_LENGTH);
404 Result_t result = DCData_DDesc_to_MD(m_DDesc);
406 if ( ASDCP_SUCCESS(result) )
408 memcpy(m_EssenceUL, m_Dict->ul(MDD_DCDataEssence), SMPTE_UL_LENGTH);
409 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
410 result = m_State.Goto_READY();
413 if ( ASDCP_SUCCESS(result) )
415 ui32_t TCFrameRate = m_DDesc.EditRate.Numerator;
417 result = WriteASDCPHeader(packageLabel, UL(m_Dict->ul(MDD_DCDataWrappingFrame)),
418 defLabel, UL(m_EssenceUL), UL(m_Dict->ul(MDD_DataDataDef)),
419 m_DDesc.EditRate, TCFrameRate);
427 ASDCP::DCData::h__Writer::WriteFrame(const FrameBuffer& FrameBuf,
428 ASDCP::AESEncContext* Ctx, ASDCP::HMACContext* HMAC)
430 Result_t result = RESULT_OK;
432 if ( m_State.Test_READY() )
433 result = m_State.Goto_RUNNING(); // first time through
435 ui64_t StreamOffset = m_StreamOffset;
437 if ( ASDCP_SUCCESS(result) )
438 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
440 if ( ASDCP_SUCCESS(result) )
442 IndexTableSegment::IndexEntry Entry;
443 Entry.StreamOffset = StreamOffset;
444 m_FooterPart.PushIndexEntry(Entry);
450 // Closes the MXF file, writing the index and other closing information.
453 ASDCP::DCData::h__Writer::Finalize()
455 if ( ! m_State.Test_RUNNING() )
458 m_State.Goto_FINAL();
460 return WriteASDCPFooter();
465 //------------------------------------------------------------------------------------------
468 class ASDCP::DCData::MXFWriter::h__Writer : public DCData::h__Writer
470 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
474 h__Writer(const Dictionary& d) : DCData::h__Writer(d) {}
475 virtual ~h__Writer() {}
479 //------------------------------------------------------------------------------------------
481 ASDCP::DCData::MXFWriter::MXFWriter()
485 ASDCP::DCData::MXFWriter::~MXFWriter()
489 // Warning: direct manipulation of MXF structures can interfere
490 // with the normal operation of the wrapper. Caveat emptor!
492 ASDCP::MXF::OP1aHeader&
493 ASDCP::DCData::MXFWriter::OP1aHeader()
495 if ( m_Writer.empty() )
497 assert(g_OP1aHeader);
498 return *g_OP1aHeader;
501 return m_Writer->m_HeaderPart;
504 // Warning: direct manipulation of MXF structures can interfere
505 // with the normal operation of the wrapper. Caveat emptor!
507 ASDCP::MXF::OPAtomIndexFooter&
508 ASDCP::DCData::MXFWriter::OPAtomIndexFooter()
510 if ( m_Writer.empty() )
512 assert(g_OPAtomIndexFooter);
513 return *g_OPAtomIndexFooter;
516 return m_Writer->m_FooterPart;
519 // Warning: direct manipulation of MXF structures can interfere
520 // with the normal operation of the wrapper. Caveat emptor!
523 ASDCP::DCData::MXFWriter::RIP()
525 if ( m_Writer.empty() )
531 return m_Writer->m_RIP;
534 // Open the file for writing. The file must not exist. Returns error if
535 // the operation cannot be completed.
537 ASDCP::DCData::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
538 const DCDataDescriptor& DDesc, ui32_t HeaderSize)
540 if ( Info.LabelSetType != LS_MXF_SMPTE )
542 DefaultLogSink().Error("DC Data support requires LS_MXF_SMPTE\n");
543 return RESULT_FORMAT;
546 m_Writer = new h__Writer(DefaultSMPTEDict());
547 m_Writer->m_Info = Info;
549 Result_t result = m_Writer->OpenWrite(filename, HeaderSize, SubDescriptorList_t());
551 if ( ASDCP_SUCCESS(result) )
552 result = m_Writer->SetSourceStream(DDesc, NULL, DC_DATA_PACKAGE_LABEL, DC_DATA_DEF_LABEL);
554 if ( ASDCP_FAILURE(result) )
560 // Writes a frame of essence to the MXF file. If the optional AESEncContext
561 // argument is present, the essence is encrypted prior to writing.
562 // Fails if the file is not open, is finalized, or an operating system
565 ASDCP::DCData::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
567 if ( m_Writer.empty() )
570 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
573 // Closes the MXF file, writing the index and other closing information.
575 ASDCP::DCData::MXFWriter::Finalize()
577 if ( m_Writer.empty() )
580 return m_Writer->Finalize();
585 // end AS_DCP_DCData.cpp