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 //------------------------------------------------------------------------------------------
38 const byte_t JP2KEssenceCompressionLabel[klv_key_size] =
40 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09,
41 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01 };
46 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
52 AspectRatio: %lu/%lu\n\
65 ContainerDuration: %lu\n",
66 PDesc.AspectRatio.Numerator ,PDesc.AspectRatio.Denominator,
67 PDesc.EditRate.Numerator ,PDesc.EditRate.Denominator,
79 PDesc.ContainerDuration
82 fprintf(stream, "Color Components:\n");
84 for ( ui32_t i = 0; i < PDesc.Csize; i++ )
86 fprintf(stream, " %lu.%lu.%lu\n",
87 PDesc.ImageComponents[i].Ssize,
88 PDesc.ImageComponents[i].XRsize,
89 PDesc.ImageComponents[i].YRsize
93 const ui32_t tmp_buf_len = 256;
94 char tmp_buf[tmp_buf_len];
96 if ( PDesc.CodingStyleLength )
97 fprintf(stream, "Default Coding (%lu): %s\n",
98 PDesc.CodingStyleLength,
99 bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength,
100 tmp_buf, tmp_buf_len)
103 if ( PDesc.QuantDefaultLength )
104 fprintf(stream, "Default Coding (%lu): %s\n",
105 PDesc.QuantDefaultLength,
106 bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength,
107 tmp_buf, tmp_buf_len)
111 //------------------------------------------------------------------------------------------
113 // hidden, internal implementation of JPEG 2000 reader
115 class ASDCP::JP2K::MXFReader::h__Reader : public ASDCP::h__Reader
117 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
120 PictureDescriptor m_PDesc; // codestream parameter list
123 Result_t OpenRead(const char*);
124 Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
125 Result_t ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
126 Result_t MD_to_JP2K_PDesc(MXF::RGBAEssenceDescriptor* PDescObj, JP2K::PictureDescriptor& PDesc);
131 ASDCP::JP2K::MXFReader::h__Reader::MD_to_JP2K_PDesc(MXF::RGBAEssenceDescriptor* PDescObj, JP2K::PictureDescriptor& PDesc)
133 ASDCP_TEST_NULL(PDescObj);
134 memset(&PDesc, 0, sizeof(PDesc));
136 PDesc.EditRate = PDescObj->SampleRate;
137 PDesc.ContainerDuration = PDescObj->ContainerDuration;
138 PDesc.StoredWidth = PDescObj->StoredWidth;
139 PDesc.StoredHeight = PDescObj->StoredHeight;
140 PDesc.AspectRatio = PDescObj->AspectRatio;
142 InterchangeObject* MDObject;
143 if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &MDObject)) )
147 DefaultLogSink().Error("Unable to locate JPEG2000PictureSubDescriptor");
151 JPEG2000PictureSubDescriptor* PSubDescObj = (JPEG2000PictureSubDescriptor*)MDObject;
153 PDesc.Rsize = PSubDescObj->Rsize;
154 PDesc.Xsize = PSubDescObj->Xsize;
155 PDesc.Ysize = PSubDescObj->Ysize;
156 PDesc.XOsize = PSubDescObj->XOsize;
157 PDesc.YOsize = PSubDescObj->YOsize;
158 PDesc.XTsize = PSubDescObj->XTsize;
159 PDesc.YTsize = PSubDescObj->YTsize;
160 PDesc.XTOsize = PSubDescObj->XTOsize;
161 PDesc.YTOsize = PSubDescObj->YTOsize;
162 PDesc.Csize = PSubDescObj->Csize;
166 // PictureComponentSizing
168 if ( DC3.Size == 17 ) // ( 2* sizeof(ui32_t) ) + 3 components * 3 byte each
170 memcpy(&PDesc.ImageComponents, DC3.Data + 8, DC3.Size - 8);
174 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %lu, should be 17\n", DC3.Size);
178 // CodingStyleDefault
179 // PDesc.CodingStyleLength = DC1.Size;
180 // memcpy(PDesc.CodingStyle, DC1.Data, DC1.Size);
182 // QuantizationDefault
183 // PDesc.QuantDefaultLength = DC2.Size;
184 // memcpy(PDesc.QuantDefault, DC2.Data, DC2.Size);
192 ASDCP::JP2K::MXFReader::h__Reader::OpenRead(const char* filename)
194 Result_t result = OpenMXFRead(filename);
196 if( ASDCP_SUCCESS(result) )
198 InterchangeObject* Object;
199 if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &Object)) )
202 result = MD_to_JP2K_PDesc((MXF::RGBAEssenceDescriptor*)Object, m_PDesc);
206 if( ASDCP_SUCCESS(result) )
207 result = InitMXFIndex();
209 if( ASDCP_SUCCESS(result) )
210 result = InitInfo(m_Info);
218 ASDCP::JP2K::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
219 AESDecContext* Ctx, HMACContext* HMAC)
221 if ( ! m_File.IsOpen() )
224 return ReadEKLVPacket(FrameNum, FrameBuf, JP2KEssenceUL_Data, Ctx, HMAC);
227 //------------------------------------------------------------------------------------------
232 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
237 fprintf(stream, "Frame: %06lu, %7lu bytes", m_FrameNumber, m_Size);
242 hexdump(m_Data, dump_len, stream);
246 //------------------------------------------------------------------------------------------
248 ASDCP::JP2K::MXFReader::MXFReader()
250 m_Reader = new h__Reader;
254 ASDCP::JP2K::MXFReader::~MXFReader()
258 // Open the file for reading. The file must exist. Returns error if the
259 // operation cannot be completed.
261 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
263 return m_Reader->OpenRead(filename);
268 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
269 AESDecContext* Ctx, HMACContext* HMAC) const
271 if ( m_Reader && m_Reader->m_File.IsOpen() )
272 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
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::FillPictureDescriptor(PictureDescriptor& PDesc) const
283 if ( m_Reader && m_Reader->m_File.IsOpen() )
285 PDesc = m_Reader->m_PDesc;
293 // Fill the struct with the values from the file's header.
294 // Returns RESULT_INIT if the file is not open.
296 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
298 if ( m_Reader && m_Reader->m_File.IsOpen() )
300 Info = m_Reader->m_Info;
309 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
311 if ( m_Reader->m_File.IsOpen() )
312 m_Reader->m_HeaderPart.Dump(stream);
318 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
320 if ( m_Reader->m_File.IsOpen() )
321 m_Reader->m_FooterPart.Dump(stream);
325 //------------------------------------------------------------------------------------------
330 class ASDCP::JP2K::MXFWriter::h__Writer : public ASDCP::h__Writer
333 PictureDescriptor m_PDesc;
336 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
338 h__Writer() : m_GOPOffset(0) {}
341 Result_t OpenWrite(const char*, ui32_t HeaderSize);
342 Result_t SetSourceStream(const PictureDescriptor&);
343 Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
345 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc, MXF::RGBAEssenceDescriptor* PDescObj);
351 ASDCP::JP2K::MXFWriter::h__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc, MXF::RGBAEssenceDescriptor* PDescObj)
354 PDescObj->SampleRate = PDesc.EditRate;
355 PDescObj->ContainerDuration = PDesc.ContainerDuration;
356 PDescObj->StoredWidth = PDesc.StoredWidth;
357 PDescObj->StoredHeight = PDesc.StoredHeight;
358 PDescObj->AspectRatio = PDesc.AspectRatio;
359 PDescObj->FrameLayout = 0;
361 InterchangeObject* MDObject;
362 if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &MDObject)) )
365 JPEG2000PictureSubDescriptor* PSubDescObj = (JPEG2000PictureSubDescriptor*)MDObject;
367 PSubDescObj->Rsize = PDesc.Rsize;
368 PSubDescObj->Xsize = PDesc.Xsize;
369 PSubDescObj->Ysize = PDesc.Ysize;
370 PSubDescObj->XOsize = PDesc.XOsize;
371 PSubDescObj->YOsize = PDesc.YOsize;
372 PSubDescObj->XTsize = PDesc.XTsize;
373 PSubDescObj->YTsize = PDesc.YTsize;
374 PSubDescObj->XTOsize = PDesc.XTOsize;
375 PSubDescObj->YTOsize = PDesc.YTOsize;
376 PSubDescObj->Csize = PDesc.Csize;
379 const ui32_t tmp_buffer_len = 64;
380 byte_t tmp_buffer[tmp_buffer_len];
382 *(ui32_t*)tmp_buffer = ASDCP_i32_BE(3L); // three components
383 *(ui32_t*)(tmp_buffer+4) = ASDCP_i32_BE(3L);
384 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
386 PSubDescObj->SetValue("PictureComponentSizing", DataChunk(17, tmp_buffer));
387 PSubDescObj->SetValue("CodingStyleDefault", DataChunk(PDesc.CodingStyleLength, PDesc.CodingStyle));
388 PSubDescObj->SetValue("QuantizationDefault", DataChunk(PDesc.QuantDefaultLength, PDesc.QuantDefault));
395 // Open the file for writing. The file must not exist. Returns error if
396 // the operation cannot be completed.
398 ASDCP::JP2K::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
400 if ( ! m_State.Test_BEGIN() )
403 Result_t result = m_File.OpenWrite(filename);
405 if ( ASDCP_SUCCESS(result) )
407 RGBAEssenceDescriptor* rgbDesc = new RGBAEssenceDescriptor;
409 JPEG2000PictureSubDescriptor* jp2kSubDesc = new JPEG2000PictureSubDescriptor;
410 m_HeaderPart.AddChildObject(jp2kSubDesc);
411 rgbDesc->SubDescriptors.push_back(jp2kSubDesc->InstanceUID);
413 m_EssenceDescriptor = rgbDesc;
414 result = m_State.Goto_INIT();
420 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
422 ASDCP::JP2K::MXFWriter::h__Writer::SetSourceStream(const PictureDescriptor& PDesc)
424 if ( ! m_State.Test_INIT() )
428 Result_t result = JP2K_PDesc_to_MD(m_PDesc, (RGBAEssenceDescriptor*)m_EssenceDescriptor);
430 if ( ASDCP_SUCCESS(result) )
431 result = WriteMXFHeader(JP2K_PACKAGE_LABEL,
432 UL(WrappingUL_Data_JPEG_2000),
433 m_PDesc.EditRate, 24 /* TCFrameRate */);
435 if ( ASDCP_SUCCESS(result) )
436 result = m_State.Goto_READY();
441 // Writes a frame of essence to the MXF file. If the optional AESEncContext
442 // argument is present, the essence is encrypted prior to writing.
443 // Fails if the file is not open, is finalized, or an operating system
447 ASDCP::JP2K::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
450 Result_t result = RESULT_OK;
452 if ( m_State.Test_READY() )
453 result = m_State.Goto_RUNNING(); // first time through
455 fpos_t ThisOffset = m_StreamOffset;
457 if ( ASDCP_SUCCESS(result) )
458 result = WriteEKLVPacket(FrameBuf, JP2KEssenceUL_Data, Ctx, HMAC);
460 if ( ASDCP_SUCCESS(result) )
462 IndexTableSegment::IndexEntry Entry;
463 Entry.StreamOffset = ThisOffset - m_FooterPart.m_ECOffset;
464 m_FooterPart.PushIndexEntry(Entry);
472 // Closes the MXF file, writing the index and other closing information.
475 ASDCP::JP2K::MXFWriter::h__Writer::Finalize()
477 if ( ! m_State.Test_RUNNING() )
480 m_State.Goto_FINAL();
482 return WriteMXFFooter();
486 //------------------------------------------------------------------------------------------
490 ASDCP::JP2K::MXFWriter::MXFWriter()
494 ASDCP::JP2K::MXFWriter::~MXFWriter()
499 // Open the file for writing. The file must not exist. Returns error if
500 // the operation cannot be completed.
502 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
503 const PictureDescriptor& PDesc, ui32_t HeaderSize)
505 m_Writer = new h__Writer;
507 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
509 if ( ASDCP_SUCCESS(result) )
511 m_Writer->m_Info = Info;
512 result = m_Writer->SetSourceStream(PDesc);
515 if ( ASDCP_FAILURE(result) )
522 // Writes a frame of essence to the MXF file. If the optional AESEncContext
523 // argument is present, the essence is encrypted prior to writing.
524 // Fails if the file is not open, is finalized, or an operating system
527 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
529 if ( m_Writer.empty() )
532 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
535 // Closes the MXF file, writing the index and other closing information.
537 ASDCP::JP2K::MXFWriter::Finalize()
539 if ( m_Writer.empty() )
542 return m_Writer->Finalize();
547 // end AS_DCP_JP2K.cpp