2 Copyright (c) 2004-2007, 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 429-4 frame wrapping of JPEG 2000 codestreams";
38 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
39 static std::string PICT_DEF_LABEL = "Picture Track";
43 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
62 ContainerDuration: %u\n",
63 PDesc.AspectRatio.Numerator ,PDesc.AspectRatio.Denominator,
64 PDesc.EditRate.Numerator ,PDesc.EditRate.Denominator,
76 PDesc.ContainerDuration
79 fprintf(stream, "Color Components:\n");
81 for ( ui32_t i = 0; i < PDesc.Csize; i++ )
83 fprintf(stream, " %u.%u.%u\n",
84 PDesc.ImageComponents[i].Ssize,
85 PDesc.ImageComponents[i].XRsize,
86 PDesc.ImageComponents[i].YRsize
90 const ui32_t tmp_buf_len = 256;
91 char tmp_buf[tmp_buf_len];
93 if ( PDesc.CodingStyleLength )
94 fprintf(stream, "Default Coding (%u): %s\n",
95 PDesc.CodingStyleLength,
96 Kumu::bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength, tmp_buf, tmp_buf_len)
99 if ( PDesc.QuantDefaultLength )
100 fprintf(stream, "Quantization Default (%u): %s\n",
101 PDesc.QuantDefaultLength,
102 Kumu::bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength, tmp_buf, tmp_buf_len)
106 //------------------------------------------------------------------------------------------
108 // hidden, internal implementation of JPEG 2000 reader
110 class ASDCP::JP2K::MXFReader::h__Reader : public ASDCP::h__Reader
112 RGBAEssenceDescriptor* m_EssenceDescriptor;
113 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
115 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
118 PictureDescriptor m_PDesc; // codestream parameter list
120 h__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0) {}
121 Result_t OpenRead(const char*);
122 Result_t ReadFrame(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 ReadEKLVFrame(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 //------------------------------------------------------------------------------------------
313 using namespace ASDCP::JP2K;
316 class lh__Writer : public ASDCP::h__Writer
318 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
321 PictureDescriptor m_PDesc;
322 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
324 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
326 lh__Writer() : m_EssenceSubDescriptor(0) {
327 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
332 Result_t OpenWrite(const char*, ui32_t HeaderSize);
333 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
334 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
335 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
337 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
343 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
345 assert(m_EssenceDescriptor);
346 assert(m_EssenceSubDescriptor);
347 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
349 PDescObj->SampleRate = PDesc.EditRate;
350 PDescObj->ContainerDuration = PDesc.ContainerDuration;
351 PDescObj->StoredWidth = PDesc.StoredWidth;
352 PDescObj->StoredHeight = PDesc.StoredHeight;
353 PDescObj->AspectRatio = PDesc.AspectRatio;
354 PDescObj->FrameLayout = 0;
356 if ( PDesc.StoredWidth < 2049 )
358 PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression_2K));
359 m_EssenceSubDescriptor->Rsize = 3;
363 PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression_4K));
364 m_EssenceSubDescriptor->Rsize = 4;
367 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
368 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
369 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
370 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
371 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
372 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
373 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
374 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
375 m_EssenceSubDescriptor->Csize = PDesc.Csize;
377 const ui32_t tmp_buffer_len = 64;
378 byte_t tmp_buffer[tmp_buffer_len];
380 *(ui32_t*)tmp_buffer = KM_i32_BE(3L); // three components
381 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(3L);
382 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
384 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, 17);
385 m_EssenceSubDescriptor->PictureComponentSizing.Length(17);
387 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), PDesc.CodingStyle, PDesc.CodingStyleLength);
388 m_EssenceSubDescriptor->CodingStyleDefault.Length(PDesc.CodingStyleLength);
390 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), PDesc.QuantDefault, PDesc.QuantDefaultLength);
391 m_EssenceSubDescriptor->QuantizationDefault.Length(PDesc.QuantDefaultLength);
397 // Open the file for writing. The file must not exist. Returns error if
398 // the operation cannot be completed.
400 lh__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
402 if ( ! m_State.Test_BEGIN() )
405 Result_t result = m_File.OpenWrite(filename);
407 if ( ASDCP_SUCCESS(result) )
409 m_HeaderSize = HeaderSize;
410 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor;
411 tmp_rgba->ComponentMaxRef = 4095;
412 tmp_rgba->ComponentMinRef = 0;
414 m_EssenceDescriptor = tmp_rgba;
415 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
416 m_EssenceSubDescriptorList.push_back((FileDescriptor*)m_EssenceSubDescriptor);
418 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
419 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
421 result = m_State.Goto_INIT();
427 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
429 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
431 if ( ! m_State.Test_INIT() )
434 if ( LocalEditRate == ASDCP::Rational(0,0) )
435 LocalEditRate = m_PDesc.EditRate;
438 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
440 if ( ASDCP_SUCCESS(result) )
441 result = WriteMXFHeader(label, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
442 PICT_DEF_LABEL, UL(Dict::ul(MDD_PictureDataDef)),
443 LocalEditRate, 24 /* TCFrameRate */);
445 if ( ASDCP_SUCCESS(result) )
447 memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
448 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
449 result = m_State.Goto_READY();
455 // Writes a frame of essence to the MXF file. If the optional AESEncContext
456 // argument is present, the essence is encrypted prior to writing.
457 // Fails if the file is not open, is finalized, or an operating system
461 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
462 AESEncContext* Ctx, HMACContext* HMAC)
464 Result_t result = RESULT_OK;
466 if ( m_State.Test_READY() )
467 result = m_State.Goto_RUNNING(); // first time through
469 ui64_t StreamOffset = m_StreamOffset;
471 if ( ASDCP_SUCCESS(result) )
472 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
474 if ( ASDCP_SUCCESS(result) && add_index )
476 IndexTableSegment::IndexEntry Entry;
477 Entry.StreamOffset = StreamOffset;
478 m_FooterPart.PushIndexEntry(Entry);
486 // Closes the MXF file, writing the index and other closing information.
489 lh__Writer::Finalize()
491 if ( ! m_State.Test_RUNNING() )
494 m_State.Goto_FINAL();
496 return WriteMXFFooter();
501 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
506 //------------------------------------------------------------------------------------------
510 ASDCP::JP2K::MXFWriter::MXFWriter()
514 ASDCP::JP2K::MXFWriter::~MXFWriter()
519 // Open the file for writing. The file must not exist. Returns error if
520 // the operation cannot be completed.
522 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
523 const PictureDescriptor& PDesc, ui32_t HeaderSize)
525 m_Writer = new h__Writer;
527 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
529 if ( ASDCP_SUCCESS(result) )
531 m_Writer->m_Info = Info;
532 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
535 if ( ASDCP_FAILURE(result) )
542 // Writes a frame of essence to the MXF file. If the optional AESEncContext
543 // argument is present, the essence is encrypted prior to writing.
544 // Fails if the file is not open, is finalized, or an operating system
547 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
549 if ( m_Writer.empty() )
552 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
555 // Closes the MXF file, writing the index and other closing information.
557 ASDCP::JP2K::MXFWriter::Finalize()
559 if ( m_Writer.empty() )
562 return m_Writer->Finalize();
566 //------------------------------------------------------------------------------------------
570 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
572 StereoscopicPhase_t m_NextPhase;
575 h__SWriter() : m_NextPhase(SP_LEFT) {}
578 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
579 AESEncContext* Ctx, HMACContext* HMAC)
581 if ( m_NextPhase != phase )
582 return RESULT_SPHASE;
584 if ( phase == SP_LEFT )
586 m_NextPhase = SP_RIGHT;
587 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
590 m_NextPhase = SP_LEFT;
591 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
597 if ( m_NextPhase != SP_LEFT )
598 return RESULT_SPHASE;
600 return lh__Writer::Finalize();
606 ASDCP::JP2K::MXFSWriter::MXFSWriter()
610 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
615 // Open the file for writing. The file must not exist. Returns error if
616 // the operation cannot be completed.
618 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
619 const PictureDescriptor& PDesc, ui32_t HeaderSize)
621 m_Writer = new h__SWriter;
623 if ( PDesc.EditRate != ASDCP::EditRate_24 )
625 DefaultLogSink().Error("Stereoscopic wrapping requires 24 fps input streams.\n");
626 return RESULT_FORMAT;
629 Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
631 if ( ASDCP_SUCCESS(result) )
633 m_Writer->m_Info = Info;
634 PictureDescriptor TmpPDesc = PDesc;
635 TmpPDesc.EditRate = ASDCP::EditRate_48;
637 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, ASDCP::EditRate_24);
640 if ( ASDCP_FAILURE(result) )
647 // Writes a frame of essence to the MXF file. If the optional AESEncContext
648 // argument is present, the essence is encrypted prior to writing.
649 // Fails if the file is not open, is finalized, or an operating system
652 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
653 AESEncContext* Ctx, HMACContext* HMAC)
655 if ( m_Writer.empty() )
658 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
661 // Closes the MXF file, writing the index and other closing information.
663 ASDCP::JP2K::MXFSWriter::Finalize()
665 if ( m_Writer.empty() )
668 return m_Writer->Finalize();
672 // end AS_DCP_JP2K.cpp