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)
48 AspectRatio: %lu/%lu\n\
61 ContainerDuration: %lu\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, " %lu.%lu.%lu\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 (%lu): %s\n",
94 PDesc.CodingStyleLength,
95 bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength,
99 if ( PDesc.QuantDefaultLength )
100 fprintf(stream, "Quantization Default (%lu): %s\n",
101 PDesc.QuantDefaultLength,
102 bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength,
103 tmp_buf, tmp_buf_len)
107 //------------------------------------------------------------------------------------------
109 // hidden, internal implementation of JPEG 2000 reader
111 class ASDCP::JP2K::MXFReader::h__Reader : public ASDCP::h__Reader
113 RGBAEssenceDescriptor* m_EssenceDescriptor;
114 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
116 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
119 PictureDescriptor m_PDesc; // codestream parameter list
121 h__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0) {}
122 Result_t OpenRead(const char*);
123 Result_t ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
124 Result_t ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
125 Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
130 ASDCP::JP2K::MXFReader::h__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
132 memset(&PDesc, 0, sizeof(PDesc));
133 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
135 PDesc.EditRate = PDescObj->SampleRate;
136 PDesc.ContainerDuration = PDescObj->ContainerDuration;
137 PDesc.StoredWidth = PDescObj->StoredWidth;
138 PDesc.StoredHeight = PDescObj->StoredHeight;
139 PDesc.AspectRatio = PDescObj->AspectRatio;
141 if ( m_EssenceSubDescriptor != 0 )
143 PDesc.Rsize = m_EssenceSubDescriptor->Rsize;
144 PDesc.Xsize = m_EssenceSubDescriptor->Xsize;
145 PDesc.Ysize = m_EssenceSubDescriptor->Ysize;
146 PDesc.XOsize = m_EssenceSubDescriptor->XOsize;
147 PDesc.YOsize = m_EssenceSubDescriptor->YOsize;
148 PDesc.XTsize = m_EssenceSubDescriptor->XTsize;
149 PDesc.YTsize = m_EssenceSubDescriptor->YTsize;
150 PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
151 PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
152 PDesc.Csize = m_EssenceSubDescriptor->Csize;
154 // PictureComponentSizing
155 ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Size();
157 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
158 memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
161 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %lu, should be 17\n", tmp_size);
163 // CodingStyleDefault
164 if ( ( PDesc.CodingStyleLength = m_EssenceSubDescriptor->CodingStyleDefault.Size() ) != 0 )
165 memcpy(PDesc.CodingStyle, m_EssenceSubDescriptor->CodingStyleDefault.RoData(), PDesc.CodingStyleLength);
167 // QuantizationDefault
168 if ( ( PDesc.QuantDefaultLength = m_EssenceSubDescriptor->QuantizationDefault.Size() ) != 0 )
169 memcpy(PDesc.QuantDefault, m_EssenceSubDescriptor->QuantizationDefault.RoData(), PDesc.QuantDefaultLength);
178 ASDCP::JP2K::MXFReader::h__Reader::OpenRead(const char* filename)
180 Result_t result = OpenMXFRead(filename);
182 if( ASDCP_SUCCESS(result) )
184 if ( m_EssenceDescriptor == 0 )
186 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), (InterchangeObject**)&m_EssenceDescriptor);
187 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), (InterchangeObject**)&m_EssenceSubDescriptor);
190 result = MD_to_JP2K_PDesc(m_PDesc);
193 if( ASDCP_SUCCESS(result) )
194 result = InitMXFIndex();
196 if( ASDCP_SUCCESS(result) )
197 result = InitInfo(m_Info);
205 ASDCP::JP2K::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
206 AESDecContext* Ctx, HMACContext* HMAC)
208 if ( ! m_File.IsOpen() )
211 return ReadEKLVPacket(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
214 //------------------------------------------------------------------------------------------
219 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
224 fprintf(stream, "Frame: %06lu, %7lu bytes", m_FrameNumber, m_Size);
229 hexdump(m_Data, dump_len, stream);
233 //------------------------------------------------------------------------------------------
235 ASDCP::JP2K::MXFReader::MXFReader()
237 m_Reader = new h__Reader;
241 ASDCP::JP2K::MXFReader::~MXFReader()
245 // Open the file for reading. The file must exist. Returns error if the
246 // operation cannot be completed.
248 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
250 return m_Reader->OpenRead(filename);
255 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
256 AESDecContext* Ctx, HMACContext* HMAC) const
258 if ( m_Reader && m_Reader->m_File.IsOpen() )
259 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
265 // Fill the struct with the values from the file's header.
266 // Returns RESULT_INIT if the file is not open.
268 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
270 if ( m_Reader && m_Reader->m_File.IsOpen() )
272 PDesc = m_Reader->m_PDesc;
280 // Fill the struct with the values from the file's header.
281 // Returns RESULT_INIT if the file is not open.
283 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
285 if ( m_Reader && m_Reader->m_File.IsOpen() )
287 Info = m_Reader->m_Info;
296 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
298 if ( m_Reader->m_File.IsOpen() )
299 m_Reader->m_HeaderPart.Dump(stream);
305 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
307 if ( m_Reader->m_File.IsOpen() )
308 m_Reader->m_FooterPart.Dump(stream);
312 //------------------------------------------------------------------------------------------
317 class ASDCP::JP2K::MXFWriter::h__Writer : public ASDCP::h__Writer
319 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
322 PictureDescriptor m_PDesc;
324 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
326 h__Writer() : m_EssenceSubDescriptor(0) {}
329 Result_t OpenWrite(const char*, ui32_t HeaderSize);
330 Result_t SetSourceStream(const PictureDescriptor&);
331 Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
333 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
339 ASDCP::JP2K::MXFWriter::h__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
341 assert(m_EssenceDescriptor);
342 assert(m_EssenceSubDescriptor);
343 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
345 PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression));
346 PDescObj->SampleRate = PDesc.EditRate;
347 PDescObj->ContainerDuration = PDesc.ContainerDuration;
348 PDescObj->StoredWidth = PDesc.StoredWidth;
349 PDescObj->StoredHeight = PDesc.StoredHeight;
350 PDescObj->AspectRatio = PDesc.AspectRatio;
351 PDescObj->FrameLayout = 0;
353 m_EssenceSubDescriptor->Rsize = PDesc.Rsize;
354 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
355 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
356 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
357 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
358 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
359 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
360 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
361 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
362 m_EssenceSubDescriptor->Csize = PDesc.Csize;
364 const ui32_t tmp_buffer_len = 64;
365 byte_t tmp_buffer[tmp_buffer_len];
367 *(ui32_t*)tmp_buffer = ASDCP_i32_BE(3L); // three components
368 *(ui32_t*)(tmp_buffer+4) = ASDCP_i32_BE(3L);
369 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
371 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, 17);
372 m_EssenceSubDescriptor->PictureComponentSizing.Size(17);
374 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), PDesc.CodingStyle, PDesc.CodingStyleLength);
375 m_EssenceSubDescriptor->CodingStyleDefault.Size(PDesc.CodingStyleLength);
377 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), PDesc.QuantDefault, PDesc.QuantDefaultLength);
378 m_EssenceSubDescriptor->QuantizationDefault.Size(PDesc.QuantDefaultLength);
384 // Open the file for writing. The file must not exist. Returns error if
385 // the operation cannot be completed.
387 ASDCP::JP2K::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
389 if ( ! m_State.Test_BEGIN() )
392 Result_t result = m_File.OpenWrite(filename);
394 if ( ASDCP_SUCCESS(result) )
396 m_HeaderSize = HeaderSize;
397 m_EssenceDescriptor = new RGBAEssenceDescriptor;
398 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
399 m_HeaderPart.AddChildObject(m_EssenceSubDescriptor);
400 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
401 result = m_State.Goto_INIT();
407 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
409 ASDCP::JP2K::MXFWriter::h__Writer::SetSourceStream(const PictureDescriptor& PDesc)
411 if ( ! m_State.Test_INIT() )
415 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
417 if ( ASDCP_SUCCESS(result) )
418 result = WriteMXFHeader(JP2K_PACKAGE_LABEL, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
419 PICT_DEF_LABEL, UL(Dict::ul(MDD_PictureDataDef)),
420 m_PDesc.EditRate, 24 /* TCFrameRate */);
422 if ( ASDCP_SUCCESS(result) )
423 result = m_State.Goto_READY();
428 // Writes a frame of essence to the MXF file. If the optional AESEncContext
429 // argument is present, the essence is encrypted prior to writing.
430 // Fails if the file is not open, is finalized, or an operating system
434 ASDCP::JP2K::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
437 Result_t result = RESULT_OK;
439 if ( m_State.Test_READY() )
440 result = m_State.Goto_RUNNING(); // first time through
442 IndexTableSegment::IndexEntry Entry;
443 Entry.StreamOffset = m_StreamOffset;
445 if ( ASDCP_SUCCESS(result) )
446 result = WriteEKLVPacket(FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
448 if ( ASDCP_SUCCESS(result) )
450 m_FooterPart.PushIndexEntry(Entry);
458 // Closes the MXF file, writing the index and other closing information.
461 ASDCP::JP2K::MXFWriter::h__Writer::Finalize()
463 if ( ! m_State.Test_RUNNING() )
466 m_State.Goto_FINAL();
468 return WriteMXFFooter();
472 //------------------------------------------------------------------------------------------
476 ASDCP::JP2K::MXFWriter::MXFWriter()
480 ASDCP::JP2K::MXFWriter::~MXFWriter()
485 // Open the file for writing. The file must not exist. Returns error if
486 // the operation cannot be completed.
488 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
489 const PictureDescriptor& PDesc, ui32_t HeaderSize)
491 m_Writer = new h__Writer;
493 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
495 if ( ASDCP_SUCCESS(result) )
497 m_Writer->m_Info = Info;
498 result = m_Writer->SetSourceStream(PDesc);
501 if ( ASDCP_FAILURE(result) )
508 // Writes a frame of essence to the MXF file. If the optional AESEncContext
509 // argument is present, the essence is encrypted prior to writing.
510 // Fails if the file is not open, is finalized, or an operating system
513 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
515 if ( m_Writer.empty() )
518 return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
521 // Closes the MXF file, writing the index and other closing information.
523 ASDCP::JP2K::MXFWriter::Finalize()
525 if ( m_Writer.empty() )
528 return m_Writer->Finalize();
533 // end AS_DCP_JP2K.cpp