2 Copyright (c) 2004-2006, 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_JP2k.cpp
29 \brief AS-DCP library, JPEG 2000 essence reader and writer implementation
32 #include "AS_DCP_internal.h"
35 //------------------------------------------------------------------------------------------
37 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE XXXM frame wrapping of JPEG 2000 codestreams";
38 static std::string PICT_DEF_LABEL = "Picture Track";
42 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
61 ContainerDuration: %u\n",
62 PDesc.AspectRatio.Numerator ,PDesc.AspectRatio.Denominator,
63 PDesc.EditRate.Numerator ,PDesc.EditRate.Denominator,
75 PDesc.ContainerDuration
78 fprintf(stream, "Color Components:\n");
80 for ( ui32_t i = 0; i < PDesc.Csize; i++ )
82 fprintf(stream, " %u.%u.%u\n",
83 PDesc.ImageComponents[i].Ssize,
84 PDesc.ImageComponents[i].XRsize,
85 PDesc.ImageComponents[i].YRsize
89 const ui32_t tmp_buf_len = 256;
90 char tmp_buf[tmp_buf_len];
92 if ( PDesc.CodingStyleLength )
93 fprintf(stream, "Default Coding (%u): %s\n",
94 PDesc.CodingStyleLength,
95 Kumu::bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength, tmp_buf, tmp_buf_len)
98 if ( PDesc.QuantDefaultLength )
99 fprintf(stream, "Quantization Default (%u): %s\n",
100 PDesc.QuantDefaultLength,
101 Kumu::bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength, tmp_buf, tmp_buf_len)
105 //------------------------------------------------------------------------------------------
107 // hidden, internal implementation of JPEG 2000 reader
109 class ASDCP::JP2K::MXFReader::h__Reader : public ASDCP::h__Reader
111 RGBAEssenceDescriptor* m_EssenceDescriptor;
112 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
114 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
117 PictureDescriptor m_PDesc; // codestream parameter list
119 h__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0) {}
120 Result_t OpenRead(const char*);
121 Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
122 Result_t ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
123 Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
128 ASDCP::JP2K::MXFReader::h__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
130 memset(&PDesc, 0, sizeof(PDesc));
131 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
133 PDesc.EditRate = PDescObj->SampleRate;
134 PDesc.ContainerDuration = PDescObj->ContainerDuration;
135 PDesc.StoredWidth = PDescObj->StoredWidth;
136 PDesc.StoredHeight = PDescObj->StoredHeight;
137 PDesc.AspectRatio = PDescObj->AspectRatio;
139 if ( m_EssenceSubDescriptor != 0 )
141 PDesc.Rsize = m_EssenceSubDescriptor->Rsize;
142 PDesc.Xsize = m_EssenceSubDescriptor->Xsize;
143 PDesc.Ysize = m_EssenceSubDescriptor->Ysize;
144 PDesc.XOsize = m_EssenceSubDescriptor->XOsize;
145 PDesc.YOsize = m_EssenceSubDescriptor->YOsize;
146 PDesc.XTsize = m_EssenceSubDescriptor->XTsize;
147 PDesc.YTsize = m_EssenceSubDescriptor->YTsize;
148 PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
149 PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
150 PDesc.Csize = m_EssenceSubDescriptor->Csize;
152 // PictureComponentSizing
153 ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
155 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
156 memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
159 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
161 // CodingStyleDefault
162 if ( ( PDesc.CodingStyleLength = m_EssenceSubDescriptor->CodingStyleDefault.Length() ) != 0 )
163 memcpy(PDesc.CodingStyle, m_EssenceSubDescriptor->CodingStyleDefault.RoData(), PDesc.CodingStyleLength);
165 // QuantizationDefault
166 if ( ( PDesc.QuantDefaultLength = m_EssenceSubDescriptor->QuantizationDefault.Length() ) != 0 )
167 memcpy(PDesc.QuantDefault, m_EssenceSubDescriptor->QuantizationDefault.RoData(), PDesc.QuantDefaultLength);
176 ASDCP::JP2K::MXFReader::h__Reader::OpenRead(const char* filename)
178 Result_t result = OpenMXFRead(filename);
180 if( ASDCP_SUCCESS(result) )
182 if ( m_EssenceDescriptor == 0 )
184 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), (InterchangeObject**)&m_EssenceDescriptor);
185 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), (InterchangeObject**)&m_EssenceSubDescriptor);
188 result = MD_to_JP2K_PDesc(m_PDesc);
191 if( ASDCP_SUCCESS(result) )
192 result = InitMXFIndex();
194 if( ASDCP_SUCCESS(result) )
203 ASDCP::JP2K::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
204 AESDecContext* Ctx, HMACContext* HMAC)
206 if ( ! m_File.IsOpen() )
209 return ReadEKLVPacket(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
212 //------------------------------------------------------------------------------------------
217 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
222 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
227 Kumu::hexdump(m_Data, dump_len, stream);
231 //------------------------------------------------------------------------------------------
233 ASDCP::JP2K::MXFReader::MXFReader()
235 m_Reader = new h__Reader;
239 ASDCP::JP2K::MXFReader::~MXFReader()
243 // Open the file for reading. The file must exist. Returns error if the
244 // operation cannot be completed.
246 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
248 return m_Reader->OpenRead(filename);
253 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
254 AESDecContext* Ctx, HMACContext* HMAC) const
256 if ( m_Reader && m_Reader->m_File.IsOpen() )
257 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
263 // Fill the struct with the values from the file's header.
264 // Returns RESULT_INIT if the file is not open.
266 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
268 if ( m_Reader && m_Reader->m_File.IsOpen() )
270 PDesc = m_Reader->m_PDesc;
278 // Fill the struct with the values from the file's header.
279 // Returns RESULT_INIT if the file is not open.
281 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
283 if ( m_Reader && m_Reader->m_File.IsOpen() )
285 Info = m_Reader->m_Info;
294 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
296 if ( m_Reader->m_File.IsOpen() )
297 m_Reader->m_HeaderPart.Dump(stream);
303 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
305 if ( m_Reader->m_File.IsOpen() )
306 m_Reader->m_FooterPart.Dump(stream);
310 //------------------------------------------------------------------------------------------
315 class ASDCP::JP2K::MXFWriter::h__Writer : public ASDCP::h__Writer
317 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
320 PictureDescriptor m_PDesc;
321 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
323 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
325 h__Writer() : m_EssenceSubDescriptor(0) {
326 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
331 Result_t OpenWrite(const char*, ui32_t HeaderSize);
332 Result_t SetSourceStream(const PictureDescriptor&);
333 Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
335 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
341 ASDCP::JP2K::MXFWriter::h__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
343 assert(m_EssenceDescriptor);
344 assert(m_EssenceSubDescriptor);
345 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
347 PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression));
348 PDescObj->SampleRate = PDesc.EditRate;
349 PDescObj->ContainerDuration = PDesc.ContainerDuration;
350 PDescObj->StoredWidth = PDesc.StoredWidth;
351 PDescObj->StoredHeight = PDesc.StoredHeight;
352 PDescObj->AspectRatio = PDesc.AspectRatio;
353 PDescObj->FrameLayout = 0;
355 m_EssenceSubDescriptor->Rsize = PDesc.Rsize;
356 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
357 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
358 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
359 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
360 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
361 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
362 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
363 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
364 m_EssenceSubDescriptor->Csize = PDesc.Csize;
366 const ui32_t tmp_buffer_len = 64;
367 byte_t tmp_buffer[tmp_buffer_len];
369 *(ui32_t*)tmp_buffer = KM_i32_BE(3L); // three components
370 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(3L);
371 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
373 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, 17);
374 m_EssenceSubDescriptor->PictureComponentSizing.Length(17);
376 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), PDesc.CodingStyle, PDesc.CodingStyleLength);
377 m_EssenceSubDescriptor->CodingStyleDefault.Length(PDesc.CodingStyleLength);
379 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), PDesc.QuantDefault, PDesc.QuantDefaultLength);
380 m_EssenceSubDescriptor->QuantizationDefault.Length(PDesc.QuantDefaultLength);
386 // Open the file for writing. The file must not exist. Returns error if
387 // the operation cannot be completed.
389 ASDCP::JP2K::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
391 if ( ! m_State.Test_BEGIN() )
394 Result_t result = m_File.OpenWrite(filename);
396 if ( ASDCP_SUCCESS(result) )
398 m_HeaderSize = HeaderSize;
399 m_EssenceDescriptor = new RGBAEssenceDescriptor;
400 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
401 m_HeaderPart.AddChildObject(m_EssenceSubDescriptor);
402 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
403 result = m_State.Goto_INIT();
409 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
411 ASDCP::JP2K::MXFWriter::h__Writer::SetSourceStream(const PictureDescriptor& PDesc)
413 if ( ! m_State.Test_INIT() )
417 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
419 if ( ASDCP_SUCCESS(result) )
420 result = WriteMXFHeader(JP2K_PACKAGE_LABEL, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
421 PICT_DEF_LABEL, UL(Dict::ul(MDD_PictureDataDef)),
422 m_PDesc.EditRate, 24 /* TCFrameRate */);
424 if ( ASDCP_SUCCESS(result) )
426 memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
427 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
428 result = m_State.Goto_READY();
434 // Writes a frame of essence to the MXF file. If the optional AESEncContext
435 // argument is present, the essence is encrypted prior to writing.
436 // Fails if the file is not open, is finalized, or an operating system
440 ASDCP::JP2K::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
443 Result_t result = RESULT_OK;
445 if ( m_State.Test_READY() )
446 result = m_State.Goto_RUNNING(); // first time through
448 IndexTableSegment::IndexEntry Entry;
449 Entry.StreamOffset = m_StreamOffset;
451 if ( ASDCP_SUCCESS(result) )
452 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
454 if ( ASDCP_SUCCESS(result) )
456 m_FooterPart.PushIndexEntry(Entry);
464 // Closes the MXF file, writing the index and other closing information.
467 ASDCP::JP2K::MXFWriter::h__Writer::Finalize()
469 if ( ! m_State.Test_RUNNING() )
472 m_State.Goto_FINAL();
474 return WriteMXFFooter();
478 //------------------------------------------------------------------------------------------
482 ASDCP::JP2K::MXFWriter::MXFWriter()
486 ASDCP::JP2K::MXFWriter::~MXFWriter()
491 // Open the file for writing. The file must not exist. Returns error if
492 // the operation cannot be completed.
494 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
495 const PictureDescriptor& PDesc, ui32_t HeaderSize)
497 m_Writer = new h__Writer;
499 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
501 if ( ASDCP_SUCCESS(result) )
503 m_Writer->m_Info = Info;
504 result = m_Writer->SetSourceStream(PDesc);
507 if ( ASDCP_FAILURE(result) )
514 // Writes a frame of essence to the MXF file. If the optional AESEncContext
515 // argument is present, the essence is encrypted prior to writing.
516 // Fails if the file is not open, is finalized, or an operating system
519 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
521 if ( m_Writer.empty() )
524 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
527 // Closes the MXF file, writing the index and other closing information.
529 ASDCP::JP2K::MXFWriter::Finalize()
531 if ( m_Writer.empty() )
534 return m_Writer->Finalize();
539 // end AS_DCP_JP2K.cpp