2 Copyright (c) 2011-2013, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. The name of the author may not be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /*! \file AS_02_JP2K.cpp
31 \brief AS-02 library, JPEG 2000 essence reader and writer implementation
34 #include "AS_02_internal.h"
39 using namespace ASDCP;
40 using namespace ASDCP::JP2K;
41 using Kumu::GenRandomValue;
43 //------------------------------------------------------------------------------------------
45 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE ST 422 / ST 2067-5 frame wrapping of JPEG 2000 codestreams";
46 static std::string PICT_DEF_LABEL = "Image Track";
48 //------------------------------------------------------------------------------------------
50 // hidden, internal implementation of JPEG 2000 reader
53 class AS_02::JP2K::MXFReader::h__Reader : public AS_02::h__AS02Reader
55 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
58 PictureDescriptor m_PDesc; // codestream parameter list
60 h__Reader(const Dictionary& d) :
61 AS_02::h__AS02Reader(d) {}
63 virtual ~h__Reader() {}
65 Result_t OpenRead(const std::string&);
66 Result_t ReadFrame(ui32_t, ASDCP::JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
71 AS_02::JP2K::MXFReader::h__Reader::OpenRead(const std::string& filename)
73 Result_t result = OpenMXFRead(filename.c_str());
75 if( KM_SUCCESS(result) )
77 InterchangeObject* tmp_iobj = 0;
79 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(CDCIEssenceDescriptor), &tmp_iobj);
83 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
88 DefaultLogSink().Error("RGBAEssenceDescriptor nor CDCIEssenceDescriptor found.\n");
91 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
95 DefaultLogSink().Error("JPEG2000PictureSubDescriptor not found.\n");
98 std::list<InterchangeObject*> ObjectList;
99 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
101 if ( ObjectList.empty() )
103 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
104 return RESULT_AS02_FORMAT;
114 AS_02::JP2K::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, ASDCP::JP2K::FrameBuffer& FrameBuf,
115 ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC)
117 if ( ! m_File.IsOpen() )
121 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
124 //------------------------------------------------------------------------------------------
127 AS_02::JP2K::MXFReader::MXFReader()
129 m_Reader = new h__Reader(DefaultCompositeDict());
133 AS_02::JP2K::MXFReader::~MXFReader()
137 // Warning: direct manipulation of MXF structures can interfere
138 // with the normal operation of the wrapper. Caveat emptor!
140 ASDCP::MXF::OP1aHeader&
141 AS_02::JP2K::MXFReader::OP1aHeader()
143 if ( m_Reader.empty() )
145 assert(g_OP1aHeader);
146 return *g_OP1aHeader;
149 return m_Reader->m_HeaderPart;
152 // Warning: direct manipulation of MXF structures can interfere
153 // with the normal operation of the wrapper. Caveat emptor!
155 AS_02::MXF::AS02IndexReader&
156 AS_02::JP2K::MXFReader::AS02IndexReader()
158 if ( m_Reader.empty() )
160 assert(g_AS02IndexReader);
161 return *g_AS02IndexReader;
164 return m_Reader->m_IndexAccess;
167 // Warning: direct manipulation of MXF structures can interfere
168 // with the normal operation of the wrapper. Caveat emptor!
171 AS_02::JP2K::MXFReader::RIP()
173 if ( m_Reader.empty() )
179 return m_Reader->m_RIP;
182 // Open the file for reading. The file must exist. Returns error if the
183 // operation cannot be completed.
185 AS_02::JP2K::MXFReader::OpenRead(const std::string& filename) const
187 return m_Reader->OpenRead(filename);
192 AS_02::JP2K::MXFReader::Close() const
194 if ( m_Reader && m_Reader->m_File.IsOpen() )
205 AS_02::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, ASDCP::JP2K::FrameBuffer& FrameBuf,
206 ASDCP::AESDecContext* Ctx, ASDCP::HMACContext* HMAC) const
208 if ( m_Reader && m_Reader->m_File.IsOpen() )
209 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
214 // Fill the struct with the values from the file's header.
215 // Returns RESULT_INIT if the file is not open.
217 AS_02::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
219 if ( m_Reader && m_Reader->m_File.IsOpen() )
221 Info = m_Reader->m_Info;
229 //------------------------------------------------------------------------------------------
232 class AS_02::JP2K::MXFWriter::h__Writer : public AS_02::h__AS02Writer
234 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
237 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
240 PictureDescriptor m_PDesc;
241 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
243 h__Writer(const Dictionary& d) : h__AS02Writer(d), m_EssenceSubDescriptor(0) {
244 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
247 virtual ~h__Writer(){}
249 Result_t OpenWrite(const std::string&, ASDCP::MXF::FileDescriptor* essence_descriptor,
250 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
251 const AS_02::IndexStrategy_t& IndexStrategy,
252 const ui32_t& PartitionSpace, const ui32_t& HeaderSize);
253 Result_t SetSourceStream(const std::string& label, const ASDCP::Rational& edit_rate);
254 Result_t WriteFrame(const ASDCP::JP2K::FrameBuffer&, ASDCP::AESEncContext*, ASDCP::HMACContext*);
259 // Open the file for writing. The file must not exist. Returns error if
260 // the operation cannot be completed.
262 AS_02::JP2K::MXFWriter::h__Writer::OpenWrite(const std::string& filename,
263 ASDCP::MXF::FileDescriptor* essence_descriptor,
264 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
265 const AS_02::IndexStrategy_t& IndexStrategy,
266 const ui32_t& PartitionSpace_sec, const ui32_t& HeaderSize)
268 if ( ! m_State.Test_BEGIN() )
273 if ( m_IndexStrategy != AS_02::IS_FOLLOW )
275 DefaultLogSink().Error("Only strategy IS_FOLLOW is supported at this time.\n");
276 return Kumu::RESULT_NOTIMPL;
279 Result_t result = m_File.OpenWrite(filename.c_str());
281 if ( KM_SUCCESS(result) )
283 m_IndexStrategy = IndexStrategy;
284 m_PartitionSpace = PartitionSpace_sec; // later converted to edit units by SetSourceStream()
285 m_HeaderSize = HeaderSize;
287 if ( essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_RGBAEssenceDescriptor))
288 && essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_CDCIEssenceDescriptor)) )
290 DefaultLogSink().Error("Essence descriptor is not a RGBAEssenceDescriptor or CDCIEssenceDescriptor.\n");
291 essence_descriptor->Dump();
292 return RESULT_AS02_FORMAT;
295 m_EssenceDescriptor = essence_descriptor;
297 ASDCP::MXF::InterchangeObject_list_t::iterator i;
298 for ( i = essence_sub_descriptor_list.begin(); i != essence_sub_descriptor_list.end(); ++i )
300 if ( (*i)->GetUL() != UL(m_Dict->ul(MDD_JPEG2000PictureSubDescriptor)) )
302 DefaultLogSink().Error("Essence sub-descriptor is not a JPEG2000PictureSubDescriptor.\n");
306 m_EssenceSubDescriptorList.push_back(*i);
307 GenRandomValue((*i)->InstanceUID);
308 m_EssenceDescriptor->SubDescriptors.push_back((*i)->InstanceUID);
309 *i = 0; // parent will only free the ones we don't keep
312 result = m_State.Goto_INIT();
318 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
320 AS_02::JP2K::MXFWriter::h__Writer::SetSourceStream(const std::string& label, const ASDCP::Rational& edit_rate)
323 if ( ! m_State.Test_INIT() )
328 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
329 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
330 Result_t result = m_State.Goto_READY();
332 if ( KM_SUCCESS(result) )
334 result = WriteAS02Header(label, UL(m_Dict->ul(MDD_JPEG_2000WrappingFrame)),
335 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
336 edit_rate, derive_timecode_rate_from_edit_rate(edit_rate));
342 // Writes a frame of essence to the MXF file. If the optional AESEncContext
343 // argument is present, the essence is encrypted prior to writing.
344 // Fails if the file is not open, is finalized, or an operating system
348 AS_02::JP2K::MXFWriter::h__Writer::WriteFrame(const ASDCP::JP2K::FrameBuffer& FrameBuf,
349 AESEncContext* Ctx, HMACContext* HMAC)
351 if ( FrameBuf.Size() == 0 )
353 DefaultLogSink().Error("The frame buffer size is zero.\n");
357 Result_t result = RESULT_OK;
359 if ( m_State.Test_READY() )
361 result = m_State.Goto_RUNNING(); // first time through
364 if ( KM_SUCCESS(result) )
366 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
373 // Closes the MXF file, writing the index and other closing information.
376 AS_02::JP2K::MXFWriter::h__Writer::Finalize()
378 if ( ! m_State.Test_RUNNING() )
381 Result_t result = m_State.Goto_FINAL();
383 if ( KM_SUCCESS(result) )
385 result = WriteAS02Footer();
392 //------------------------------------------------------------------------------------------
396 AS_02::JP2K::MXFWriter::MXFWriter()
400 AS_02::JP2K::MXFWriter::~MXFWriter()
404 // Warning: direct manipulation of MXF structures can interfere
405 // with the normal operation of the wrapper. Caveat emptor!
407 ASDCP::MXF::OP1aHeader&
408 AS_02::JP2K::MXFWriter::OP1aHeader()
410 if ( m_Writer.empty() )
412 assert(g_OP1aHeader);
413 return *g_OP1aHeader;
416 return m_Writer->m_HeaderPart;
419 // Warning: direct manipulation of MXF structures can interfere
420 // with the normal operation of the wrapper. Caveat emptor!
423 AS_02::JP2K::MXFWriter::RIP()
425 if ( m_Writer.empty() )
431 return m_Writer->m_RIP;
434 // Open the file for writing. The file must not exist. Returns error if
435 // the operation cannot be completed.
437 AS_02::JP2K::MXFWriter::OpenWrite(const std::string& filename, const ASDCP::WriterInfo& Info,
438 ASDCP::MXF::FileDescriptor* essence_descriptor,
439 ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
440 const ASDCP::Rational& edit_rate, const ui32_t& header_size,
441 const IndexStrategy_t& strategy, const ui32_t& partition_space)
443 if ( essence_descriptor == 0 )
445 DefaultLogSink().Error("Essence descriptor object required.\n");
449 m_Writer = new AS_02::JP2K::MXFWriter::h__Writer(DefaultSMPTEDict());
450 m_Writer->m_Info = Info;
452 Result_t result = m_Writer->OpenWrite(filename, essence_descriptor, essence_sub_descriptor_list,
453 strategy, partition_space, header_size);
455 if ( KM_SUCCESS(result) )
456 result = m_Writer->SetSourceStream(JP2K_PACKAGE_LABEL, edit_rate);
458 if ( KM_FAILURE(result) )
464 // Writes a frame of essence to the MXF file. If the optional AESEncContext
465 // argument is present, the essence is encrypted prior to writing.
466 // Fails if the file is not open, is finalized, or an operating system
469 AS_02::JP2K::MXFWriter::WriteFrame(const ASDCP::JP2K::FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
471 if ( m_Writer.empty() )
474 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
477 // Closes the MXF file, writing the index and other closing information.
479 AS_02::JP2K::MXFWriter::Finalize()
481 if ( m_Writer.empty() )
484 return m_Writer->Finalize();
489 // end AS_02_JP2K.cpp