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 = KM_i32_BE(MaxComponents); // three components
878 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
879 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
881 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
882 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
883 m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
885 ui32_t precinct_set_size = 0, i;
886 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
889 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
890 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
891 m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
893 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
894 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
895 m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
901 // Open the file for writing. The file must not exist. Returns error if
902 // the operation cannot be completed.
904 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
906 if ( ! m_State.Test_BEGIN() )
909 Result_t result = m_File.OpenWrite(filename);
911 if ( ASDCP_SUCCESS(result) )
913 m_HeaderSize = HeaderSize;
914 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
915 tmp_rgba->ComponentMaxRef = 4095;
916 tmp_rgba->ComponentMinRef = 0;
918 m_EssenceDescriptor = tmp_rgba;
919 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
920 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
922 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
923 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
925 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
927 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
928 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
929 GenRandomValue(StereoSubDesc->InstanceUID);
930 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
933 result = m_State.Goto_INIT();
939 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
941 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
944 if ( ! m_State.Test_INIT() )
947 if ( LocalEditRate == ASDCP::Rational(0,0) )
948 LocalEditRate = PDesc.EditRate;
951 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
953 if ( ASDCP_SUCCESS(result) )
955 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
956 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
957 result = m_State.Goto_READY();
960 if ( ASDCP_SUCCESS(result) )
962 ui32_t TCFrameRate = ( m_PDesc.EditRate == EditRate_23_98 ) ? 24 : m_PDesc.EditRate.Numerator;
964 result = WriteMXFHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
965 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
966 LocalEditRate, TCFrameRate);
972 // Writes a frame of essence to the MXF file. If the optional AESEncContext
973 // argument is present, the essence is encrypted prior to writing.
974 // Fails if the file is not open, is finalized, or an operating system
978 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
979 AESEncContext* Ctx, HMACContext* HMAC)
981 Result_t result = RESULT_OK;
983 if ( m_State.Test_READY() )
984 result = m_State.Goto_RUNNING(); // first time through
986 ui64_t StreamOffset = m_StreamOffset;
988 if ( ASDCP_SUCCESS(result) )
989 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
991 if ( ASDCP_SUCCESS(result) && add_index )
993 IndexTableSegment::IndexEntry Entry;
994 Entry.StreamOffset = StreamOffset;
995 m_FooterPart.PushIndexEntry(Entry);
1003 // Closes the MXF file, writing the index and other closing information.
1006 lh__Writer::Finalize()
1008 if ( ! m_State.Test_RUNNING() )
1009 return RESULT_STATE;
1011 m_State.Goto_FINAL();
1013 return WriteMXFFooter();
1018 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1020 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1024 h__Writer(const Dictionary& d) : lh__Writer(d) {}
1028 //------------------------------------------------------------------------------------------
1032 ASDCP::JP2K::MXFWriter::MXFWriter()
1036 ASDCP::JP2K::MXFWriter::~MXFWriter()
1040 // Warning: direct manipulation of MXF structures can interfere
1041 // with the normal operation of the wrapper. Caveat emptor!
1043 ASDCP::MXF::OPAtomHeader&
1044 ASDCP::JP2K::MXFWriter::OPAtomHeader()
1046 if ( m_Writer.empty() )
1048 assert(g_OPAtomHeader);
1049 return *g_OPAtomHeader;
1052 return m_Writer->m_HeaderPart;
1055 // Warning: direct manipulation of MXF structures can interfere
1056 // with the normal operation of the wrapper. Caveat emptor!
1058 ASDCP::MXF::OPAtomIndexFooter&
1059 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1061 if ( m_Writer.empty() )
1063 assert(g_OPAtomIndexFooter);
1064 return *g_OPAtomIndexFooter;
1067 return m_Writer->m_FooterPart;
1070 // Open the file for writing. The file must not exist. Returns error if
1071 // the operation cannot be completed.
1073 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1074 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1076 if ( Info.LabelSetType == LS_MXF_SMPTE )
1077 m_Writer = new h__Writer(DefaultSMPTEDict());
1079 m_Writer = new h__Writer(DefaultInteropDict());
1081 m_Writer->m_Info = Info;
1083 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1085 if ( ASDCP_SUCCESS(result) )
1086 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1088 if ( ASDCP_FAILURE(result) )
1095 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1096 // argument is present, the essence is encrypted prior to writing.
1097 // Fails if the file is not open, is finalized, or an operating system
1100 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1102 if ( m_Writer.empty() )
1105 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1108 // Closes the MXF file, writing the index and other closing information.
1110 ASDCP::JP2K::MXFWriter::Finalize()
1112 if ( m_Writer.empty() )
1115 return m_Writer->Finalize();
1119 //------------------------------------------------------------------------------------------
1123 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1125 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1127 StereoscopicPhase_t m_NextPhase;
1130 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1133 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1134 AESEncContext* Ctx, HMACContext* HMAC)
1136 if ( m_NextPhase != phase )
1137 return RESULT_SPHASE;
1139 if ( phase == SP_LEFT )
1141 m_NextPhase = SP_RIGHT;
1142 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1145 m_NextPhase = SP_LEFT;
1146 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1152 if ( m_NextPhase != SP_LEFT )
1153 return RESULT_SPHASE;
1155 assert( m_FramesWritten % 2 == 0 );
1156 m_FramesWritten /= 2;
1157 return lh__Writer::Finalize();
1163 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1167 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1171 // Warning: direct manipulation of MXF structures can interfere
1172 // with the normal operation of the wrapper. Caveat emptor!
1174 ASDCP::MXF::OPAtomHeader&
1175 ASDCP::JP2K::MXFSWriter::OPAtomHeader()
1177 if ( m_Writer.empty() )
1179 assert(g_OPAtomHeader);
1180 return *g_OPAtomHeader;
1183 return m_Writer->m_HeaderPart;
1186 // Warning: direct manipulation of MXF structures can interfere
1187 // with the normal operation of the wrapper. Caveat emptor!
1189 ASDCP::MXF::OPAtomIndexFooter&
1190 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1192 if ( m_Writer.empty() )
1194 assert(g_OPAtomIndexFooter);
1195 return *g_OPAtomIndexFooter;
1198 return m_Writer->m_FooterPart;
1201 // Open the file for writing. The file must not exist. Returns error if
1202 // the operation cannot be completed.
1204 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1205 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1207 if ( Info.LabelSetType == LS_MXF_SMPTE )
1208 m_Writer = new h__SWriter(DefaultSMPTEDict());
1210 m_Writer = new h__SWriter(DefaultInteropDict());
1212 if ( PDesc.EditRate != ASDCP::EditRate_24
1213 && PDesc.EditRate != ASDCP::EditRate_25
1214 && PDesc.EditRate != ASDCP::EditRate_30
1215 && PDesc.EditRate != ASDCP::EditRate_48
1216 && PDesc.EditRate != ASDCP::EditRate_50
1217 && PDesc.EditRate != ASDCP::EditRate_60 )
1219 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1220 return RESULT_FORMAT;
1223 if ( PDesc.StoredWidth > 2048 )
1224 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1226 m_Writer->m_Info = Info;
1228 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1230 if ( ASDCP_SUCCESS(result) )
1232 PictureDescriptor TmpPDesc = PDesc;
1234 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1235 TmpPDesc.EditRate = ASDCP::EditRate_48;
1237 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1238 TmpPDesc.EditRate = ASDCP::EditRate_50;
1240 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1241 TmpPDesc.EditRate = ASDCP::EditRate_60;
1243 else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1244 TmpPDesc.EditRate = ASDCP::EditRate_96;
1246 else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1247 TmpPDesc.EditRate = ASDCP::EditRate_100;
1249 else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1250 TmpPDesc.EditRate = ASDCP::EditRate_120;
1252 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1255 if ( ASDCP_FAILURE(result) )
1262 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1264 if ( m_Writer.empty() )
1267 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1269 if ( ASDCP_SUCCESS(result) )
1270 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1275 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1276 // argument is present, the essence is encrypted prior to writing.
1277 // Fails if the file is not open, is finalized, or an operating system
1280 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1281 AESEncContext* Ctx, HMACContext* HMAC)
1283 if ( m_Writer.empty() )
1286 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1289 // Closes the MXF file, writing the index and other closing information.
1291 ASDCP::JP2K::MXFSWriter::Finalize()
1293 if ( m_Writer.empty() )
1296 return m_Writer->Finalize();
1300 // end AS_DCP_JP2K.cpp