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 assert(PDescObj->ContainerDuration <= 0xFFFFFFFFL);
164 PDesc.ContainerDuration = (ui32_t) PDescObj->ContainerDuration;
165 PDesc.StoredWidth = PDescObj->StoredWidth;
166 PDesc.StoredHeight = PDescObj->StoredHeight;
167 PDesc.AspectRatio = PDescObj->AspectRatio;
169 if ( m_EssenceSubDescriptor != 0 )
171 PDesc.Rsize = m_EssenceSubDescriptor->Rsize;
172 PDesc.Xsize = m_EssenceSubDescriptor->Xsize;
173 PDesc.Ysize = m_EssenceSubDescriptor->Ysize;
174 PDesc.XOsize = m_EssenceSubDescriptor->XOsize;
175 PDesc.YOsize = m_EssenceSubDescriptor->YOsize;
176 PDesc.XTsize = m_EssenceSubDescriptor->XTsize;
177 PDesc.YTsize = m_EssenceSubDescriptor->YTsize;
178 PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
179 PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
180 PDesc.Csize = m_EssenceSubDescriptor->Csize;
182 // PictureComponentSizing
183 ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
185 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
186 memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
189 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
191 // CodingStyleDefault
192 memset(&m_PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
193 memcpy(&m_PDesc.CodingStyleDefault,
194 m_EssenceSubDescriptor->CodingStyleDefault.RoData(),
195 m_EssenceSubDescriptor->CodingStyleDefault.Length());
197 // QuantizationDefault
198 memset(&m_PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
199 memcpy(&m_PDesc.QuantizationDefault,
200 m_EssenceSubDescriptor->QuantizationDefault.RoData(),
201 m_EssenceSubDescriptor->QuantizationDefault.Length());
203 m_PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1;
212 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
214 Result_t result = OpenMXFRead(filename);
216 if( ASDCP_SUCCESS(result) )
218 InterchangeObject* tmp_iobj = 0;
219 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
220 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
222 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
223 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
225 std::list<InterchangeObject*> ObjectList;
226 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
228 if ( ObjectList.empty() )
230 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
231 return RESULT_FORMAT;
234 m_EditRate = ((Track*)ObjectList.front())->EditRate;
236 if ( type == ASDCP::ESS_JPEG_2000 )
238 if ( m_EditRate != m_EssenceDescriptor->SampleRate )
240 DefaultLogSink().Error("EditRate and SampleRate do not match (%.03f, %.03f).\n",
241 m_EditRate.Quotient(), m_EssenceDescriptor->SampleRate.Quotient());
243 if ( m_EditRate == EditRate_24 && m_EssenceDescriptor->SampleRate == EditRate_48 )
245 DefaultLogSink().Error("File may contain JPEG Interop stereoscopic images.\n");
246 return RESULT_SFORMAT;
249 return RESULT_FORMAT;
252 else if ( type == ASDCP::ESS_JPEG_2000_S )
254 if ( ! ( m_EditRate == EditRate_24 && m_EssenceDescriptor->SampleRate == EditRate_48 ) )
256 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
257 return RESULT_FORMAT;
262 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
266 result = MD_to_JP2K_PDesc(m_PDesc);
269 if( ASDCP_SUCCESS(result) )
270 result = InitMXFIndex();
272 if( ASDCP_SUCCESS(result) )
281 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
282 AESDecContext* Ctx, HMACContext* HMAC)
284 if ( ! m_File.IsOpen() )
287 return ReadEKLVFrame(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
292 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
298 //------------------------------------------------------------------------------------------
303 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
308 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
313 Kumu::hexdump(m_Data, dump_len, stream);
317 //------------------------------------------------------------------------------------------
319 ASDCP::JP2K::MXFReader::MXFReader()
321 m_Reader = new h__Reader;
325 ASDCP::JP2K::MXFReader::~MXFReader()
329 // Open the file for reading. The file must exist. Returns error if the
330 // operation cannot be completed.
332 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
334 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
339 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
340 AESDecContext* Ctx, HMACContext* HMAC) const
342 if ( m_Reader && m_Reader->m_File.IsOpen() )
343 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
349 // Fill the struct with the values from the file's header.
350 // Returns RESULT_INIT if the file is not open.
352 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
354 if ( m_Reader && m_Reader->m_File.IsOpen() )
356 PDesc = m_Reader->m_PDesc;
364 // Fill the struct with the values from the file's header.
365 // Returns RESULT_INIT if the file is not open.
367 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
369 if ( m_Reader && m_Reader->m_File.IsOpen() )
371 Info = m_Reader->m_Info;
380 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
382 if ( m_Reader->m_File.IsOpen() )
383 m_Reader->m_HeaderPart.Dump(stream);
389 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
391 if ( m_Reader->m_File.IsOpen() )
392 m_Reader->m_FooterPart.Dump(stream);
396 //------------------------------------------------------------------------------------------
398 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
400 ui32_t m_StereoFrameReady;
403 h__SReader() : m_StereoFrameReady(0xffffffff) {}
406 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
407 AESDecContext* Ctx, HMACContext* HMAC)
409 // look up frame index node
410 IndexTableSegment::IndexEntry TmpEntry;
412 if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
414 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
418 // get frame position
419 Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
420 Result_t result = RESULT_OK;
422 if ( phase == SP_LEFT )
424 if ( FilePosition != m_LastPosition )
426 m_LastPosition = FilePosition;
427 result = m_File.Seek(FilePosition);
430 // the call to ReadEKLVPacket() will leave the file on an R frame
431 m_StereoFrameReady = FrameNum;
433 else if ( phase == SP_RIGHT )
435 if ( m_StereoFrameReady != FrameNum )
437 // the file is not already positioned, we must do some work
438 // seek to the companion SP_LEFT frame and read the frame's key and length
439 if ( FilePosition != m_LastPosition )
441 m_LastPosition = FilePosition;
442 result = m_File.Seek(FilePosition);
446 result = Reader.ReadKLFromFile(m_File);
448 if ( ASDCP_SUCCESS(result) )
450 // skip over the companion SP_LEFT frame
451 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
452 result = m_File.Seek(new_pos);
456 // the call to ReadEKLVPacket() will leave the file not on an R frame
457 m_StereoFrameReady = 0xffffffff;
461 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
465 if( ASDCP_SUCCESS(result) )
467 ui32_t SequenceNum = FrameNum * 2;
468 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
469 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
478 ASDCP::JP2K::MXFSReader::MXFSReader()
480 m_Reader = new h__SReader;
484 ASDCP::JP2K::MXFSReader::~MXFSReader()
488 // Open the file for reading. The file must exist. Returns error if the
489 // operation cannot be completed.
491 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
493 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
498 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
500 Result_t result = RESULT_INIT;
502 if ( m_Reader && m_Reader->m_File.IsOpen() )
504 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
506 if ( ASDCP_SUCCESS(result) )
507 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
515 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
516 AESDecContext* Ctx, HMACContext* HMAC) const
518 if ( m_Reader && m_Reader->m_File.IsOpen() )
519 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
524 // Fill the struct with the values from the file's header.
525 // Returns RESULT_INIT if the file is not open.
527 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
529 if ( m_Reader && m_Reader->m_File.IsOpen() )
531 PDesc = m_Reader->m_PDesc;
539 // Fill the struct with the values from the file's header.
540 // Returns RESULT_INIT if the file is not open.
542 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
544 if ( m_Reader && m_Reader->m_File.IsOpen() )
546 Info = m_Reader->m_Info;
555 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
557 if ( m_Reader->m_File.IsOpen() )
558 m_Reader->m_HeaderPart.Dump(stream);
564 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
566 if ( m_Reader->m_File.IsOpen() )
567 m_Reader->m_FooterPart.Dump(stream);
570 //------------------------------------------------------------------------------------------
574 class lh__Writer : public ASDCP::h__Writer
576 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
579 PictureDescriptor m_PDesc;
580 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
582 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
584 lh__Writer() : m_EssenceSubDescriptor(0) {
585 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
590 Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
591 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
592 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
593 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
595 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
598 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
599 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
600 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
604 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
606 assert(m_EssenceDescriptor);
607 assert(m_EssenceSubDescriptor);
608 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
610 PDescObj->ContainerDuration = PDesc.ContainerDuration;
611 PDescObj->SampleRate = PDesc.EditRate;
612 PDescObj->FrameLayout = 0;
613 PDescObj->StoredWidth = PDesc.StoredWidth;
614 PDescObj->StoredHeight = PDesc.StoredHeight;
615 PDescObj->AspectRatio = PDesc.AspectRatio;
617 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
619 // PictureEssenceCoding UL =
620 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
622 // ComponentMaxRef ui32_t = 4095
623 // ComponentMinRef ui32_t = 0
624 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
627 if ( PDesc.StoredWidth < 2049 )
629 PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_2K));
630 m_EssenceSubDescriptor->Rsize = 3;
634 PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_4K));
635 m_EssenceSubDescriptor->Rsize = 4;
638 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
639 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
640 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
641 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
642 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
643 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
644 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
645 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
646 m_EssenceSubDescriptor->Csize = PDesc.Csize;
648 const ui32_t tmp_buffer_len = 1024;
649 byte_t tmp_buffer[tmp_buffer_len];
651 *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
652 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
653 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
655 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
656 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
657 m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
659 ui32_t precinct_set_size = 0, i;
660 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
663 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
664 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
665 m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
667 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
668 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
669 m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
675 // Open the file for writing. The file must not exist. Returns error if
676 // the operation cannot be completed.
678 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
680 if ( ! m_State.Test_BEGIN() )
683 Result_t result = m_File.OpenWrite(filename);
685 if ( ASDCP_SUCCESS(result) )
687 m_HeaderSize = HeaderSize;
688 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor;
689 tmp_rgba->ComponentMaxRef = 4095;
690 tmp_rgba->ComponentMinRef = 0;
692 m_EssenceDescriptor = tmp_rgba;
693 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
694 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
696 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
697 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
699 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
701 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor;
702 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
703 GenRandomValue(StereoSubDesc->InstanceUID);
704 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
707 result = m_State.Goto_INIT();
713 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
715 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
717 if ( ! m_State.Test_INIT() )
720 if ( LocalEditRate == ASDCP::Rational(0,0) )
721 LocalEditRate = PDesc.EditRate;
724 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
726 if ( ASDCP_SUCCESS(result) )
727 result = WriteMXFHeader(label, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
728 PICT_DEF_LABEL, UL(Dict::ul(MDD_PictureDataDef)),
729 LocalEditRate, 24 /* TCFrameRate */);
731 if ( ASDCP_SUCCESS(result) )
733 memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
734 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
735 result = m_State.Goto_READY();
741 // Writes a frame of essence to the MXF file. If the optional AESEncContext
742 // argument is present, the essence is encrypted prior to writing.
743 // Fails if the file is not open, is finalized, or an operating system
747 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
748 AESEncContext* Ctx, HMACContext* HMAC)
750 Result_t result = RESULT_OK;
752 if ( m_State.Test_READY() )
753 result = m_State.Goto_RUNNING(); // first time through
755 ui64_t StreamOffset = m_StreamOffset;
757 if ( ASDCP_SUCCESS(result) )
758 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
760 if ( ASDCP_SUCCESS(result) && add_index )
762 IndexTableSegment::IndexEntry Entry;
763 Entry.StreamOffset = StreamOffset;
764 m_FooterPart.PushIndexEntry(Entry);
772 // Closes the MXF file, writing the index and other closing information.
775 lh__Writer::Finalize()
777 if ( ! m_State.Test_RUNNING() )
780 m_State.Goto_FINAL();
782 return WriteMXFFooter();
787 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
792 //------------------------------------------------------------------------------------------
796 ASDCP::JP2K::MXFWriter::MXFWriter()
800 ASDCP::JP2K::MXFWriter::~MXFWriter()
805 // Open the file for writing. The file must not exist. Returns error if
806 // the operation cannot be completed.
808 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
809 const PictureDescriptor& PDesc, ui32_t HeaderSize)
811 m_Writer = new h__Writer;
812 m_Writer->m_Info = Info;
814 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
816 if ( ASDCP_SUCCESS(result) )
817 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
819 if ( ASDCP_FAILURE(result) )
826 // Writes a frame of essence to the MXF file. If the optional AESEncContext
827 // argument is present, the essence is encrypted prior to writing.
828 // Fails if the file is not open, is finalized, or an operating system
831 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
833 if ( m_Writer.empty() )
836 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
839 // Closes the MXF file, writing the index and other closing information.
841 ASDCP::JP2K::MXFWriter::Finalize()
843 if ( m_Writer.empty() )
846 return m_Writer->Finalize();
850 //------------------------------------------------------------------------------------------
854 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
856 StereoscopicPhase_t m_NextPhase;
859 h__SWriter() : m_NextPhase(SP_LEFT) {}
862 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
863 AESEncContext* Ctx, HMACContext* HMAC)
865 if ( m_NextPhase != phase )
866 return RESULT_SPHASE;
868 if ( phase == SP_LEFT )
870 m_NextPhase = SP_RIGHT;
871 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
874 m_NextPhase = SP_LEFT;
875 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
881 if ( m_NextPhase != SP_LEFT )
882 return RESULT_SPHASE;
884 assert( m_FramesWritten % 2 == 0 );
885 m_FramesWritten /= 2;
886 return lh__Writer::Finalize();
892 ASDCP::JP2K::MXFSWriter::MXFSWriter()
896 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
901 // Open the file for writing. The file must not exist. Returns error if
902 // the operation cannot be completed.
904 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
905 const PictureDescriptor& PDesc, ui32_t HeaderSize)
907 m_Writer = new h__SWriter;
909 if ( PDesc.EditRate != ASDCP::EditRate_24 )
911 DefaultLogSink().Error("Stereoscopic wrapping requires 24 fps input streams.\n");
912 return RESULT_FORMAT;
915 if ( PDesc.StoredWidth > 2048 )
916 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
918 m_Writer->m_Info = Info;
920 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
922 if ( ASDCP_SUCCESS(result) )
924 PictureDescriptor TmpPDesc = PDesc;
925 TmpPDesc.EditRate = ASDCP::EditRate_48;
927 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, ASDCP::EditRate_24);
930 if ( ASDCP_FAILURE(result) )
937 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
939 if ( m_Writer.empty() )
942 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
944 if ( ASDCP_SUCCESS(result) )
945 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
950 // Writes a frame of essence to the MXF file. If the optional AESEncContext
951 // argument is present, the essence is encrypted prior to writing.
952 // Fails if the file is not open, is finalized, or an operating system
955 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
956 AESEncContext* Ctx, HMACContext* HMAC)
958 if ( m_Writer.empty() )
961 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
964 // Closes the MXF file, writing the index and other closing information.
966 ASDCP::JP2K::MXFSWriter::Finalize()
968 if ( m_Writer.empty() )
971 return m_Writer->Finalize();
975 // end AS_DCP_JP2K.cpp