2 Copyright (c) 2004-2013, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 /*! \file AS_DCP_JP2k.cpp
29 \brief AS-DCP library, JPEG 2000 essence reader and writer implementation
32 #include "AS_DCP_internal.h"
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__ASDCPReader
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__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
224 virtual ~lh__Reader() {}
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;
286 // Compares the actual floating point value of the rates.
287 // This allows, for example, {300000,1001} and {2997,100) to be considered equivalent.
290 epsilon_compare(const ASDCP::Rational& left, const ASDCP::Rational& right, double epsilon = 0.001)
293 double difference = left.Quotient() - right.Quotient();
295 if (fabs(difference) < epsilon)
305 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
307 Result_t result = OpenMXFRead(filename);
309 if( ASDCP_SUCCESS(result) )
311 InterchangeObject* tmp_iobj = 0;
312 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
313 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
315 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
316 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
318 std::list<InterchangeObject*> ObjectList;
319 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
321 if ( ObjectList.empty() )
323 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
324 return RESULT_FORMAT;
327 m_EditRate = ((Track*)ObjectList.front())->EditRate;
328 m_SampleRate = m_EssenceDescriptor->SampleRate;
330 if ( type == ASDCP::ESS_JPEG_2000 )
332 if ( m_EditRate != m_SampleRate )
334 DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
335 m_EditRate.Quotient(), m_SampleRate.Quotient());
337 if ( m_EditRate == EditRate_24 && m_SampleRate == EditRate_48 ||
338 m_EditRate == EditRate_25 && m_SampleRate == EditRate_50 ||
339 m_EditRate == EditRate_30 && m_SampleRate == EditRate_60 ||
340 m_EditRate == EditRate_48 && m_SampleRate == EditRate_96 ||
341 m_EditRate == EditRate_50 && m_SampleRate == EditRate_100 ||
342 m_EditRate == EditRate_60 && m_SampleRate == EditRate_120 )
344 DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
345 return RESULT_SFORMAT;
348 return RESULT_FORMAT;
351 else if ( type == ASDCP::ESS_JPEG_2000_S )
353 if ( m_EditRate == EditRate_24 )
355 if ( m_SampleRate != EditRate_48 )
357 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
358 return RESULT_FORMAT;
361 else if ( m_EditRate == EditRate_25 )
363 if ( m_SampleRate != EditRate_50 )
365 DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
366 return RESULT_FORMAT;
369 else if ( m_EditRate == EditRate_30 )
371 if ( m_SampleRate != EditRate_60 )
373 DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
374 return RESULT_FORMAT;
377 else if ( m_EditRate == EditRate_48 )
379 if ( m_SampleRate != EditRate_96 )
381 DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
382 return RESULT_FORMAT;
385 else if ( m_EditRate == EditRate_50 )
387 if ( m_SampleRate != EditRate_100 )
389 DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
390 return RESULT_FORMAT;
393 else if ( m_EditRate == EditRate_60 )
395 if ( m_SampleRate != EditRate_120 )
397 DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
398 return RESULT_FORMAT;
403 DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
404 m_EditRate.Numerator, m_EditRate.Denominator);
405 return RESULT_FORMAT;
410 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
414 result = MD_to_JP2K_PDesc(m_PDesc);
423 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
424 AESDecContext* Ctx, HMACContext* HMAC)
426 if ( ! m_File.IsOpen() )
430 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
435 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
437 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
441 h__Reader(const Dictionary& d) : lh__Reader(d) {}
446 //------------------------------------------------------------------------------------------
451 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
456 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
461 Kumu::hexdump(m_Data, dump_len, stream);
465 //------------------------------------------------------------------------------------------
467 ASDCP::JP2K::MXFReader::MXFReader()
469 m_Reader = new h__Reader(DefaultCompositeDict());
473 ASDCP::JP2K::MXFReader::~MXFReader()
475 if ( m_Reader && m_Reader->m_File.IsOpen() )
479 // Warning: direct manipulation of MXF structures can interfere
480 // with the normal operation of the wrapper. Caveat emptor!
482 ASDCP::MXF::OP1aHeader&
483 ASDCP::JP2K::MXFReader::OP1aHeader()
485 if ( m_Reader.empty() )
487 assert(g_OP1aHeader);
488 return *g_OP1aHeader;
491 return m_Reader->m_HeaderPart;
494 // Warning: direct manipulation of MXF structures can interfere
495 // with the normal operation of the wrapper. Caveat emptor!
497 ASDCP::MXF::OPAtomIndexFooter&
498 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
500 if ( m_Reader.empty() )
502 assert(g_OPAtomIndexFooter);
503 return *g_OPAtomIndexFooter;
506 return m_Reader->m_IndexAccess;
509 // Warning: direct manipulation of MXF structures can interfere
510 // with the normal operation of the wrapper. Caveat emptor!
513 ASDCP::JP2K::MXFReader::RIP()
515 if ( m_Reader.empty() )
521 return m_Reader->m_RIP;
524 // Open the file for reading. The file must exist. Returns error if the
525 // operation cannot be completed.
527 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
529 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
534 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
535 AESDecContext* Ctx, HMACContext* HMAC) const
537 if ( m_Reader && m_Reader->m_File.IsOpen() )
538 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
544 ASDCP::JP2K::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
546 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
550 // Fill the struct with the values from the file's header.
551 // Returns RESULT_INIT if the file is not open.
553 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
555 if ( m_Reader && m_Reader->m_File.IsOpen() )
557 PDesc = m_Reader->m_PDesc;
565 // Fill the struct with the values from the file's header.
566 // Returns RESULT_INIT if the file is not open.
568 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
570 if ( m_Reader && m_Reader->m_File.IsOpen() )
572 Info = m_Reader->m_Info;
581 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
583 if ( m_Reader->m_File.IsOpen() )
584 m_Reader->m_HeaderPart.Dump(stream);
590 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
592 if ( m_Reader->m_File.IsOpen() )
593 m_Reader->m_IndexAccess.Dump(stream);
598 ASDCP::JP2K::MXFReader::Close() const
600 if ( m_Reader && m_Reader->m_File.IsOpen() )
610 //------------------------------------------------------------------------------------------
613 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
615 ui32_t m_StereoFrameReady;
618 h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
621 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
622 AESDecContext* Ctx, HMACContext* HMAC)
624 // look up frame index node
625 IndexTableSegment::IndexEntry TmpEntry;
627 if ( ASDCP_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
629 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
633 // get frame position
634 Kumu::fpos_t FilePosition = m_HeaderPart.BodyOffset + TmpEntry.StreamOffset;
635 Result_t result = RESULT_OK;
637 if ( phase == SP_LEFT )
639 if ( FilePosition != m_LastPosition )
641 m_LastPosition = FilePosition;
642 result = m_File.Seek(FilePosition);
645 // the call to ReadEKLVPacket() will leave the file on an R frame
646 m_StereoFrameReady = FrameNum;
648 else if ( phase == SP_RIGHT )
650 if ( m_StereoFrameReady != FrameNum )
652 // the file is not already positioned, we must do some work
653 // seek to the companion SP_LEFT frame and read the frame's key and length
654 if ( FilePosition != m_LastPosition )
656 m_LastPosition = FilePosition;
657 result = m_File.Seek(FilePosition);
661 result = Reader.ReadKLFromFile(m_File);
663 if ( ASDCP_SUCCESS(result) )
665 // skip over the companion SP_LEFT frame
666 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
667 result = m_File.Seek(new_pos);
671 // the call to ReadEKLVPacket() will leave the file not on an R frame
672 m_StereoFrameReady = 0xffffffff;
676 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
680 if( ASDCP_SUCCESS(result) )
682 ui32_t SequenceNum = FrameNum * 2;
683 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
685 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
694 ASDCP::JP2K::MXFSReader::MXFSReader()
696 m_Reader = new h__SReader(DefaultCompositeDict());
700 ASDCP::JP2K::MXFSReader::~MXFSReader()
702 if ( m_Reader && m_Reader->m_File.IsOpen() )
706 // Warning: direct manipulation of MXF structures can interfere
707 // with the normal operation of the wrapper. Caveat emptor!
709 ASDCP::MXF::OP1aHeader&
710 ASDCP::JP2K::MXFSReader::OP1aHeader()
712 if ( m_Reader.empty() )
714 assert(g_OP1aHeader);
715 return *g_OP1aHeader;
718 return m_Reader->m_HeaderPart;
721 // Warning: direct manipulation of MXF structures can interfere
722 // with the normal operation of the wrapper. Caveat emptor!
724 ASDCP::MXF::OPAtomIndexFooter&
725 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
727 if ( m_Reader.empty() )
729 assert(g_OPAtomIndexFooter);
730 return *g_OPAtomIndexFooter;
733 return m_Reader->m_IndexAccess;
736 // Warning: direct manipulation of MXF structures can interfere
737 // with the normal operation of the wrapper. Caveat emptor!
740 ASDCP::JP2K::MXFSReader::RIP()
742 if ( m_Reader.empty() )
748 return m_Reader->m_RIP;
751 // Open the file for reading. The file must exist. Returns error if the
752 // operation cannot be completed.
754 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
756 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
761 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
763 Result_t result = RESULT_INIT;
765 if ( m_Reader && m_Reader->m_File.IsOpen() )
767 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
769 if ( ASDCP_SUCCESS(result) )
770 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
778 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
779 AESDecContext* Ctx, HMACContext* HMAC) const
781 if ( m_Reader && m_Reader->m_File.IsOpen() )
782 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
788 ASDCP::JP2K::MXFSReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
790 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
793 // Fill the struct with the values from the file's header.
794 // Returns RESULT_INIT if the file is not open.
796 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
798 if ( m_Reader && m_Reader->m_File.IsOpen() )
800 PDesc = m_Reader->m_PDesc;
808 // Fill the struct with the values from the file's header.
809 // Returns RESULT_INIT if the file is not open.
811 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
813 if ( m_Reader && m_Reader->m_File.IsOpen() )
815 Info = m_Reader->m_Info;
824 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
826 if ( m_Reader->m_File.IsOpen() )
827 m_Reader->m_HeaderPart.Dump(stream);
833 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
835 if ( m_Reader->m_File.IsOpen() )
836 m_Reader->m_IndexAccess.Dump(stream);
841 ASDCP::JP2K::MXFSReader::Close() const
843 if ( m_Reader && m_Reader->m_File.IsOpen() )
853 //------------------------------------------------------------------------------------------
857 class lh__Writer : public ASDCP::h__ASDCPWriter
859 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
862 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
865 PictureDescriptor m_PDesc;
866 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
868 lh__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_EssenceSubDescriptor(0) {
869 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
872 virtual ~lh__Writer(){}
874 Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
875 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
876 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
877 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
879 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
882 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
883 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
884 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
888 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
890 assert(m_EssenceDescriptor);
891 assert(m_EssenceSubDescriptor);
892 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
894 PDescObj->ContainerDuration = PDesc.ContainerDuration;
895 PDescObj->SampleRate = PDesc.EditRate;
896 PDescObj->FrameLayout = 0;
897 PDescObj->StoredWidth = PDesc.StoredWidth;
898 PDescObj->StoredHeight = PDesc.StoredHeight;
899 PDescObj->AspectRatio = PDesc.AspectRatio;
901 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
903 // PictureEssenceCoding UL =
904 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
906 // ComponentMaxRef ui32_t = 4095
907 // ComponentMinRef ui32_t = 0
908 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
912 if ( PDesc.StoredWidth < 2049 )
914 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
915 m_EssenceSubDescriptor->Rsize = 3;
919 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
920 m_EssenceSubDescriptor->Rsize = 4;
923 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
924 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
925 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
926 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
927 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
928 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
929 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
930 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
931 m_EssenceSubDescriptor->Csize = PDesc.Csize;
933 const ui32_t tmp_buffer_len = 1024;
934 byte_t tmp_buffer[tmp_buffer_len];
936 *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
937 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
938 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
940 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
941 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
942 m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
944 ui32_t precinct_set_size = 0, i;
945 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
948 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
949 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
950 m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
952 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
953 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
954 m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
960 // Open the file for writing. The file must not exist. Returns error if
961 // the operation cannot be completed.
963 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
965 if ( ! m_State.Test_BEGIN() )
968 Result_t result = m_File.OpenWrite(filename);
970 if ( ASDCP_SUCCESS(result) )
972 m_HeaderSize = HeaderSize;
973 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
974 tmp_rgba->ComponentMaxRef = 4095;
975 tmp_rgba->ComponentMinRef = 0;
977 m_EssenceDescriptor = tmp_rgba;
978 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
979 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
981 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
982 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
984 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
986 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
987 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
988 GenRandomValue(StereoSubDesc->InstanceUID);
989 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
992 result = m_State.Goto_INIT();
998 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
1000 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
1003 if ( ! m_State.Test_INIT() )
1004 return RESULT_STATE;
1006 if ( LocalEditRate == ASDCP::Rational(0,0) )
1007 LocalEditRate = PDesc.EditRate;
1010 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
1012 if ( ASDCP_SUCCESS(result) )
1014 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
1015 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
1016 result = m_State.Goto_READY();
1019 if ( ASDCP_SUCCESS(result) )
1021 ui32_t TCFrameRate = ( m_PDesc.EditRate == EditRate_23_98 ) ? 24 : m_PDesc.EditRate.Numerator;
1023 result = WriteASDCPHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
1024 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
1025 LocalEditRate, TCFrameRate);
1031 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1032 // argument is present, the essence is encrypted prior to writing.
1033 // Fails if the file is not open, is finalized, or an operating system
1037 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
1038 AESEncContext* Ctx, HMACContext* HMAC)
1040 Result_t result = RESULT_OK;
1042 if ( m_State.Test_READY() )
1043 result = m_State.Goto_RUNNING(); // first time through
1045 ui64_t StreamOffset = m_StreamOffset;
1047 if ( ASDCP_SUCCESS(result) )
1048 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
1050 if ( ASDCP_SUCCESS(result) && add_index )
1052 IndexTableSegment::IndexEntry Entry;
1053 Entry.StreamOffset = StreamOffset;
1054 m_FooterPart.PushIndexEntry(Entry);
1062 // Closes the MXF file, writing the index and other closing information.
1065 lh__Writer::Finalize()
1067 if ( ! m_State.Test_RUNNING() )
1068 return RESULT_STATE;
1070 m_State.Goto_FINAL();
1072 return WriteASDCPFooter();
1077 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1079 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1083 h__Writer(const Dictionary& d) : lh__Writer(d) {}
1087 //------------------------------------------------------------------------------------------
1091 ASDCP::JP2K::MXFWriter::MXFWriter()
1095 ASDCP::JP2K::MXFWriter::~MXFWriter()
1099 // Warning: direct manipulation of MXF structures can interfere
1100 // with the normal operation of the wrapper. Caveat emptor!
1102 ASDCP::MXF::OP1aHeader&
1103 ASDCP::JP2K::MXFWriter::OP1aHeader()
1105 if ( m_Writer.empty() )
1107 assert(g_OP1aHeader);
1108 return *g_OP1aHeader;
1111 return m_Writer->m_HeaderPart;
1114 // Warning: direct manipulation of MXF structures can interfere
1115 // with the normal operation of the wrapper. Caveat emptor!
1117 ASDCP::MXF::OPAtomIndexFooter&
1118 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1120 if ( m_Writer.empty() )
1122 assert(g_OPAtomIndexFooter);
1123 return *g_OPAtomIndexFooter;
1126 return m_Writer->m_FooterPart;
1129 // Warning: direct manipulation of MXF structures can interfere
1130 // with the normal operation of the wrapper. Caveat emptor!
1133 ASDCP::JP2K::MXFWriter::RIP()
1135 if ( m_Writer.empty() )
1141 return m_Writer->m_RIP;
1144 // Open the file for writing. The file must not exist. Returns error if
1145 // the operation cannot be completed.
1147 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1148 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1150 if ( Info.LabelSetType == LS_MXF_SMPTE )
1151 m_Writer = new h__Writer(DefaultSMPTEDict());
1153 m_Writer = new h__Writer(DefaultInteropDict());
1155 m_Writer->m_Info = Info;
1157 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1159 if ( ASDCP_SUCCESS(result) )
1160 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1162 if ( ASDCP_FAILURE(result) )
1169 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1170 // argument is present, the essence is encrypted prior to writing.
1171 // Fails if the file is not open, is finalized, or an operating system
1174 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1176 if ( m_Writer.empty() )
1179 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1182 // Closes the MXF file, writing the index and other closing information.
1184 ASDCP::JP2K::MXFWriter::Finalize()
1186 if ( m_Writer.empty() )
1189 return m_Writer->Finalize();
1193 //------------------------------------------------------------------------------------------
1197 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1199 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1201 StereoscopicPhase_t m_NextPhase;
1204 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1207 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1208 AESEncContext* Ctx, HMACContext* HMAC)
1210 if ( m_NextPhase != phase )
1211 return RESULT_SPHASE;
1213 if ( phase == SP_LEFT )
1215 m_NextPhase = SP_RIGHT;
1216 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1219 m_NextPhase = SP_LEFT;
1220 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1226 if ( m_NextPhase != SP_LEFT )
1227 return RESULT_SPHASE;
1229 assert( m_FramesWritten % 2 == 0 );
1230 m_FramesWritten /= 2;
1231 return lh__Writer::Finalize();
1237 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1241 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1245 // Warning: direct manipulation of MXF structures can interfere
1246 // with the normal operation of the wrapper. Caveat emptor!
1248 ASDCP::MXF::OP1aHeader&
1249 ASDCP::JP2K::MXFSWriter::OP1aHeader()
1251 if ( m_Writer.empty() )
1253 assert(g_OP1aHeader);
1254 return *g_OP1aHeader;
1257 return m_Writer->m_HeaderPart;
1260 // Warning: direct manipulation of MXF structures can interfere
1261 // with the normal operation of the wrapper. Caveat emptor!
1263 ASDCP::MXF::OPAtomIndexFooter&
1264 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1266 if ( m_Writer.empty() )
1268 assert(g_OPAtomIndexFooter);
1269 return *g_OPAtomIndexFooter;
1272 return m_Writer->m_FooterPart;
1275 // Warning: direct manipulation of MXF structures can interfere
1276 // with the normal operation of the wrapper. Caveat emptor!
1279 ASDCP::JP2K::MXFSWriter::RIP()
1281 if ( m_Writer.empty() )
1287 return m_Writer->m_RIP;
1290 // Open the file for writing. The file must not exist. Returns error if
1291 // the operation cannot be completed.
1293 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1294 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1296 if ( Info.LabelSetType == LS_MXF_SMPTE )
1297 m_Writer = new h__SWriter(DefaultSMPTEDict());
1299 m_Writer = new h__SWriter(DefaultInteropDict());
1301 if ( PDesc.EditRate != ASDCP::EditRate_24
1302 && PDesc.EditRate != ASDCP::EditRate_25
1303 && PDesc.EditRate != ASDCP::EditRate_30
1304 && PDesc.EditRate != ASDCP::EditRate_48
1305 && PDesc.EditRate != ASDCP::EditRate_50
1306 && PDesc.EditRate != ASDCP::EditRate_60 )
1308 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1309 return RESULT_FORMAT;
1312 if ( PDesc.StoredWidth > 2048 )
1313 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1315 m_Writer->m_Info = Info;
1317 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1319 if ( ASDCP_SUCCESS(result) )
1321 PictureDescriptor TmpPDesc = PDesc;
1323 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1324 TmpPDesc.EditRate = ASDCP::EditRate_48;
1326 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1327 TmpPDesc.EditRate = ASDCP::EditRate_50;
1329 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1330 TmpPDesc.EditRate = ASDCP::EditRate_60;
1332 else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1333 TmpPDesc.EditRate = ASDCP::EditRate_96;
1335 else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1336 TmpPDesc.EditRate = ASDCP::EditRate_100;
1338 else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1339 TmpPDesc.EditRate = ASDCP::EditRate_120;
1341 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1344 if ( ASDCP_FAILURE(result) )
1351 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1353 if ( m_Writer.empty() )
1356 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1358 if ( ASDCP_SUCCESS(result) )
1359 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1364 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1365 // argument is present, the essence is encrypted prior to writing.
1366 // Fails if the file is not open, is finalized, or an operating system
1369 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1370 AESEncContext* Ctx, HMACContext* HMAC)
1372 if ( m_Writer.empty() )
1375 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1378 // Closes the MXF file, writing the index and other closing information.
1380 ASDCP::JP2K::MXFSWriter::Finalize()
1382 if ( m_Writer.empty() )
1385 return m_Writer->Finalize();
1389 // end AS_DCP_JP2K.cpp