2 Copyright (c) 2004-2014, 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
28 \version $Id: AS_DCP_JP2K.cpp,v 1.69 2015/10/07 16:41:23 jhurst Exp $
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 < MaxComponents; ++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 < MaxPrecincts; ++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 < MaxComponents; 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: %hhu\n", PDesc.CodingStyleDefault.Scod);
167 fprintf(stream, " ProgressionOrder: %hhu\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: %hhu\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
172 fprintf(stream, "DecompositionLevels: %hhu\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
173 fprintf(stream, " CodeblockWidth: %hhu\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
174 fprintf(stream, " CodeblockHeight: %hhu\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
175 fprintf(stream, " CodeblockStyle: %hhu\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
176 fprintf(stream, " Transformation: %hhu\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: %u\n", precinct_set_size);
185 fprintf(stream, "precinct dimensions:\n");
187 for ( i = 0; i < precinct_set_size && i < MaxPrecincts; 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: %hhu\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 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
204 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
205 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
209 ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc,
210 const ASDCP::Dictionary&,
211 ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
212 ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor)
214 EssenceDescriptor.ContainerDuration = PDesc.ContainerDuration;
215 EssenceDescriptor.SampleRate = PDesc.EditRate;
216 EssenceDescriptor.FrameLayout = 0;
217 EssenceDescriptor.StoredWidth = PDesc.StoredWidth;
218 EssenceDescriptor.StoredHeight = PDesc.StoredHeight;
219 EssenceDescriptor.AspectRatio = PDesc.AspectRatio;
221 EssenceSubDescriptor.Rsize = PDesc.Rsize;
222 EssenceSubDescriptor.Xsize = PDesc.Xsize;
223 EssenceSubDescriptor.Ysize = PDesc.Ysize;
224 EssenceSubDescriptor.XOsize = PDesc.XOsize;
225 EssenceSubDescriptor.YOsize = PDesc.YOsize;
226 EssenceSubDescriptor.XTsize = PDesc.XTsize;
227 EssenceSubDescriptor.YTsize = PDesc.YTsize;
228 EssenceSubDescriptor.XTOsize = PDesc.XTOsize;
229 EssenceSubDescriptor.YTOsize = PDesc.YTOsize;
230 EssenceSubDescriptor.Csize = PDesc.Csize;
232 const ui32_t tmp_buffer_len = 1024;
233 byte_t tmp_buffer[tmp_buffer_len];
235 ui32_t* tmp_buffer_ui32 = (ui32_t*) tmp_buffer;
237 *tmp_buffer_ui32 = KM_i32_BE(MaxComponents); // three components
238 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
239 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
241 const ui32_t pcomp_size = (sizeof(ui32_t) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
242 memcpy(EssenceSubDescriptor.PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size);
243 EssenceSubDescriptor.PictureComponentSizing.get().Length(pcomp_size);
244 EssenceSubDescriptor.PictureComponentSizing.set_has_value();
246 ui32_t precinct_set_size = 0;
247 for ( ui32_t i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; ++i )
250 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
251 memcpy(EssenceSubDescriptor.CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size);
252 EssenceSubDescriptor.CodingStyleDefault.get().Length(csd_size);
253 EssenceSubDescriptor.CodingStyleDefault.set_has_value();
255 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
256 memcpy(EssenceSubDescriptor.QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size);
257 EssenceSubDescriptor.QuantizationDefault.get().Length(qdflt_size);
258 EssenceSubDescriptor.QuantizationDefault.set_has_value();
266 ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
267 const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
268 const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
269 ASDCP::JP2K::PictureDescriptor& PDesc)
271 memset(&PDesc, 0, sizeof(PDesc));
273 PDesc.EditRate = EditRate;
274 PDesc.SampleRate = SampleRate;
275 assert(EssenceDescriptor.ContainerDuration.const_get() <= 0xFFFFFFFFL);
276 PDesc.ContainerDuration = static_cast<ui32_t>(EssenceDescriptor.ContainerDuration.const_get());
277 PDesc.StoredWidth = EssenceDescriptor.StoredWidth;
278 PDesc.StoredHeight = EssenceDescriptor.StoredHeight;
279 PDesc.AspectRatio = EssenceDescriptor.AspectRatio;
281 PDesc.Rsize = EssenceSubDescriptor.Rsize;
282 PDesc.Xsize = EssenceSubDescriptor.Xsize;
283 PDesc.Ysize = EssenceSubDescriptor.Ysize;
284 PDesc.XOsize = EssenceSubDescriptor.XOsize;
285 PDesc.YOsize = EssenceSubDescriptor.YOsize;
286 PDesc.XTsize = EssenceSubDescriptor.XTsize;
287 PDesc.YTsize = EssenceSubDescriptor.YTsize;
288 PDesc.XTOsize = EssenceSubDescriptor.XTOsize;
289 PDesc.YTOsize = EssenceSubDescriptor.YTOsize;
290 PDesc.Csize = EssenceSubDescriptor.Csize;
292 // PictureComponentSizing
293 ui32_t tmp_size = EssenceSubDescriptor.PictureComponentSizing.const_get().Length();
295 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
297 memcpy(&PDesc.ImageComponents, EssenceSubDescriptor.PictureComponentSizing.const_get().RoData() + 8, tmp_size - 8);
301 DefaultLogSink().Warn("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
304 // CodingStyleDefault
305 memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
306 memcpy(&PDesc.CodingStyleDefault,
307 EssenceSubDescriptor.CodingStyleDefault.const_get().RoData(),
308 EssenceSubDescriptor.CodingStyleDefault.const_get().Length());
310 // QuantizationDefault
311 memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
312 memcpy(&PDesc.QuantizationDefault,
313 EssenceSubDescriptor.QuantizationDefault.const_get().RoData(),
314 EssenceSubDescriptor.QuantizationDefault.const_get().Length());
316 PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1;
321 //------------------------------------------------------------------------------------------
323 // hidden, internal implementation of JPEG 2000 reader
326 class lh__Reader : public ASDCP::h__ASDCPReader
328 RGBAEssenceDescriptor* m_EssenceDescriptor;
329 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
330 ASDCP::Rational m_EditRate;
331 ASDCP::Rational m_SampleRate;
332 EssenceType_t m_Format;
334 ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
337 PictureDescriptor m_PDesc; // codestream parameter list
339 lh__Reader(const Dictionary& d) :
340 ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
342 virtual ~lh__Reader() {}
344 Result_t OpenRead(const std::string&, EssenceType_t);
345 Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
352 lh__Reader::OpenRead(const std::string& filename, EssenceType_t type)
354 Result_t result = OpenMXFRead(filename);
356 if( ASDCP_SUCCESS(result) )
358 InterchangeObject* tmp_iobj = 0;
359 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
360 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
362 if ( m_EssenceDescriptor == 0 )
364 DefaultLogSink().Error("RGBAEssenceDescriptor object not found.\n");
365 return RESULT_FORMAT;
368 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
369 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
371 if ( m_EssenceSubDescriptor == 0 )
373 m_EssenceDescriptor = 0;
374 DefaultLogSink().Error("JPEG2000PictureSubDescriptor object not found.\n");
375 return RESULT_FORMAT;
378 std::list<InterchangeObject*> ObjectList;
379 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
381 if ( ObjectList.empty() )
383 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
384 return RESULT_FORMAT;
387 m_EditRate = ((Track*)ObjectList.front())->EditRate;
388 m_SampleRate = m_EssenceDescriptor->SampleRate;
390 if ( type == ASDCP::ESS_JPEG_2000 )
392 if ( m_EditRate != m_SampleRate )
394 DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
395 m_EditRate.Quotient(), m_SampleRate.Quotient());
397 if ( ( m_EditRate == EditRate_24 && m_SampleRate == EditRate_48 )
398 || ( m_EditRate == EditRate_25 && m_SampleRate == EditRate_50 )
399 || ( m_EditRate == EditRate_30 && m_SampleRate == EditRate_60 )
400 || ( m_EditRate == EditRate_48 && m_SampleRate == EditRate_96 )
401 || ( m_EditRate == EditRate_50 && m_SampleRate == EditRate_100 )
402 || ( m_EditRate == EditRate_60 && m_SampleRate == EditRate_120 ) )
404 DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
405 return RESULT_SFORMAT;
408 return RESULT_FORMAT;
411 else if ( type == ASDCP::ESS_JPEG_2000_S )
413 if ( m_EditRate == EditRate_24 )
415 if ( m_SampleRate != EditRate_48 )
417 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
418 return RESULT_FORMAT;
421 else if ( m_EditRate == EditRate_25 )
423 if ( m_SampleRate != EditRate_50 )
425 DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
426 return RESULT_FORMAT;
429 else if ( m_EditRate == EditRate_30 )
431 if ( m_SampleRate != EditRate_60 )
433 DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
434 return RESULT_FORMAT;
437 else if ( m_EditRate == EditRate_48 )
439 if ( m_SampleRate != EditRate_96 )
441 DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
442 return RESULT_FORMAT;
445 else if ( m_EditRate == EditRate_50 )
447 if ( m_SampleRate != EditRate_100 )
449 DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
450 return RESULT_FORMAT;
453 else if ( m_EditRate == EditRate_60 )
455 if ( m_SampleRate != EditRate_120 )
457 DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
458 return RESULT_FORMAT;
463 DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
464 m_EditRate.Numerator, m_EditRate.Denominator);
465 return RESULT_FORMAT;
470 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
474 result = MD_to_JP2K_PDesc(*m_EssenceDescriptor, *m_EssenceSubDescriptor, m_EditRate, m_SampleRate, m_PDesc);
483 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
484 AESDecContext* Ctx, HMACContext* HMAC)
486 if ( ! m_File.IsOpen() )
490 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
495 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
497 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
501 h__Reader(const Dictionary& d) : lh__Reader(d) {}
506 //------------------------------------------------------------------------------------------
511 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
516 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
521 Kumu::hexdump(m_Data, dump_len, stream);
525 //------------------------------------------------------------------------------------------
527 ASDCP::JP2K::MXFReader::MXFReader()
529 m_Reader = new h__Reader(DefaultCompositeDict());
533 ASDCP::JP2K::MXFReader::~MXFReader()
535 if ( m_Reader && m_Reader->m_File.IsOpen() )
539 // Warning: direct manipulation of MXF structures can interfere
540 // with the normal operation of the wrapper. Caveat emptor!
542 ASDCP::MXF::OP1aHeader&
543 ASDCP::JP2K::MXFReader::OP1aHeader()
545 if ( m_Reader.empty() )
547 assert(g_OP1aHeader);
548 return *g_OP1aHeader;
551 return m_Reader->m_HeaderPart;
554 // Warning: direct manipulation of MXF structures can interfere
555 // with the normal operation of the wrapper. Caveat emptor!
557 ASDCP::MXF::OPAtomIndexFooter&
558 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
560 if ( m_Reader.empty() )
562 assert(g_OPAtomIndexFooter);
563 return *g_OPAtomIndexFooter;
566 return m_Reader->m_IndexAccess;
569 // Warning: direct manipulation of MXF structures can interfere
570 // with the normal operation of the wrapper. Caveat emptor!
573 ASDCP::JP2K::MXFReader::RIP()
575 if ( m_Reader.empty() )
581 return m_Reader->m_RIP;
584 // Open the file for reading. The file must exist. Returns error if the
585 // operation cannot be completed.
587 ASDCP::JP2K::MXFReader::OpenRead(const std::string& filename) const
589 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
594 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
595 AESDecContext* Ctx, HMACContext* HMAC) const
597 if ( m_Reader && m_Reader->m_File.IsOpen() )
598 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
604 ASDCP::JP2K::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
606 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
610 // Fill the struct with the values from the file's header.
611 // Returns RESULT_INIT if the file is not open.
613 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
615 if ( m_Reader && m_Reader->m_File.IsOpen() )
617 PDesc = m_Reader->m_PDesc;
625 // Fill the struct with the values from the file's header.
626 // Returns RESULT_INIT if the file is not open.
628 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
630 if ( m_Reader && m_Reader->m_File.IsOpen() )
632 Info = m_Reader->m_Info;
641 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
643 if ( m_Reader->m_File.IsOpen() )
644 m_Reader->m_HeaderPart.Dump(stream);
650 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
652 if ( m_Reader->m_File.IsOpen() )
653 m_Reader->m_IndexAccess.Dump(stream);
658 ASDCP::JP2K::MXFReader::Close() const
660 if ( m_Reader && m_Reader->m_File.IsOpen() )
670 //------------------------------------------------------------------------------------------
673 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
675 ui32_t m_StereoFrameReady;
678 h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
681 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
682 AESDecContext* Ctx, HMACContext* HMAC)
684 // look up frame index node
685 IndexTableSegment::IndexEntry TmpEntry;
687 if ( ASDCP_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
692 // get frame position
693 Kumu::fpos_t FilePosition = m_HeaderPart.BodyOffset + TmpEntry.StreamOffset;
694 Result_t result = RESULT_OK;
696 if ( phase == SP_LEFT )
698 if ( FilePosition != m_LastPosition )
700 m_LastPosition = FilePosition;
701 result = m_File.Seek(FilePosition);
704 // the call to ReadEKLVPacket() will leave the file on an R frame
705 m_StereoFrameReady = FrameNum;
707 else if ( phase == SP_RIGHT )
709 if ( m_StereoFrameReady != FrameNum )
711 // the file is not already positioned, we must do some work
712 // seek to the companion SP_LEFT frame and read the frame's key and length
713 if ( FilePosition != m_LastPosition )
715 m_LastPosition = FilePosition;
716 result = m_File.Seek(FilePosition);
720 result = Reader.ReadKLFromFile(m_File);
722 if ( ASDCP_SUCCESS(result) )
724 // skip over the companion SP_LEFT frame
725 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
726 result = m_File.Seek(new_pos);
730 // the call to ReadEKLVPacket() will leave the file not on an R frame
731 m_StereoFrameReady = 0xffffffff;
735 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
739 if( ASDCP_SUCCESS(result) )
741 ui32_t SequenceNum = FrameNum * 2;
742 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
744 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
753 ASDCP::JP2K::MXFSReader::MXFSReader()
755 m_Reader = new h__SReader(DefaultCompositeDict());
759 ASDCP::JP2K::MXFSReader::~MXFSReader()
761 if ( m_Reader && m_Reader->m_File.IsOpen() )
765 // Warning: direct manipulation of MXF structures can interfere
766 // with the normal operation of the wrapper. Caveat emptor!
768 ASDCP::MXF::OP1aHeader&
769 ASDCP::JP2K::MXFSReader::OP1aHeader()
771 if ( m_Reader.empty() )
773 assert(g_OP1aHeader);
774 return *g_OP1aHeader;
777 return m_Reader->m_HeaderPart;
780 // Warning: direct manipulation of MXF structures can interfere
781 // with the normal operation of the wrapper. Caveat emptor!
783 ASDCP::MXF::OPAtomIndexFooter&
784 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
786 if ( m_Reader.empty() )
788 assert(g_OPAtomIndexFooter);
789 return *g_OPAtomIndexFooter;
792 return m_Reader->m_IndexAccess;
795 // Warning: direct manipulation of MXF structures can interfere
796 // with the normal operation of the wrapper. Caveat emptor!
799 ASDCP::JP2K::MXFSReader::RIP()
801 if ( m_Reader.empty() )
807 return m_Reader->m_RIP;
810 // Open the file for reading. The file must exist. Returns error if the
811 // operation cannot be completed.
813 ASDCP::JP2K::MXFSReader::OpenRead(const std::string& filename) const
815 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
820 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
822 Result_t result = RESULT_INIT;
824 if ( m_Reader && m_Reader->m_File.IsOpen() )
826 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
828 if ( ASDCP_SUCCESS(result) )
829 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
837 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
838 AESDecContext* Ctx, HMACContext* HMAC) const
840 if ( m_Reader && m_Reader->m_File.IsOpen() )
841 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
847 ASDCP::JP2K::MXFSReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
849 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
852 // Fill the struct with the values from the file's header.
853 // Returns RESULT_INIT if the file is not open.
855 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
857 if ( m_Reader && m_Reader->m_File.IsOpen() )
859 PDesc = m_Reader->m_PDesc;
867 // Fill the struct with the values from the file's header.
868 // Returns RESULT_INIT if the file is not open.
870 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
872 if ( m_Reader && m_Reader->m_File.IsOpen() )
874 Info = m_Reader->m_Info;
883 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
885 if ( m_Reader->m_File.IsOpen() )
886 m_Reader->m_HeaderPart.Dump(stream);
892 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
894 if ( m_Reader->m_File.IsOpen() )
895 m_Reader->m_IndexAccess.Dump(stream);
900 ASDCP::JP2K::MXFSReader::Close() const
902 if ( m_Reader && m_Reader->m_File.IsOpen() )
912 //------------------------------------------------------------------------------------------
916 class lh__Writer : public ASDCP::h__ASDCPWriter
918 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
921 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
924 PictureDescriptor m_PDesc;
925 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
927 lh__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_EssenceSubDescriptor(0) {
928 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
931 virtual ~lh__Writer(){}
933 Result_t OpenWrite(const std::string&, EssenceType_t type, ui32_t HeaderSize);
934 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
935 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
936 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
940 // Open the file for writing. The file must not exist. Returns error if
941 // the operation cannot be completed.
943 lh__Writer::OpenWrite(const std::string& filename, EssenceType_t type, ui32_t HeaderSize)
945 if ( ! m_State.Test_BEGIN() )
948 Result_t result = m_File.OpenWrite(filename);
950 if ( ASDCP_SUCCESS(result) )
952 m_HeaderSize = HeaderSize;
953 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
954 tmp_rgba->ComponentMaxRef = 4095;
955 tmp_rgba->ComponentMinRef = 0;
957 m_EssenceDescriptor = tmp_rgba;
958 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
959 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
961 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
962 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
964 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
966 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
967 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
968 GenRandomValue(StereoSubDesc->InstanceUID);
969 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
972 result = m_State.Goto_INIT();
978 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
980 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
983 if ( ! m_State.Test_INIT() )
986 if ( LocalEditRate == ASDCP::Rational(0,0) )
987 LocalEditRate = PDesc.EditRate;
991 assert(m_EssenceDescriptor);
992 assert(m_EssenceSubDescriptor);
993 Result_t result = JP2K_PDesc_to_MD(m_PDesc, *m_Dict,
994 *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(m_EssenceDescriptor),
995 *m_EssenceSubDescriptor);
997 if ( ASDCP_SUCCESS(result) )
999 if ( PDesc.StoredWidth < 2049 )
1001 static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
1002 m_EssenceSubDescriptor->Rsize = 3;
1006 static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
1007 m_EssenceSubDescriptor->Rsize = 4;
1010 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
1011 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
1012 result = m_State.Goto_READY();
1015 if ( ASDCP_SUCCESS(result) )
1017 result = WriteASDCPHeader(label, UL(m_Dict->ul(MDD_JPEG_2000WrappingFrame)),
1018 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
1019 LocalEditRate, derive_timecode_rate_from_edit_rate(m_PDesc.EditRate));
1025 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1026 // argument is present, the essence is encrypted prior to writing.
1027 // Fails if the file is not open, is finalized, or an operating system
1031 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
1032 AESEncContext* Ctx, HMACContext* HMAC)
1034 Result_t result = RESULT_OK;
1036 if ( m_State.Test_READY() )
1037 result = m_State.Goto_RUNNING(); // first time through
1039 ui64_t StreamOffset = m_StreamOffset;
1041 if ( ASDCP_SUCCESS(result) )
1042 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
1044 if ( ASDCP_SUCCESS(result) && add_index )
1046 IndexTableSegment::IndexEntry Entry;
1047 Entry.StreamOffset = StreamOffset;
1048 m_FooterPart.PushIndexEntry(Entry);
1056 // Closes the MXF file, writing the index and other closing information.
1059 lh__Writer::Finalize()
1061 if ( ! m_State.Test_RUNNING() )
1062 return RESULT_STATE;
1064 m_State.Goto_FINAL();
1066 return WriteASDCPFooter();
1071 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1073 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1077 h__Writer(const Dictionary& d) : lh__Writer(d) {}
1081 //------------------------------------------------------------------------------------------
1085 ASDCP::JP2K::MXFWriter::MXFWriter()
1089 ASDCP::JP2K::MXFWriter::~MXFWriter()
1093 // Warning: direct manipulation of MXF structures can interfere
1094 // with the normal operation of the wrapper. Caveat emptor!
1096 ASDCP::MXF::OP1aHeader&
1097 ASDCP::JP2K::MXFWriter::OP1aHeader()
1099 if ( m_Writer.empty() )
1101 assert(g_OP1aHeader);
1102 return *g_OP1aHeader;
1105 return m_Writer->m_HeaderPart;
1108 // Warning: direct manipulation of MXF structures can interfere
1109 // with the normal operation of the wrapper. Caveat emptor!
1111 ASDCP::MXF::OPAtomIndexFooter&
1112 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1114 if ( m_Writer.empty() )
1116 assert(g_OPAtomIndexFooter);
1117 return *g_OPAtomIndexFooter;
1120 return m_Writer->m_FooterPart;
1123 // Warning: direct manipulation of MXF structures can interfere
1124 // with the normal operation of the wrapper. Caveat emptor!
1127 ASDCP::JP2K::MXFWriter::RIP()
1129 if ( m_Writer.empty() )
1135 return m_Writer->m_RIP;
1138 // Open the file for writing. The file must not exist. Returns error if
1139 // the operation cannot be completed.
1141 ASDCP::JP2K::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
1142 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1144 if ( Info.LabelSetType == LS_MXF_SMPTE )
1145 m_Writer = new h__Writer(DefaultSMPTEDict());
1147 m_Writer = new h__Writer(DefaultInteropDict());
1149 m_Writer->m_Info = Info;
1151 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1153 if ( ASDCP_SUCCESS(result) )
1154 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1156 if ( ASDCP_FAILURE(result) )
1163 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1164 // argument is present, the essence is encrypted prior to writing.
1165 // Fails if the file is not open, is finalized, or an operating system
1168 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1170 if ( m_Writer.empty() )
1173 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1176 // Closes the MXF file, writing the index and other closing information.
1178 ASDCP::JP2K::MXFWriter::Finalize()
1180 if ( m_Writer.empty() )
1183 return m_Writer->Finalize();
1187 //------------------------------------------------------------------------------------------
1191 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1193 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1195 StereoscopicPhase_t m_NextPhase;
1198 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1201 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1202 AESEncContext* Ctx, HMACContext* HMAC)
1204 if ( m_NextPhase != phase )
1205 return RESULT_SPHASE;
1207 if ( phase == SP_LEFT )
1209 m_NextPhase = SP_RIGHT;
1210 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1213 m_NextPhase = SP_LEFT;
1214 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1220 if ( m_NextPhase != SP_LEFT )
1221 return RESULT_SPHASE;
1223 assert( m_FramesWritten % 2 == 0 );
1224 m_FramesWritten /= 2;
1225 return lh__Writer::Finalize();
1231 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1235 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1239 // Warning: direct manipulation of MXF structures can interfere
1240 // with the normal operation of the wrapper. Caveat emptor!
1242 ASDCP::MXF::OP1aHeader&
1243 ASDCP::JP2K::MXFSWriter::OP1aHeader()
1245 if ( m_Writer.empty() )
1247 assert(g_OP1aHeader);
1248 return *g_OP1aHeader;
1251 return m_Writer->m_HeaderPart;
1254 // Warning: direct manipulation of MXF structures can interfere
1255 // with the normal operation of the wrapper. Caveat emptor!
1257 ASDCP::MXF::OPAtomIndexFooter&
1258 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1260 if ( m_Writer.empty() )
1262 assert(g_OPAtomIndexFooter);
1263 return *g_OPAtomIndexFooter;
1266 return m_Writer->m_FooterPart;
1269 // Warning: direct manipulation of MXF structures can interfere
1270 // with the normal operation of the wrapper. Caveat emptor!
1273 ASDCP::JP2K::MXFSWriter::RIP()
1275 if ( m_Writer.empty() )
1281 return m_Writer->m_RIP;
1284 // Open the file for writing. The file must not exist. Returns error if
1285 // the operation cannot be completed.
1287 ASDCP::JP2K::MXFSWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
1288 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1290 if ( Info.LabelSetType == LS_MXF_SMPTE )
1291 m_Writer = new h__SWriter(DefaultSMPTEDict());
1293 m_Writer = new h__SWriter(DefaultInteropDict());
1295 if ( PDesc.EditRate != ASDCP::EditRate_24
1296 && PDesc.EditRate != ASDCP::EditRate_25
1297 && PDesc.EditRate != ASDCP::EditRate_30
1298 && PDesc.EditRate != ASDCP::EditRate_48
1299 && PDesc.EditRate != ASDCP::EditRate_50
1300 && PDesc.EditRate != ASDCP::EditRate_60 )
1302 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1303 return RESULT_FORMAT;
1306 if ( PDesc.StoredWidth > 2048 )
1307 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1309 m_Writer->m_Info = Info;
1311 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1313 if ( ASDCP_SUCCESS(result) )
1315 PictureDescriptor TmpPDesc = PDesc;
1317 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1318 TmpPDesc.EditRate = ASDCP::EditRate_48;
1320 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1321 TmpPDesc.EditRate = ASDCP::EditRate_50;
1323 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1324 TmpPDesc.EditRate = ASDCP::EditRate_60;
1326 else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1327 TmpPDesc.EditRate = ASDCP::EditRate_96;
1329 else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1330 TmpPDesc.EditRate = ASDCP::EditRate_100;
1332 else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1333 TmpPDesc.EditRate = ASDCP::EditRate_120;
1335 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1338 if ( ASDCP_FAILURE(result) )
1345 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1347 if ( m_Writer.empty() )
1350 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1352 if ( ASDCP_SUCCESS(result) )
1353 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1358 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1359 // argument is present, the essence is encrypted prior to writing.
1360 // Fails if the file is not open, is finalized, or an operating system
1363 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1364 AESEncContext* Ctx, HMACContext* HMAC)
1366 if ( m_Writer.empty() )
1369 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1372 // Closes the MXF file, writing the index and other closing information.
1374 ASDCP::JP2K::MXFSWriter::Finalize()
1376 if ( m_Writer.empty() )
1379 return m_Writer->Finalize();
1383 // end AS_DCP_JP2K.cpp