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;
999 cout << "Real write @ " << StreamOffset << " (header is " << m_HeaderSize << ")\n";
1000 cout << "\tfile @ " << m_File.Tell() << "\n";
1002 if ( ASDCP_SUCCESS(result) )
1003 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC, hash);
1005 if ( ASDCP_SUCCESS(result) && add_index )
1007 IndexTableSegment::IndexEntry Entry;
1008 Entry.StreamOffset = StreamOffset;
1009 m_FooterPart.PushIndexEntry(Entry);
1017 lh__Writer::FakeWriteFrame(int size, bool add_index)
1019 Result_t result = RESULT_OK;
1021 if ( m_State.Test_READY() )
1022 result = m_State.Goto_RUNNING();
1024 ui64_t StreamOffset = m_StreamOffset;
1025 cout << "Fake write @ " << StreamOffset << " (header is " << m_HeaderSize << ")\n";
1026 cout << "\tfile @ " << m_File.Tell() << "\n";
1028 if ( ASDCP_SUCCESS(result) )
1029 result = FakeWriteEKLVPacket(size);
1031 if ( ASDCP_SUCCESS(result) && add_index )
1033 IndexTableSegment::IndexEntry Entry;
1034 Entry.StreamOffset = StreamOffset;
1035 m_FooterPart.PushIndexEntry(Entry);
1043 // Closes the MXF file, writing the index and other closing information.
1046 lh__Writer::Finalize()
1048 if ( ! m_State.Test_RUNNING() )
1049 return RESULT_STATE;
1051 m_State.Goto_FINAL();
1053 return WriteMXFFooter();
1058 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1060 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1064 h__Writer(const Dictionary& d) : lh__Writer(d) {}
1068 //------------------------------------------------------------------------------------------
1072 ASDCP::JP2K::MXFWriter::MXFWriter()
1076 ASDCP::JP2K::MXFWriter::~MXFWriter()
1080 // Warning: direct manipulation of MXF structures can interfere
1081 // with the normal operation of the wrapper. Caveat emptor!
1083 ASDCP::MXF::OPAtomHeader&
1084 ASDCP::JP2K::MXFWriter::OPAtomHeader()
1086 if ( m_Writer.empty() )
1088 assert(g_OPAtomHeader);
1089 return *g_OPAtomHeader;
1092 return m_Writer->m_HeaderPart;
1095 // Warning: direct manipulation of MXF structures can interfere
1096 // with the normal operation of the wrapper. Caveat emptor!
1098 ASDCP::MXF::OPAtomIndexFooter&
1099 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1101 if ( m_Writer.empty() )
1103 assert(g_OPAtomIndexFooter);
1104 return *g_OPAtomIndexFooter;
1107 return m_Writer->m_FooterPart;
1110 // Open the file for writing. The file must not exist unless overwrite is true. Returns error if
1111 // the operation cannot be completed.
1113 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1114 const PictureDescriptor& PDesc, ui32_t HeaderSize, bool overwrite)
1116 if ( Info.LabelSetType == LS_MXF_SMPTE )
1117 m_Writer = new h__Writer(DefaultSMPTEDict());
1119 m_Writer = new h__Writer(DefaultInteropDict());
1121 m_Writer->m_Info = Info;
1123 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize, overwrite);
1125 if ( ASDCP_SUCCESS(result) )
1126 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1128 if ( ASDCP_FAILURE(result) )
1135 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1136 // argument is present, the essence is encrypted prior to writing.
1137 // Fails if the file is not open, is finalized, or an operating system
1140 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC, std::string* hash)
1142 if ( m_Writer.empty() )
1145 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC, hash);
1149 ASDCP::JP2K::MXFWriter::FakeWriteFrame(int size)
1151 if ( m_Writer.empty() )
1154 return m_Writer->FakeWriteFrame(size, true);
1157 // Closes the MXF file, writing the index and other closing information.
1159 ASDCP::JP2K::MXFWriter::Finalize()
1161 if ( m_Writer.empty() )
1164 return m_Writer->Finalize();
1168 ASDCP::JP2K::MXFWriter::Tell() const
1170 return m_Writer->m_File.Tell();
1174 //------------------------------------------------------------------------------------------
1178 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1180 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1182 StereoscopicPhase_t m_NextPhase;
1185 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1188 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1189 AESEncContext* Ctx, HMACContext* HMAC)
1191 if ( m_NextPhase != phase )
1192 return RESULT_SPHASE;
1194 if ( phase == SP_LEFT )
1196 m_NextPhase = SP_RIGHT;
1197 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1200 m_NextPhase = SP_LEFT;
1201 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1207 if ( m_NextPhase != SP_LEFT )
1208 return RESULT_SPHASE;
1210 assert( m_FramesWritten % 2 == 0 );
1211 m_FramesWritten /= 2;
1212 return lh__Writer::Finalize();
1218 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1222 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1226 // Warning: direct manipulation of MXF structures can interfere
1227 // with the normal operation of the wrapper. Caveat emptor!
1229 ASDCP::MXF::OPAtomHeader&
1230 ASDCP::JP2K::MXFSWriter::OPAtomHeader()
1232 if ( m_Writer.empty() )
1234 assert(g_OPAtomHeader);
1235 return *g_OPAtomHeader;
1238 return m_Writer->m_HeaderPart;
1241 // Warning: direct manipulation of MXF structures can interfere
1242 // with the normal operation of the wrapper. Caveat emptor!
1244 ASDCP::MXF::OPAtomIndexFooter&
1245 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1247 if ( m_Writer.empty() )
1249 assert(g_OPAtomIndexFooter);
1250 return *g_OPAtomIndexFooter;
1253 return m_Writer->m_FooterPart;
1256 // Open the file for writing. The file must not exist. Returns error if
1257 // the operation cannot be completed.
1259 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1260 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1262 if ( Info.LabelSetType == LS_MXF_SMPTE )
1263 m_Writer = new h__SWriter(DefaultSMPTEDict());
1265 m_Writer = new h__SWriter(DefaultInteropDict());
1267 if ( PDesc.EditRate != ASDCP::EditRate_24
1268 && PDesc.EditRate != ASDCP::EditRate_25
1269 && PDesc.EditRate != ASDCP::EditRate_30
1270 && PDesc.EditRate != ASDCP::EditRate_48
1271 && PDesc.EditRate != ASDCP::EditRate_50
1272 && PDesc.EditRate != ASDCP::EditRate_60 )
1274 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1275 return RESULT_FORMAT;
1278 if ( PDesc.StoredWidth > 2048 )
1279 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1281 m_Writer->m_Info = Info;
1283 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize, false);
1285 if ( ASDCP_SUCCESS(result) )
1287 PictureDescriptor TmpPDesc = PDesc;
1289 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1290 TmpPDesc.EditRate = ASDCP::EditRate_48;
1292 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1293 TmpPDesc.EditRate = ASDCP::EditRate_50;
1295 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1296 TmpPDesc.EditRate = ASDCP::EditRate_60;
1298 else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1299 TmpPDesc.EditRate = ASDCP::EditRate_96;
1301 else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1302 TmpPDesc.EditRate = ASDCP::EditRate_100;
1304 else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1305 TmpPDesc.EditRate = ASDCP::EditRate_120;
1307 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1310 if ( ASDCP_FAILURE(result) )
1317 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1319 if ( m_Writer.empty() )
1322 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1324 if ( ASDCP_SUCCESS(result) )
1325 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1330 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1331 // argument is present, the essence is encrypted prior to writing.
1332 // Fails if the file is not open, is finalized, or an operating system
1335 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1336 AESEncContext* Ctx, HMACContext* HMAC)
1338 if ( m_Writer.empty() )
1341 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1344 // Closes the MXF file, writing the index and other closing information.
1346 ASDCP::JP2K::MXFSWriter::Finalize()
1348 if ( m_Writer.empty() )
1351 return m_Writer->Finalize();
1355 // end AS_DCP_JP2K.cpp