1 /* -*- c-basic-offset: 2; -*- */
4 Copyright (c) 2004-2012, John Hurst
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
10 1. Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15 3. The name of the author may not be used to endorse or promote products
16 derived from this software without specific prior written permission.
18 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /*! \file AS_DCP_JP2k.cpp
30 \version $Id: AS_DCP_JP2K.cpp,v 1.54 2012/02/07 18:54:24 jhurst Exp $
31 \brief AS-DCP library, JPEG 2000 essence reader and writer implementation
34 #include "AS_DCP_internal.h"
39 using namespace ASDCP::JP2K;
40 using Kumu::GenRandomValue;
42 //------------------------------------------------------------------------------------------
44 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
45 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
46 static std::string PICT_DEF_LABEL = "Picture Track";
48 int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
52 ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc)
54 strm << " AspectRatio: " << PDesc.AspectRatio.Numerator << "/" << PDesc.AspectRatio.Denominator << std::endl;
55 strm << " EditRate: " << PDesc.EditRate.Numerator << "/" << PDesc.EditRate.Denominator << std::endl;
56 strm << " SampleRate: " << PDesc.SampleRate.Numerator << "/" << PDesc.SampleRate.Denominator << std::endl;
57 strm << " StoredWidth: " << (unsigned) PDesc.StoredWidth << std::endl;
58 strm << " StoredHeight: " << (unsigned) PDesc.StoredHeight << std::endl;
59 strm << " Rsize: " << (unsigned) PDesc.Rsize << std::endl;
60 strm << " Xsize: " << (unsigned) PDesc.Xsize << std::endl;
61 strm << " Ysize: " << (unsigned) PDesc.Ysize << std::endl;
62 strm << " XOsize: " << (unsigned) PDesc.XOsize << std::endl;
63 strm << " YOsize: " << (unsigned) PDesc.YOsize << std::endl;
64 strm << " XTsize: " << (unsigned) PDesc.XTsize << std::endl;
65 strm << " YTsize: " << (unsigned) PDesc.YTsize << std::endl;
66 strm << " XTOsize: " << (unsigned) PDesc.XTOsize << std::endl;
67 strm << " YTOsize: " << (unsigned) PDesc.YTOsize << std::endl;
68 strm << " ContainerDuration: " << (unsigned) PDesc.ContainerDuration << std::endl;
70 strm << "-- JPEG 2000 Metadata --" << std::endl;
71 strm << " ImageComponents:" << std::endl;
72 strm << " bits h-sep v-sep" << std::endl;
75 for ( i = 0; i < PDesc.Csize; i++ )
77 strm << " " << std::setw(4) << PDesc.ImageComponents[i].Ssize + 1 /* See ISO 15444-1, Table A11, for the origin of '+1' */
78 << " " << std::setw(5) << PDesc.ImageComponents[i].XRsize
79 << " " << std::setw(5) << PDesc.ImageComponents[i].YRsize
83 strm << " Scod: " << (short) PDesc.CodingStyleDefault.Scod << std::endl;
84 strm << " ProgressionOrder: " << (short) PDesc.CodingStyleDefault.SGcod.ProgressionOrder << std::endl;
85 strm << " NumberOfLayers: " << (short) KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)) << std::endl;
86 strm << " MultiCompTransform: " << (short) PDesc.CodingStyleDefault.SGcod.MultiCompTransform << std::endl;
87 strm << "DecompositionLevels: " << (short) PDesc.CodingStyleDefault.SPcod.DecompositionLevels << std::endl;
88 strm << " CodeblockWidth: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockWidth << std::endl;
89 strm << " CodeblockHeight: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockHeight << std::endl;
90 strm << " CodeblockStyle: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockStyle << std::endl;
91 strm << " Transformation: " << (short) PDesc.CodingStyleDefault.SPcod.Transformation << std::endl;
94 ui32_t precinct_set_size = 0;
96 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
99 strm << " Precincts: " << (short) precinct_set_size << std::endl;
100 strm << "precinct dimensions:" << std::endl;
102 for ( i = 0; i < precinct_set_size; i++ )
103 strm << " " << i + 1 << ": " << s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f] << " x "
104 << s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] << std::endl;
106 strm << " Sqcd: " << (short) PDesc.QuantizationDefault.Sqcd << std::endl;
108 char tmp_buf[MaxDefaults*2];
109 strm << " SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2)
117 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
123 AspectRatio: %d/%d\n\
137 ContainerDuration: %u\n",
138 PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
139 PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
140 PDesc.SampleRate.Numerator, PDesc.SampleRate.Denominator,
152 PDesc.ContainerDuration
155 fprintf(stream, "-- JPEG 2000 Metadata --\n");
156 fprintf(stream, " ImageComponents:\n");
157 fprintf(stream, " bits h-sep v-sep\n");
160 for ( i = 0; i < PDesc.Csize; i++ )
162 fprintf(stream, " %4d %5d %5d\n",
163 PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
164 PDesc.ImageComponents[i].XRsize,
165 PDesc.ImageComponents[i].YRsize
169 fprintf(stream, " Scod: %hd\n", PDesc.CodingStyleDefault.Scod);
170 fprintf(stream, " ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
171 fprintf(stream, " NumberOfLayers: %hd\n",
172 KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
174 fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
175 fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
176 fprintf(stream, " CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
177 fprintf(stream, " CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
178 fprintf(stream, " CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
179 fprintf(stream, " Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
182 ui32_t precinct_set_size = 0;
184 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
187 fprintf(stream, " Precincts: %hd\n", precinct_set_size);
188 fprintf(stream, "precinct dimensions:\n");
190 for ( i = 0; i < precinct_set_size; i++ )
191 fprintf(stream, " %d: %d x %d\n", i + 1,
192 s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
193 s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
196 fprintf(stream, " Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd);
198 char tmp_buf[MaxDefaults*2];
199 fprintf(stream, " SPqcd: %s\n",
200 Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
201 tmp_buf, MaxDefaults*2)
206 //------------------------------------------------------------------------------------------
208 // hidden, internal implementation of JPEG 2000 reader
211 class lh__Reader : public ASDCP::h__Reader
213 RGBAEssenceDescriptor* m_EssenceDescriptor;
214 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
215 ASDCP::Rational m_EditRate;
216 ASDCP::Rational m_SampleRate;
217 EssenceType_t m_Format;
219 ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
222 PictureDescriptor m_PDesc; // codestream parameter list
224 lh__Reader(const Dictionary& d) :
225 ASDCP::h__Reader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
226 Result_t OpenRead(const char*, EssenceType_t);
227 Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
228 Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
233 lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
235 memset(&PDesc, 0, sizeof(PDesc));
236 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
238 PDesc.EditRate = m_EditRate;
239 PDesc.SampleRate = m_SampleRate;
240 assert(PDescObj->ContainerDuration <= 0xFFFFFFFFL);
241 PDesc.ContainerDuration = (ui32_t) PDescObj->ContainerDuration;
242 PDesc.StoredWidth = PDescObj->StoredWidth;
243 PDesc.StoredHeight = PDescObj->StoredHeight;
244 PDesc.AspectRatio = PDescObj->AspectRatio;
246 if ( m_EssenceSubDescriptor != 0 )
248 PDesc.Rsize = m_EssenceSubDescriptor->Rsize;
249 PDesc.Xsize = m_EssenceSubDescriptor->Xsize;
250 PDesc.Ysize = m_EssenceSubDescriptor->Ysize;
251 PDesc.XOsize = m_EssenceSubDescriptor->XOsize;
252 PDesc.YOsize = m_EssenceSubDescriptor->YOsize;
253 PDesc.XTsize = m_EssenceSubDescriptor->XTsize;
254 PDesc.YTsize = m_EssenceSubDescriptor->YTsize;
255 PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
256 PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
257 PDesc.Csize = m_EssenceSubDescriptor->Csize;
259 // PictureComponentSizing
260 ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
262 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
263 memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
266 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
268 // CodingStyleDefault
269 memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
270 memcpy(&PDesc.CodingStyleDefault,
271 m_EssenceSubDescriptor->CodingStyleDefault.RoData(),
272 m_EssenceSubDescriptor->CodingStyleDefault.Length());
274 // QuantizationDefault
275 memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
276 memcpy(&PDesc.QuantizationDefault,
277 m_EssenceSubDescriptor->QuantizationDefault.RoData(),
278 m_EssenceSubDescriptor->QuantizationDefault.Length());
280 PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1;
289 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
291 Result_t result = OpenMXFRead(filename);
293 if( ASDCP_SUCCESS(result) )
295 InterchangeObject* tmp_iobj = 0;
296 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
297 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
299 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
300 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
302 std::list<InterchangeObject*> ObjectList;
303 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
305 if ( ObjectList.empty() )
307 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
308 return RESULT_FORMAT;
311 m_EditRate = ((Track*)ObjectList.front())->EditRate;
312 m_SampleRate = m_EssenceDescriptor->SampleRate;
314 if ( type == ASDCP::ESS_JPEG_2000 )
316 if ( m_EditRate != m_SampleRate )
318 DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
319 m_EditRate.Quotient(), m_SampleRate.Quotient());
321 if ( (m_EditRate == EditRate_24 && m_SampleRate == EditRate_48) ||
322 (m_EditRate == EditRate_25 && m_SampleRate == EditRate_50) ||
323 (m_EditRate == EditRate_30 && m_SampleRate == EditRate_60) ||
324 (m_EditRate == EditRate_48 && m_SampleRate == EditRate_96) ||
325 (m_EditRate == EditRate_50 && m_SampleRate == EditRate_100) ||
326 (m_EditRate == EditRate_60 && m_SampleRate == EditRate_120) )
328 DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
329 return RESULT_SFORMAT;
332 return RESULT_FORMAT;
335 else if ( type == ASDCP::ESS_JPEG_2000_S )
337 if ( m_EditRate == EditRate_24 )
339 if ( m_SampleRate != EditRate_48 )
341 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
342 return RESULT_FORMAT;
345 else if ( m_EditRate == EditRate_25 )
347 if ( m_SampleRate != EditRate_50 )
349 DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
350 return RESULT_FORMAT;
353 else if ( m_EditRate == EditRate_30 )
355 if ( m_SampleRate != EditRate_60 )
357 DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
358 return RESULT_FORMAT;
361 else if ( m_EditRate == EditRate_48 )
363 if ( m_SampleRate != EditRate_96 )
365 DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
366 return RESULT_FORMAT;
369 else if ( m_EditRate == EditRate_50 )
371 if ( m_SampleRate != EditRate_100 )
373 DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
374 return RESULT_FORMAT;
377 else if ( m_EditRate == EditRate_60 )
379 if ( m_SampleRate != EditRate_120 )
381 DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
382 return RESULT_FORMAT;
387 DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
388 m_EditRate.Numerator, m_EditRate.Denominator);
389 return RESULT_FORMAT;
394 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
398 result = MD_to_JP2K_PDesc(m_PDesc);
401 if( ASDCP_SUCCESS(result) )
402 result = InitMXFIndex();
404 if( ASDCP_SUCCESS(result) )
413 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
414 AESDecContext* Ctx, HMACContext* HMAC)
416 if ( ! m_File.IsOpen() )
420 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
425 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
427 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
431 h__Reader(const Dictionary& d) : lh__Reader(d) {}
436 //------------------------------------------------------------------------------------------
441 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
446 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
451 Kumu::hexdump(m_Data, dump_len, stream);
455 //------------------------------------------------------------------------------------------
457 ASDCP::JP2K::MXFReader::MXFReader()
459 m_Reader = new h__Reader(DefaultCompositeDict());
463 ASDCP::JP2K::MXFReader::~MXFReader()
467 // Warning: direct manipulation of MXF structures can interfere
468 // with the normal operation of the wrapper. Caveat emptor!
470 ASDCP::MXF::OPAtomHeader&
471 ASDCP::JP2K::MXFReader::OPAtomHeader()
473 if ( m_Reader.empty() )
475 assert(g_OPAtomHeader);
476 return *g_OPAtomHeader;
479 return m_Reader->m_HeaderPart;
482 // Warning: direct manipulation of MXF structures can interfere
483 // with the normal operation of the wrapper. Caveat emptor!
485 ASDCP::MXF::OPAtomIndexFooter&
486 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
488 if ( m_Reader.empty() )
490 assert(g_OPAtomIndexFooter);
491 return *g_OPAtomIndexFooter;
494 return m_Reader->m_FooterPart;
497 // Open the file for reading. The file must exist. Returns error if the
498 // operation cannot be completed.
500 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
502 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
507 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
508 AESDecContext* Ctx, HMACContext* HMAC) const
510 if ( m_Reader && m_Reader->m_File.IsOpen() )
511 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
517 // Fill the struct with the values from the file's header.
518 // Returns RESULT_INIT if the file is not open.
520 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
522 if ( m_Reader && m_Reader->m_File.IsOpen() )
524 PDesc = m_Reader->m_PDesc;
532 // Fill the struct with the values from the file's header.
533 // Returns RESULT_INIT if the file is not open.
535 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
537 if ( m_Reader && m_Reader->m_File.IsOpen() )
539 Info = m_Reader->m_Info;
548 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
550 if ( m_Reader->m_File.IsOpen() )
551 m_Reader->m_HeaderPart.Dump(stream);
557 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
559 if ( m_Reader->m_File.IsOpen() )
560 m_Reader->m_FooterPart.Dump(stream);
565 ASDCP::JP2K::MXFReader::Close() const
567 if ( m_Reader && m_Reader->m_File.IsOpen() )
577 //------------------------------------------------------------------------------------------
580 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
582 ui32_t m_StereoFrameReady;
585 h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
588 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
589 AESDecContext* Ctx, HMACContext* HMAC)
591 // look up frame index node
592 IndexTableSegment::IndexEntry TmpEntry;
594 if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
596 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
600 // get frame position
601 Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
602 Result_t result = RESULT_OK;
604 if ( phase == SP_LEFT )
606 if ( FilePosition != m_LastPosition )
608 m_LastPosition = FilePosition;
609 result = m_File.Seek(FilePosition);
612 // the call to ReadEKLVPacket() will leave the file on an R frame
613 m_StereoFrameReady = FrameNum;
615 else if ( phase == SP_RIGHT )
617 if ( m_StereoFrameReady != FrameNum )
619 // the file is not already positioned, we must do some work
620 // seek to the companion SP_LEFT frame and read the frame's key and length
621 if ( FilePosition != m_LastPosition )
623 m_LastPosition = FilePosition;
624 result = m_File.Seek(FilePosition);
628 result = Reader.ReadKLFromFile(m_File);
630 if ( ASDCP_SUCCESS(result) )
632 // skip over the companion SP_LEFT frame
633 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
634 result = m_File.Seek(new_pos);
638 // the call to ReadEKLVPacket() will leave the file not on an R frame
639 m_StereoFrameReady = 0xffffffff;
643 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
647 if( ASDCP_SUCCESS(result) )
649 ui32_t SequenceNum = FrameNum * 2;
650 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
652 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
661 ASDCP::JP2K::MXFSReader::MXFSReader()
663 m_Reader = new h__SReader(DefaultCompositeDict());
667 ASDCP::JP2K::MXFSReader::~MXFSReader()
671 // Warning: direct manipulation of MXF structures can interfere
672 // with the normal operation of the wrapper. Caveat emptor!
674 ASDCP::MXF::OPAtomHeader&
675 ASDCP::JP2K::MXFSReader::OPAtomHeader()
677 if ( m_Reader.empty() )
679 assert(g_OPAtomHeader);
680 return *g_OPAtomHeader;
683 return m_Reader->m_HeaderPart;
686 // Warning: direct manipulation of MXF structures can interfere
687 // with the normal operation of the wrapper. Caveat emptor!
689 ASDCP::MXF::OPAtomIndexFooter&
690 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
692 if ( m_Reader.empty() )
694 assert(g_OPAtomIndexFooter);
695 return *g_OPAtomIndexFooter;
698 return m_Reader->m_FooterPart;
701 // Open the file for reading. The file must exist. Returns error if the
702 // operation cannot be completed.
704 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
706 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
711 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
713 Result_t result = RESULT_INIT;
715 if ( m_Reader && m_Reader->m_File.IsOpen() )
717 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
719 if ( ASDCP_SUCCESS(result) )
720 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
728 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
729 AESDecContext* Ctx, HMACContext* HMAC) const
731 if ( m_Reader && m_Reader->m_File.IsOpen() )
732 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
737 // Fill the struct with the values from the file's header.
738 // Returns RESULT_INIT if the file is not open.
740 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
742 if ( m_Reader && m_Reader->m_File.IsOpen() )
744 PDesc = m_Reader->m_PDesc;
752 // Fill the struct with the values from the file's header.
753 // Returns RESULT_INIT if the file is not open.
755 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
757 if ( m_Reader && m_Reader->m_File.IsOpen() )
759 Info = m_Reader->m_Info;
768 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
770 if ( m_Reader->m_File.IsOpen() )
771 m_Reader->m_HeaderPart.Dump(stream);
777 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
779 if ( m_Reader->m_File.IsOpen() )
780 m_Reader->m_FooterPart.Dump(stream);
785 ASDCP::JP2K::MXFSReader::Close() const
787 if ( m_Reader && m_Reader->m_File.IsOpen() )
797 //------------------------------------------------------------------------------------------
801 class lh__Writer : public ASDCP::h__Writer
803 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
806 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
809 PictureDescriptor m_PDesc;
810 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
812 lh__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceSubDescriptor(0) {
813 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
818 Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize, bool);
819 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
820 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
821 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*, std::string* hash = 0);
822 Result_t FakeWriteFrame(int size, bool add_index);
824 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
827 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
828 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
829 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
833 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
835 assert(m_EssenceDescriptor);
836 assert(m_EssenceSubDescriptor);
837 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
839 PDescObj->ContainerDuration = PDesc.ContainerDuration;
840 PDescObj->SampleRate = PDesc.EditRate;
841 PDescObj->FrameLayout = 0;
842 PDescObj->StoredWidth = PDesc.StoredWidth;
843 PDescObj->StoredHeight = PDesc.StoredHeight;
844 PDescObj->AspectRatio = PDesc.AspectRatio;
846 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
848 // PictureEssenceCoding UL =
849 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
851 // ComponentMaxRef ui32_t = 4095
852 // ComponentMinRef ui32_t = 0
853 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
857 if ( PDesc.StoredWidth < 2049 )
859 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
860 m_EssenceSubDescriptor->Rsize = 3;
864 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
865 m_EssenceSubDescriptor->Rsize = 4;
868 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
869 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
870 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
871 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
872 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
873 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
874 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
875 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
876 m_EssenceSubDescriptor->Csize = PDesc.Csize;
878 const ui32_t tmp_buffer_len = 1024;
879 byte_t tmp_buffer[tmp_buffer_len];
881 ui32_t* tmp_buffer_ui32 = (ui32_t*) tmp_buffer;
882 *tmp_buffer_ui32 = KM_i32_BE(MaxComponents); // three components
884 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
885 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
887 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
888 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
889 m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
891 ui32_t precinct_set_size = 0, i;
892 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
895 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
896 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
897 m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
899 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
900 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
901 m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
907 // Open the file for writing. The file must not exist unless overwrite is true. Returns error if
908 // the operation cannot be completed.
910 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize, bool overwrite)
912 if ( ! m_State.Test_BEGIN() )
915 Result_t result = RESULT_OK;
917 result = m_File.OpenModify(filename);
920 result = m_File.OpenWrite(filename);
923 if ( ASDCP_SUCCESS(result) )
925 m_HeaderSize = HeaderSize;
926 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
927 tmp_rgba->ComponentMaxRef = 4095;
928 tmp_rgba->ComponentMinRef = 0;
930 m_EssenceDescriptor = tmp_rgba;
931 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
932 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
934 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
935 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
937 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
939 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
940 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
941 GenRandomValue(StereoSubDesc->InstanceUID);
942 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
945 result = m_State.Goto_INIT();
951 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
953 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
956 if ( ! m_State.Test_INIT() )
959 if ( LocalEditRate == ASDCP::Rational(0,0) )
960 LocalEditRate = PDesc.EditRate;
963 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
965 if ( ASDCP_SUCCESS(result) )
967 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
968 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
969 result = m_State.Goto_READY();
972 if ( ASDCP_SUCCESS(result) )
974 ui32_t TCFrameRate = ( m_PDesc.EditRate == EditRate_23_98 ) ? 24 : m_PDesc.EditRate.Numerator;
976 result = WriteMXFHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
977 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
978 LocalEditRate, TCFrameRate);
984 // Writes a frame of essence to the MXF file. If the optional AESEncContext
985 // argument is present, the essence is encrypted prior to writing.
986 // Fails if the file is not open, is finalized, or an operating system
990 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
991 AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
993 Result_t result = RESULT_OK;
995 if ( m_State.Test_READY() )
996 result = m_State.Goto_RUNNING(); // first time through
998 ui64_t StreamOffset = m_StreamOffset;
1000 if ( ASDCP_SUCCESS(result) )
1001 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC, hash);
1003 if ( ASDCP_SUCCESS(result) && add_index )
1005 IndexTableSegment::IndexEntry Entry;
1006 Entry.StreamOffset = StreamOffset;
1007 m_FooterPart.PushIndexEntry(Entry);
1015 lh__Writer::FakeWriteFrame(int size, bool add_index)
1017 Result_t result = RESULT_OK;
1019 if ( m_State.Test_READY() )
1020 result = m_State.Goto_RUNNING();
1022 ui64_t StreamOffset = m_StreamOffset;
1024 if ( ASDCP_SUCCESS(result) )
1025 result = FakeWriteEKLVPacket(size);
1027 if ( ASDCP_SUCCESS(result) && add_index )
1029 IndexTableSegment::IndexEntry Entry;
1030 Entry.StreamOffset = StreamOffset;
1031 m_FooterPart.PushIndexEntry(Entry);
1039 // Closes the MXF file, writing the index and other closing information.
1042 lh__Writer::Finalize()
1044 if ( ! m_State.Test_RUNNING() )
1045 return RESULT_STATE;
1047 m_State.Goto_FINAL();
1049 return WriteMXFFooter();
1054 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1056 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1060 h__Writer(const Dictionary& d) : lh__Writer(d) {}
1064 //------------------------------------------------------------------------------------------
1068 ASDCP::JP2K::MXFWriter::MXFWriter()
1072 ASDCP::JP2K::MXFWriter::~MXFWriter()
1076 // Warning: direct manipulation of MXF structures can interfere
1077 // with the normal operation of the wrapper. Caveat emptor!
1079 ASDCP::MXF::OPAtomHeader&
1080 ASDCP::JP2K::MXFWriter::OPAtomHeader()
1082 if ( m_Writer.empty() )
1084 assert(g_OPAtomHeader);
1085 return *g_OPAtomHeader;
1088 return m_Writer->m_HeaderPart;
1091 // Warning: direct manipulation of MXF structures can interfere
1092 // with the normal operation of the wrapper. Caveat emptor!
1094 ASDCP::MXF::OPAtomIndexFooter&
1095 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1097 if ( m_Writer.empty() )
1099 assert(g_OPAtomIndexFooter);
1100 return *g_OPAtomIndexFooter;
1103 return m_Writer->m_FooterPart;
1106 // Open the file for writing. The file must not exist unless overwrite is true. Returns error if
1107 // the operation cannot be completed.
1109 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1110 const PictureDescriptor& PDesc, ui32_t HeaderSize, bool overwrite)
1112 if ( Info.LabelSetType == LS_MXF_SMPTE )
1113 m_Writer = new h__Writer(DefaultSMPTEDict());
1115 m_Writer = new h__Writer(DefaultInteropDict());
1117 m_Writer->m_Info = Info;
1119 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize, overwrite);
1121 if ( ASDCP_SUCCESS(result) )
1122 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1124 if ( ASDCP_FAILURE(result) )
1131 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1132 // argument is present, the essence is encrypted prior to writing.
1133 // Fails if the file is not open, is finalized, or an operating system
1136 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
1138 if ( m_Writer.empty() )
1141 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC, hash);
1145 ASDCP::JP2K::MXFWriter::FakeWriteFrame(int size)
1147 if ( m_Writer.empty() )
1150 return m_Writer->FakeWriteFrame(size, true);
1153 // Closes the MXF file, writing the index and other closing information.
1155 ASDCP::JP2K::MXFWriter::Finalize()
1157 if ( m_Writer.empty() )
1160 return m_Writer->Finalize();
1164 ASDCP::JP2K::MXFWriter::Tell() const
1166 return m_Writer->m_File.Tell();
1170 //------------------------------------------------------------------------------------------
1174 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1176 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1178 StereoscopicPhase_t m_NextPhase;
1181 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1184 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1185 AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
1187 if ( m_NextPhase != phase )
1188 return RESULT_SPHASE;
1190 if ( phase == SP_LEFT )
1192 m_NextPhase = SP_RIGHT;
1193 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC, hash);
1196 m_NextPhase = SP_LEFT;
1197 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC, hash);
1200 Result_t FakeWriteFrame(int size, StereoscopicPhase_t phase)
1202 if (m_NextPhase != phase)
1204 return RESULT_SPHASE;
1207 if (phase == SP_LEFT)
1209 m_NextPhase = SP_RIGHT;
1210 return lh__Writer::FakeWriteFrame(size, true);
1213 m_NextPhase = SP_LEFT;
1214 return lh__Writer::FakeWriteFrame(size, false);
1220 if ( m_NextPhase != SP_LEFT )
1221 return RESULT_SPHASE;
1223 assert( m_FramesWritten % 2 == 0 );
1224 m_FramesWritten /= 2;
1225 return lh__Writer::Finalize();
1231 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1235 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1239 // Warning: direct manipulation of MXF structures can interfere
1240 // with the normal operation of the wrapper. Caveat emptor!
1242 ASDCP::MXF::OPAtomHeader&
1243 ASDCP::JP2K::MXFSWriter::OPAtomHeader()
1245 if ( m_Writer.empty() )
1247 assert(g_OPAtomHeader);
1248 return *g_OPAtomHeader;
1251 return m_Writer->m_HeaderPart;
1254 // Warning: direct manipulation of MXF structures can interfere
1255 // with the normal operation of the wrapper. Caveat emptor!
1257 ASDCP::MXF::OPAtomIndexFooter&
1258 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1260 if ( m_Writer.empty() )
1262 assert(g_OPAtomIndexFooter);
1263 return *g_OPAtomIndexFooter;
1266 return m_Writer->m_FooterPart;
1269 // Open the file for writing. The file must not exist. Returns error if
1270 // the operation cannot be completed.
1272 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1273 const PictureDescriptor& PDesc, ui32_t HeaderSize, bool overwrite)
1275 if ( Info.LabelSetType == LS_MXF_SMPTE )
1276 m_Writer = new h__SWriter(DefaultSMPTEDict());
1278 m_Writer = new h__SWriter(DefaultInteropDict());
1280 if ( PDesc.EditRate != ASDCP::EditRate_24
1281 && PDesc.EditRate != ASDCP::EditRate_25
1282 && PDesc.EditRate != ASDCP::EditRate_30
1283 && PDesc.EditRate != ASDCP::EditRate_48
1284 && PDesc.EditRate != ASDCP::EditRate_50
1285 && PDesc.EditRate != ASDCP::EditRate_60 )
1287 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1288 return RESULT_FORMAT;
1291 if ( PDesc.StoredWidth > 2048 )
1292 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1294 m_Writer->m_Info = Info;
1296 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize, overwrite);
1298 if ( ASDCP_SUCCESS(result) )
1300 PictureDescriptor TmpPDesc = PDesc;
1302 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1303 TmpPDesc.EditRate = ASDCP::EditRate_48;
1305 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1306 TmpPDesc.EditRate = ASDCP::EditRate_50;
1308 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1309 TmpPDesc.EditRate = ASDCP::EditRate_60;
1311 else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1312 TmpPDesc.EditRate = ASDCP::EditRate_96;
1314 else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1315 TmpPDesc.EditRate = ASDCP::EditRate_100;
1317 else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1318 TmpPDesc.EditRate = ASDCP::EditRate_120;
1320 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1323 if ( ASDCP_FAILURE(result) )
1330 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1332 if ( m_Writer.empty() )
1335 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC, 0);
1337 if ( ASDCP_SUCCESS(result) )
1338 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC, 0);
1343 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1344 // argument is present, the essence is encrypted prior to writing.
1345 // Fails if the file is not open, is finalized, or an operating system
1348 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1349 AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
1351 if ( m_Writer.empty() )
1354 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC, hash);
1358 ASDCP::JP2K::MXFSWriter::FakeWriteFrame(int size, StereoscopicPhase_t phase)
1360 if ( m_Writer.empty() )
1363 return m_Writer->FakeWriteFrame(size, phase);
1366 // Closes the MXF file, writing the index and other closing information.
1368 ASDCP::JP2K::MXFSWriter::Finalize()
1370 if ( m_Writer.empty() )
1373 return m_Writer->Finalize();
1377 ASDCP::JP2K::MXFSWriter::Tell() const
1379 return m_Writer->m_File.Tell();
1383 // end AS_DCP_JP2K.cpp