2 Copyright (c) 2004-2013, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 /*! \file AS_DCP_JP2k.cpp
29 \brief AS-DCP library, JPEG 2000 essence reader and writer implementation
32 #include "AS_DCP_internal.h"
36 using namespace ASDCP::JP2K;
37 using Kumu::GenRandomValue;
39 //------------------------------------------------------------------------------------------
41 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
42 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
43 static std::string PICT_DEF_LABEL = "Picture Track";
45 int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
49 ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc)
51 strm << " AspectRatio: " << PDesc.AspectRatio.Numerator << "/" << PDesc.AspectRatio.Denominator << std::endl;
52 strm << " EditRate: " << PDesc.EditRate.Numerator << "/" << PDesc.EditRate.Denominator << std::endl;
53 strm << " SampleRate: " << PDesc.SampleRate.Numerator << "/" << PDesc.SampleRate.Denominator << std::endl;
54 strm << " StoredWidth: " << (unsigned) PDesc.StoredWidth << std::endl;
55 strm << " StoredHeight: " << (unsigned) PDesc.StoredHeight << std::endl;
56 strm << " Rsize: " << (unsigned) PDesc.Rsize << std::endl;
57 strm << " Xsize: " << (unsigned) PDesc.Xsize << std::endl;
58 strm << " Ysize: " << (unsigned) PDesc.Ysize << std::endl;
59 strm << " XOsize: " << (unsigned) PDesc.XOsize << std::endl;
60 strm << " YOsize: " << (unsigned) PDesc.YOsize << std::endl;
61 strm << " XTsize: " << (unsigned) PDesc.XTsize << std::endl;
62 strm << " YTsize: " << (unsigned) PDesc.YTsize << std::endl;
63 strm << " XTOsize: " << (unsigned) PDesc.XTOsize << std::endl;
64 strm << " YTOsize: " << (unsigned) PDesc.YTOsize << std::endl;
65 strm << " ContainerDuration: " << (unsigned) PDesc.ContainerDuration << std::endl;
67 strm << "-- JPEG 2000 Metadata --" << std::endl;
68 strm << " ImageComponents:" << std::endl;
69 strm << " bits h-sep v-sep" << std::endl;
72 for ( i = 0; i < PDesc.Csize; i++ )
74 strm << " " << std::setw(4) << PDesc.ImageComponents[i].Ssize + 1 /* See ISO 15444-1, Table A11, for the origin of '+1' */
75 << " " << std::setw(5) << PDesc.ImageComponents[i].XRsize
76 << " " << std::setw(5) << PDesc.ImageComponents[i].YRsize
80 strm << " Scod: " << (short) PDesc.CodingStyleDefault.Scod << std::endl;
81 strm << " ProgressionOrder: " << (short) PDesc.CodingStyleDefault.SGcod.ProgressionOrder << std::endl;
82 strm << " NumberOfLayers: " << (short) KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)) << std::endl;
83 strm << " MultiCompTransform: " << (short) PDesc.CodingStyleDefault.SGcod.MultiCompTransform << std::endl;
84 strm << "DecompositionLevels: " << (short) PDesc.CodingStyleDefault.SPcod.DecompositionLevels << std::endl;
85 strm << " CodeblockWidth: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockWidth << std::endl;
86 strm << " CodeblockHeight: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockHeight << std::endl;
87 strm << " CodeblockStyle: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockStyle << std::endl;
88 strm << " Transformation: " << (short) PDesc.CodingStyleDefault.SPcod.Transformation << std::endl;
91 ui32_t precinct_set_size = 0;
93 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
96 strm << " Precincts: " << (short) precinct_set_size << std::endl;
97 strm << "precinct dimensions:" << std::endl;
99 for ( i = 0; i < precinct_set_size; i++ )
100 strm << " " << i + 1 << ": " << s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f] << " x "
101 << s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] << std::endl;
103 strm << " Sqcd: " << (short) PDesc.QuantizationDefault.Sqcd << std::endl;
105 char tmp_buf[MaxDefaults*2];
106 strm << " SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2)
114 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
120 AspectRatio: %d/%d\n\
134 ContainerDuration: %u\n",
135 PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
136 PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
137 PDesc.SampleRate.Numerator, PDesc.SampleRate.Denominator,
149 PDesc.ContainerDuration
152 fprintf(stream, "-- JPEG 2000 Metadata --\n");
153 fprintf(stream, " ImageComponents:\n");
154 fprintf(stream, " bits h-sep v-sep\n");
157 for ( i = 0; i < PDesc.Csize; i++ )
159 fprintf(stream, " %4d %5d %5d\n",
160 PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
161 PDesc.ImageComponents[i].XRsize,
162 PDesc.ImageComponents[i].YRsize
166 fprintf(stream, " Scod: %hd\n", PDesc.CodingStyleDefault.Scod);
167 fprintf(stream, " ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
168 fprintf(stream, " NumberOfLayers: %hd\n",
169 KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
171 fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
172 fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
173 fprintf(stream, " CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
174 fprintf(stream, " CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
175 fprintf(stream, " CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
176 fprintf(stream, " Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
179 ui32_t precinct_set_size = 0;
181 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
184 fprintf(stream, " Precincts: %hd\n", precinct_set_size);
185 fprintf(stream, "precinct dimensions:\n");
187 for ( i = 0; i < precinct_set_size; i++ )
188 fprintf(stream, " %d: %d x %d\n", i + 1,
189 s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
190 s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
193 fprintf(stream, " Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd);
195 char tmp_buf[MaxDefaults*2];
196 fprintf(stream, " SPqcd: %s\n",
197 Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
198 tmp_buf, MaxDefaults*2)
203 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& dict,
211 ASDCP::MXF::RGBAEssenceDescriptor *EssenceDescriptor,
212 ASDCP::MXF::JPEG2000PictureSubDescriptor *EssenceSubDescriptor)
214 if ( EssenceDescriptor == 0 || EssenceSubDescriptor == 0 )
217 EssenceDescriptor->ContainerDuration = PDesc.ContainerDuration;
218 EssenceDescriptor->SampleRate = PDesc.EditRate;
219 EssenceDescriptor->FrameLayout = 0;
220 EssenceDescriptor->StoredWidth = PDesc.StoredWidth;
221 EssenceDescriptor->StoredHeight = PDesc.StoredHeight;
222 EssenceDescriptor->AspectRatio = PDesc.AspectRatio;
224 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
226 // PictureEssenceCoding UL =
227 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
229 // ComponentMaxRef ui32_t = 4095
230 // ComponentMinRef ui32_t = 0
231 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
234 if ( PDesc.StoredWidth < 2049 )
236 EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_2K));
237 EssenceSubDescriptor->Rsize = 3;
241 EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_4K));
242 EssenceSubDescriptor->Rsize = 4;
245 EssenceSubDescriptor->Xsize = PDesc.Xsize;
246 EssenceSubDescriptor->Ysize = PDesc.Ysize;
247 EssenceSubDescriptor->XOsize = PDesc.XOsize;
248 EssenceSubDescriptor->YOsize = PDesc.YOsize;
249 EssenceSubDescriptor->XTsize = PDesc.XTsize;
250 EssenceSubDescriptor->YTsize = PDesc.YTsize;
251 EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
252 EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
253 EssenceSubDescriptor->Csize = PDesc.Csize;
255 const ui32_t tmp_buffer_len = 1024;
256 byte_t tmp_buffer[tmp_buffer_len];
258 *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
259 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
260 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
262 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
263 memcpy(EssenceSubDescriptor->PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size);
264 EssenceSubDescriptor->PictureComponentSizing.get().Length(pcomp_size);
266 ui32_t precinct_set_size = 0, i;
267 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
270 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
271 memcpy(EssenceSubDescriptor->CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size);
272 EssenceSubDescriptor->CodingStyleDefault.get().Length(csd_size);
274 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
275 memcpy(EssenceSubDescriptor->QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size);
276 EssenceSubDescriptor->QuantizationDefault.get().Length(qdflt_size);
284 ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::RGBAEssenceDescriptor& EssenceDescriptor,
285 const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
286 const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
287 ASDCP::JP2K::PictureDescriptor& PDesc)
289 memset(&PDesc, 0, sizeof(PDesc));
291 PDesc.EditRate = EditRate;
292 PDesc.SampleRate = SampleRate;
293 assert(EssenceDescriptor.ContainerDuration.const_get() <= 0xFFFFFFFFL);
294 PDesc.ContainerDuration = static_cast<ui32_t>(EssenceDescriptor.ContainerDuration.const_get());
295 PDesc.StoredWidth = EssenceDescriptor.StoredWidth;
296 PDesc.StoredHeight = EssenceDescriptor.StoredHeight;
297 PDesc.AspectRatio = EssenceDescriptor.AspectRatio;
299 PDesc.Rsize = EssenceSubDescriptor.Rsize;
300 PDesc.Xsize = EssenceSubDescriptor.Xsize;
301 PDesc.Ysize = EssenceSubDescriptor.Ysize;
302 PDesc.XOsize = EssenceSubDescriptor.XOsize;
303 PDesc.YOsize = EssenceSubDescriptor.YOsize;
304 PDesc.XTsize = EssenceSubDescriptor.XTsize;
305 PDesc.YTsize = EssenceSubDescriptor.YTsize;
306 PDesc.XTOsize = EssenceSubDescriptor.XTOsize;
307 PDesc.YTOsize = EssenceSubDescriptor.YTOsize;
308 PDesc.Csize = EssenceSubDescriptor.Csize;
310 // PictureComponentSizing
311 ui32_t tmp_size = EssenceSubDescriptor.PictureComponentSizing.const_get().Length();
313 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
315 memcpy(&PDesc.ImageComponents, EssenceSubDescriptor.PictureComponentSizing.const_get().RoData() + 8, tmp_size - 8);
319 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
322 // CodingStyleDefault
323 memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
324 memcpy(&PDesc.CodingStyleDefault,
325 EssenceSubDescriptor.CodingStyleDefault.const_get().RoData(),
326 EssenceSubDescriptor.CodingStyleDefault.const_get().Length());
328 // QuantizationDefault
329 memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
330 memcpy(&PDesc.QuantizationDefault,
331 EssenceSubDescriptor.QuantizationDefault.const_get().RoData(),
332 EssenceSubDescriptor.QuantizationDefault.const_get().Length());
334 PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1;
340 ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc,
341 const ASDCP::Dictionary& dict,
342 ASDCP::MXF::CDCIEssenceDescriptor *EssenceDescriptor,
343 ASDCP::MXF::JPEG2000PictureSubDescriptor *EssenceSubDescriptor)
345 if ( EssenceDescriptor == 0 || EssenceSubDescriptor == 0 )
348 EssenceDescriptor->ContainerDuration = PDesc.ContainerDuration;
349 EssenceDescriptor->SampleRate = PDesc.EditRate;
350 EssenceDescriptor->FrameLayout = 0;
351 EssenceDescriptor->StoredWidth = PDesc.StoredWidth;
352 EssenceDescriptor->StoredHeight = PDesc.StoredHeight;
353 EssenceDescriptor->AspectRatio = PDesc.AspectRatio;
355 // if ( m_Info.LabelSetType == LS_MXF_SMPTE )
357 // PictureEssenceCoding UL =
358 // Video Line Map ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
360 // ComponentMaxRef ui32_t = 4095
361 // ComponentMinRef ui32_t = 0
362 // PixelLayout byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
365 if ( PDesc.StoredWidth < 2049 )
367 EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_2K));
368 EssenceSubDescriptor->Rsize = 3;
372 EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_4K));
373 EssenceSubDescriptor->Rsize = 4;
376 EssenceSubDescriptor->Xsize = PDesc.Xsize;
377 EssenceSubDescriptor->Ysize = PDesc.Ysize;
378 EssenceSubDescriptor->XOsize = PDesc.XOsize;
379 EssenceSubDescriptor->YOsize = PDesc.YOsize;
380 EssenceSubDescriptor->XTsize = PDesc.XTsize;
381 EssenceSubDescriptor->YTsize = PDesc.YTsize;
382 EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
383 EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
384 EssenceSubDescriptor->Csize = PDesc.Csize;
386 const ui32_t tmp_buffer_len = 1024;
387 byte_t tmp_buffer[tmp_buffer_len];
389 *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
390 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
391 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
393 const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
394 memcpy(EssenceSubDescriptor->PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size);
395 EssenceSubDescriptor->PictureComponentSizing.get().Length(pcomp_size);
397 ui32_t precinct_set_size = 0, i;
398 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
401 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
402 memcpy(EssenceSubDescriptor->CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size);
403 EssenceSubDescriptor->CodingStyleDefault.get().Length(csd_size);
405 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
406 memcpy(EssenceSubDescriptor->QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size);
407 EssenceSubDescriptor->QuantizationDefault.get().Length(qdflt_size);
415 ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::CDCIEssenceDescriptor& EssenceDescriptor,
416 const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
417 const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
418 ASDCP::JP2K::PictureDescriptor& PDesc)
420 memset(&PDesc, 0, sizeof(PDesc));
422 PDesc.EditRate = EditRate;
423 PDesc.SampleRate = SampleRate;
424 assert(EssenceDescriptor.ContainerDuration.const_get() <= 0xFFFFFFFFL);
425 PDesc.ContainerDuration = static_cast<ui32_t>(EssenceDescriptor.ContainerDuration.const_get());
426 PDesc.StoredWidth = EssenceDescriptor.StoredWidth;
427 PDesc.StoredHeight = EssenceDescriptor.StoredHeight;
428 PDesc.AspectRatio = EssenceDescriptor.AspectRatio;
430 PDesc.Rsize = EssenceSubDescriptor.Rsize;
431 PDesc.Xsize = EssenceSubDescriptor.Xsize;
432 PDesc.Ysize = EssenceSubDescriptor.Ysize;
433 PDesc.XOsize = EssenceSubDescriptor.XOsize;
434 PDesc.YOsize = EssenceSubDescriptor.YOsize;
435 PDesc.XTsize = EssenceSubDescriptor.XTsize;
436 PDesc.YTsize = EssenceSubDescriptor.YTsize;
437 PDesc.XTOsize = EssenceSubDescriptor.XTOsize;
438 PDesc.YTOsize = EssenceSubDescriptor.YTOsize;
439 PDesc.Csize = EssenceSubDescriptor.Csize;
441 // PictureComponentSizing
442 ui32_t tmp_size = EssenceSubDescriptor.PictureComponentSizing.const_get().Length();
444 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
446 memcpy(&PDesc.ImageComponents, EssenceSubDescriptor.PictureComponentSizing.const_get().RoData() + 8, tmp_size - 8);
450 DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
453 // CodingStyleDefault
454 memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
455 memcpy(&PDesc.CodingStyleDefault,
456 EssenceSubDescriptor.CodingStyleDefault.const_get().RoData(),
457 EssenceSubDescriptor.CodingStyleDefault.const_get().Length());
459 // QuantizationDefault
460 memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
461 memcpy(&PDesc.QuantizationDefault,
462 EssenceSubDescriptor.QuantizationDefault.const_get().RoData(),
463 EssenceSubDescriptor.QuantizationDefault.const_get().Length());
465 PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1;
469 // Compares the actual floating point value of the rates.
470 // This allows, for example, {300000,1001} and {2997,100) to be considered equivalent.
473 epsilon_compare(const ASDCP::Rational& left, const ASDCP::Rational& right, double epsilon = 0.001)
476 double difference = left.Quotient() - right.Quotient();
478 if (fabs(difference) < epsilon)
486 //------------------------------------------------------------------------------------------
488 // hidden, internal implementation of JPEG 2000 reader
491 class lh__Reader : public ASDCP::h__ASDCPReader
493 RGBAEssenceDescriptor* m_EssenceDescriptor;
494 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
495 ASDCP::Rational m_EditRate;
496 ASDCP::Rational m_SampleRate;
497 EssenceType_t m_Format;
499 ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
502 PictureDescriptor m_PDesc; // codestream parameter list
504 lh__Reader(const Dictionary& d) :
505 ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
507 virtual ~lh__Reader() {}
509 Result_t OpenRead(const char*, EssenceType_t);
510 Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
517 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
519 Result_t result = OpenMXFRead(filename);
521 if( ASDCP_SUCCESS(result) )
523 InterchangeObject* tmp_iobj = 0;
524 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
525 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
527 if ( m_EssenceDescriptor == 0 )
529 DefaultLogSink().Error("RGBAEssenceDescriptor object not found.\n");
530 return RESULT_FORMAT;
533 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
534 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
536 if ( m_EssenceSubDescriptor == 0 )
538 m_EssenceDescriptor = 0;
539 DefaultLogSink().Error("JPEG2000PictureSubDescriptor object not found.\n");
540 return RESULT_FORMAT;
543 std::list<InterchangeObject*> ObjectList;
544 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
546 if ( ObjectList.empty() )
548 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
549 return RESULT_FORMAT;
552 m_EditRate = ((Track*)ObjectList.front())->EditRate;
553 m_SampleRate = m_EssenceDescriptor->SampleRate;
555 if ( type == ASDCP::ESS_JPEG_2000 )
557 if ( m_EditRate != m_SampleRate )
559 DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
560 m_EditRate.Quotient(), m_SampleRate.Quotient());
562 if ( m_EditRate == EditRate_24 && m_SampleRate == EditRate_48 ||
563 m_EditRate == EditRate_25 && m_SampleRate == EditRate_50 ||
564 m_EditRate == EditRate_30 && m_SampleRate == EditRate_60 ||
565 m_EditRate == EditRate_48 && m_SampleRate == EditRate_96 ||
566 m_EditRate == EditRate_50 && m_SampleRate == EditRate_100 ||
567 m_EditRate == EditRate_60 && m_SampleRate == EditRate_120 )
569 DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
570 return RESULT_SFORMAT;
573 return RESULT_FORMAT;
576 else if ( type == ASDCP::ESS_JPEG_2000_S )
578 if ( m_EditRate == EditRate_24 )
580 if ( m_SampleRate != EditRate_48 )
582 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
583 return RESULT_FORMAT;
586 else if ( m_EditRate == EditRate_25 )
588 if ( m_SampleRate != EditRate_50 )
590 DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
591 return RESULT_FORMAT;
594 else if ( m_EditRate == EditRate_30 )
596 if ( m_SampleRate != EditRate_60 )
598 DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
599 return RESULT_FORMAT;
602 else if ( m_EditRate == EditRate_48 )
604 if ( m_SampleRate != EditRate_96 )
606 DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
607 return RESULT_FORMAT;
610 else if ( m_EditRate == EditRate_50 )
612 if ( m_SampleRate != EditRate_100 )
614 DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
615 return RESULT_FORMAT;
618 else if ( m_EditRate == EditRate_60 )
620 if ( m_SampleRate != EditRate_120 )
622 DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
623 return RESULT_FORMAT;
628 DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
629 m_EditRate.Numerator, m_EditRate.Denominator);
630 return RESULT_FORMAT;
635 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
639 result = MD_to_JP2K_PDesc(*m_EssenceDescriptor, *m_EssenceSubDescriptor, m_EditRate, m_SampleRate, m_PDesc);
648 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
649 AESDecContext* Ctx, HMACContext* HMAC)
651 if ( ! m_File.IsOpen() )
655 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
660 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
662 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
666 h__Reader(const Dictionary& d) : lh__Reader(d) {}
671 //------------------------------------------------------------------------------------------
676 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
681 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
686 Kumu::hexdump(m_Data, dump_len, stream);
690 //------------------------------------------------------------------------------------------
692 ASDCP::JP2K::MXFReader::MXFReader()
694 m_Reader = new h__Reader(DefaultCompositeDict());
698 ASDCP::JP2K::MXFReader::~MXFReader()
700 if ( m_Reader && m_Reader->m_File.IsOpen() )
704 // Warning: direct manipulation of MXF structures can interfere
705 // with the normal operation of the wrapper. Caveat emptor!
707 ASDCP::MXF::OP1aHeader&
708 ASDCP::JP2K::MXFReader::OP1aHeader()
710 if ( m_Reader.empty() )
712 assert(g_OP1aHeader);
713 return *g_OP1aHeader;
716 return m_Reader->m_HeaderPart;
719 // Warning: direct manipulation of MXF structures can interfere
720 // with the normal operation of the wrapper. Caveat emptor!
722 ASDCP::MXF::OPAtomIndexFooter&
723 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
725 if ( m_Reader.empty() )
727 assert(g_OPAtomIndexFooter);
728 return *g_OPAtomIndexFooter;
731 return m_Reader->m_IndexAccess;
734 // Warning: direct manipulation of MXF structures can interfere
735 // with the normal operation of the wrapper. Caveat emptor!
738 ASDCP::JP2K::MXFReader::RIP()
740 if ( m_Reader.empty() )
746 return m_Reader->m_RIP;
749 // Open the file for reading. The file must exist. Returns error if the
750 // operation cannot be completed.
752 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
754 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
759 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
760 AESDecContext* Ctx, HMACContext* HMAC) const
762 if ( m_Reader && m_Reader->m_File.IsOpen() )
763 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
769 ASDCP::JP2K::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
771 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
775 // Fill the struct with the values from the file's header.
776 // Returns RESULT_INIT if the file is not open.
778 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
780 if ( m_Reader && m_Reader->m_File.IsOpen() )
782 PDesc = m_Reader->m_PDesc;
790 // Fill the struct with the values from the file's header.
791 // Returns RESULT_INIT if the file is not open.
793 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
795 if ( m_Reader && m_Reader->m_File.IsOpen() )
797 Info = m_Reader->m_Info;
806 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
808 if ( m_Reader->m_File.IsOpen() )
809 m_Reader->m_HeaderPart.Dump(stream);
815 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
817 if ( m_Reader->m_File.IsOpen() )
818 m_Reader->m_IndexAccess.Dump(stream);
823 ASDCP::JP2K::MXFReader::Close() const
825 if ( m_Reader && m_Reader->m_File.IsOpen() )
835 //------------------------------------------------------------------------------------------
838 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
840 ui32_t m_StereoFrameReady;
843 h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
846 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
847 AESDecContext* Ctx, HMACContext* HMAC)
849 // look up frame index node
850 IndexTableSegment::IndexEntry TmpEntry;
852 if ( ASDCP_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
854 DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
858 // get frame position
859 Kumu::fpos_t FilePosition = m_HeaderPart.BodyOffset + TmpEntry.StreamOffset;
860 Result_t result = RESULT_OK;
862 if ( phase == SP_LEFT )
864 if ( FilePosition != m_LastPosition )
866 m_LastPosition = FilePosition;
867 result = m_File.Seek(FilePosition);
870 // the call to ReadEKLVPacket() will leave the file on an R frame
871 m_StereoFrameReady = FrameNum;
873 else if ( phase == SP_RIGHT )
875 if ( m_StereoFrameReady != FrameNum )
877 // the file is not already positioned, we must do some work
878 // seek to the companion SP_LEFT frame and read the frame's key and length
879 if ( FilePosition != m_LastPosition )
881 m_LastPosition = FilePosition;
882 result = m_File.Seek(FilePosition);
886 result = Reader.ReadKLFromFile(m_File);
888 if ( ASDCP_SUCCESS(result) )
890 // skip over the companion SP_LEFT frame
891 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
892 result = m_File.Seek(new_pos);
896 // the call to ReadEKLVPacket() will leave the file not on an R frame
897 m_StereoFrameReady = 0xffffffff;
901 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
905 if( ASDCP_SUCCESS(result) )
907 ui32_t SequenceNum = FrameNum * 2;
908 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
910 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
919 ASDCP::JP2K::MXFSReader::MXFSReader()
921 m_Reader = new h__SReader(DefaultCompositeDict());
925 ASDCP::JP2K::MXFSReader::~MXFSReader()
927 if ( m_Reader && m_Reader->m_File.IsOpen() )
931 // Warning: direct manipulation of MXF structures can interfere
932 // with the normal operation of the wrapper. Caveat emptor!
934 ASDCP::MXF::OP1aHeader&
935 ASDCP::JP2K::MXFSReader::OP1aHeader()
937 if ( m_Reader.empty() )
939 assert(g_OP1aHeader);
940 return *g_OP1aHeader;
943 return m_Reader->m_HeaderPart;
946 // Warning: direct manipulation of MXF structures can interfere
947 // with the normal operation of the wrapper. Caveat emptor!
949 ASDCP::MXF::OPAtomIndexFooter&
950 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
952 if ( m_Reader.empty() )
954 assert(g_OPAtomIndexFooter);
955 return *g_OPAtomIndexFooter;
958 return m_Reader->m_IndexAccess;
961 // Warning: direct manipulation of MXF structures can interfere
962 // with the normal operation of the wrapper. Caveat emptor!
965 ASDCP::JP2K::MXFSReader::RIP()
967 if ( m_Reader.empty() )
973 return m_Reader->m_RIP;
976 // Open the file for reading. The file must exist. Returns error if the
977 // operation cannot be completed.
979 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
981 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
986 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
988 Result_t result = RESULT_INIT;
990 if ( m_Reader && m_Reader->m_File.IsOpen() )
992 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
994 if ( ASDCP_SUCCESS(result) )
995 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
1003 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
1004 AESDecContext* Ctx, HMACContext* HMAC) const
1006 if ( m_Reader && m_Reader->m_File.IsOpen() )
1007 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
1013 ASDCP::JP2K::MXFSReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
1015 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
1018 // Fill the struct with the values from the file's header.
1019 // Returns RESULT_INIT if the file is not open.
1021 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
1023 if ( m_Reader && m_Reader->m_File.IsOpen() )
1025 PDesc = m_Reader->m_PDesc;
1033 // Fill the struct with the values from the file's header.
1034 // Returns RESULT_INIT if the file is not open.
1036 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
1038 if ( m_Reader && m_Reader->m_File.IsOpen() )
1040 Info = m_Reader->m_Info;
1049 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
1051 if ( m_Reader->m_File.IsOpen() )
1052 m_Reader->m_HeaderPart.Dump(stream);
1058 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
1060 if ( m_Reader->m_File.IsOpen() )
1061 m_Reader->m_IndexAccess.Dump(stream);
1066 ASDCP::JP2K::MXFSReader::Close() const
1068 if ( m_Reader && m_Reader->m_File.IsOpen() )
1078 //------------------------------------------------------------------------------------------
1082 class lh__Writer : public ASDCP::h__ASDCPWriter
1084 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
1087 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
1090 PictureDescriptor m_PDesc;
1091 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
1093 lh__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_EssenceSubDescriptor(0) {
1094 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
1097 virtual ~lh__Writer(){}
1099 Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
1100 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
1101 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
1102 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
1103 Result_t Finalize();
1106 // Open the file for writing. The file must not exist. Returns error if
1107 // the operation cannot be completed.
1109 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
1111 if ( ! m_State.Test_BEGIN() )
1112 return RESULT_STATE;
1114 Result_t result = m_File.OpenWrite(filename);
1116 if ( ASDCP_SUCCESS(result) )
1118 m_HeaderSize = HeaderSize;
1119 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
1120 tmp_rgba->ComponentMaxRef = 4095;
1121 tmp_rgba->ComponentMinRef = 0;
1123 m_EssenceDescriptor = tmp_rgba;
1124 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
1125 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
1127 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
1128 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
1130 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
1132 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
1133 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
1134 GenRandomValue(StereoSubDesc->InstanceUID);
1135 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
1138 result = m_State.Goto_INIT();
1144 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
1146 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
1149 if ( ! m_State.Test_INIT() )
1150 return RESULT_STATE;
1152 if ( LocalEditRate == ASDCP::Rational(0,0) )
1153 LocalEditRate = PDesc.EditRate;
1157 Result_t result = JP2K_PDesc_to_MD(m_PDesc, *m_Dict,
1158 (ASDCP::MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor,
1159 m_EssenceSubDescriptor);
1161 if ( ASDCP_SUCCESS(result) )
1163 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
1164 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
1165 result = m_State.Goto_READY();
1168 if ( ASDCP_SUCCESS(result) )
1170 result = WriteASDCPHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
1171 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
1172 LocalEditRate, derive_timecode_rate_from_edit_rate(m_PDesc.EditRate));
1178 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1179 // argument is present, the essence is encrypted prior to writing.
1180 // Fails if the file is not open, is finalized, or an operating system
1184 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
1185 AESEncContext* Ctx, HMACContext* HMAC)
1187 Result_t result = RESULT_OK;
1189 if ( m_State.Test_READY() )
1190 result = m_State.Goto_RUNNING(); // first time through
1192 ui64_t StreamOffset = m_StreamOffset;
1194 if ( ASDCP_SUCCESS(result) )
1195 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
1197 if ( ASDCP_SUCCESS(result) && add_index )
1199 IndexTableSegment::IndexEntry Entry;
1200 Entry.StreamOffset = StreamOffset;
1201 m_FooterPart.PushIndexEntry(Entry);
1209 // Closes the MXF file, writing the index and other closing information.
1212 lh__Writer::Finalize()
1214 if ( ! m_State.Test_RUNNING() )
1215 return RESULT_STATE;
1217 m_State.Goto_FINAL();
1219 return WriteASDCPFooter();
1224 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1226 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1230 h__Writer(const Dictionary& d) : lh__Writer(d) {}
1234 //------------------------------------------------------------------------------------------
1238 ASDCP::JP2K::MXFWriter::MXFWriter()
1242 ASDCP::JP2K::MXFWriter::~MXFWriter()
1246 // Warning: direct manipulation of MXF structures can interfere
1247 // with the normal operation of the wrapper. Caveat emptor!
1249 ASDCP::MXF::OP1aHeader&
1250 ASDCP::JP2K::MXFWriter::OP1aHeader()
1252 if ( m_Writer.empty() )
1254 assert(g_OP1aHeader);
1255 return *g_OP1aHeader;
1258 return m_Writer->m_HeaderPart;
1261 // Warning: direct manipulation of MXF structures can interfere
1262 // with the normal operation of the wrapper. Caveat emptor!
1264 ASDCP::MXF::OPAtomIndexFooter&
1265 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1267 if ( m_Writer.empty() )
1269 assert(g_OPAtomIndexFooter);
1270 return *g_OPAtomIndexFooter;
1273 return m_Writer->m_FooterPart;
1276 // Warning: direct manipulation of MXF structures can interfere
1277 // with the normal operation of the wrapper. Caveat emptor!
1280 ASDCP::JP2K::MXFWriter::RIP()
1282 if ( m_Writer.empty() )
1288 return m_Writer->m_RIP;
1291 // Open the file for writing. The file must not exist. Returns error if
1292 // the operation cannot be completed.
1294 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1295 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1297 if ( Info.LabelSetType == LS_MXF_SMPTE )
1298 m_Writer = new h__Writer(DefaultSMPTEDict());
1300 m_Writer = new h__Writer(DefaultInteropDict());
1302 m_Writer->m_Info = Info;
1304 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1306 if ( ASDCP_SUCCESS(result) )
1307 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1309 if ( ASDCP_FAILURE(result) )
1316 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1317 // argument is present, the essence is encrypted prior to writing.
1318 // Fails if the file is not open, is finalized, or an operating system
1321 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1323 if ( m_Writer.empty() )
1326 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1329 // Closes the MXF file, writing the index and other closing information.
1331 ASDCP::JP2K::MXFWriter::Finalize()
1333 if ( m_Writer.empty() )
1336 return m_Writer->Finalize();
1340 //------------------------------------------------------------------------------------------
1344 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1346 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1348 StereoscopicPhase_t m_NextPhase;
1351 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1354 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1355 AESEncContext* Ctx, HMACContext* HMAC)
1357 if ( m_NextPhase != phase )
1358 return RESULT_SPHASE;
1360 if ( phase == SP_LEFT )
1362 m_NextPhase = SP_RIGHT;
1363 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1366 m_NextPhase = SP_LEFT;
1367 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1373 if ( m_NextPhase != SP_LEFT )
1374 return RESULT_SPHASE;
1376 assert( m_FramesWritten % 2 == 0 );
1377 m_FramesWritten /= 2;
1378 return lh__Writer::Finalize();
1384 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1388 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1392 // Warning: direct manipulation of MXF structures can interfere
1393 // with the normal operation of the wrapper. Caveat emptor!
1395 ASDCP::MXF::OP1aHeader&
1396 ASDCP::JP2K::MXFSWriter::OP1aHeader()
1398 if ( m_Writer.empty() )
1400 assert(g_OP1aHeader);
1401 return *g_OP1aHeader;
1404 return m_Writer->m_HeaderPart;
1407 // Warning: direct manipulation of MXF structures can interfere
1408 // with the normal operation of the wrapper. Caveat emptor!
1410 ASDCP::MXF::OPAtomIndexFooter&
1411 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1413 if ( m_Writer.empty() )
1415 assert(g_OPAtomIndexFooter);
1416 return *g_OPAtomIndexFooter;
1419 return m_Writer->m_FooterPart;
1422 // Warning: direct manipulation of MXF structures can interfere
1423 // with the normal operation of the wrapper. Caveat emptor!
1426 ASDCP::JP2K::MXFSWriter::RIP()
1428 if ( m_Writer.empty() )
1434 return m_Writer->m_RIP;
1437 // Open the file for writing. The file must not exist. Returns error if
1438 // the operation cannot be completed.
1440 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1441 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1443 if ( Info.LabelSetType == LS_MXF_SMPTE )
1444 m_Writer = new h__SWriter(DefaultSMPTEDict());
1446 m_Writer = new h__SWriter(DefaultInteropDict());
1448 if ( PDesc.EditRate != ASDCP::EditRate_24
1449 && PDesc.EditRate != ASDCP::EditRate_25
1450 && PDesc.EditRate != ASDCP::EditRate_30
1451 && PDesc.EditRate != ASDCP::EditRate_48
1452 && PDesc.EditRate != ASDCP::EditRate_50
1453 && PDesc.EditRate != ASDCP::EditRate_60 )
1455 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1456 return RESULT_FORMAT;
1459 if ( PDesc.StoredWidth > 2048 )
1460 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1462 m_Writer->m_Info = Info;
1464 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1466 if ( ASDCP_SUCCESS(result) )
1468 PictureDescriptor TmpPDesc = PDesc;
1470 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1471 TmpPDesc.EditRate = ASDCP::EditRate_48;
1473 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1474 TmpPDesc.EditRate = ASDCP::EditRate_50;
1476 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1477 TmpPDesc.EditRate = ASDCP::EditRate_60;
1479 else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1480 TmpPDesc.EditRate = ASDCP::EditRate_96;
1482 else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1483 TmpPDesc.EditRate = ASDCP::EditRate_100;
1485 else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1486 TmpPDesc.EditRate = ASDCP::EditRate_120;
1488 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1491 if ( ASDCP_FAILURE(result) )
1498 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1500 if ( m_Writer.empty() )
1503 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1505 if ( ASDCP_SUCCESS(result) )
1506 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1511 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1512 // argument is present, the essence is encrypted prior to writing.
1513 // Fails if the file is not open, is finalized, or an operating system
1516 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1517 AESEncContext* Ctx, HMACContext* HMAC)
1519 if ( m_Writer.empty() )
1522 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1525 // Closes the MXF file, writing the index and other closing information.
1527 ASDCP::JP2K::MXFSWriter::Finalize()
1529 if ( m_Writer.empty() )
1532 return m_Writer->Finalize();
1536 // end AS_DCP_JP2K.cpp