2 Copyright (c) 2004-2016, 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"
37 using namespace ASDCP::JP2K;
38 using Kumu::GenRandomValue;
40 //------------------------------------------------------------------------------------------
42 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
43 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
44 static std::string PICT_DEF_LABEL = "Picture Track";
46 static int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
50 ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc)
52 strm << " AspectRatio: " << PDesc.AspectRatio.Numerator << "/" << PDesc.AspectRatio.Denominator << std::endl;
53 strm << " EditRate: " << PDesc.EditRate.Numerator << "/" << PDesc.EditRate.Denominator << std::endl;
54 strm << " SampleRate: " << PDesc.SampleRate.Numerator << "/" << PDesc.SampleRate.Denominator << std::endl;
55 strm << " StoredWidth: " << (unsigned) PDesc.StoredWidth << std::endl;
56 strm << " StoredHeight: " << (unsigned) PDesc.StoredHeight << std::endl;
57 strm << " Rsize: " << (unsigned) PDesc.Rsize << std::endl;
58 strm << " Xsize: " << (unsigned) PDesc.Xsize << std::endl;
59 strm << " Ysize: " << (unsigned) PDesc.Ysize << std::endl;
60 strm << " XOsize: " << (unsigned) PDesc.XOsize << std::endl;
61 strm << " YOsize: " << (unsigned) PDesc.YOsize << std::endl;
62 strm << " XTsize: " << (unsigned) PDesc.XTsize << std::endl;
63 strm << " YTsize: " << (unsigned) PDesc.YTsize << std::endl;
64 strm << " XTOsize: " << (unsigned) PDesc.XTOsize << std::endl;
65 strm << " YTOsize: " << (unsigned) PDesc.YTOsize << std::endl;
66 strm << " ContainerDuration: " << (unsigned) PDesc.ContainerDuration << std::endl;
68 strm << "-- JPEG 2000 Metadata --" << std::endl;
69 strm << " ImageComponents:" << std::endl;
70 strm << " bits h-sep v-sep" << std::endl;
73 for ( i = 0; i < PDesc.Csize && i < MaxComponents; ++i )
75 strm << " " << std::setw(4) << PDesc.ImageComponents[i].Ssize + 1 /* See ISO 15444-1, Table A11, for the origin of '+1' */
76 << " " << std::setw(5) << PDesc.ImageComponents[i].XRsize
77 << " " << std::setw(5) << PDesc.ImageComponents[i].YRsize
81 strm << " Scod: " << (short) PDesc.CodingStyleDefault.Scod << std::endl;
82 strm << " ProgressionOrder: " << (short) PDesc.CodingStyleDefault.SGcod.ProgressionOrder << std::endl;
83 strm << " NumberOfLayers: " << (short) KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)) << std::endl;
84 strm << " MultiCompTransform: " << (short) PDesc.CodingStyleDefault.SGcod.MultiCompTransform << std::endl;
85 strm << "DecompositionLevels: " << (short) PDesc.CodingStyleDefault.SPcod.DecompositionLevels << std::endl;
86 strm << " CodeblockWidth: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockWidth << std::endl;
87 strm << " CodeblockHeight: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockHeight << std::endl;
88 strm << " CodeblockStyle: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockStyle << std::endl;
89 strm << " Transformation: " << (short) PDesc.CodingStyleDefault.SPcod.Transformation << std::endl;
92 ui32_t precinct_set_size = 0;
94 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; ++i )
97 strm << " Precincts: " << (short) precinct_set_size << std::endl;
98 strm << "precinct dimensions:" << std::endl;
100 for ( i = 0; i < precinct_set_size && i < MaxPrecincts; ++i )
101 strm << " " << i + 1 << ": " << s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f] << " x "
102 << s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] << std::endl;
104 strm << " Sqcd: " << (short) PDesc.QuantizationDefault.Sqcd << std::endl;
106 char tmp_buf[MaxDefaults*2];
107 strm << " SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2)
110 if (PDesc.Profile.N != 0) {
111 strm << "Profile:" << std::endl;
113 for (ui16_t i = 0; i < PDesc.Profile.N; i++) {
114 strm << " Pprf(" << (i + 1) << "): "
115 << std::hex << std::showbase << PDesc.Profile.Pprf[i] << std::dec << std::noshowbase
120 if (PDesc.CorrespondingProfile.N != 0) {
121 strm << "Corresponding Profile:" << std::endl;
123 for (ui16_t i = 0; i < PDesc.CorrespondingProfile.N; i++) {
125 strm << " Pcpf(" << (i + 1) << "): "
126 << std::hex << std::showbase << PDesc.CorrespondingProfile.Pcpf[i] << std::dec << std::noshowbase
131 if (PDesc.ExtendedCapabilities.N != JP2K::NoExtendedCapabilitiesSignaled && PDesc.ExtendedCapabilities.Pcap != 0) {
133 strm << "Extended Capabilities:" << std::endl;
136 strm << " Pcap:" << PDesc.ExtendedCapabilities.Pcap << std::endl;
138 for (i32_t b = 0, i = 0; b < JP2K::MaxCapabilities; b++) {
140 if ((PDesc.ExtendedCapabilities.Pcap >> b) & 0x1) {
142 strm << " Ccap(" << (JP2K::MaxCapabilities - b) << "): " <<
143 std::hex << std::showbase << PDesc.ExtendedCapabilities.Ccap[i++] << std::dec << std::noshowbase
155 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
161 AspectRatio: %d/%d\n\
175 ContainerDuration: %u\n",
176 PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
177 PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
178 PDesc.SampleRate.Numerator, PDesc.SampleRate.Denominator,
190 PDesc.ContainerDuration
193 fprintf(stream, "-- JPEG 2000 Metadata --\n");
194 fprintf(stream, " ImageComponents:\n");
195 fprintf(stream, " bits h-sep v-sep\n");
198 for ( i = 0; i < PDesc.Csize && i < MaxComponents; i++ )
200 fprintf(stream, " %4d %5d %5d\n",
201 PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
202 PDesc.ImageComponents[i].XRsize,
203 PDesc.ImageComponents[i].YRsize
207 fprintf(stream, " Scod: %hhu\n", PDesc.CodingStyleDefault.Scod);
208 fprintf(stream, " ProgressionOrder: %hhu\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
209 fprintf(stream, " NumberOfLayers: %hd\n",
210 KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
212 fprintf(stream, " MultiCompTransform: %hhu\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
213 fprintf(stream, "DecompositionLevels: %hhu\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
214 fprintf(stream, " CodeblockWidth: %hhu\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
215 fprintf(stream, " CodeblockHeight: %hhu\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
216 fprintf(stream, " CodeblockStyle: %hhu\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
217 fprintf(stream, " Transformation: %hhu\n", PDesc.CodingStyleDefault.SPcod.Transformation);
220 ui32_t precinct_set_size = 0;
222 for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; ++i )
225 fprintf(stream, " Precincts: %u\n", precinct_set_size);
226 fprintf(stream, "precinct dimensions:\n");
228 for ( i = 0; i < precinct_set_size && i < MaxPrecincts; i++ )
229 fprintf(stream, " %d: %d x %d\n", i + 1,
230 s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
231 s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
234 fprintf(stream, " Sqcd: %hhu\n", PDesc.QuantizationDefault.Sqcd);
236 char tmp_buf[MaxDefaults*2];
237 fprintf(stream, " SPqcd: %s\n",
238 Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
239 tmp_buf, MaxDefaults*2)
243 if (PDesc.Profile.N != 0) {
244 fprintf(stream, " Profile:\n");
246 for (ui16_t i = 0; i < PDesc.Profile.N; i++) {
248 fprintf(stream, " Pprf(%d): %hx\n", i + 1, PDesc.Profile.Pprf[i]);
253 if (PDesc.CorrespondingProfile.N != 0) {
254 fprintf(stream, "Corresponding Profile:\n");
256 for (ui16_t i = 0; i < PDesc.CorrespondingProfile.N; i++) {
257 fprintf(stream, " Pcpf(%d): %hx\n", i + 1, PDesc.CorrespondingProfile.Pcpf[i]);
262 if (PDesc.ExtendedCapabilities.N != JP2K::NoExtendedCapabilitiesSignaled) {
264 fprintf(stream, "Extended Capabilities: %x\n", PDesc.ExtendedCapabilities.Pcap);
266 for (i32_t b = 0, i = 0; b < JP2K::MaxCapabilities && i < PDesc.ExtendedCapabilities.N; b++) {
268 if ((PDesc.ExtendedCapabilities.Pcap >> (JP2K::MaxCapabilities - b - 1)) & 0x1) {
270 fprintf(stream, " Ccap(%d): %hx\n", b + 1, PDesc.ExtendedCapabilities.Ccap[i++]);
280 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
281 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
282 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
286 ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc,
287 const ASDCP::Dictionary& dict,
288 ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
289 ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor)
291 EssenceDescriptor.ContainerDuration = PDesc.ContainerDuration;
292 EssenceDescriptor.SampleRate = PDesc.EditRate;
293 EssenceDescriptor.FrameLayout = 0;
294 EssenceDescriptor.StoredWidth = PDesc.StoredWidth;
295 EssenceDescriptor.StoredHeight = PDesc.StoredHeight;
296 EssenceDescriptor.AspectRatio = PDesc.AspectRatio;
298 EssenceSubDescriptor.Rsize = PDesc.Rsize;
299 EssenceSubDescriptor.Xsize = PDesc.Xsize;
300 EssenceSubDescriptor.Ysize = PDesc.Ysize;
301 EssenceSubDescriptor.XOsize = PDesc.XOsize;
302 EssenceSubDescriptor.YOsize = PDesc.YOsize;
303 EssenceSubDescriptor.XTsize = PDesc.XTsize;
304 EssenceSubDescriptor.YTsize = PDesc.YTsize;
305 EssenceSubDescriptor.XTOsize = PDesc.XTOsize;
306 EssenceSubDescriptor.YTOsize = PDesc.YTOsize;
307 EssenceSubDescriptor.Csize = PDesc.Csize;
309 const ui32_t tmp_buffer_len = 1024;
310 byte_t tmp_buffer[tmp_buffer_len];
312 *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
313 *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
314 memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
316 const ui32_t pcomp_size = (sizeof(ui32_t) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
317 memcpy(EssenceSubDescriptor.PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size);
318 EssenceSubDescriptor.PictureComponentSizing.get().Length(pcomp_size);
319 EssenceSubDescriptor.PictureComponentSizing.set_has_value();
321 ui32_t precinct_set_size = 0;
322 for ( ui32_t i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; ++i )
325 ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
326 memcpy(EssenceSubDescriptor.CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size);
327 EssenceSubDescriptor.CodingStyleDefault.get().Length(csd_size);
328 EssenceSubDescriptor.CodingStyleDefault.set_has_value();
330 ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
331 memcpy(EssenceSubDescriptor.QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size);
332 EssenceSubDescriptor.QuantizationDefault.get().Length(qdflt_size);
333 EssenceSubDescriptor.QuantizationDefault.set_has_value();
337 if (PDesc.Profile.N == 0) {
338 EssenceSubDescriptor.J2KProfile.set_has_value(false);
340 EssenceSubDescriptor.J2KProfile.get().resize(PDesc.Profile.N);
342 std::copy(PDesc.Profile.Pprf,
343 PDesc.Profile.Pprf + PDesc.Profile.N,
344 EssenceSubDescriptor.J2KProfile.get().begin());
346 EssenceSubDescriptor.J2KProfile.set_has_value();
349 // Corresponding profile
351 if (PDesc.CorrespondingProfile.N == 0) {
353 EssenceSubDescriptor.J2KCorrespondingProfile.set_has_value(false);
356 EssenceSubDescriptor.J2KCorrespondingProfile.get().resize(PDesc.CorrespondingProfile.N);
358 std::copy(PDesc.CorrespondingProfile.Pcpf,
359 PDesc.CorrespondingProfile.Pcpf + PDesc.CorrespondingProfile.N,
360 EssenceSubDescriptor.J2KCorrespondingProfile.get().begin());
362 EssenceSubDescriptor.J2KCorrespondingProfile.set_has_value();
365 // Extended capabilities
367 if (PDesc.ExtendedCapabilities.N == JP2K::NoExtendedCapabilitiesSignaled) {
369 /* No extended capabilities are signaled */
371 EssenceSubDescriptor.J2KExtendedCapabilities.set_has_value(false);
375 EssenceSubDescriptor.J2KExtendedCapabilities.get().Pcap = PDesc.ExtendedCapabilities.Pcap;
377 EssenceSubDescriptor.J2KExtendedCapabilities.get().Ccap.resize(PDesc.ExtendedCapabilities.N);
379 std::copy(PDesc.ExtendedCapabilities.Ccap,
380 PDesc.ExtendedCapabilities.Ccap + PDesc.ExtendedCapabilities.N,
381 EssenceSubDescriptor.J2KExtendedCapabilities.get().Ccap.begin());
383 EssenceSubDescriptor.J2KExtendedCapabilities.set_has_value(true);
393 ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
394 const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
395 const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
396 ASDCP::JP2K::PictureDescriptor& PDesc)
398 memset(&PDesc, 0, sizeof(PDesc));
400 PDesc.EditRate = EditRate;
401 PDesc.SampleRate = SampleRate;
402 assert(EssenceDescriptor.ContainerDuration.const_get() <= 0xFFFFFFFFL);
403 PDesc.ContainerDuration = static_cast<ui32_t>(EssenceDescriptor.ContainerDuration.const_get());
404 PDesc.StoredWidth = EssenceDescriptor.StoredWidth;
405 PDesc.StoredHeight = EssenceDescriptor.StoredHeight;
406 PDesc.AspectRatio = EssenceDescriptor.AspectRatio;
408 PDesc.Rsize = EssenceSubDescriptor.Rsize;
409 PDesc.Xsize = EssenceSubDescriptor.Xsize;
410 PDesc.Ysize = EssenceSubDescriptor.Ysize;
411 PDesc.XOsize = EssenceSubDescriptor.XOsize;
412 PDesc.YOsize = EssenceSubDescriptor.YOsize;
413 PDesc.XTsize = EssenceSubDescriptor.XTsize;
414 PDesc.YTsize = EssenceSubDescriptor.YTsize;
415 PDesc.XTOsize = EssenceSubDescriptor.XTOsize;
416 PDesc.YTOsize = EssenceSubDescriptor.YTOsize;
417 PDesc.Csize = EssenceSubDescriptor.Csize;
419 // PictureComponentSizing
420 ui32_t tmp_size = EssenceSubDescriptor.PictureComponentSizing.const_get().Length();
422 if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
424 memcpy(&PDesc.ImageComponents, EssenceSubDescriptor.PictureComponentSizing.const_get().RoData() + 8, tmp_size - 8);
428 DefaultLogSink().Warn("Unexpected PictureComponentSizing size: %u, should be 17.\n", tmp_size);
431 // CodingStyleDefault
432 memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
433 memcpy(&PDesc.CodingStyleDefault,
434 EssenceSubDescriptor.CodingStyleDefault.const_get().RoData(),
435 EssenceSubDescriptor.CodingStyleDefault.const_get().Length());
437 // QuantizationDefault
438 memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
439 memcpy(&PDesc.QuantizationDefault,
440 EssenceSubDescriptor.QuantizationDefault.const_get().RoData(),
441 EssenceSubDescriptor.QuantizationDefault.const_get().Length());
443 PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1;
447 std::fill(PDesc.Profile.Pprf, PDesc.Profile.Pprf + JP2K::MaxPRFN, 0);
449 if (EssenceSubDescriptor.J2KProfile.empty() ||
450 EssenceSubDescriptor.J2KProfile.const_get().size() == 0) {
456 PDesc.Profile.N = EssenceSubDescriptor.J2KProfile.const_get().size();
458 std::copy(EssenceSubDescriptor.J2KProfile.const_get().begin(),
459 EssenceSubDescriptor.J2KProfile.const_get().end(),
464 // Corresponding profile
466 std::fill(PDesc.CorrespondingProfile.Pcpf, PDesc.CorrespondingProfile.Pcpf + JP2K::MaxCPFN, 0);
468 if (EssenceSubDescriptor.J2KCorrespondingProfile.empty() ||
469 EssenceSubDescriptor.J2KCorrespondingProfile.const_get().size() == 0) {
471 PDesc.CorrespondingProfile.N = 0;
476 PDesc.CorrespondingProfile.N = EssenceSubDescriptor.J2KCorrespondingProfile.const_get().size();
478 std::copy(EssenceSubDescriptor.J2KCorrespondingProfile.const_get().begin(),
479 EssenceSubDescriptor.J2KCorrespondingProfile.const_get().end(),
480 PDesc.CorrespondingProfile.Pcpf);
484 // Extended capabilities
486 std::fill(PDesc.ExtendedCapabilities.Ccap, PDesc.ExtendedCapabilities.Ccap + JP2K::MaxCapabilities, 0);
488 if (EssenceSubDescriptor.J2KExtendedCapabilities.empty()) {
490 PDesc.ExtendedCapabilities.Pcap = 0;
491 PDesc.ExtendedCapabilities.N = JP2K::NoExtendedCapabilitiesSignaled;
496 PDesc.ExtendedCapabilities.Pcap = EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Pcap;
497 PDesc.ExtendedCapabilities.N = EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Ccap.size();
499 std::copy(EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Ccap.begin(),
500 EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Ccap.end(),
501 PDesc.ExtendedCapabilities.Ccap);
509 //------------------------------------------------------------------------------------------
511 // hidden, internal implementation of JPEG 2000 reader
514 class lh__Reader : public ASDCP::h__ASDCPReader
516 RGBAEssenceDescriptor* m_EssenceDescriptor;
517 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
518 ASDCP::Rational m_EditRate;
519 ASDCP::Rational m_SampleRate;
520 EssenceType_t m_Format;
522 ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
525 PictureDescriptor m_PDesc; // codestream parameter list
527 lh__Reader(const Dictionary& d) :
528 ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
530 virtual ~lh__Reader() {}
532 Result_t OpenRead(const std::string&, EssenceType_t);
533 Result_t ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
540 lh__Reader::OpenRead(const std::string& filename, EssenceType_t type)
542 Result_t result = OpenMXFRead(filename);
544 if( ASDCP_SUCCESS(result) )
546 InterchangeObject* tmp_iobj = 0;
547 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
548 m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
550 if ( m_EssenceDescriptor == 0 )
552 DefaultLogSink().Error("RGBAEssenceDescriptor object not found.\n");
553 return RESULT_FORMAT;
556 m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
557 m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
559 if ( m_EssenceSubDescriptor == 0 )
561 m_EssenceDescriptor = 0;
562 DefaultLogSink().Error("JPEG2000PictureSubDescriptor object not found.\n");
563 return RESULT_FORMAT;
566 std::list<InterchangeObject*> ObjectList;
567 m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
569 if ( ObjectList.empty() )
571 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
572 return RESULT_FORMAT;
575 m_EditRate = ((Track*)ObjectList.front())->EditRate;
576 m_SampleRate = m_EssenceDescriptor->SampleRate;
578 if ( type == ASDCP::ESS_JPEG_2000 )
580 if ( m_EditRate != m_SampleRate )
582 DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
583 m_EditRate.Quotient(), m_SampleRate.Quotient());
585 if ( ( m_EditRate == EditRate_24 && m_SampleRate == EditRate_48 )
586 || ( m_EditRate == EditRate_25 && m_SampleRate == EditRate_50 )
587 || ( m_EditRate == EditRate_30 && m_SampleRate == EditRate_60 )
588 || ( m_EditRate == EditRate_48 && m_SampleRate == EditRate_96 )
589 || ( m_EditRate == EditRate_50 && m_SampleRate == EditRate_100 )
590 || ( m_EditRate == EditRate_60 && m_SampleRate == EditRate_120 )
591 || ( m_EditRate == EditRate_96 && m_SampleRate == EditRate_192 )
592 || ( m_EditRate == EditRate_100 && m_SampleRate == EditRate_200 )
593 || ( m_EditRate == EditRate_120 && m_SampleRate == EditRate_240 ) )
595 DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
596 return RESULT_SFORMAT;
599 return RESULT_FORMAT;
602 else if ( type == ASDCP::ESS_JPEG_2000_S )
604 if ( m_EditRate == EditRate_24 )
606 if ( m_SampleRate != EditRate_48 )
608 DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
609 return RESULT_FORMAT;
612 else if ( m_EditRate == EditRate_25 )
614 if ( m_SampleRate != EditRate_50 )
616 DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
617 return RESULT_FORMAT;
620 else if ( m_EditRate == EditRate_30 )
622 if ( m_SampleRate != EditRate_60 )
624 DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
625 return RESULT_FORMAT;
628 else if ( m_EditRate == EditRate_48 )
630 if ( m_SampleRate != EditRate_96 )
632 DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
633 return RESULT_FORMAT;
636 else if ( m_EditRate == EditRate_50 )
638 if ( m_SampleRate != EditRate_100 )
640 DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
641 return RESULT_FORMAT;
644 else if ( m_EditRate == EditRate_60 )
646 if ( m_SampleRate != EditRate_120 )
648 DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
649 return RESULT_FORMAT;
652 else if ( m_EditRate == EditRate_96 )
654 if ( m_SampleRate != EditRate_192 )
656 DefaultLogSink().Error("EditRate and SampleRate not correct for 96/192 stereoscopic essence.\n");
657 return RESULT_FORMAT;
660 else if ( m_EditRate == EditRate_100 )
662 if ( m_SampleRate != EditRate_200 )
664 DefaultLogSink().Error("EditRate and SampleRate not correct for 100/200 stereoscopic essence.\n");
665 return RESULT_FORMAT;
668 else if ( m_EditRate == EditRate_120 )
670 if ( m_SampleRate != EditRate_240 )
672 DefaultLogSink().Error("EditRate and SampleRate not correct for 120/240 stereoscopic essence.\n");
673 return RESULT_FORMAT;
678 DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
679 m_EditRate.Numerator, m_EditRate.Denominator);
680 return RESULT_FORMAT;
685 DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
689 result = MD_to_JP2K_PDesc(*m_EssenceDescriptor, *m_EssenceSubDescriptor, m_EditRate, m_SampleRate, m_PDesc);
698 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
699 AESDecContext* Ctx, HMACContext* HMAC)
701 if ( ! m_File.IsOpen() )
705 return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
710 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
712 ASDCP_NO_COPY_CONSTRUCT(h__Reader);
716 h__Reader(const Dictionary& d) : lh__Reader(d) {}
721 //------------------------------------------------------------------------------------------
726 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
731 fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
736 Kumu::hexdump(m_Data, dump_len, stream);
740 //------------------------------------------------------------------------------------------
742 ASDCP::JP2K::MXFReader::MXFReader()
744 m_Reader = new h__Reader(DefaultCompositeDict());
748 ASDCP::JP2K::MXFReader::~MXFReader()
750 if ( m_Reader && m_Reader->m_File.IsOpen() )
754 // Warning: direct manipulation of MXF structures can interfere
755 // with the normal operation of the wrapper. Caveat emptor!
757 ASDCP::MXF::OP1aHeader&
758 ASDCP::JP2K::MXFReader::OP1aHeader()
760 if ( m_Reader.empty() )
762 assert(g_OP1aHeader);
763 return *g_OP1aHeader;
766 return m_Reader->m_HeaderPart;
769 // Warning: direct manipulation of MXF structures can interfere
770 // with the normal operation of the wrapper. Caveat emptor!
772 ASDCP::MXF::OPAtomIndexFooter&
773 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
775 if ( m_Reader.empty() )
777 assert(g_OPAtomIndexFooter);
778 return *g_OPAtomIndexFooter;
781 return m_Reader->m_IndexAccess;
784 // Warning: direct manipulation of MXF structures can interfere
785 // with the normal operation of the wrapper. Caveat emptor!
788 ASDCP::JP2K::MXFReader::RIP()
790 if ( m_Reader.empty() )
796 return m_Reader->m_RIP;
799 // Open the file for reading. The file must exist. Returns error if the
800 // operation cannot be completed.
802 ASDCP::JP2K::MXFReader::OpenRead(const std::string& filename) const
804 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
809 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
810 AESDecContext* Ctx, HMACContext* HMAC) const
812 if ( m_Reader && m_Reader->m_File.IsOpen() )
813 return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
819 ASDCP::JP2K::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
821 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
825 // Fill the struct with the values from the file's header.
826 // Returns RESULT_INIT if the file is not open.
828 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
830 if ( m_Reader && m_Reader->m_File.IsOpen() )
832 PDesc = m_Reader->m_PDesc;
840 // Fill the struct with the values from the file's header.
841 // Returns RESULT_INIT if the file is not open.
843 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
845 if ( m_Reader && m_Reader->m_File.IsOpen() )
847 Info = m_Reader->m_Info;
856 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
858 if ( m_Reader->m_File.IsOpen() )
859 m_Reader->m_HeaderPart.Dump(stream);
865 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
867 if ( m_Reader->m_File.IsOpen() )
868 m_Reader->m_IndexAccess.Dump(stream);
873 ASDCP::JP2K::MXFReader::Close() const
875 if ( m_Reader && m_Reader->m_File.IsOpen() )
885 //------------------------------------------------------------------------------------------
888 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
890 ui32_t m_StereoFrameReady;
893 h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
896 Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
897 AESDecContext* Ctx, HMACContext* HMAC)
899 // look up frame index node
900 IndexTableSegment::IndexEntry TmpEntry;
902 if ( ASDCP_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
907 // get frame position
908 Kumu::fpos_t FilePosition = m_HeaderPart.BodyOffset + TmpEntry.StreamOffset;
909 Result_t result = RESULT_OK;
911 if ( phase == SP_LEFT )
913 if ( FilePosition != m_LastPosition )
915 m_LastPosition = FilePosition;
916 result = m_File.Seek(FilePosition);
919 // the call to ReadEKLVPacket() will leave the file on an R frame
920 m_StereoFrameReady = FrameNum;
922 else if ( phase == SP_RIGHT )
924 if ( m_StereoFrameReady != FrameNum )
926 // the file is not already positioned, we must do some work
927 // seek to the companion SP_LEFT frame and read the frame's key and length
928 if ( FilePosition != m_LastPosition )
930 m_LastPosition = FilePosition;
931 result = m_File.Seek(FilePosition);
935 result = Reader.ReadKLFromFile(m_File);
937 if ( ASDCP_SUCCESS(result) )
939 // skip over the companion SP_LEFT frame
940 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
941 result = m_File.Seek(new_pos);
945 // the call to ReadEKLVPacket() will leave the file not on an R frame
946 m_StereoFrameReady = 0xffffffff;
950 DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
954 if( ASDCP_SUCCESS(result) )
956 ui32_t SequenceNum = FrameNum * 2;
957 SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
959 result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
968 ASDCP::JP2K::MXFSReader::MXFSReader()
970 m_Reader = new h__SReader(DefaultCompositeDict());
974 ASDCP::JP2K::MXFSReader::~MXFSReader()
976 if ( m_Reader && m_Reader->m_File.IsOpen() )
980 // Warning: direct manipulation of MXF structures can interfere
981 // with the normal operation of the wrapper. Caveat emptor!
983 ASDCP::MXF::OP1aHeader&
984 ASDCP::JP2K::MXFSReader::OP1aHeader()
986 if ( m_Reader.empty() )
988 assert(g_OP1aHeader);
989 return *g_OP1aHeader;
992 return m_Reader->m_HeaderPart;
995 // Warning: direct manipulation of MXF structures can interfere
996 // with the normal operation of the wrapper. Caveat emptor!
998 ASDCP::MXF::OPAtomIndexFooter&
999 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
1001 if ( m_Reader.empty() )
1003 assert(g_OPAtomIndexFooter);
1004 return *g_OPAtomIndexFooter;
1007 return m_Reader->m_IndexAccess;
1010 // Warning: direct manipulation of MXF structures can interfere
1011 // with the normal operation of the wrapper. Caveat emptor!
1014 ASDCP::JP2K::MXFSReader::RIP()
1016 if ( m_Reader.empty() )
1022 return m_Reader->m_RIP;
1025 // Open the file for reading. The file must exist. Returns error if the
1026 // operation cannot be completed.
1028 ASDCP::JP2K::MXFSReader::OpenRead(const std::string& filename) const
1030 return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
1035 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
1037 Result_t result = RESULT_INIT;
1039 if ( m_Reader && m_Reader->m_File.IsOpen() )
1041 result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
1043 if ( ASDCP_SUCCESS(result) )
1044 result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
1052 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
1053 AESDecContext* Ctx, HMACContext* HMAC) const
1055 if ( m_Reader && m_Reader->m_File.IsOpen() )
1056 return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
1062 ASDCP::JP2K::MXFSReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
1064 return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
1067 // Fill the struct with the values from the file's header.
1068 // Returns RESULT_INIT if the file is not open.
1070 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
1072 if ( m_Reader && m_Reader->m_File.IsOpen() )
1074 PDesc = m_Reader->m_PDesc;
1082 // Fill the struct with the values from the file's header.
1083 // Returns RESULT_INIT if the file is not open.
1085 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
1087 if ( m_Reader && m_Reader->m_File.IsOpen() )
1089 Info = m_Reader->m_Info;
1098 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
1100 if ( m_Reader->m_File.IsOpen() )
1101 m_Reader->m_HeaderPart.Dump(stream);
1107 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
1109 if ( m_Reader->m_File.IsOpen() )
1110 m_Reader->m_IndexAccess.Dump(stream);
1115 ASDCP::JP2K::MXFSReader::Close() const
1117 if ( m_Reader && m_Reader->m_File.IsOpen() )
1127 //------------------------------------------------------------------------------------------
1131 class lh__Writer : public ASDCP::h__ASDCPWriter
1133 ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
1136 JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
1139 PictureDescriptor m_PDesc;
1140 byte_t m_EssenceUL[SMPTE_UL_LENGTH];
1142 lh__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_EssenceSubDescriptor(0) {
1143 memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
1146 virtual ~lh__Writer(){}
1148 Result_t OpenWrite(const std::string&, EssenceType_t type, ui32_t HeaderSize);
1149 Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
1150 ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
1151 Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
1152 Result_t Finalize();
1155 // Open the file for writing. The file must not exist. Returns error if
1156 // the operation cannot be completed.
1158 lh__Writer::OpenWrite(const std::string& filename, EssenceType_t type, ui32_t HeaderSize)
1160 if ( ! m_State.Test_BEGIN() )
1161 return RESULT_STATE;
1163 Result_t result = m_File.OpenWrite(filename);
1165 if ( ASDCP_SUCCESS(result) )
1167 m_HeaderSize = HeaderSize;
1168 RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
1169 tmp_rgba->ComponentMaxRef = 4095;
1170 tmp_rgba->ComponentMinRef = 0;
1172 m_EssenceDescriptor = tmp_rgba;
1173 m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
1174 m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
1176 GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
1177 m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
1179 if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
1181 InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
1182 m_EssenceSubDescriptorList.push_back(StereoSubDesc);
1183 GenRandomValue(StereoSubDesc->InstanceUID);
1184 m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
1187 result = m_State.Goto_INIT();
1193 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
1195 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
1198 if ( ! m_State.Test_INIT() )
1199 return RESULT_STATE;
1201 if ( LocalEditRate == ASDCP::Rational(0,0) )
1202 LocalEditRate = PDesc.EditRate;
1206 assert(m_EssenceDescriptor);
1207 assert(m_EssenceSubDescriptor);
1208 Result_t result = JP2K_PDesc_to_MD(m_PDesc, *m_Dict,
1209 *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(m_EssenceDescriptor),
1210 *m_EssenceSubDescriptor);
1212 if ( ASDCP_SUCCESS(result) )
1214 if ( PDesc.StoredWidth < 2049 )
1216 static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
1217 m_EssenceSubDescriptor->Rsize = 3;
1221 static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
1222 m_EssenceSubDescriptor->Rsize = 4;
1225 memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
1226 m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
1227 result = m_State.Goto_READY();
1230 if ( ASDCP_SUCCESS(result) )
1232 result = WriteASDCPHeader(label, UL(m_Dict->ul(MDD_MXFGCFUFrameWrappedPictureElement)),
1233 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
1234 LocalEditRate, derive_timecode_rate_from_edit_rate(m_PDesc.EditRate));
1240 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1241 // argument is present, the essence is encrypted prior to writing.
1242 // Fails if the file is not open, is finalized, or an operating system
1246 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
1247 AESEncContext* Ctx, HMACContext* HMAC)
1249 Result_t result = RESULT_OK;
1251 if ( m_State.Test_READY() )
1252 result = m_State.Goto_RUNNING(); // first time through
1254 ui64_t StreamOffset = m_StreamOffset;
1256 if ( ASDCP_SUCCESS(result) )
1257 result = WriteEKLVPacket(FrameBuf, m_EssenceUL, MXF_BER_LENGTH, Ctx, HMAC);
1259 if ( ASDCP_SUCCESS(result) && add_index )
1261 IndexTableSegment::IndexEntry Entry;
1262 Entry.StreamOffset = StreamOffset;
1263 m_FooterPart.PushIndexEntry(Entry);
1271 // Closes the MXF file, writing the index and other closing information.
1274 lh__Writer::Finalize()
1276 if ( ! m_State.Test_RUNNING() )
1277 return RESULT_STATE;
1279 m_State.Goto_FINAL();
1281 return WriteASDCPFooter();
1286 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1288 ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1292 h__Writer(const Dictionary& d) : lh__Writer(d) {}
1296 //------------------------------------------------------------------------------------------
1300 ASDCP::JP2K::MXFWriter::MXFWriter()
1304 ASDCP::JP2K::MXFWriter::~MXFWriter()
1308 // Warning: direct manipulation of MXF structures can interfere
1309 // with the normal operation of the wrapper. Caveat emptor!
1311 ASDCP::MXF::OP1aHeader&
1312 ASDCP::JP2K::MXFWriter::OP1aHeader()
1314 if ( m_Writer.empty() )
1316 assert(g_OP1aHeader);
1317 return *g_OP1aHeader;
1320 return m_Writer->m_HeaderPart;
1323 // Warning: direct manipulation of MXF structures can interfere
1324 // with the normal operation of the wrapper. Caveat emptor!
1326 ASDCP::MXF::OPAtomIndexFooter&
1327 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1329 if ( m_Writer.empty() )
1331 assert(g_OPAtomIndexFooter);
1332 return *g_OPAtomIndexFooter;
1335 return m_Writer->m_FooterPart;
1338 // Warning: direct manipulation of MXF structures can interfere
1339 // with the normal operation of the wrapper. Caveat emptor!
1342 ASDCP::JP2K::MXFWriter::RIP()
1344 if ( m_Writer.empty() )
1350 return m_Writer->m_RIP;
1353 // Open the file for writing. The file must not exist. Returns error if
1354 // the operation cannot be completed.
1356 ASDCP::JP2K::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
1357 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1359 if ( Info.LabelSetType == LS_MXF_SMPTE )
1360 m_Writer = new h__Writer(DefaultSMPTEDict());
1362 m_Writer = new h__Writer(DefaultInteropDict());
1364 m_Writer->m_Info = Info;
1366 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1368 if ( ASDCP_SUCCESS(result) )
1369 result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1371 if ( ASDCP_FAILURE(result) )
1378 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1379 // argument is present, the essence is encrypted prior to writing.
1380 // Fails if the file is not open, is finalized, or an operating system
1383 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1385 if ( m_Writer.empty() )
1388 return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1391 // Closes the MXF file, writing the index and other closing information.
1393 ASDCP::JP2K::MXFWriter::Finalize()
1395 if ( m_Writer.empty() )
1398 return m_Writer->Finalize();
1402 //------------------------------------------------------------------------------------------
1406 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1408 ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1410 StereoscopicPhase_t m_NextPhase;
1413 h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1416 Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1417 AESEncContext* Ctx, HMACContext* HMAC)
1419 if ( m_NextPhase != phase )
1420 return RESULT_SPHASE;
1422 if ( phase == SP_LEFT )
1424 m_NextPhase = SP_RIGHT;
1425 return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1428 m_NextPhase = SP_LEFT;
1429 return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1435 if ( m_NextPhase != SP_LEFT )
1436 return RESULT_SPHASE;
1438 assert( m_FramesWritten % 2 == 0 );
1439 m_FramesWritten /= 2;
1440 return lh__Writer::Finalize();
1446 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1450 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1454 // Warning: direct manipulation of MXF structures can interfere
1455 // with the normal operation of the wrapper. Caveat emptor!
1457 ASDCP::MXF::OP1aHeader&
1458 ASDCP::JP2K::MXFSWriter::OP1aHeader()
1460 if ( m_Writer.empty() )
1462 assert(g_OP1aHeader);
1463 return *g_OP1aHeader;
1466 return m_Writer->m_HeaderPart;
1469 // Warning: direct manipulation of MXF structures can interfere
1470 // with the normal operation of the wrapper. Caveat emptor!
1472 ASDCP::MXF::OPAtomIndexFooter&
1473 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1475 if ( m_Writer.empty() )
1477 assert(g_OPAtomIndexFooter);
1478 return *g_OPAtomIndexFooter;
1481 return m_Writer->m_FooterPart;
1484 // Warning: direct manipulation of MXF structures can interfere
1485 // with the normal operation of the wrapper. Caveat emptor!
1488 ASDCP::JP2K::MXFSWriter::RIP()
1490 if ( m_Writer.empty() )
1496 return m_Writer->m_RIP;
1499 // Open the file for writing. The file must not exist. Returns error if
1500 // the operation cannot be completed.
1502 ASDCP::JP2K::MXFSWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
1503 const PictureDescriptor& PDesc, ui32_t HeaderSize)
1505 if ( Info.LabelSetType == LS_MXF_SMPTE )
1506 m_Writer = new h__SWriter(DefaultSMPTEDict());
1508 m_Writer = new h__SWriter(DefaultInteropDict());
1510 if ( PDesc.EditRate != ASDCP::EditRate_24
1511 && PDesc.EditRate != ASDCP::EditRate_25
1512 && PDesc.EditRate != ASDCP::EditRate_30
1513 && PDesc.EditRate != ASDCP::EditRate_48
1514 && PDesc.EditRate != ASDCP::EditRate_50
1515 && PDesc.EditRate != ASDCP::EditRate_60 )
1517 DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1518 return RESULT_FORMAT;
1521 if ( PDesc.StoredWidth > 2048 )
1522 DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1524 m_Writer->m_Info = Info;
1526 Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1528 if ( ASDCP_SUCCESS(result) )
1530 PictureDescriptor TmpPDesc = PDesc;
1532 if ( PDesc.EditRate == ASDCP::EditRate_24 )
1533 TmpPDesc.EditRate = ASDCP::EditRate_48;
1535 else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1536 TmpPDesc.EditRate = ASDCP::EditRate_50;
1538 else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1539 TmpPDesc.EditRate = ASDCP::EditRate_60;
1541 else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1542 TmpPDesc.EditRate = ASDCP::EditRate_96;
1544 else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1545 TmpPDesc.EditRate = ASDCP::EditRate_100;
1547 else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1548 TmpPDesc.EditRate = ASDCP::EditRate_120;
1550 else if ( PDesc.EditRate == ASDCP::EditRate_96 )
1551 TmpPDesc.EditRate = ASDCP::EditRate_192;
1553 else if ( PDesc.EditRate == ASDCP::EditRate_100 )
1554 TmpPDesc.EditRate = ASDCP::EditRate_200;
1556 else if ( PDesc.EditRate == ASDCP::EditRate_120 )
1557 TmpPDesc.EditRate = ASDCP::EditRate_240;
1559 result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1562 if ( ASDCP_FAILURE(result) )
1569 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1571 if ( m_Writer.empty() )
1574 Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1576 if ( ASDCP_SUCCESS(result) )
1577 result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1582 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1583 // argument is present, the essence is encrypted prior to writing.
1584 // Fails if the file is not open, is finalized, or an operating system
1587 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1588 AESEncContext* Ctx, HMACContext* HMAC)
1590 if ( m_Writer.empty() )
1593 return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1596 // Closes the MXF file, writing the index and other closing information.
1598 ASDCP::JP2K::MXFSWriter::Finalize()
1600 if ( m_Writer.empty() )
1603 return m_Writer->Finalize();
1607 // end AS_DCP_JP2K.cpp