2 Copyright (c) 2004-2007, 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;
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");
87 for ( ui32_t i = 0; i < PDesc.Csize; i++ )
89 fprintf(stream, " %4d %5d %5d\n",
90 PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
91 PDesc.ImageComponents[i].XRsize,
92 PDesc.ImageComponents[i].YRsize
96 fprintf(stream, " Scod: %hd\n", PDesc.CodingStyleDefault.Scod);
97 fprintf(stream, " ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
98 fprintf(stream, " NumberOfLayers: %hd\n",
99 KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
101 fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
102 fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
103 fprintf(stream, " CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
104 fprintf(stream, " CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
105 fprintf(stream, " CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
106 fprintf(stream, " Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
109 ui32_t precinct_set_size = 0, i;
111 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
114 fprintf(stream, " Precincts: %hd\n", precinct_set_size);
115 fprintf(stream, "precinct dimensions:\n");
117 for ( i = 0; i < precinct_set_size; i++ )
118 fprintf(stream, " %d: %d x %d\n", i + 1,
119 s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
120 s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
123 fprintf(stream, " Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd);
125 char tmp_buf[MaxDefaults*2];
126 fprintf(stream, " SPqcd: %s\n",
127 Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
128 tmp_buf, MaxDefaults*2)
132 //------------------------------------------------------------------------------------------
134 // hidden, internal implementation of JPEG 2000 reader
136 class lh__Reader : public ASDCP::h__Reader
138 RGBAEssenceDescriptor* m_EssenceDescriptor;
139 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
140 ASDCP::Rational m_EditRate;
141 EssenceType_t m_Format;
143 ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
146 PictureDescriptor m_PDesc; // codestream parameter list
148 lh__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
149 Result_t OpenRead(const char*, EssenceType_t);
150 Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
151 Result_t MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
156 lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
158 memset(&PDesc, 0, sizeof(PDesc));
159 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
161 PDesc.EditRate = m_EditRate;
162 PDesc.ContainerDuration = PDescObj->ContainerDuration;
163 PDesc.StoredWidth = PDescObj->StoredWidth;
164 PDesc.StoredHeight = PDescObj->StoredHeight;
165 PDesc.AspectRatio = PDescObj->AspectRatio;
167 if ( m_EssenceSubDescriptor != 0 )
169 PDesc.Rsize = m_EssenceSubDescriptor->Rsize;
170 PDesc.Xsize = m_EssenceSubDescriptor->Xsize;
171 PDesc.Ysize = m_EssenceSubDescriptor->Ysize;
172 PDesc.XOsize = m_EssenceSubDescriptor->XOsize;
173 PDesc.YOsize = m_EssenceSubDescriptor->YOsize;
174 PDesc.XTsize = m_EssenceSubDescriptor->XTsize;
175 PDesc.YTsize = m_EssenceSubDescriptor->YTsize;
176 PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
177 PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
178 PDesc.Csize = m_EssenceSubDescriptor->Csize;
180 // PictureComponentSizing
181 ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
183 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
184 memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
187 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
189 // CodingStyleDefault
190 memset(&m_PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
191 memcpy(&m_PDesc.CodingStyleDefault,
192 m_EssenceSubDescriptor->CodingStyleDefault.RoData(),
193 m_EssenceSubDescriptor->CodingStyleDefault.Length());
195 // QuantizationDefault
196 memset(&m_PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
197 memcpy(&m_PDesc.QuantizationDefault,
198 m_EssenceSubDescriptor->QuantizationDefault.RoData(),
199 m_EssenceSubDescriptor->QuantizationDefault.Length());
201 m_PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1;
210 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
212 Result_t result = OpenMXFRead(filename);
214 if( ASDCP_SUCCESS(result) )
216 InterchangeObject* tmp_iobj = 0;
217 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
218 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
220 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
221 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
223 std::list<InterchangeObject*> ObjectList;
224 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
226 if ( ObjectList.empty() )
228 DefaultLogSink().Error("MXF Metadata contains no Track Sets\n");
229 return RESULT_FORMAT;
232 m_EditRate = ((Track*)ObjectList.front())->EditRate;
234 if ( type == ASDCP::ESS_JPEG_2000 )
236 if ( m_EditRate != m_EssenceDescriptor->SampleRate )
238 DefaultLogSink().Error("EditRate and SampleRate do not match (%.03f, %.03f)\n",
239 m_EditRate.Quotient(), m_EssenceDescriptor->SampleRate.Quotient());
240 return RESULT_SFORMAT;
243 else if ( type == ASDCP::ESS_JPEG_2000_S )
245 if ( ! ( m_EditRate == EditRate_24 && m_EssenceDescriptor->SampleRate == EditRate_48 ) )
247 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence\n");
248 return RESULT_FORMAT;
253 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
257 result = MD_to_JP2K_PDesc(m_PDesc);
260 if( ASDCP_SUCCESS(result) )
261 result = InitMXFIndex();
263 if( ASDCP_SUCCESS(result) )
272 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
273 AESDecContext* Ctx, HMACContext* HMAC)
275 if ( ! m_File.IsOpen() )
278 return ReadEKLVFrame(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
283 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
289 //------------------------------------------------------------------------------------------
294 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
299 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
304 Kumu::hexdump(m_Data, dump_len, stream);
308 //------------------------------------------------------------------------------------------
310 ASDCP::JP2K::MXFReader::MXFReader()
312 m_Reader = new h__Reader;
316 ASDCP::JP2K::MXFReader::~MXFReader()
320 // Open the file for reading. The file must exist. Returns error if the
321 // operation cannot be completed.
323 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
325 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
330 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
331 AESDecContext* Ctx, HMACContext* HMAC) const
333 if ( m_Reader && m_Reader->m_File.IsOpen() )
334 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
340 // Fill the struct with the values from the file's header.
341 // Returns RESULT_INIT if the file is not open.
343 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
345 if ( m_Reader && m_Reader->m_File.IsOpen() )
347 PDesc = m_Reader->m_PDesc;
355 // Fill the struct with the values from the file's header.
356 // Returns RESULT_INIT if the file is not open.
358 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
360 if ( m_Reader && m_Reader->m_File.IsOpen() )
362 Info = m_Reader->m_Info;
371 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
373 if ( m_Reader->m_File.IsOpen() )
374 m_Reader->m_HeaderPart.Dump(stream);
380 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
382 if ( m_Reader->m_File.IsOpen() )
383 m_Reader->m_FooterPart.Dump(stream);
387 //------------------------------------------------------------------------------------------
389 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
391 ui32_t m_StereoFrameReady;
394 h__SReader() : m_StereoFrameReady(0xffffffff) {}
397 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
398 AESDecContext* Ctx, HMACContext* HMAC)
400 // look up frame index node
401 IndexTableSegment::IndexEntry TmpEntry;
403 if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
405 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
409 // get frame position
410 Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
411 Result_t result = RESULT_OK;
413 if ( phase == SP_LEFT )
415 if ( FilePosition != m_LastPosition )
417 m_LastPosition = FilePosition;
418 result = m_File.Seek(FilePosition);
421 // the call to ReadEKLVPacket() will leave the file on an R frame
422 m_StereoFrameReady = FrameNum;
424 else if ( phase == SP_RIGHT )
426 if ( m_StereoFrameReady != FrameNum )
428 // the file is not already positioned, we must do some work
429 // seek to the companion SP_LEFT frame and read the frame's key and length
430 if ( FilePosition != m_LastPosition )
432 m_LastPosition = FilePosition;
433 result = m_File.Seek(FilePosition);
437 result = Reader.ReadKLFromFile(m_File);
439 if ( ASDCP_SUCCESS(result) )
441 // skip over the companion SP_LEFT frame
442 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
443 result = m_File.Seek(new_pos);
447 // the call to ReadEKLVPacket() will leave the file not on an R frame
448 m_StereoFrameReady = 0xffffffff;
452 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
456 if( ASDCP_SUCCESS(result) )
458 ui32_t SequenceNum = FrameNum * 2;
459 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
460 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
469 ASDCP::JP2K::MXFSReader::MXFSReader()
471 m_Reader = new h__SReader;
475 ASDCP::JP2K::MXFSReader::~MXFSReader()
479 // Open the file for reading. The file must exist. Returns error if the
480 // operation cannot be completed.
482 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
484 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
489 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
490 AESDecContext* Ctx, HMACContext* HMAC) const
492 if ( m_Reader && m_Reader->m_File.IsOpen() )
493 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
499 // Fill the struct with the values from the file's header.
500 // Returns RESULT_INIT if the file is not open.
502 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
504 if ( m_Reader && m_Reader->m_File.IsOpen() )
506 PDesc = m_Reader->m_PDesc;
514 // Fill the struct with the values from the file's header.
515 // Returns RESULT_INIT if the file is not open.
517 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
519 if ( m_Reader && m_Reader->m_File.IsOpen() )
521 Info = m_Reader->m_Info;
530 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
532 if ( m_Reader->m_File.IsOpen() )
533 m_Reader->m_HeaderPart.Dump(stream);
539 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
541 if ( m_Reader->m_File.IsOpen() )
542 m_Reader->m_FooterPart.Dump(stream);
545 //------------------------------------------------------------------------------------------
549 class lh__Writer : public ASDCP::h__Writer
551 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
554 PictureDescriptor m_PDesc;
555 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
557 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
559 lh__Writer() : m_EssenceSubDescriptor(0) {
560 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
565 Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
566 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
567 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
568 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
570 Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
573 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
574 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
575 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
579 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
581 assert(m_EssenceDescriptor);
582 assert(m_EssenceSubDescriptor);
583 MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
585 PDescObj->ContainerDuration = PDesc.ContainerDuration;
586 PDescObj->SampleRate = PDesc.EditRate;
587 PDescObj->FrameLayout = 0;
588 PDescObj->StoredWidth = PDesc.StoredWidth;
589 PDescObj->StoredHeight = PDesc.StoredHeight;
590 PDescObj->AspectRatio = PDesc.AspectRatio;
592 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
594 // PictureEssenceCoding UL =
595 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
597 // ComponentMaxRef ui32_t = 4095
598 // ComponentMinRef ui32_t = 0
599 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
602 if ( PDesc.StoredWidth < 2049 )
604 PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_2K));
605 m_EssenceSubDescriptor->Rsize = 3;
609 PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_4K));
610 m_EssenceSubDescriptor->Rsize = 4;
613 m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
614 m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
615 m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
616 m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
617 m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
618 m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
619 m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
620 m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
621 m_EssenceSubDescriptor->Csize = PDesc.Csize;
623 const ui32_t tmp_buffer_len = 1024;
624 byte_t tmp_buffer[tmp_buffer_len];
626 *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
627 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
628 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
630 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
631 memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
632 m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
634 ui32_t precinct_set_size = 0, i;
635 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
638 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
639 memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
640 m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
642 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
643 memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
644 m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
650 // Open the file for writing. The file must not exist. Returns error if
651 // the operation cannot be completed.
653 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
655 if ( ! m_State.Test_BEGIN() )
658 Result_t result = m_File.OpenWrite(filename);
660 if ( ASDCP_SUCCESS(result) )
662 m_HeaderSize = HeaderSize;
663 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor;
664 tmp_rgba->ComponentMaxRef = 4095;
665 tmp_rgba->ComponentMinRef = 0;
667 m_EssenceDescriptor = tmp_rgba;
668 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
669 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
671 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
672 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
674 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
676 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor;
677 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
678 GenRandomValue(StereoSubDesc->InstanceUID);
679 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
682 result = m_State.Goto_INIT();
688 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
690 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
692 if ( ! m_State.Test_INIT() )
695 if ( LocalEditRate == ASDCP::Rational(0,0) )
696 LocalEditRate = PDesc.EditRate;
699 Result_t result = JP2K_PDesc_to_MD(m_PDesc);
701 if ( ASDCP_SUCCESS(result) )
702 result = WriteMXFHeader(label, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
703 PICT_DEF_LABEL, UL(Dict::ul(MDD_PictureDataDef)),
704 LocalEditRate, 24 /* TCFrameRate */);
706 if ( ASDCP_SUCCESS(result) )
708 memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
709 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
710 result = m_State.Goto_READY();
716 // Writes a frame of essence to the MXF file. If the optional AESEncContext
717 // argument is present, the essence is encrypted prior to writing.
718 // Fails if the file is not open, is finalized, or an operating system
722 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
723 AESEncContext* Ctx, HMACContext* HMAC)
725 Result_t result = RESULT_OK;
727 if ( m_State.Test_READY() )
728 result = m_State.Goto_RUNNING(); // first time through
730 ui64_t StreamOffset = m_StreamOffset;
732 if ( ASDCP_SUCCESS(result) )
733 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
735 if ( ASDCP_SUCCESS(result) && add_index )
737 IndexTableSegment::IndexEntry Entry;
738 Entry.StreamOffset = StreamOffset;
739 m_FooterPart.PushIndexEntry(Entry);
747 // Closes the MXF file, writing the index and other closing information.
750 lh__Writer::Finalize()
752 if ( ! m_State.Test_RUNNING() )
755 m_State.Goto_FINAL();
757 return WriteMXFFooter();
762 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
767 //------------------------------------------------------------------------------------------
771 ASDCP::JP2K::MXFWriter::MXFWriter()
775 ASDCP::JP2K::MXFWriter::~MXFWriter()
780 // Open the file for writing. The file must not exist. Returns error if
781 // the operation cannot be completed.
783 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
784 const PictureDescriptor& PDesc, ui32_t HeaderSize)
786 m_Writer = new h__Writer;
788 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
790 if ( ASDCP_SUCCESS(result) )
792 m_Writer->m_Info = Info;
793 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
796 if ( ASDCP_FAILURE(result) )
803 // Writes a frame of essence to the MXF file. If the optional AESEncContext
804 // argument is present, the essence is encrypted prior to writing.
805 // Fails if the file is not open, is finalized, or an operating system
808 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
810 if ( m_Writer.empty() )
813 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
816 // Closes the MXF file, writing the index and other closing information.
818 ASDCP::JP2K::MXFWriter::Finalize()
820 if ( m_Writer.empty() )
823 return m_Writer->Finalize();
827 //------------------------------------------------------------------------------------------
831 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
833 StereoscopicPhase_t m_NextPhase;
836 h__SWriter() : m_NextPhase(SP_LEFT) {}
839 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
840 AESEncContext* Ctx, HMACContext* HMAC)
842 if ( m_NextPhase != phase )
843 return RESULT_SPHASE;
845 if ( phase == SP_LEFT )
847 m_NextPhase = SP_RIGHT;
848 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
851 m_NextPhase = SP_LEFT;
852 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
858 if ( m_NextPhase != SP_LEFT )
859 return RESULT_SPHASE;
861 assert( m_FramesWritten % 2 == 0 );
862 m_FramesWritten /= 2;
863 return lh__Writer::Finalize();
869 ASDCP::JP2K::MXFSWriter::MXFSWriter()
873 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
878 // Open the file for writing. The file must not exist. Returns error if
879 // the operation cannot be completed.
881 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
882 const PictureDescriptor& PDesc, ui32_t HeaderSize)
884 m_Writer = new h__SWriter;
886 if ( PDesc.EditRate != ASDCP::EditRate_24 )
888 DefaultLogSink().Error("Stereoscopic wrapping requires 24 fps input streams.\n");
889 return RESULT_FORMAT;
892 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
894 if ( ASDCP_SUCCESS(result) )
896 m_Writer->m_Info = Info;
897 PictureDescriptor TmpPDesc = PDesc;
898 TmpPDesc.EditRate = ASDCP::EditRate_48;
900 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, ASDCP::EditRate_24);
903 if ( ASDCP_FAILURE(result) )
910 // Writes a frame of essence to the MXF file. If the optional AESEncContext
911 // argument is present, the essence is encrypted prior to writing.
912 // Fails if the file is not open, is finalized, or an operating system
915 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
916 AESEncContext* Ctx, HMACContext* HMAC)
918 if ( m_Writer.empty() )
921 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
924 // Closes the MXF file, writing the index and other closing information.
926 ASDCP::JP2K::MXFSWriter::Finalize()
928 if ( m_Writer.empty() )
931 return m_Writer->Finalize();
935 // end AS_DCP_JP2K.cpp