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"
37 //------------------------------------------------------------------------------------------
40 const byte_t JP2KEssenceCompressionLabel[klv_key_size] =
42 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x09,
43 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x01, 0x01 };
47 ASDCP::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc, MDObject& PDescObj)
51 PDescObj.SetValue("Codec", DataChunk(klv_key_size, JP2KEssenceCompressionLabel));
53 sprintf(text_buf, "%ld/%ld", PDesc.EditRate.Numerator, PDesc.EditRate.Denominator);
54 PDescObj.SetString("SampleRate", text_buf);
56 sprintf(text_buf, "%ld/%ld", PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator);
57 PDescObj.SetString("AspectRatio", text_buf);
59 PDescObj.SetUint("FrameLayout", 0);
60 PDescObj.SetUint("StoredWidth", PDesc.StoredWidth);
61 PDescObj.SetUint("StoredHeight", PDesc.StoredHeight);
62 PDescObj.SetUint("ContainerDuration", PDesc.ContainerDuration);
64 MDObject* PSubDescObj = GetMDObjectByType(PDescObj, "JPEG2000PictureSubDescriptor");
66 if ( PSubDescObj == 0 )
68 DefaultLogSink().Error("Unable to locate JPEG2000PictureSubDescriptor");
72 PSubDescObj->SetUint("Rsize", PDesc.Rsize);
73 PSubDescObj->SetUint("Xsize", PDesc.Xsize);
74 PSubDescObj->SetUint("Ysize", PDesc.Ysize);
75 PSubDescObj->SetUint("XOsize", PDesc.XOsize);
76 PSubDescObj->SetUint("YOsize", PDesc.YOsize);
77 PSubDescObj->SetUint("XTsize", PDesc.XTsize);
78 PSubDescObj->SetUint("YTsize", PDesc.YTsize);
79 PSubDescObj->SetUint("XTOsize", PDesc.XTOsize);
80 PSubDescObj->SetUint("YTOsize", PDesc.YTOsize);
81 PSubDescObj->SetUint("Csize", PDesc.Csize);
83 const ui32_t tmp_buffer_len = 64;
84 byte_t tmp_buffer[tmp_buffer_len];
86 *(ui32_t*)tmp_buffer = ASDCP_i32_BE(3L); // three components
87 *(ui32_t*)(tmp_buffer+4) = ASDCP_i32_BE(3L);
88 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
90 PSubDescObj->SetValue("PictureComponentSizing", DataChunk(17, tmp_buffer));
91 PSubDescObj->SetValue("CodingStyleDefault", DataChunk(PDesc.CodingStyleLength, PDesc.CodingStyle));
92 PSubDescObj->SetValue("QuantizationDefault", DataChunk(PDesc.QuantDefaultLength, PDesc.QuantDefault));
100 ASDCP::MD_to_JP2K_PDesc(MXF::RGBAEssenceDescriptor* PDescObj, JP2K::PictureDescriptor& PDesc)
102 ASDCP_TEST_NULL(PDescObj);
103 PDesc.CodingStyleLength = PDesc.QuantDefaultLength = 0;
106 PDesc.StoredWidth = PDescObj.GetUint("StoredWidth");
107 PDesc.StoredHeight = PDescObj.GetUint("StoredHeight");
108 PDesc.ContainerDuration = PDescObj.GetUint("ContainerDuration");
111 MDObject* Ptr = PDescObj["SampleRate"]; // should be EditRate
115 PDesc.EditRate.Numerator = Ptr->GetInt("Numerator");
116 PDesc.EditRate.Denominator = Ptr->GetInt("Denominator");
120 Ptr = PDescObj["AspectRatio"];
124 PDesc.AspectRatio.Numerator = Ptr->GetInt("Numerator");
125 PDesc.AspectRatio.Denominator = Ptr->GetInt("Denominator");
128 MDObject* PSubDescObj = GetMDObjectByType(PDescObj, "JPEG2000PictureSubDescriptor");
130 if ( PSubDescObj == 0 )
132 DefaultLogSink().Error("Unable to locate JPEG2000PictureSubDescriptor");
136 PDesc.Rsize = PSubDescObj->GetUint("Rsize");
137 PDesc.Xsize = PSubDescObj->GetUint("Xsize");
138 PDesc.Ysize = PSubDescObj->GetUint("Ysize");
139 PDesc.XOsize = PSubDescObj->GetUint("XOsize");
140 PDesc.YOsize = PSubDescObj->GetUint("YOsize");
141 PDesc.XTsize = PSubDescObj->GetUint("XTsize");
142 PDesc.YTsize = PSubDescObj->GetUint("YTsize");
143 PDesc.XTOsize = PSubDescObj->GetUint("XTOsize");
144 PDesc.YTOsize = PSubDescObj->GetUint("YTOsize");
145 PDesc.Csize = PSubDescObj->GetUint("Csize");
148 Ptr = (*PSubDescObj)["PictureComponentSizing"];
152 DataChunk DC3 = Ptr->GetData();
154 if ( DC3.Size == 17 ) // ( 2* sizeof(ui32_t) ) + 3 components * 3 byte each
156 memcpy(&PDesc.ImageComponents, DC3.Data + 8, DC3.Size - 8);
160 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %lu, should be 17\n", DC3.Size);
165 Ptr = (*PSubDescObj)["CodingStyleDefault"];
169 DataChunk DC1 = Ptr->GetData();
170 PDesc.CodingStyleLength = DC1.Size;
171 memcpy(PDesc.CodingStyle, DC1.Data, DC1.Size);
175 Ptr = (*PSubDescObj)["QuantizationDefault"];
179 DataChunk DC2 = Ptr->GetData();
180 PDesc.QuantDefaultLength = DC2.Size;
181 memcpy(PDesc.QuantDefault, DC2.Data, DC2.Size);
189 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
195 AspectRatio: %lu/%lu\n\
208 ContainerDuration: %lu\n",
209 PDesc.AspectRatio.Numerator ,PDesc.AspectRatio.Denominator,
210 PDesc.EditRate.Numerator ,PDesc.EditRate.Denominator,
222 PDesc.ContainerDuration
225 fprintf(stream, "Color Components:\n");
227 for ( ui32_t i = 0; i < PDesc.Csize; i++ )
229 fprintf(stream, " %lu.%lu.%lu\n",
230 PDesc.ImageComponents[i].Ssize,
231 PDesc.ImageComponents[i].XRsize,
232 PDesc.ImageComponents[i].YRsize
236 const ui32_t tmp_buf_len = 256;
237 char tmp_buf[tmp_buf_len];
239 if ( PDesc.CodingStyleLength )
240 fprintf(stream, "Default Coding (%lu): %s\n",
241 PDesc.CodingStyleLength,
242 bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength,
243 tmp_buf, tmp_buf_len)
246 if ( PDesc.QuantDefaultLength )
247 fprintf(stream, "Default Coding (%lu): %s\n",
248 PDesc.QuantDefaultLength,
249 bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength,
250 tmp_buf, tmp_buf_len)
254 //------------------------------------------------------------------------------------------
256 // hidden, internal implementation of JPEG 2000 reader
258 class ASDCP::JP2K::MXFReader::h__Reader : public ASDCP::h__Reader
260 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
263 PictureDescriptor m_PDesc; // codestream parameter list
266 Result_t OpenRead(const char*);
267 Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
268 Result_t ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
275 ASDCP::JP2K::MXFReader::h__Reader::OpenRead(const char* filename)
277 Result_t result = OpenMXFRead(filename);
279 if( ASDCP_SUCCESS(result) )
281 InterchangeObject* Object;
282 if ( ASDCP_SUCCESS(m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &Object)) )
285 result = MD_to_JP2K_PDesc((MXF::RGBAEssenceDescriptor*)Object, m_PDesc);
289 if( ASDCP_SUCCESS(result) )
290 result = InitMXFIndex();
292 if( ASDCP_SUCCESS(result) )
293 result = InitInfo(m_Info);
301 ASDCP::JP2K::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
302 AESDecContext* Ctx, HMACContext* HMAC)
304 if ( ! m_File.IsOpen() )
307 return ReadEKLVPacket(FrameNum, FrameBuf, JP2KEssenceUL_Data, Ctx, HMAC);
310 //------------------------------------------------------------------------------------------
315 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
320 fprintf(stream, "Frame: %06lu, %7lu bytes", m_FrameNumber, m_Size);
325 hexdump(m_Data, dump_len, stream);
329 //------------------------------------------------------------------------------------------
331 ASDCP::JP2K::MXFReader::MXFReader()
333 m_Reader = new h__Reader;
337 ASDCP::JP2K::MXFReader::~MXFReader()
341 // Open the file for reading. The file must exist. Returns error if the
342 // operation cannot be completed.
344 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
346 return m_Reader->OpenRead(filename);
351 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
352 AESDecContext* Ctx, HMACContext* HMAC) const
354 if ( m_Reader && m_Reader->m_File.IsOpen() )
355 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
361 // Fill the struct with the values from the file's header.
362 // Returns RESULT_INIT if the file is not open.
364 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
366 if ( m_Reader && m_Reader->m_File.IsOpen() )
368 PDesc = m_Reader->m_PDesc;
376 // Fill the struct with the values from the file's header.
377 // Returns RESULT_INIT if the file is not open.
379 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
381 if ( m_Reader && m_Reader->m_File.IsOpen() )
383 Info = m_Reader->m_Info;
392 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
394 if ( m_Reader->m_File.IsOpen() )
395 m_Reader->m_HeaderPart.Dump(stream);
401 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
403 if ( m_Reader->m_File.IsOpen() )
404 m_Reader->m_FooterPart.Dump(stream);
408 //------------------------------------------------------------------------------------------
413 class ASDCP::JP2K::MXFWriter::h__Writer : public ASDCP::h__Writer
416 PictureDescriptor m_PDesc;
419 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
421 h__Writer() : m_GOPOffset(0) {}
424 Result_t OpenWrite(const char*, ui32_t HeaderSize);
425 Result_t SetSourceStream(const PictureDescriptor&);
426 Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
431 // Open the file for writing. The file must not exist. Returns error if
432 // the operation cannot be completed.
434 ASDCP::JP2K::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
436 if ( ! m_State.Test_BEGIN() )
439 m_File = new MXFFile;
441 Result_t result = m_File.OpenWrite(filename);
443 if ( ASDCP_SUCCESS(result) )
445 m_EssenceDescriptor = new MDObject("RGBAEssenceDescriptor");
446 MDObject* jp2kDesc = new MDObject("JPEG2000PictureSubDescriptor");
447 MDObject* md01 = m_EssenceDescriptor->AddChild("SubDescriptors");
451 DefaultLogSink().Error("Unable to locate JPEG2000PictureSubDescriptor, incomplete dictionary?\n");
455 MDObject* md02 = md01->AddChild("SubDescriptor");
457 md02->MakeLink(*jp2kDesc);
459 result = m_State.Goto_INIT();
465 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
467 ASDCP::JP2K::MXFWriter::h__Writer::SetSourceStream(const PictureDescriptor& PDesc)
469 if ( ! m_State.Test_INIT() )
473 Result_t result = JP2K_PDesc_to_MD(m_PDesc, *m_EssenceDescriptor);
475 if ( ASDCP_SUCCESS(result) )
476 result = WriteMXFHeader(ESS_JPEG_2000, m_PDesc.EditRate, 24 /* TCFrameRate */);
478 if ( ASDCP_SUCCESS(result) )
479 result = m_State.Goto_READY();
484 // Writes a frame of essence to the MXF file. If the optional AESEncContext
485 // argument is present, the essence is encrypted prior to writing.
486 // Fails if the file is not open, is finalized, or an operating system
490 ASDCP::JP2K::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
493 Result_t result = RESULT_OK;
495 if ( m_State.Test_READY() )
496 result = m_State.Goto_RUNNING(); // first time through
498 ui64_t ThisOffset = m_StreamOffset;
500 if ( ASDCP_SUCCESS(result) )
501 result = WriteEKLVPacket(FrameBuf, JP2KEssenceUL_Data, Ctx, HMAC);
503 if ( ASDCP_SUCCESS(result) )
505 m_IndexMan->OfferEditUnit(0, m_FramesWritten, 0, 1);
506 m_IndexMan->OfferOffset(0, m_FramesWritten, ThisOffset);
514 // Closes the MXF file, writing the index and other closing information.
517 ASDCP::JP2K::MXFWriter::h__Writer::Finalize()
519 if ( ! m_State.Test_RUNNING() )
525 m_State.Goto_FINAL();
527 return WriteMXFFooter(ESS_JPEG_2000);
531 //------------------------------------------------------------------------------------------
535 ASDCP::JP2K::MXFWriter::MXFWriter()
539 ASDCP::JP2K::MXFWriter::~MXFWriter()
544 // Open the file for writing. The file must not exist. Returns error if
545 // the operation cannot be completed.
547 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
548 const PictureDescriptor& PDesc, ui32_t HeaderSize)
550 m_Writer = new h__Writer;
552 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
554 if ( ASDCP_SUCCESS(result) )
556 m_Writer->m_Info = Info;
557 result = m_Writer->SetSourceStream(PDesc);
560 if ( ASDCP_FAILURE(result) )
567 // Writes a frame of essence to the MXF file. If the optional AESEncContext
568 // argument is present, the essence is encrypted prior to writing.
569 // Fails if the file is not open, is finalized, or an operating system
572 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
574 if ( m_Writer.empty() )
577 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
580 // Closes the MXF file, writing the index and other closing information.
582 ASDCP::JP2K::MXFWriter::Finalize()
584 if ( m_Writer.empty() )
587 return m_Writer->Finalize();
593 // end AS_DCP_JP2K.cpp