2 Copyright (c) 2004-2012, 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
28 \version $Id: AS_DCP_JP2K.cpp,v 1.54 2012/02/07 18:54:24 jhurst Exp $
29 \brief AS-DCP library, JPEG 2000 essence reader and writer implementation
32 #include "AS_DCP_internal.h"
36 using namespace ASDCP::JP2K;
37 using Kumu::GenRandomValue;
39 //------------------------------------------------------------------------------------------
41 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
42 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
43 static std::string PICT_DEF_LABEL = "Picture Track";
45 int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
49 ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc)
51 strm << " AspectRatio: " << PDesc.AspectRatio.Numerator << "/" << PDesc.AspectRatio.Denominator << std::endl;
52 strm << " EditRate: " << PDesc.EditRate.Numerator << "/" << PDesc.EditRate.Denominator << std::endl;
53 strm << " SampleRate: " << PDesc.SampleRate.Numerator << "/" << PDesc.SampleRate.Denominator << std::endl;
54 strm << " StoredWidth: " << (unsigned) PDesc.StoredWidth << std::endl;
55 strm << " StoredHeight: " << (unsigned) PDesc.StoredHeight << std::endl;
56 strm << " Rsize: " << (unsigned) PDesc.Rsize << std::endl;
57 strm << " Xsize: " << (unsigned) PDesc.Xsize << std::endl;
58 strm << " Ysize: " << (unsigned) PDesc.Ysize << std::endl;
59 strm << " XOsize: " << (unsigned) PDesc.XOsize << std::endl;
60 strm << " YOsize: " << (unsigned) PDesc.YOsize << std::endl;
61 strm << " XTsize: " << (unsigned) PDesc.XTsize << std::endl;
62 strm << " YTsize: " << (unsigned) PDesc.YTsize << std::endl;
63 strm << " XTOsize: " << (unsigned) PDesc.XTOsize << std::endl;
64 strm << " YTOsize: " << (unsigned) PDesc.YTOsize << std::endl;
65 strm << " ContainerDuration: " << (unsigned) PDesc.ContainerDuration << std::endl;
67 strm << "-- JPEG 2000 Metadata --" << std::endl;
68 strm << " ImageComponents:" << std::endl;
69 strm << " bits h-sep v-sep" << std::endl;
72 for ( i = 0; i < PDesc.Csize; i++ )
74 strm << " " << std::setw(4) << PDesc.ImageComponents[i].Ssize + 1 /* See ISO 15444-1, Table A11, for the origin of '+1' */
75 << " " << std::setw(5) << PDesc.ImageComponents[i].XRsize
76 << " " << std::setw(5) << PDesc.ImageComponents[i].YRsize
80 strm << " Scod: " << (short) PDesc.CodingStyleDefault.Scod << std::endl;
81 strm << " ProgressionOrder: " << (short) PDesc.CodingStyleDefault.SGcod.ProgressionOrder << std::endl;
82 strm << " NumberOfLayers: " << (short) KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)) << std::endl;
83 strm << " MultiCompTransform: " << (short) PDesc.CodingStyleDefault.SGcod.MultiCompTransform << std::endl;
84 strm << "DecompositionLevels: " << (short) PDesc.CodingStyleDefault.SPcod.DecompositionLevels << std::endl;
85 strm << " CodeblockWidth: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockWidth << std::endl;
86 strm << " CodeblockHeight: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockHeight << std::endl;
87 strm << " CodeblockStyle: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockStyle << std::endl;
88 strm << " Transformation: " << (short) PDesc.CodingStyleDefault.SPcod.Transformation << std::endl;
91 ui32_t precinct_set_size = 0;
93 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
96 strm << " Precincts: " << (short) precinct_set_size << std::endl;
97 strm << "precinct dimensions:" << std::endl;
99 for ( i = 0; i < precinct_set_size; i++ )
100 strm << " " << i + 1 << ": " << s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f] << " x "
101 << s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] << std::endl;
103 strm << " Sqcd: " << (short) PDesc.QuantizationDefault.Sqcd << std::endl;
105 char tmp_buf[MaxDefaults*2];
106 strm << " SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2)
114 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
120 AspectRatio: %d/%d\n\
134 ContainerDuration: %u\n",
135 PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
136 PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
137 PDesc.SampleRate.Numerator, PDesc.SampleRate.Denominator,
149 PDesc.ContainerDuration
152 fprintf(stream, "-- JPEG 2000 Metadata --\n");
153 fprintf(stream, " ImageComponents:\n");
154 fprintf(stream, " bits h-sep v-sep\n");
157 for ( i = 0; i < PDesc.Csize; i++ )
159 fprintf(stream, " %4d %5d %5d\n",
160 PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
161 PDesc.ImageComponents[i].XRsize,
162 PDesc.ImageComponents[i].YRsize
166 fprintf(stream, " Scod: %hd\n", PDesc.CodingStyleDefault.Scod);
167 fprintf(stream, " ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
168 fprintf(stream, " NumberOfLayers: %hd\n",
169 KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
171 fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
172 fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
173 fprintf(stream, " CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
174 fprintf(stream, " CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
175 fprintf(stream, " CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
176 fprintf(stream, " Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
179 ui32_t precinct_set_size = 0;
181 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
184 fprintf(stream, " Precincts: %hd\n", precinct_set_size);
185 fprintf(stream, "precinct dimensions:\n");
187 for ( i = 0; i < precinct_set_size; i++ )
188 fprintf(stream, " %d: %d x %d\n", i + 1,
189 s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
190 s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
193 fprintf(stream, " Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd);
195 char tmp_buf[MaxDefaults*2];
196 fprintf(stream, " SPqcd: %s\n",
197 Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
198 tmp_buf, MaxDefaults*2)
203 //------------------------------------------------------------------------------------------
205 // hidden, internal implementation of JPEG 2000 reader
208 class lh__Reader : public ASDCP::h__Reader
210 RGBAEssenceDescriptor* m_EssenceDescriptor;
211 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
212 ASDCP::Rational m_EditRate;
213 ASDCP::Rational m_SampleRate;
214 EssenceType_t m_Format;
216 ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
219 PictureDescriptor m_PDesc; // codestream parameter list
221 lh__Reader(const Dictionary& d) :
222 ASDCP::h__Reader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
223 Result_t OpenRead(const char*, EssenceType_t);
224 Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
225 Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
230 lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
232 memset(&PDesc, 0, sizeof(PDesc));
233 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
235 PDesc.EditRate = m_EditRate;
236 PDesc.SampleRate = m_SampleRate;
237 assert(PDescObj->ContainerDuration <= 0xFFFFFFFFL);
238 PDesc.ContainerDuration = (ui32_t) PDescObj->ContainerDuration;
239 PDesc.StoredWidth = PDescObj->StoredWidth;
240 PDesc.StoredHeight = PDescObj->StoredHeight;
241 PDesc.AspectRatio = PDescObj->AspectRatio;
243 if ( m_EssenceSubDescriptor != 0 )
245 PDesc.Rsize = m_EssenceSubDescriptor->Rsize;
246 PDesc.Xsize = m_EssenceSubDescriptor->Xsize;
247 PDesc.Ysize = m_EssenceSubDescriptor->Ysize;
248 PDesc.XOsize = m_EssenceSubDescriptor->XOsize;
249 PDesc.YOsize = m_EssenceSubDescriptor->YOsize;
250 PDesc.XTsize = m_EssenceSubDescriptor->XTsize;
251 PDesc.YTsize = m_EssenceSubDescriptor->YTsize;
252 PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
253 PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
254 PDesc.Csize = m_EssenceSubDescriptor->Csize;
256 // PictureComponentSizing
257 ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
259 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
260 memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
263 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
265 // CodingStyleDefault
266 memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
267 memcpy(&PDesc.CodingStyleDefault,
268 m_EssenceSubDescriptor->CodingStyleDefault.RoData(),
269 m_EssenceSubDescriptor->CodingStyleDefault.Length());
271 // QuantizationDefault
272 memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
273 memcpy(&PDesc.QuantizationDefault,
274 m_EssenceSubDescriptor->QuantizationDefault.RoData(),
275 m_EssenceSubDescriptor->QuantizationDefault.Length());
277 PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1;
286 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
288 Result_t result = OpenMXFRead(filename);
290 if( ASDCP_SUCCESS(result) )
292 InterchangeObject* tmp_iobj = 0;
293 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
294 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
296 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
297 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
299 std::list<InterchangeObject*> ObjectList;
300 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
302 if ( ObjectList.empty() )
304 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
305 return RESULT_FORMAT;
308 m_EditRate = ((Track*)ObjectList.front())->EditRate;
309 m_SampleRate = m_EssenceDescriptor->SampleRate;
311 if ( type == ASDCP::ESS_JPEG_2000 )
313 if ( m_EditRate != m_SampleRate )
315 DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
316 m_EditRate.Quotient(), m_SampleRate.Quotient());
318 if ( (m_EditRate == EditRate_24 && m_SampleRate == EditRate_48) ||
319 (m_EditRate == EditRate_25 && m_SampleRate == EditRate_50) ||
320 (m_EditRate == EditRate_30 && m_SampleRate == EditRate_60) ||
321 (m_EditRate == EditRate_48 && m_SampleRate == EditRate_96) ||
322 (m_EditRate == EditRate_50 && m_SampleRate == EditRate_100) ||
323 (m_EditRate == EditRate_60 && m_SampleRate == EditRate_120) )
325 DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
326 return RESULT_SFORMAT;
329 return RESULT_FORMAT;
332 else if ( type == ASDCP::ESS_JPEG_2000_S )
334 if ( m_EditRate == EditRate_24 )
336 if ( m_SampleRate != EditRate_48 )
338 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
339 return RESULT_FORMAT;
342 else if ( m_EditRate == EditRate_25 )
344 if ( m_SampleRate != EditRate_50 )
346 DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
347 return RESULT_FORMAT;
350 else if ( m_EditRate == EditRate_30 )
352 if ( m_SampleRate != EditRate_60 )
354 DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
355 return RESULT_FORMAT;
358 else if ( m_EditRate == EditRate_48 )
360 if ( m_SampleRate != EditRate_96 )
362 DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
363 return RESULT_FORMAT;
366 else if ( m_EditRate == EditRate_50 )
368 if ( m_SampleRate != EditRate_100 )
370 DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
371 return RESULT_FORMAT;
374 else if ( m_EditRate == EditRate_60 )
376 if ( m_SampleRate != EditRate_120 )
378 DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
379 return RESULT_FORMAT;
384 DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
385 m_EditRate.Numerator, m_EditRate.Denominator);
386 return RESULT_FORMAT;
391 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
395 result = MD_to_JP2K_PDesc(m_PDesc);
398 if( ASDCP_SUCCESS(result) )
399 result = InitMXFIndex();
401 if( ASDCP_SUCCESS(result) )
410 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
411 AESDecContext* Ctx, HMACContext* HMAC)
413 if ( ! m_File.IsOpen() )
417 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
422 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
424 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
428 h__Reader(const Dictionary& d) : lh__Reader(d) {}
433 //------------------------------------------------------------------------------------------
438 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
443 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
448 Kumu::hexdump(m_Data, dump_len, stream);
452 //------------------------------------------------------------------------------------------
454 ASDCP::JP2K::MXFReader::MXFReader()
456 m_Reader = new h__Reader(DefaultCompositeDict());
460 ASDCP::JP2K::MXFReader::~MXFReader()
464 // Warning: direct manipulation of MXF structures can interfere
465 // with the normal operation of the wrapper. Caveat emptor!
467 ASDCP::MXF::OPAtomHeader&
468 ASDCP::JP2K::MXFReader::OPAtomHeader()
470 if ( m_Reader.empty() )
472 assert(g_OPAtomHeader);
473 return *g_OPAtomHeader;
476 return m_Reader->m_HeaderPart;
479 // Warning: direct manipulation of MXF structures can interfere
480 // with the normal operation of the wrapper. Caveat emptor!
482 ASDCP::MXF::OPAtomIndexFooter&
483 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
485 if ( m_Reader.empty() )
487 assert(g_OPAtomIndexFooter);
488 return *g_OPAtomIndexFooter;
491 return m_Reader->m_FooterPart;
494 // Open the file for reading. The file must exist. Returns error if the
495 // operation cannot be completed.
497 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
499 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
504 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
505 AESDecContext* Ctx, HMACContext* HMAC) const
507 if ( m_Reader && m_Reader->m_File.IsOpen() )
508 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
514 // Fill the struct with the values from the file's header.
515 // Returns RESULT_INIT if the file is not open.
517 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
519 if ( m_Reader && m_Reader->m_File.IsOpen() )
521 PDesc = m_Reader->m_PDesc;
529 // Fill the struct with the values from the file's header.
530 // Returns RESULT_INIT if the file is not open.
532 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
534 if ( m_Reader && m_Reader->m_File.IsOpen() )
536 Info = m_Reader->m_Info;
545 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
547 if ( m_Reader->m_File.IsOpen() )
548 m_Reader->m_HeaderPart.Dump(stream);
554 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
556 if ( m_Reader->m_File.IsOpen() )
557 m_Reader->m_FooterPart.Dump(stream);
562 ASDCP::JP2K::MXFReader::Close() const
564 if ( m_Reader && m_Reader->m_File.IsOpen() )
574 //------------------------------------------------------------------------------------------
577 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
579 ui32_t m_StereoFrameReady;
582 h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
585 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
586 AESDecContext* Ctx, HMACContext* HMAC)
588 // look up frame index node
589 IndexTableSegment::IndexEntry TmpEntry;
591 if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
593 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
597 // get frame position
598 Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
599 Result_t result = RESULT_OK;
601 if ( phase == SP_LEFT )
603 if ( FilePosition != m_LastPosition )
605 m_LastPosition = FilePosition;
606 result = m_File.Seek(FilePosition);
609 // the call to ReadEKLVPacket() will leave the file on an R frame
610 m_StereoFrameReady = FrameNum;
612 else if ( phase == SP_RIGHT )
614 if ( m_StereoFrameReady != FrameNum )
616 // the file is not already positioned, we must do some work
617 // seek to the companion SP_LEFT frame and read the frame's key and length
618 if ( FilePosition != m_LastPosition )
620 m_LastPosition = FilePosition;
621 result = m_File.Seek(FilePosition);
625 result = Reader.ReadKLFromFile(m_File);
627 if ( ASDCP_SUCCESS(result) )
629 // skip over the companion SP_LEFT frame
630 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
631 result = m_File.Seek(new_pos);
635 // the call to ReadEKLVPacket() will leave the file not on an R frame
636 m_StereoFrameReady = 0xffffffff;
640 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
644 if( ASDCP_SUCCESS(result) )
646 ui32_t SequenceNum = FrameNum * 2;
647 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
649 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
658 ASDCP::JP2K::MXFSReader::MXFSReader()
660 m_Reader = new h__SReader(DefaultCompositeDict());
664 ASDCP::JP2K::MXFSReader::~MXFSReader()
668 // Warning: direct manipulation of MXF structures can interfere
669 // with the normal operation of the wrapper. Caveat emptor!
671 ASDCP::MXF::OPAtomHeader&
672 ASDCP::JP2K::MXFSReader::OPAtomHeader()
674 if ( m_Reader.empty() )
676 assert(g_OPAtomHeader);
677 return *g_OPAtomHeader;
680 return m_Reader->m_HeaderPart;
683 // Warning: direct manipulation of MXF structures can interfere
684 // with the normal operation of the wrapper. Caveat emptor!
686 ASDCP::MXF::OPAtomIndexFooter&
687 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
689 if ( m_Reader.empty() )
691 assert(g_OPAtomIndexFooter);
692 return *g_OPAtomIndexFooter;
695 return m_Reader->m_FooterPart;
698 // Open the file for reading. The file must exist. Returns error if the
699 // operation cannot be completed.
701 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
703 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
708 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
710 Result_t result = RESULT_INIT;
712 if ( m_Reader && m_Reader->m_File.IsOpen() )
714 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
716 if ( ASDCP_SUCCESS(result) )
717 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
725 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
726 AESDecContext* Ctx, HMACContext* HMAC) const
728 if ( m_Reader && m_Reader->m_File.IsOpen() )
729 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
734 // Fill the struct with the values from the file's header.
735 // Returns RESULT_INIT if the file is not open.
737 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
739 if ( m_Reader && m_Reader->m_File.IsOpen() )
741 PDesc = m_Reader->m_PDesc;
749 // Fill the struct with the values from the file's header.
750 // Returns RESULT_INIT if the file is not open.
752 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
754 if ( m_Reader && m_Reader->m_File.IsOpen() )
756 Info = m_Reader->m_Info;
765 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
767 if ( m_Reader->m_File.IsOpen() )
768 m_Reader->m_HeaderPart.Dump(stream);
774 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
776 if ( m_Reader->m_File.IsOpen() )
777 m_Reader->m_FooterPart.Dump(stream);
782 ASDCP::JP2K::MXFSReader::Close() const
784 if ( m_Reader && m_Reader->m_File.IsOpen() )
794 //------------------------------------------------------------------------------------------
798 class lh__Writer : public ASDCP::h__Writer
800 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
803 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
806 PictureDescriptor m_PDesc;
807 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
809 lh__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceSubDescriptor(0) {
810 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
815 Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
816 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
817 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
818 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
820 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
823 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
824 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
825 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
829 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
831 assert(m_EssenceDescriptor);
832 assert(m_EssenceSubDescriptor);
833 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
835 PDescObj->ContainerDuration = PDesc.ContainerDuration;
836 PDescObj->SampleRate = PDesc.EditRate;
837 PDescObj->FrameLayout = 0;
838 PDescObj->StoredWidth = PDesc.StoredWidth;
839 PDescObj->StoredHeight = PDesc.StoredHeight;
840 PDescObj->AspectRatio = PDesc.AspectRatio;
842 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
844 // PictureEssenceCoding UL =
845 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
847 // ComponentMaxRef ui32_t = 4095
848 // ComponentMinRef ui32_t = 0
849 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
853 if ( PDesc.StoredWidth < 2049 )
855 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
856 m_EssenceSubDescriptor->Rsize = 3;
860 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
861 m_EssenceSubDescriptor->Rsize = 4;
864 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
865 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
866 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
867 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
868 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
869 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
870 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
871 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
872 m_EssenceSubDescriptor->Csize = PDesc.Csize;
874 const ui32_t tmp_buffer_len = 1024;
875 byte_t tmp_buffer[tmp_buffer_len];
877 ui32_t* tmp_buffer_ui32 = (ui32_t*) tmp_buffer;
878 *tmp_buffer_ui32 = KM_i32_BE(MaxComponents); // three components
880 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
881 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
883 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
884 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
885 m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
887 ui32_t precinct_set_size = 0, i;
888 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
891 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
892 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
893 m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
895 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
896 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
897 m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
903 // Open the file for writing. The file must not exist. Returns error if
904 // the operation cannot be completed.
906 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
908 if ( ! m_State.Test_BEGIN() )
911 Result_t result = m_File.OpenWrite(filename);
913 if ( ASDCP_SUCCESS(result) )
915 m_HeaderSize = HeaderSize;
916 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
917 tmp_rgba->ComponentMaxRef = 4095;
918 tmp_rgba->ComponentMinRef = 0;
920 m_EssenceDescriptor = tmp_rgba;
921 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
922 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
924 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
925 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
927 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
929 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
930 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
931 GenRandomValue(StereoSubDesc->InstanceUID);
932 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
935 result = m_State.Goto_INIT();
941 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
943 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
946 if ( ! m_State.Test_INIT() )
949 if ( LocalEditRate == ASDCP::Rational(0,0) )
950 LocalEditRate = PDesc.EditRate;
953 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
955 if ( ASDCP_SUCCESS(result) )
957 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
958 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
959 result = m_State.Goto_READY();
962 if ( ASDCP_SUCCESS(result) )
964 ui32_t TCFrameRate = ( m_PDesc.EditRate == EditRate_23_98 ) ? 24 : m_PDesc.EditRate.Numerator;
966 result = WriteMXFHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
967 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
968 LocalEditRate, TCFrameRate);
974 // Writes a frame of essence to the MXF file. If the optional AESEncContext
975 // argument is present, the essence is encrypted prior to writing.
976 // Fails if the file is not open, is finalized, or an operating system
980 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
981 AESEncContext* Ctx, HMACContext* HMAC)
983 Result_t result = RESULT_OK;
985 if ( m_State.Test_READY() )
986 result = m_State.Goto_RUNNING(); // first time through
988 ui64_t StreamOffset = m_StreamOffset;
990 if ( ASDCP_SUCCESS(result) )
991 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
993 if ( ASDCP_SUCCESS(result) && add_index )
995 IndexTableSegment::IndexEntry Entry;
996 Entry.StreamOffset = StreamOffset;
997 m_FooterPart.PushIndexEntry(Entry);
1005 // Closes the MXF file, writing the index and other closing information.
1008 lh__Writer::Finalize()
1010 if ( ! m_State.Test_RUNNING() )
1011 return RESULT_STATE;
1013 m_State.Goto_FINAL();
1015 return WriteMXFFooter();
1020 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1022 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1026 h__Writer(const Dictionary& d) : lh__Writer(d) {}
1030 //------------------------------------------------------------------------------------------
1034 ASDCP::JP2K::MXFWriter::MXFWriter()
1038 ASDCP::JP2K::MXFWriter::~MXFWriter()
1042 // Warning: direct manipulation of MXF structures can interfere
1043 // with the normal operation of the wrapper. Caveat emptor!
1045 ASDCP::MXF::OPAtomHeader&
1046 ASDCP::JP2K::MXFWriter::OPAtomHeader()
1048 if ( m_Writer.empty() )
1050 assert(g_OPAtomHeader);
1051 return *g_OPAtomHeader;
1054 return m_Writer->m_HeaderPart;
1057 // Warning: direct manipulation of MXF structures can interfere
1058 // with the normal operation of the wrapper. Caveat emptor!
1060 ASDCP::MXF::OPAtomIndexFooter&
1061 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1063 if ( m_Writer.empty() )
1065 assert(g_OPAtomIndexFooter);
1066 return *g_OPAtomIndexFooter;
1069 return m_Writer->m_FooterPart;
1072 // Open the file for writing. The file must not exist. Returns error if
1073 // the operation cannot be completed.
1075 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1076 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1078 if ( Info.LabelSetType == LS_MXF_SMPTE )
1079 m_Writer = new h__Writer(DefaultSMPTEDict());
1081 m_Writer = new h__Writer(DefaultInteropDict());
1083 m_Writer->m_Info = Info;
1085 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1087 if ( ASDCP_SUCCESS(result) )
1088 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1090 if ( ASDCP_FAILURE(result) )
1097 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1098 // argument is present, the essence is encrypted prior to writing.
1099 // Fails if the file is not open, is finalized, or an operating system
1102 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1104 if ( m_Writer.empty() )
1107 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1110 // Closes the MXF file, writing the index and other closing information.
1112 ASDCP::JP2K::MXFWriter::Finalize()
1114 if ( m_Writer.empty() )
1117 return m_Writer->Finalize();
1121 //------------------------------------------------------------------------------------------
1125 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1127 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1129 StereoscopicPhase_t m_NextPhase;
1132 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1135 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1136 AESEncContext* Ctx, HMACContext* HMAC)
1138 if ( m_NextPhase != phase )
1139 return RESULT_SPHASE;
1141 if ( phase == SP_LEFT )
1143 m_NextPhase = SP_RIGHT;
1144 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1147 m_NextPhase = SP_LEFT;
1148 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1154 if ( m_NextPhase != SP_LEFT )
1155 return RESULT_SPHASE;
1157 assert( m_FramesWritten % 2 == 0 );
1158 m_FramesWritten /= 2;
1159 return lh__Writer::Finalize();
1165 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1169 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1173 // Warning: direct manipulation of MXF structures can interfere
1174 // with the normal operation of the wrapper. Caveat emptor!
1176 ASDCP::MXF::OPAtomHeader&
1177 ASDCP::JP2K::MXFSWriter::OPAtomHeader()
1179 if ( m_Writer.empty() )
1181 assert(g_OPAtomHeader);
1182 return *g_OPAtomHeader;
1185 return m_Writer->m_HeaderPart;
1188 // Warning: direct manipulation of MXF structures can interfere
1189 // with the normal operation of the wrapper. Caveat emptor!
1191 ASDCP::MXF::OPAtomIndexFooter&
1192 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1194 if ( m_Writer.empty() )
1196 assert(g_OPAtomIndexFooter);
1197 return *g_OPAtomIndexFooter;
1200 return m_Writer->m_FooterPart;
1203 // Open the file for writing. The file must not exist. Returns error if
1204 // the operation cannot be completed.
1206 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1207 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1209 if ( Info.LabelSetType == LS_MXF_SMPTE )
1210 m_Writer = new h__SWriter(DefaultSMPTEDict());
1212 m_Writer = new h__SWriter(DefaultInteropDict());
1214 if ( PDesc.EditRate != ASDCP::EditRate_24
1215 && PDesc.EditRate != ASDCP::EditRate_25
1216 && PDesc.EditRate != ASDCP::EditRate_30
1217 && PDesc.EditRate != ASDCP::EditRate_48
1218 && PDesc.EditRate != ASDCP::EditRate_50
1219 && PDesc.EditRate != ASDCP::EditRate_60 )
1221 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1222 return RESULT_FORMAT;
1225 if ( PDesc.StoredWidth > 2048 )
1226 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1228 m_Writer->m_Info = Info;
1230 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1232 if ( ASDCP_SUCCESS(result) )
1234 PictureDescriptor TmpPDesc = PDesc;
1236 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1237 TmpPDesc.EditRate = ASDCP::EditRate_48;
1239 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1240 TmpPDesc.EditRate = ASDCP::EditRate_50;
1242 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1243 TmpPDesc.EditRate = ASDCP::EditRate_60;
1245 else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1246 TmpPDesc.EditRate = ASDCP::EditRate_96;
1248 else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1249 TmpPDesc.EditRate = ASDCP::EditRate_100;
1251 else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1252 TmpPDesc.EditRate = ASDCP::EditRate_120;
1254 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1257 if ( ASDCP_FAILURE(result) )
1264 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1266 if ( m_Writer.empty() )
1269 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1271 if ( ASDCP_SUCCESS(result) )
1272 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1277 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1278 // argument is present, the essence is encrypted prior to writing.
1279 // Fails if the file is not open, is finalized, or an operating system
1282 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1283 AESEncContext* Ctx, HMACContext* HMAC)
1285 if ( m_Writer.empty() )
1288 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1291 // Closes the MXF file, writing the index and other closing information.
1293 ASDCP::JP2K::MXFSWriter::Finalize()
1295 if ( m_Writer.empty() )
1298 return m_Writer->Finalize();
1302 // end AS_DCP_JP2K.cpp