2 Copyright (c) 2004-2008, 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"
34 using namespace ASDCP::JP2K;
35 using Kumu::GenRandomValue;
37 //------------------------------------------------------------------------------------------
39 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
40 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
41 static std::string PICT_DEF_LABEL = "Picture Track";
43 int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
47 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
66 ContainerDuration: %u\n",
67 PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
68 PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
80 PDesc.ContainerDuration
83 fprintf(stream, "-- JPEG 2000 Metadata --\n");
84 fprintf(stream, " ImageComponents:\n");
85 fprintf(stream, " bits h-sep v-sep\n");
88 for ( i = 0; i < PDesc.Csize; i++ )
90 fprintf(stream, " %4d %5d %5d\n",
91 PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
92 PDesc.ImageComponents[i].XRsize,
93 PDesc.ImageComponents[i].YRsize
97 fprintf(stream, " Scod: %hd\n", PDesc.CodingStyleDefault.Scod);
98 fprintf(stream, " ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
99 fprintf(stream, " NumberOfLayers: %hd\n",
100 KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
102 fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
103 fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
104 fprintf(stream, " CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
105 fprintf(stream, " CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
106 fprintf(stream, " CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
107 fprintf(stream, " Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
110 ui32_t precinct_set_size = 0;
112 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
115 fprintf(stream, " Precincts: %hd\n", precinct_set_size);
116 fprintf(stream, "precinct dimensions:\n");
118 for ( i = 0; i < precinct_set_size; i++ )
119 fprintf(stream, " %d: %d x %d\n", i + 1,
120 s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
121 s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
124 fprintf(stream, " Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd);
126 char tmp_buf[MaxDefaults*2];
127 fprintf(stream, " SPqcd: %s\n",
128 Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
129 tmp_buf, MaxDefaults*2)
133 //------------------------------------------------------------------------------------------
135 // hidden, internal implementation of JPEG 2000 reader
137 class lh__Reader : public ASDCP::h__Reader
139 RGBAEssenceDescriptor* m_EssenceDescriptor;
140 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
141 ASDCP::Rational m_EditRate;
142 EssenceType_t m_Format;
144 ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
147 PictureDescriptor m_PDesc; // codestream parameter list
149 lh__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
150 Result_t OpenRead(const char*, EssenceType_t);
151 Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
152 Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
157 lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
159 memset(&PDesc, 0, sizeof(PDesc));
160 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
162 PDesc.EditRate = m_EditRate;
163 PDesc.ContainerDuration = PDescObj->ContainerDuration;
164 PDesc.StoredWidth = PDescObj->StoredWidth;
165 PDesc.StoredHeight = PDescObj->StoredHeight;
166 PDesc.AspectRatio = PDescObj->AspectRatio;
168 if ( m_EssenceSubDescriptor != 0 )
170 PDesc.Rsize = m_EssenceSubDescriptor->Rsize;
171 PDesc.Xsize = m_EssenceSubDescriptor->Xsize;
172 PDesc.Ysize = m_EssenceSubDescriptor->Ysize;
173 PDesc.XOsize = m_EssenceSubDescriptor->XOsize;
174 PDesc.YOsize = m_EssenceSubDescriptor->YOsize;
175 PDesc.XTsize = m_EssenceSubDescriptor->XTsize;
176 PDesc.YTsize = m_EssenceSubDescriptor->YTsize;
177 PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
178 PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
179 PDesc.Csize = m_EssenceSubDescriptor->Csize;
181 // PictureComponentSizing
182 ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
184 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
185 memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
188 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
190 // CodingStyleDefault
191 memset(&m_PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
192 memcpy(&m_PDesc.CodingStyleDefault,
193 m_EssenceSubDescriptor->CodingStyleDefault.RoData(),
194 m_EssenceSubDescriptor->CodingStyleDefault.Length());
196 // QuantizationDefault
197 memset(&m_PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
198 memcpy(&m_PDesc.QuantizationDefault,
199 m_EssenceSubDescriptor->QuantizationDefault.RoData(),
200 m_EssenceSubDescriptor->QuantizationDefault.Length());
202 m_PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1;
211 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
213 Result_t result = OpenMXFRead(filename);
215 if( ASDCP_SUCCESS(result) )
217 InterchangeObject* tmp_iobj = 0;
218 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
219 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
221 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
222 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
224 std::list<InterchangeObject*> ObjectList;
225 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
227 if ( ObjectList.empty() )
229 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
230 return RESULT_FORMAT;
233 m_EditRate = ((Track*)ObjectList.front())->EditRate;
235 if ( type == ASDCP::ESS_JPEG_2000 )
237 if ( m_EditRate != m_EssenceDescriptor->SampleRate )
239 DefaultLogSink().Error("EditRate and SampleRate do not match (%.03f, %.03f).\n",
240 m_EditRate.Quotient(), m_EssenceDescriptor->SampleRate.Quotient());
242 if ( m_EditRate == EditRate_24 && m_EssenceDescriptor->SampleRate == EditRate_48 )
244 DefaultLogSink().Error("File may contain JPEG Interop stereoscopic images.\n");
245 return RESULT_SFORMAT;
248 return RESULT_FORMAT;
251 else if ( type == ASDCP::ESS_JPEG_2000_S )
253 if ( ! ( m_EditRate == EditRate_24 && m_EssenceDescriptor->SampleRate == EditRate_48 ) )
255 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
256 return RESULT_FORMAT;
261 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
265 result = MD_to_JP2K_PDesc(m_PDesc);
268 if( ASDCP_SUCCESS(result) )
269 result = InitMXFIndex();
271 if( ASDCP_SUCCESS(result) )
280 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
281 AESDecContext* Ctx, HMACContext* HMAC)
283 if ( ! m_File.IsOpen() )
286 return ReadEKLVFrame(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
291 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
297 //------------------------------------------------------------------------------------------
302 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
307 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
312 Kumu::hexdump(m_Data, dump_len, stream);
316 //------------------------------------------------------------------------------------------
318 ASDCP::JP2K::MXFReader::MXFReader()
320 m_Reader = new h__Reader;
324 ASDCP::JP2K::MXFReader::~MXFReader()
328 // Open the file for reading. The file must exist. Returns error if the
329 // operation cannot be completed.
331 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
333 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
338 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
339 AESDecContext* Ctx, HMACContext* HMAC) const
341 if ( m_Reader && m_Reader->m_File.IsOpen() )
342 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
348 // Fill the struct with the values from the file's header.
349 // Returns RESULT_INIT if the file is not open.
351 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
353 if ( m_Reader && m_Reader->m_File.IsOpen() )
355 PDesc = m_Reader->m_PDesc;
363 // Fill the struct with the values from the file's header.
364 // Returns RESULT_INIT if the file is not open.
366 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
368 if ( m_Reader && m_Reader->m_File.IsOpen() )
370 Info = m_Reader->m_Info;
379 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
381 if ( m_Reader->m_File.IsOpen() )
382 m_Reader->m_HeaderPart.Dump(stream);
388 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
390 if ( m_Reader->m_File.IsOpen() )
391 m_Reader->m_FooterPart.Dump(stream);
395 //------------------------------------------------------------------------------------------
397 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
399 ui32_t m_StereoFrameReady;
402 h__SReader() : m_StereoFrameReady(0xffffffff) {}
405 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
406 AESDecContext* Ctx, HMACContext* HMAC)
408 // look up frame index node
409 IndexTableSegment::IndexEntry TmpEntry;
411 if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
413 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
417 // get frame position
418 Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
419 Result_t result = RESULT_OK;
421 if ( phase == SP_LEFT )
423 if ( FilePosition != m_LastPosition )
425 m_LastPosition = FilePosition;
426 result = m_File.Seek(FilePosition);
429 // the call to ReadEKLVPacket() will leave the file on an R frame
430 m_StereoFrameReady = FrameNum;
432 else if ( phase == SP_RIGHT )
434 if ( m_StereoFrameReady != FrameNum )
436 // the file is not already positioned, we must do some work
437 // seek to the companion SP_LEFT frame and read the frame's key and length
438 if ( FilePosition != m_LastPosition )
440 m_LastPosition = FilePosition;
441 result = m_File.Seek(FilePosition);
445 result = Reader.ReadKLFromFile(m_File);
447 if ( ASDCP_SUCCESS(result) )
449 // skip over the companion SP_LEFT frame
450 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
451 result = m_File.Seek(new_pos);
455 // the call to ReadEKLVPacket() will leave the file not on an R frame
456 m_StereoFrameReady = 0xffffffff;
460 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
464 if( ASDCP_SUCCESS(result) )
466 ui32_t SequenceNum = FrameNum * 2;
467 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
468 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
477 ASDCP::JP2K::MXFSReader::MXFSReader()
479 m_Reader = new h__SReader;
483 ASDCP::JP2K::MXFSReader::~MXFSReader()
487 // Open the file for reading. The file must exist. Returns error if the
488 // operation cannot be completed.
490 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
492 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
497 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
499 Result_t result = RESULT_INIT;
501 if ( m_Reader && m_Reader->m_File.IsOpen() )
503 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
505 if ( ASDCP_SUCCESS(result) )
506 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
514 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
515 AESDecContext* Ctx, HMACContext* HMAC) const
517 if ( m_Reader && m_Reader->m_File.IsOpen() )
518 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
523 // Fill the struct with the values from the file's header.
524 // Returns RESULT_INIT if the file is not open.
526 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
528 if ( m_Reader && m_Reader->m_File.IsOpen() )
530 PDesc = m_Reader->m_PDesc;
538 // Fill the struct with the values from the file's header.
539 // Returns RESULT_INIT if the file is not open.
541 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
543 if ( m_Reader && m_Reader->m_File.IsOpen() )
545 Info = m_Reader->m_Info;
554 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
556 if ( m_Reader->m_File.IsOpen() )
557 m_Reader->m_HeaderPart.Dump(stream);
563 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
565 if ( m_Reader->m_File.IsOpen() )
566 m_Reader->m_FooterPart.Dump(stream);
569 //------------------------------------------------------------------------------------------
573 class lh__Writer : public ASDCP::h__Writer
575 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
578 PictureDescriptor m_PDesc;
579 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
581 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
583 lh__Writer() : m_EssenceSubDescriptor(0) {
584 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
589 Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
590 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
591 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
592 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
594 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
597 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
598 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
599 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
603 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
605 assert(m_EssenceDescriptor);
606 assert(m_EssenceSubDescriptor);
607 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
609 PDescObj->ContainerDuration = PDesc.ContainerDuration;
610 PDescObj->SampleRate = PDesc.EditRate;
611 PDescObj->FrameLayout = 0;
612 PDescObj->StoredWidth = PDesc.StoredWidth;
613 PDescObj->StoredHeight = PDesc.StoredHeight;
614 PDescObj->AspectRatio = PDesc.AspectRatio;
616 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
618 // PictureEssenceCoding UL =
619 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
621 // ComponentMaxRef ui32_t = 4095
622 // ComponentMinRef ui32_t = 0
623 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
626 if ( PDesc.StoredWidth < 2049 )
628 PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_2K));
629 m_EssenceSubDescriptor->Rsize = 3;
633 PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_4K));
634 m_EssenceSubDescriptor->Rsize = 4;
637 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
638 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
639 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
640 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
641 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
642 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
643 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
644 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
645 m_EssenceSubDescriptor->Csize = PDesc.Csize;
647 const ui32_t tmp_buffer_len = 1024;
648 byte_t tmp_buffer[tmp_buffer_len];
650 *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
651 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
652 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
654 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
655 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
656 m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
658 ui32_t precinct_set_size = 0, i;
659 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
662 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
663 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
664 m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
666 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
667 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
668 m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
674 // Open the file for writing. The file must not exist. Returns error if
675 // the operation cannot be completed.
677 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
679 if ( ! m_State.Test_BEGIN() )
682 Result_t result = m_File.OpenWrite(filename);
684 if ( ASDCP_SUCCESS(result) )
686 m_HeaderSize = HeaderSize;
687 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor;
688 tmp_rgba->ComponentMaxRef = 4095;
689 tmp_rgba->ComponentMinRef = 0;
691 m_EssenceDescriptor = tmp_rgba;
692 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
693 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
695 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
696 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
698 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
700 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor;
701 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
702 GenRandomValue(StereoSubDesc->InstanceUID);
703 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
706 result = m_State.Goto_INIT();
712 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
714 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
716 if ( ! m_State.Test_INIT() )
719 if ( LocalEditRate == ASDCP::Rational(0,0) )
720 LocalEditRate = PDesc.EditRate;
723 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
725 if ( ASDCP_SUCCESS(result) )
726 result = WriteMXFHeader(label, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
727 PICT_DEF_LABEL, UL(Dict::ul(MDD_PictureDataDef)),
728 LocalEditRate, 24 /* TCFrameRate */);
730 if ( ASDCP_SUCCESS(result) )
732 memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
733 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
734 result = m_State.Goto_READY();
740 // Writes a frame of essence to the MXF file. If the optional AESEncContext
741 // argument is present, the essence is encrypted prior to writing.
742 // Fails if the file is not open, is finalized, or an operating system
746 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
747 AESEncContext* Ctx, HMACContext* HMAC)
749 Result_t result = RESULT_OK;
751 if ( m_State.Test_READY() )
752 result = m_State.Goto_RUNNING(); // first time through
754 ui64_t StreamOffset = m_StreamOffset;
756 if ( ASDCP_SUCCESS(result) )
757 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
759 if ( ASDCP_SUCCESS(result) && add_index )
761 IndexTableSegment::IndexEntry Entry;
762 Entry.StreamOffset = StreamOffset;
763 m_FooterPart.PushIndexEntry(Entry);
771 // Closes the MXF file, writing the index and other closing information.
774 lh__Writer::Finalize()
776 if ( ! m_State.Test_RUNNING() )
779 m_State.Goto_FINAL();
781 return WriteMXFFooter();
786 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
791 //------------------------------------------------------------------------------------------
795 ASDCP::JP2K::MXFWriter::MXFWriter()
799 ASDCP::JP2K::MXFWriter::~MXFWriter()
804 // Open the file for writing. The file must not exist. Returns error if
805 // the operation cannot be completed.
807 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
808 const PictureDescriptor& PDesc, ui32_t HeaderSize)
810 m_Writer = new h__Writer;
811 m_Writer->m_Info = Info;
813 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
815 if ( ASDCP_SUCCESS(result) )
816 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
818 if ( ASDCP_FAILURE(result) )
825 // Writes a frame of essence to the MXF file. If the optional AESEncContext
826 // argument is present, the essence is encrypted prior to writing.
827 // Fails if the file is not open, is finalized, or an operating system
830 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
832 if ( m_Writer.empty() )
835 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
838 // Closes the MXF file, writing the index and other closing information.
840 ASDCP::JP2K::MXFWriter::Finalize()
842 if ( m_Writer.empty() )
845 return m_Writer->Finalize();
849 //------------------------------------------------------------------------------------------
853 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
855 StereoscopicPhase_t m_NextPhase;
858 h__SWriter() : m_NextPhase(SP_LEFT) {}
861 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
862 AESEncContext* Ctx, HMACContext* HMAC)
864 if ( m_NextPhase != phase )
865 return RESULT_SPHASE;
867 if ( phase == SP_LEFT )
869 m_NextPhase = SP_RIGHT;
870 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
873 m_NextPhase = SP_LEFT;
874 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
880 if ( m_NextPhase != SP_LEFT )
881 return RESULT_SPHASE;
883 assert( m_FramesWritten % 2 == 0 );
884 m_FramesWritten /= 2;
885 return lh__Writer::Finalize();
891 ASDCP::JP2K::MXFSWriter::MXFSWriter()
895 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
900 // Open the file for writing. The file must not exist. Returns error if
901 // the operation cannot be completed.
903 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
904 const PictureDescriptor& PDesc, ui32_t HeaderSize)
906 m_Writer = new h__SWriter;
908 if ( PDesc.EditRate != ASDCP::EditRate_24 )
910 DefaultLogSink().Error("Stereoscopic wrapping requires 24 fps input streams.\n");
911 return RESULT_FORMAT;
914 if ( PDesc.StoredWidth > 2048 )
915 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
917 m_Writer->m_Info = Info;
919 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
921 if ( ASDCP_SUCCESS(result) )
923 PictureDescriptor TmpPDesc = PDesc;
924 TmpPDesc.EditRate = ASDCP::EditRate_48;
926 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, ASDCP::EditRate_24);
929 if ( ASDCP_FAILURE(result) )
936 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
938 if ( m_Writer.empty() )
941 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
943 if ( ASDCP_SUCCESS(result) )
944 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
949 // Writes a frame of essence to the MXF file. If the optional AESEncContext
950 // argument is present, the essence is encrypted prior to writing.
951 // Fails if the file is not open, is finalized, or an operating system
954 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
955 AESEncContext* Ctx, HMACContext* HMAC)
957 if ( m_Writer.empty() )
960 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
963 // Closes the MXF file, writing the index and other closing information.
965 ASDCP::JP2K::MXFSWriter::Finalize()
967 if ( m_Writer.empty() )
970 return m_Writer->Finalize();
974 // end AS_DCP_JP2K.cpp