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
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 const ASDCP::Dictionary *sg_dict = &DefaultSMPTEDict();
42 static MXF::OPAtomHeader sg_OPAtomHeader(sg_dict);
43 static MXF::OPAtomIndexFooter sg_OPAtomIndexFooter(sg_dict);
45 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
46 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
47 static std::string PICT_DEF_LABEL = "Picture Track";
49 int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
53 ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc)
55 strm << " AspectRatio: " << PDesc.AspectRatio.Numerator << "/" << PDesc.AspectRatio.Denominator << std::endl;
56 strm << " EditRate: " << PDesc.EditRate.Numerator << "/" << PDesc.EditRate.Denominator << std::endl;
57 strm << " SampleRate: " << PDesc.SampleRate.Numerator << "/" << PDesc.SampleRate.Denominator << std::endl;
58 strm << " StoredWidth: " << (unsigned) PDesc.StoredWidth << std::endl;
59 strm << " StoredHeight: " << (unsigned) PDesc.StoredHeight << std::endl;
60 strm << " Rsize: " << (unsigned) PDesc.Rsize << std::endl;
61 strm << " Xsize: " << (unsigned) PDesc.Xsize << std::endl;
62 strm << " Ysize: " << (unsigned) PDesc.Ysize << std::endl;
63 strm << " XOsize: " << (unsigned) PDesc.XOsize << std::endl;
64 strm << " YOsize: " << (unsigned) PDesc.YOsize << std::endl;
65 strm << " XTsize: " << (unsigned) PDesc.XTsize << std::endl;
66 strm << " YTsize: " << (unsigned) PDesc.YTsize << std::endl;
67 strm << " XTOsize: " << (unsigned) PDesc.XTOsize << std::endl;
68 strm << " YTOsize: " << (unsigned) PDesc.YTOsize << std::endl;
69 strm << " ContainerDuration: " << (unsigned) PDesc.ContainerDuration << std::endl;
71 strm << "-- JPEG 2000 Metadata --" << std::endl;
72 strm << " ImageComponents:" << std::endl;
73 strm << " bits h-sep v-sep" << std::endl;
76 for ( i = 0; i < PDesc.Csize; i++ )
78 strm << " " << std::setw(4) << PDesc.ImageComponents[i].Ssize + 1 /* See ISO 15444-1, Table A11, for the origin of '+1' */
79 << " " << std::setw(5) << PDesc.ImageComponents[i].XRsize
80 << " " << std::setw(5) << PDesc.ImageComponents[i].YRsize
84 strm << " Scod: " << (short) PDesc.CodingStyleDefault.Scod << std::endl;
85 strm << " ProgressionOrder: " << (short) PDesc.CodingStyleDefault.SGcod.ProgressionOrder << std::endl;
86 strm << " NumberOfLayers: " << (short) KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)) << std::endl;
87 strm << " MultiCompTransform: " << (short) PDesc.CodingStyleDefault.SGcod.MultiCompTransform << std::endl;
88 strm << "DecompositionLevels: " << (short) PDesc.CodingStyleDefault.SPcod.DecompositionLevels << std::endl;
89 strm << " CodeblockWidth: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockWidth << std::endl;
90 strm << " CodeblockHeight: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockHeight << std::endl;
91 strm << " CodeblockStyle: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockStyle << std::endl;
92 strm << " Transformation: " << (short) PDesc.CodingStyleDefault.SPcod.Transformation << std::endl;
95 ui32_t precinct_set_size = 0;
97 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
100 strm << " Precincts: " << (short) precinct_set_size << std::endl;
101 strm << "precinct dimensions:" << std::endl;
103 for ( i = 0; i < precinct_set_size; i++ )
104 strm << " " << i + 1 << ": " << s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f] << " x "
105 << s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] << std::endl;
107 strm << " Sqcd: " << (short) PDesc.QuantizationDefault.Sqcd << std::endl;
109 char tmp_buf[MaxDefaults*2];
110 strm << " SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2)
118 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
124 AspectRatio: %d/%d\n\
138 ContainerDuration: %u\n",
139 PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
140 PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
141 PDesc.SampleRate.Numerator, PDesc.SampleRate.Denominator,
153 PDesc.ContainerDuration
156 fprintf(stream, "-- JPEG 2000 Metadata --\n");
157 fprintf(stream, " ImageComponents:\n");
158 fprintf(stream, " bits h-sep v-sep\n");
161 for ( i = 0; i < PDesc.Csize; i++ )
163 fprintf(stream, " %4d %5d %5d\n",
164 PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
165 PDesc.ImageComponents[i].XRsize,
166 PDesc.ImageComponents[i].YRsize
170 fprintf(stream, " Scod: %hd\n", PDesc.CodingStyleDefault.Scod);
171 fprintf(stream, " ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
172 fprintf(stream, " NumberOfLayers: %hd\n",
173 KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
175 fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
176 fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
177 fprintf(stream, " CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
178 fprintf(stream, " CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
179 fprintf(stream, " CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
180 fprintf(stream, " Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
183 ui32_t precinct_set_size = 0;
185 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
188 fprintf(stream, " Precincts: %hd\n", precinct_set_size);
189 fprintf(stream, "precinct dimensions:\n");
191 for ( i = 0; i < precinct_set_size; i++ )
192 fprintf(stream, " %d: %d x %d\n", i + 1,
193 s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
194 s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
197 fprintf(stream, " Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd);
199 char tmp_buf[MaxDefaults*2];
200 fprintf(stream, " SPqcd: %s\n",
201 Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
202 tmp_buf, MaxDefaults*2)
207 //------------------------------------------------------------------------------------------
209 // hidden, internal implementation of JPEG 2000 reader
212 class lh__Reader : public ASDCP::h__Reader
214 RGBAEssenceDescriptor* m_EssenceDescriptor;
215 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
216 ASDCP::Rational m_EditRate;
217 ASDCP::Rational m_SampleRate;
218 EssenceType_t m_Format;
220 ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
223 PictureDescriptor m_PDesc; // codestream parameter list
225 lh__Reader(const Dictionary& d) :
226 ASDCP::h__Reader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
227 Result_t OpenRead(const char*, EssenceType_t);
228 Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
229 Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
234 lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
236 memset(&PDesc, 0, sizeof(PDesc));
237 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
239 PDesc.EditRate = m_EditRate;
240 PDesc.SampleRate = m_SampleRate;
241 assert(PDescObj->ContainerDuration <= 0xFFFFFFFFL);
242 PDesc.ContainerDuration = (ui32_t) PDescObj->ContainerDuration;
243 PDesc.StoredWidth = PDescObj->StoredWidth;
244 PDesc.StoredHeight = PDescObj->StoredHeight;
245 PDesc.AspectRatio = PDescObj->AspectRatio;
247 if ( m_EssenceSubDescriptor != 0 )
249 PDesc.Rsize = m_EssenceSubDescriptor->Rsize;
250 PDesc.Xsize = m_EssenceSubDescriptor->Xsize;
251 PDesc.Ysize = m_EssenceSubDescriptor->Ysize;
252 PDesc.XOsize = m_EssenceSubDescriptor->XOsize;
253 PDesc.YOsize = m_EssenceSubDescriptor->YOsize;
254 PDesc.XTsize = m_EssenceSubDescriptor->XTsize;
255 PDesc.YTsize = m_EssenceSubDescriptor->YTsize;
256 PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
257 PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
258 PDesc.Csize = m_EssenceSubDescriptor->Csize;
260 // PictureComponentSizing
261 ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
263 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
264 memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
267 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
269 // CodingStyleDefault
270 memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
271 memcpy(&PDesc.CodingStyleDefault,
272 m_EssenceSubDescriptor->CodingStyleDefault.RoData(),
273 m_EssenceSubDescriptor->CodingStyleDefault.Length());
275 // QuantizationDefault
276 memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
277 memcpy(&PDesc.QuantizationDefault,
278 m_EssenceSubDescriptor->QuantizationDefault.RoData(),
279 m_EssenceSubDescriptor->QuantizationDefault.Length());
281 PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1;
290 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
292 Result_t result = OpenMXFRead(filename);
294 if( ASDCP_SUCCESS(result) )
296 InterchangeObject* tmp_iobj = 0;
297 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
298 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
300 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
301 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
303 std::list<InterchangeObject*> ObjectList;
304 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
306 if ( ObjectList.empty() )
308 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
309 return RESULT_FORMAT;
312 m_EditRate = ((Track*)ObjectList.front())->EditRate;
313 m_SampleRate = m_EssenceDescriptor->SampleRate;
315 if ( type == ASDCP::ESS_JPEG_2000 )
317 if ( m_EditRate != m_SampleRate )
319 DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
320 m_EditRate.Quotient(), m_SampleRate.Quotient());
322 if ( m_EditRate == EditRate_24 && m_SampleRate == EditRate_48 ||
323 m_EditRate == EditRate_25 && m_SampleRate == EditRate_50 ||
324 m_EditRate == EditRate_30 && m_SampleRate == EditRate_60 ||
325 m_EditRate == EditRate_48 && m_SampleRate == EditRate_96 ||
326 m_EditRate == EditRate_50 && m_SampleRate == EditRate_100 ||
327 m_EditRate == EditRate_60 && m_SampleRate == EditRate_120 )
329 DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
330 return RESULT_SFORMAT;
333 return RESULT_FORMAT;
336 else if ( type == ASDCP::ESS_JPEG_2000_S )
338 if ( m_EditRate == EditRate_24 )
340 if ( m_SampleRate != EditRate_48 )
342 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
343 return RESULT_FORMAT;
346 else if ( m_EditRate == EditRate_25 )
348 if ( m_SampleRate != EditRate_50 )
350 DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
351 return RESULT_FORMAT;
354 else if ( m_EditRate == EditRate_30 )
356 if ( m_SampleRate != EditRate_60 )
358 DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
359 return RESULT_FORMAT;
362 else if ( m_EditRate == EditRate_48 )
364 if ( m_SampleRate != EditRate_96 )
366 DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
367 return RESULT_FORMAT;
370 else if ( m_EditRate == EditRate_50 )
372 if ( m_SampleRate != EditRate_100 )
374 DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
375 return RESULT_FORMAT;
378 else if ( m_EditRate == EditRate_60 )
380 if ( m_SampleRate != EditRate_120 )
382 DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
383 return RESULT_FORMAT;
388 DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
389 m_EditRate.Numerator, m_EditRate.Denominator);
390 return RESULT_FORMAT;
395 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
399 result = MD_to_JP2K_PDesc(m_PDesc);
402 if( ASDCP_SUCCESS(result) )
403 result = InitMXFIndex();
405 if( ASDCP_SUCCESS(result) )
414 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
415 AESDecContext* Ctx, HMACContext* HMAC)
417 if ( ! m_File.IsOpen() )
421 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
426 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
428 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
432 h__Reader(const Dictionary& d) : lh__Reader(d) {}
437 //------------------------------------------------------------------------------------------
442 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
447 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
452 Kumu::hexdump(m_Data, dump_len, stream);
456 //------------------------------------------------------------------------------------------
458 ASDCP::JP2K::MXFReader::MXFReader()
460 m_Reader = new h__Reader(DefaultCompositeDict());
464 ASDCP::JP2K::MXFReader::~MXFReader()
468 // Warning: direct manipulation of MXF structures can interfere
469 // with the normal operation of the wrapper. Caveat emptor!
471 ASDCP::MXF::OPAtomHeader&
472 ASDCP::JP2K::MXFReader::OPAtomHeader()
474 if ( m_Reader.empty() )
475 return sg_OPAtomHeader;
477 return m_Reader->m_HeaderPart;
480 // Warning: direct manipulation of MXF structures can interfere
481 // with the normal operation of the wrapper. Caveat emptor!
483 ASDCP::MXF::OPAtomIndexFooter&
484 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
486 if ( m_Reader.empty() )
487 return sg_OPAtomIndexFooter;
489 return m_Reader->m_FooterPart;
492 // Open the file for reading. The file must exist. Returns error if the
493 // operation cannot be completed.
495 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
497 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
502 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
503 AESDecContext* Ctx, HMACContext* HMAC) const
505 if ( m_Reader && m_Reader->m_File.IsOpen() )
506 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
512 // Fill the struct with the values from the file's header.
513 // Returns RESULT_INIT if the file is not open.
515 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
517 if ( m_Reader && m_Reader->m_File.IsOpen() )
519 PDesc = m_Reader->m_PDesc;
527 // Fill the struct with the values from the file's header.
528 // Returns RESULT_INIT if the file is not open.
530 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
532 if ( m_Reader && m_Reader->m_File.IsOpen() )
534 Info = m_Reader->m_Info;
543 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
545 if ( m_Reader->m_File.IsOpen() )
546 m_Reader->m_HeaderPart.Dump(stream);
552 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
554 if ( m_Reader->m_File.IsOpen() )
555 m_Reader->m_FooterPart.Dump(stream);
560 ASDCP::JP2K::MXFReader::Close() const
562 if ( m_Reader && m_Reader->m_File.IsOpen() )
572 //------------------------------------------------------------------------------------------
575 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
577 ui32_t m_StereoFrameReady;
580 h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
583 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
584 AESDecContext* Ctx, HMACContext* HMAC)
586 // look up frame index node
587 IndexTableSegment::IndexEntry TmpEntry;
589 if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
591 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
595 // get frame position
596 Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
597 Result_t result = RESULT_OK;
599 if ( phase == SP_LEFT )
601 if ( FilePosition != m_LastPosition )
603 m_LastPosition = FilePosition;
604 result = m_File.Seek(FilePosition);
607 // the call to ReadEKLVPacket() will leave the file on an R frame
608 m_StereoFrameReady = FrameNum;
610 else if ( phase == SP_RIGHT )
612 if ( m_StereoFrameReady != FrameNum )
614 // the file is not already positioned, we must do some work
615 // seek to the companion SP_LEFT frame and read the frame's key and length
616 if ( FilePosition != m_LastPosition )
618 m_LastPosition = FilePosition;
619 result = m_File.Seek(FilePosition);
623 result = Reader.ReadKLFromFile(m_File);
625 if ( ASDCP_SUCCESS(result) )
627 // skip over the companion SP_LEFT frame
628 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
629 result = m_File.Seek(new_pos);
633 // the call to ReadEKLVPacket() will leave the file not on an R frame
634 m_StereoFrameReady = 0xffffffff;
638 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
642 if( ASDCP_SUCCESS(result) )
644 ui32_t SequenceNum = FrameNum * 2;
645 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
647 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
656 ASDCP::JP2K::MXFSReader::MXFSReader()
658 m_Reader = new h__SReader(DefaultCompositeDict());
662 ASDCP::JP2K::MXFSReader::~MXFSReader()
666 // Warning: direct manipulation of MXF structures can interfere
667 // with the normal operation of the wrapper. Caveat emptor!
669 ASDCP::MXF::OPAtomHeader&
670 ASDCP::JP2K::MXFSReader::OPAtomHeader()
672 if ( m_Reader.empty() )
673 return sg_OPAtomHeader;
675 return m_Reader->m_HeaderPart;
678 // Warning: direct manipulation of MXF structures can interfere
679 // with the normal operation of the wrapper. Caveat emptor!
681 ASDCP::MXF::OPAtomIndexFooter&
682 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
684 if ( m_Reader.empty() )
685 return sg_OPAtomIndexFooter;
687 return m_Reader->m_FooterPart;
690 // Open the file for reading. The file must exist. Returns error if the
691 // operation cannot be completed.
693 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
695 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
700 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
702 Result_t result = RESULT_INIT;
704 if ( m_Reader && m_Reader->m_File.IsOpen() )
706 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
708 if ( ASDCP_SUCCESS(result) )
709 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
717 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
718 AESDecContext* Ctx, HMACContext* HMAC) const
720 if ( m_Reader && m_Reader->m_File.IsOpen() )
721 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
726 // Fill the struct with the values from the file's header.
727 // Returns RESULT_INIT if the file is not open.
729 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
731 if ( m_Reader && m_Reader->m_File.IsOpen() )
733 PDesc = m_Reader->m_PDesc;
741 // Fill the struct with the values from the file's header.
742 // Returns RESULT_INIT if the file is not open.
744 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
746 if ( m_Reader && m_Reader->m_File.IsOpen() )
748 Info = m_Reader->m_Info;
757 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
759 if ( m_Reader->m_File.IsOpen() )
760 m_Reader->m_HeaderPart.Dump(stream);
766 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
768 if ( m_Reader->m_File.IsOpen() )
769 m_Reader->m_FooterPart.Dump(stream);
774 ASDCP::JP2K::MXFSReader::Close() const
776 if ( m_Reader && m_Reader->m_File.IsOpen() )
786 //------------------------------------------------------------------------------------------
790 class lh__Writer : public ASDCP::h__Writer
792 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
795 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
798 PictureDescriptor m_PDesc;
799 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
801 lh__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceSubDescriptor(0) {
802 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
807 Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
808 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
809 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
810 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
812 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
815 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
816 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
817 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
821 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
823 assert(m_EssenceDescriptor);
824 assert(m_EssenceSubDescriptor);
825 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
827 PDescObj->ContainerDuration = PDesc.ContainerDuration;
828 PDescObj->SampleRate = PDesc.EditRate;
829 PDescObj->FrameLayout = 0;
830 PDescObj->StoredWidth = PDesc.StoredWidth;
831 PDescObj->StoredHeight = PDesc.StoredHeight;
832 PDescObj->AspectRatio = PDesc.AspectRatio;
834 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
836 // PictureEssenceCoding UL =
837 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
839 // ComponentMaxRef ui32_t = 4095
840 // ComponentMinRef ui32_t = 0
841 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
845 if ( PDesc.StoredWidth < 2049 )
847 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
848 m_EssenceSubDescriptor->Rsize = 3;
852 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
853 m_EssenceSubDescriptor->Rsize = 4;
856 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
857 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
858 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
859 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
860 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
861 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
862 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
863 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
864 m_EssenceSubDescriptor->Csize = PDesc.Csize;
866 const ui32_t tmp_buffer_len = 1024;
867 byte_t tmp_buffer[tmp_buffer_len];
869 *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
870 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
871 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
873 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
874 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
875 m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
877 ui32_t precinct_set_size = 0, i;
878 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
881 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
882 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
883 m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
885 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
886 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
887 m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
893 // Open the file for writing. The file must not exist. Returns error if
894 // the operation cannot be completed.
896 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
898 if ( ! m_State.Test_BEGIN() )
901 Result_t result = m_File.OpenWrite(filename);
903 if ( ASDCP_SUCCESS(result) )
905 m_HeaderSize = HeaderSize;
906 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
907 tmp_rgba->ComponentMaxRef = 4095;
908 tmp_rgba->ComponentMinRef = 0;
910 m_EssenceDescriptor = tmp_rgba;
911 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
912 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
914 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
915 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
917 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
919 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
920 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
921 GenRandomValue(StereoSubDesc->InstanceUID);
922 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
925 result = m_State.Goto_INIT();
931 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
933 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
936 if ( ! m_State.Test_INIT() )
939 if ( LocalEditRate == ASDCP::Rational(0,0) )
940 LocalEditRate = PDesc.EditRate;
943 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
945 if ( ASDCP_SUCCESS(result) )
947 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
948 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
949 result = m_State.Goto_READY();
952 if ( ASDCP_SUCCESS(result) )
954 ui32_t TCFrameRate = ( m_PDesc.EditRate == EditRate_23_98 ) ? 24 : m_PDesc.EditRate.Numerator;
956 result = WriteMXFHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
957 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
958 LocalEditRate, TCFrameRate);
964 // Writes a frame of essence to the MXF file. If the optional AESEncContext
965 // argument is present, the essence is encrypted prior to writing.
966 // Fails if the file is not open, is finalized, or an operating system
970 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
971 AESEncContext* Ctx, HMACContext* HMAC)
973 Result_t result = RESULT_OK;
975 if ( m_State.Test_READY() )
976 result = m_State.Goto_RUNNING(); // first time through
978 ui64_t StreamOffset = m_StreamOffset;
980 if ( ASDCP_SUCCESS(result) )
981 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
983 if ( ASDCP_SUCCESS(result) && add_index )
985 IndexTableSegment::IndexEntry Entry;
986 Entry.StreamOffset = StreamOffset;
987 m_FooterPart.PushIndexEntry(Entry);
995 // Closes the MXF file, writing the index and other closing information.
998 lh__Writer::Finalize()
1000 if ( ! m_State.Test_RUNNING() )
1001 return RESULT_STATE;
1003 m_State.Goto_FINAL();
1005 return WriteMXFFooter();
1010 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1012 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1016 h__Writer(const Dictionary& d) : lh__Writer(d) {}
1020 //------------------------------------------------------------------------------------------
1024 ASDCP::JP2K::MXFWriter::MXFWriter()
1028 ASDCP::JP2K::MXFWriter::~MXFWriter()
1032 // Warning: direct manipulation of MXF structures can interfere
1033 // with the normal operation of the wrapper. Caveat emptor!
1035 ASDCP::MXF::OPAtomHeader&
1036 ASDCP::JP2K::MXFWriter::OPAtomHeader()
1038 if ( m_Writer.empty() )
1039 return sg_OPAtomHeader;
1041 return m_Writer->m_HeaderPart;
1044 // Warning: direct manipulation of MXF structures can interfere
1045 // with the normal operation of the wrapper. Caveat emptor!
1047 ASDCP::MXF::OPAtomIndexFooter&
1048 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1050 if ( m_Writer.empty() )
1051 return sg_OPAtomIndexFooter;
1053 return m_Writer->m_FooterPart;
1056 // Open the file for writing. The file must not exist. Returns error if
1057 // the operation cannot be completed.
1059 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1060 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1062 if ( Info.LabelSetType == LS_MXF_SMPTE )
1063 m_Writer = new h__Writer(DefaultSMPTEDict());
1065 m_Writer = new h__Writer(DefaultInteropDict());
1067 m_Writer->m_Info = Info;
1069 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1071 if ( ASDCP_SUCCESS(result) )
1072 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1074 if ( ASDCP_FAILURE(result) )
1081 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1082 // argument is present, the essence is encrypted prior to writing.
1083 // Fails if the file is not open, is finalized, or an operating system
1086 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1088 if ( m_Writer.empty() )
1091 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1094 // Closes the MXF file, writing the index and other closing information.
1096 ASDCP::JP2K::MXFWriter::Finalize()
1098 if ( m_Writer.empty() )
1101 return m_Writer->Finalize();
1105 //------------------------------------------------------------------------------------------
1109 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1111 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1113 StereoscopicPhase_t m_NextPhase;
1116 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1119 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1120 AESEncContext* Ctx, HMACContext* HMAC)
1122 if ( m_NextPhase != phase )
1123 return RESULT_SPHASE;
1125 if ( phase == SP_LEFT )
1127 m_NextPhase = SP_RIGHT;
1128 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1131 m_NextPhase = SP_LEFT;
1132 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1138 if ( m_NextPhase != SP_LEFT )
1139 return RESULT_SPHASE;
1141 assert( m_FramesWritten % 2 == 0 );
1142 m_FramesWritten /= 2;
1143 return lh__Writer::Finalize();
1149 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1153 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1157 // Warning: direct manipulation of MXF structures can interfere
1158 // with the normal operation of the wrapper. Caveat emptor!
1160 ASDCP::MXF::OPAtomHeader&
1161 ASDCP::JP2K::MXFSWriter::OPAtomHeader()
1163 if ( m_Writer.empty() )
1164 return sg_OPAtomHeader;
1166 return m_Writer->m_HeaderPart;
1169 // Warning: direct manipulation of MXF structures can interfere
1170 // with the normal operation of the wrapper. Caveat emptor!
1172 ASDCP::MXF::OPAtomIndexFooter&
1173 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1175 if ( m_Writer.empty() )
1176 return sg_OPAtomIndexFooter;
1178 return m_Writer->m_FooterPart;
1181 // Open the file for writing. The file must not exist. Returns error if
1182 // the operation cannot be completed.
1184 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1185 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1187 if ( Info.LabelSetType == LS_MXF_SMPTE )
1188 m_Writer = new h__SWriter(DefaultSMPTEDict());
1190 m_Writer = new h__SWriter(DefaultInteropDict());
1192 if ( PDesc.EditRate != ASDCP::EditRate_24
1193 && PDesc.EditRate != ASDCP::EditRate_25
1194 && PDesc.EditRate != ASDCP::EditRate_30
1195 && PDesc.EditRate != ASDCP::EditRate_48
1196 && PDesc.EditRate != ASDCP::EditRate_50
1197 && PDesc.EditRate != ASDCP::EditRate_60 )
1199 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1200 return RESULT_FORMAT;
1203 if ( PDesc.StoredWidth > 2048 )
1204 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1206 m_Writer->m_Info = Info;
1208 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1210 if ( ASDCP_SUCCESS(result) )
1212 PictureDescriptor TmpPDesc = PDesc;
1214 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1215 TmpPDesc.EditRate = ASDCP::EditRate_48;
1217 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1218 TmpPDesc.EditRate = ASDCP::EditRate_50;
1220 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1221 TmpPDesc.EditRate = ASDCP::EditRate_60;
1223 else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1224 TmpPDesc.EditRate = ASDCP::EditRate_96;
1226 else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1227 TmpPDesc.EditRate = ASDCP::EditRate_100;
1229 else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1230 TmpPDesc.EditRate = ASDCP::EditRate_120;
1232 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1235 if ( ASDCP_FAILURE(result) )
1242 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1244 if ( m_Writer.empty() )
1247 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1249 if ( ASDCP_SUCCESS(result) )
1250 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1255 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1256 // argument is present, the essence is encrypted prior to writing.
1257 // Fails if the file is not open, is finalized, or an operating system
1260 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1261 AESEncContext* Ctx, HMACContext* HMAC)
1263 if ( m_Writer.empty() )
1266 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1269 // Closes the MXF file, writing the index and other closing information.
1271 ASDCP::JP2K::MXFSWriter::Finalize()
1273 if ( m_Writer.empty() )
1276 return m_Writer->Finalize();
1280 // end AS_DCP_JP2K.cpp