2 Copyright (c) 2004-2010, 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__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 )
320 DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
321 return RESULT_SFORMAT;
324 return RESULT_FORMAT;
327 else if ( type == ASDCP::ESS_JPEG_2000_S )
329 if ( m_EditRate == EditRate_24 )
331 if ( m_SampleRate != EditRate_48 )
333 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
334 return RESULT_FORMAT;
337 else if ( m_EditRate == EditRate_25 )
339 if ( m_SampleRate != EditRate_50 )
341 DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
342 return RESULT_FORMAT;
345 else if ( m_EditRate == EditRate_30 )
347 if ( m_SampleRate != EditRate_60 )
349 DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
350 return RESULT_FORMAT;
355 DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
356 m_EditRate.Numerator, m_EditRate.Denominator);
357 return RESULT_FORMAT;
362 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
366 result = MD_to_JP2K_PDesc(m_PDesc);
369 if( ASDCP_SUCCESS(result) )
370 result = InitMXFIndex();
372 if( ASDCP_SUCCESS(result) )
381 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
382 AESDecContext* Ctx, HMACContext* HMAC)
384 if ( ! m_File.IsOpen() )
388 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
393 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
395 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
399 h__Reader(const Dictionary& d) : lh__Reader(d) {}
404 //------------------------------------------------------------------------------------------
409 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
414 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
419 Kumu::hexdump(m_Data, dump_len, stream);
423 //------------------------------------------------------------------------------------------
425 ASDCP::JP2K::MXFReader::MXFReader()
427 m_Reader = new h__Reader(DefaultCompositeDict());
431 ASDCP::JP2K::MXFReader::~MXFReader()
435 // Open the file for reading. The file must exist. Returns error if the
436 // operation cannot be completed.
438 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
440 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
445 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
446 AESDecContext* Ctx, HMACContext* HMAC) const
448 if ( m_Reader && m_Reader->m_File.IsOpen() )
449 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
455 // Fill the struct with the values from the file's header.
456 // Returns RESULT_INIT if the file is not open.
458 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
460 if ( m_Reader && m_Reader->m_File.IsOpen() )
462 PDesc = m_Reader->m_PDesc;
470 // Fill the struct with the values from the file's header.
471 // Returns RESULT_INIT if the file is not open.
473 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
475 if ( m_Reader && m_Reader->m_File.IsOpen() )
477 Info = m_Reader->m_Info;
486 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
488 if ( m_Reader->m_File.IsOpen() )
489 m_Reader->m_HeaderPart.Dump(stream);
495 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
497 if ( m_Reader->m_File.IsOpen() )
498 m_Reader->m_FooterPart.Dump(stream);
503 ASDCP::JP2K::MXFReader::Close() const
505 if ( m_Reader && m_Reader->m_File.IsOpen() )
515 //------------------------------------------------------------------------------------------
518 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
520 ui32_t m_StereoFrameReady;
523 h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
526 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
527 AESDecContext* Ctx, HMACContext* HMAC)
529 // look up frame index node
530 IndexTableSegment::IndexEntry TmpEntry;
532 if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
534 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
538 // get frame position
539 Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
540 Result_t result = RESULT_OK;
542 if ( phase == SP_LEFT )
544 if ( FilePosition != m_LastPosition )
546 m_LastPosition = FilePosition;
547 result = m_File.Seek(FilePosition);
550 // the call to ReadEKLVPacket() will leave the file on an R frame
551 m_StereoFrameReady = FrameNum;
553 else if ( phase == SP_RIGHT )
555 if ( m_StereoFrameReady != FrameNum )
557 // the file is not already positioned, we must do some work
558 // seek to the companion SP_LEFT frame and read the frame's key and length
559 if ( FilePosition != m_LastPosition )
561 m_LastPosition = FilePosition;
562 result = m_File.Seek(FilePosition);
566 result = Reader.ReadKLFromFile(m_File);
568 if ( ASDCP_SUCCESS(result) )
570 // skip over the companion SP_LEFT frame
571 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
572 result = m_File.Seek(new_pos);
576 // the call to ReadEKLVPacket() will leave the file not on an R frame
577 m_StereoFrameReady = 0xffffffff;
581 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
585 if( ASDCP_SUCCESS(result) )
587 ui32_t SequenceNum = FrameNum * 2;
588 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
590 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
599 ASDCP::JP2K::MXFSReader::MXFSReader()
601 m_Reader = new h__SReader(DefaultCompositeDict());
605 ASDCP::JP2K::MXFSReader::~MXFSReader()
609 // Open the file for reading. The file must exist. Returns error if the
610 // operation cannot be completed.
612 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
614 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
619 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
621 Result_t result = RESULT_INIT;
623 if ( m_Reader && m_Reader->m_File.IsOpen() )
625 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
627 if ( ASDCP_SUCCESS(result) )
628 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
636 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
637 AESDecContext* Ctx, HMACContext* HMAC) const
639 if ( m_Reader && m_Reader->m_File.IsOpen() )
640 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
645 // Fill the struct with the values from the file's header.
646 // Returns RESULT_INIT if the file is not open.
648 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
650 if ( m_Reader && m_Reader->m_File.IsOpen() )
652 PDesc = m_Reader->m_PDesc;
660 // Fill the struct with the values from the file's header.
661 // Returns RESULT_INIT if the file is not open.
663 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
665 if ( m_Reader && m_Reader->m_File.IsOpen() )
667 Info = m_Reader->m_Info;
676 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
678 if ( m_Reader->m_File.IsOpen() )
679 m_Reader->m_HeaderPart.Dump(stream);
685 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
687 if ( m_Reader->m_File.IsOpen() )
688 m_Reader->m_FooterPart.Dump(stream);
693 ASDCP::JP2K::MXFSReader::Close() const
695 if ( m_Reader && m_Reader->m_File.IsOpen() )
705 //------------------------------------------------------------------------------------------
709 class lh__Writer : public ASDCP::h__Writer
711 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
714 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
717 PictureDescriptor m_PDesc;
718 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
720 lh__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceSubDescriptor(0) {
721 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
726 Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
727 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
728 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
729 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
731 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
734 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
735 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
736 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
740 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
742 assert(m_EssenceDescriptor);
743 assert(m_EssenceSubDescriptor);
744 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
746 PDescObj->ContainerDuration = PDesc.ContainerDuration;
747 PDescObj->SampleRate = PDesc.EditRate;
748 PDescObj->FrameLayout = 0;
749 PDescObj->StoredWidth = PDesc.StoredWidth;
750 PDescObj->StoredHeight = PDesc.StoredHeight;
751 PDescObj->AspectRatio = PDesc.AspectRatio;
753 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
755 // PictureEssenceCoding UL =
756 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
758 // ComponentMaxRef ui32_t = 4095
759 // ComponentMinRef ui32_t = 0
760 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
764 if ( PDesc.StoredWidth < 2049 )
766 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
767 m_EssenceSubDescriptor->Rsize = 3;
771 PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
772 m_EssenceSubDescriptor->Rsize = 4;
775 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
776 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
777 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
778 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
779 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
780 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
781 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
782 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
783 m_EssenceSubDescriptor->Csize = PDesc.Csize;
785 const ui32_t tmp_buffer_len = 1024;
786 byte_t tmp_buffer[tmp_buffer_len];
788 *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
789 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
790 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
792 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
793 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
794 m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
796 ui32_t precinct_set_size = 0, i;
797 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
800 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
801 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
802 m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
804 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
805 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
806 m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
812 // Open the file for writing. The file must not exist. Returns error if
813 // the operation cannot be completed.
815 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
817 if ( ! m_State.Test_BEGIN() )
820 Result_t result = m_File.OpenWrite(filename);
822 if ( ASDCP_SUCCESS(result) )
824 m_HeaderSize = HeaderSize;
825 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
826 tmp_rgba->ComponentMaxRef = 4095;
827 tmp_rgba->ComponentMinRef = 0;
829 m_EssenceDescriptor = tmp_rgba;
830 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
831 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
833 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
834 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
836 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
838 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
839 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
840 GenRandomValue(StereoSubDesc->InstanceUID);
841 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
844 result = m_State.Goto_INIT();
850 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
852 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
855 if ( ! m_State.Test_INIT() )
858 if ( LocalEditRate == ASDCP::Rational(0,0) )
859 LocalEditRate = PDesc.EditRate;
862 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
864 if ( ASDCP_SUCCESS(result) )
866 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
867 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
868 result = m_State.Goto_READY();
871 if ( ASDCP_SUCCESS(result) )
873 ui32_t TCFrameRate = ( m_PDesc.EditRate == EditRate_23_98 ) ? 24 : m_PDesc.EditRate.Numerator;
875 result = WriteMXFHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
876 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
877 LocalEditRate, TCFrameRate);
883 // Writes a frame of essence to the MXF file. If the optional AESEncContext
884 // argument is present, the essence is encrypted prior to writing.
885 // Fails if the file is not open, is finalized, or an operating system
889 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
890 AESEncContext* Ctx, HMACContext* HMAC)
892 Result_t result = RESULT_OK;
894 if ( m_State.Test_READY() )
895 result = m_State.Goto_RUNNING(); // first time through
897 ui64_t StreamOffset = m_StreamOffset;
899 if ( ASDCP_SUCCESS(result) )
900 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
902 if ( ASDCP_SUCCESS(result) && add_index )
904 IndexTableSegment::IndexEntry Entry;
905 Entry.StreamOffset = StreamOffset;
906 m_FooterPart.PushIndexEntry(Entry);
914 // Closes the MXF file, writing the index and other closing information.
917 lh__Writer::Finalize()
919 if ( ! m_State.Test_RUNNING() )
922 m_State.Goto_FINAL();
924 return WriteMXFFooter();
929 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
931 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
935 h__Writer(const Dictionary& d) : lh__Writer(d) {}
939 //------------------------------------------------------------------------------------------
943 ASDCP::JP2K::MXFWriter::MXFWriter()
947 ASDCP::JP2K::MXFWriter::~MXFWriter()
952 // Open the file for writing. The file must not exist. Returns error if
953 // the operation cannot be completed.
955 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
956 const PictureDescriptor& PDesc, ui32_t HeaderSize)
958 if ( Info.LabelSetType == LS_MXF_SMPTE )
959 m_Writer = new h__Writer(DefaultSMPTEDict());
961 m_Writer = new h__Writer(DefaultInteropDict());
963 m_Writer->m_Info = Info;
965 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
967 if ( ASDCP_SUCCESS(result) )
968 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
970 if ( ASDCP_FAILURE(result) )
977 // Writes a frame of essence to the MXF file. If the optional AESEncContext
978 // argument is present, the essence is encrypted prior to writing.
979 // Fails if the file is not open, is finalized, or an operating system
982 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
984 if ( m_Writer.empty() )
987 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
990 // Closes the MXF file, writing the index and other closing information.
992 ASDCP::JP2K::MXFWriter::Finalize()
994 if ( m_Writer.empty() )
997 return m_Writer->Finalize();
1001 //------------------------------------------------------------------------------------------
1005 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1007 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1009 StereoscopicPhase_t m_NextPhase;
1012 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1015 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1016 AESEncContext* Ctx, HMACContext* HMAC)
1018 if ( m_NextPhase != phase )
1019 return RESULT_SPHASE;
1021 if ( phase == SP_LEFT )
1023 m_NextPhase = SP_RIGHT;
1024 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1027 m_NextPhase = SP_LEFT;
1028 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1034 if ( m_NextPhase != SP_LEFT )
1035 return RESULT_SPHASE;
1037 assert( m_FramesWritten % 2 == 0 );
1038 m_FramesWritten /= 2;
1039 return lh__Writer::Finalize();
1045 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1049 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1054 // Open the file for writing. The file must not exist. Returns error if
1055 // the operation cannot be completed.
1057 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1058 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1060 if ( Info.LabelSetType == LS_MXF_SMPTE )
1061 m_Writer = new h__SWriter(DefaultSMPTEDict());
1063 m_Writer = new h__SWriter(DefaultInteropDict());
1065 if ( PDesc.EditRate != ASDCP::EditRate_24
1066 && PDesc.EditRate != ASDCP::EditRate_25
1067 && PDesc.EditRate != ASDCP::EditRate_30 )
1069 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25 or 30 fps input streams.\n");
1070 return RESULT_FORMAT;
1073 if ( PDesc.StoredWidth > 2048 )
1074 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1076 m_Writer->m_Info = Info;
1078 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1080 if ( ASDCP_SUCCESS(result) )
1082 PictureDescriptor TmpPDesc = PDesc;
1084 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1085 TmpPDesc.EditRate = ASDCP::EditRate_48;
1087 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1088 TmpPDesc.EditRate = ASDCP::EditRate_50;
1090 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1091 TmpPDesc.EditRate = ASDCP::EditRate_60;
1093 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1096 if ( ASDCP_FAILURE(result) )
1103 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1105 if ( m_Writer.empty() )
1108 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1110 if ( ASDCP_SUCCESS(result) )
1111 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1116 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1117 // argument is present, the essence is encrypted prior to writing.
1118 // Fails if the file is not open, is finalized, or an operating system
1121 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1122 AESEncContext* Ctx, HMACContext* HMAC)
1124 if ( m_Writer.empty() )
1127 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1130 // Closes the MXF file, writing the index and other closing information.
1132 ASDCP::JP2K::MXFSWriter::Finalize()
1134 if ( m_Writer.empty() )
1137 return m_Writer->Finalize();
1141 // end AS_DCP_JP2K.cpp