Bump patch version post tag.
[asdcplib.git] / src / AS_DCP_JP2K.cpp
1 /*
2 Copyright (c) 2004-2016, John Hurst
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
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.
15
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.
26 */
27 /*! \file    AS_DCP_JP2k.cpp
28     \version $Id$
29     \brief   AS-DCP library, JPEG 2000 essence reader and writer implementation
30 */
31
32 #include "AS_DCP_internal.h"
33 #include <iostream>
34 #include <iomanip>
35 #include <algorithm>
36
37 using namespace ASDCP::JP2K;
38 using Kumu::GenRandomValue;
39
40 //------------------------------------------------------------------------------------------
41
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";
45
46 static int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
47
48 //
49 std::ostream&
50 ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc)
51 {
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;
67
68   strm << "-- JPEG 2000 Metadata --" << std::endl;
69   strm << "    ImageComponents:" << std::endl;
70   strm << "  bits  h-sep v-sep" << std::endl;
71
72   ui32_t i;
73   for ( i = 0; i < PDesc.Csize && i < MaxComponents; ++i )
74     {
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
78            << std::endl;
79     }
80
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;
90
91
92   ui32_t precinct_set_size = 0;
93
94   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; ++i )
95     precinct_set_size++;
96
97   strm << "          Precincts: " << (short) precinct_set_size << std::endl;
98   strm << "precinct dimensions:" << std::endl;
99
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;
103
104   strm << "               Sqcd: " << (short) PDesc.QuantizationDefault.Sqcd << std::endl;
105
106   char tmp_buf[MaxDefaults*2];
107   strm << "              SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2)
108        << std::endl;
109
110   if (PDesc.Profile.N != 0) {
111           strm << "Profile:" << std::endl;
112
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
116                           << std::endl;
117           }
118   }
119
120   if (PDesc.CorrespondingProfile.N != 0) {
121           strm << "Corresponding Profile:" << std::endl;
122
123           for (ui16_t i = 0; i < PDesc.CorrespondingProfile.N; i++) {
124
125                   strm << "              Pcpf(" << (i + 1) << "): "
126                           << std::hex << std::showbase <<  PDesc.CorrespondingProfile.Pcpf[i] << std::dec << std::noshowbase
127                           << std::endl;
128           }
129   }
130
131   if (PDesc.ExtendedCapabilities.N != JP2K::NoExtendedCapabilitiesSignaled && PDesc.ExtendedCapabilities.Pcap != 0) {
132
133           strm << "Extended Capabilities:" << std::endl;
134
135
136           strm << "                     Pcap:" << PDesc.ExtendedCapabilities.Pcap << std::endl;
137
138           for (i32_t b = 0, i = 0; b < JP2K::MaxCapabilities; b++) {
139
140                   if ((PDesc.ExtendedCapabilities.Pcap >> b) & 0x1) {
141
142                           strm << "              Ccap(" << (JP2K::MaxCapabilities - b) << "): " <<
143                                   std::hex << std::showbase << PDesc.ExtendedCapabilities.Ccap[i++] << std::dec << std::noshowbase
144                                   << std::endl;
145
146                   }
147           }
148   }
149
150   return strm;
151 }
152
153 //
154 void
155 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
156 {
157   if ( stream == 0 )
158     stream = stderr;
159
160   fprintf(stream, "\
161        AspectRatio: %d/%d\n\
162           EditRate: %d/%d\n\
163         SampleRate: %d/%d\n\
164        StoredWidth: %u\n\
165       StoredHeight: %u\n\
166              Rsize: %u\n\
167              Xsize: %u\n\
168              Ysize: %u\n\
169             XOsize: %u\n\
170             YOsize: %u\n\
171             XTsize: %u\n\
172             YTsize: %u\n\
173            XTOsize: %u\n\
174            YTOsize: %u\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,
179           PDesc.StoredWidth,
180           PDesc.StoredHeight,
181           PDesc.Rsize,
182           PDesc.Xsize,
183           PDesc.Ysize,
184           PDesc.XOsize,
185           PDesc.YOsize,
186           PDesc.XTsize,
187           PDesc.YTsize,
188           PDesc.XTOsize,
189           PDesc.YTOsize,
190           PDesc.ContainerDuration
191           );
192
193   fprintf(stream, "-- JPEG 2000 Metadata --\n");
194   fprintf(stream, "    ImageComponents:\n");
195   fprintf(stream, "  bits  h-sep v-sep\n");
196
197   ui32_t i;
198   for ( i = 0; i < PDesc.Csize && i < MaxComponents; i++ )
199     {
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
204               );
205     }
206   
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)));
211
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);
218
219
220   ui32_t precinct_set_size = 0;
221
222   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; ++i )
223     precinct_set_size++;
224
225   fprintf(stream, "          Precincts: %u\n", precinct_set_size);
226   fprintf(stream, "precinct dimensions:\n");
227
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]
232             );
233
234   fprintf(stream, "               Sqcd: %hhu\n", PDesc.QuantizationDefault.Sqcd);
235
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)
240           );
241
242
243   if (PDesc.Profile.N != 0) {
244           fprintf(stream, "               Profile:\n");
245
246           for (ui16_t i = 0; i < PDesc.Profile.N; i++) {
247
248                   fprintf(stream, "              Pprf(%d): %hx\n", i + 1, PDesc.Profile.Pprf[i]);
249
250           }
251   }
252
253   if (PDesc.CorrespondingProfile.N != 0) {
254           fprintf(stream, "Corresponding Profile:\n");
255
256           for (ui16_t i = 0; i < PDesc.CorrespondingProfile.N; i++) {
257                   fprintf(stream, "              Pcpf(%d): %hx\n", i + 1, PDesc.CorrespondingProfile.Pcpf[i]);
258
259           }
260   }
261
262   if (PDesc.ExtendedCapabilities.N != JP2K::NoExtendedCapabilitiesSignaled) {
263
264           fprintf(stream, "Extended Capabilities: %x\n", PDesc.ExtendedCapabilities.Pcap);
265
266           for (i32_t b = 0, i = 0; b < JP2K::MaxCapabilities && i < PDesc.ExtendedCapabilities.N; b++) {
267
268                   if ((PDesc.ExtendedCapabilities.Pcap >> (JP2K::MaxCapabilities - b - 1)) & 0x1) {
269
270                           fprintf(stream, "           Ccap(%d): %hx\n", b + 1, PDesc.ExtendedCapabilities.Ccap[i++]);
271
272                   }
273           }
274
275   }
276   
277 }
278
279
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 };
283
284 //
285 ASDCP::Result_t
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)
290 {
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;
297
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;
308
309   const ui32_t tmp_buffer_len = 1024;
310   byte_t tmp_buffer[tmp_buffer_len];
311
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);
315
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();
320
321   ui32_t precinct_set_size = 0;
322   for ( ui32_t i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; ++i )
323     precinct_set_size++;
324
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();
329
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();
334
335   // Profile
336
337   if (PDesc.Profile.N == 0) {
338           EssenceSubDescriptor.J2KProfile.set_has_value(false);
339   } else {
340           EssenceSubDescriptor.J2KProfile.get().resize(PDesc.Profile.N);
341
342           std::copy(PDesc.Profile.Pprf,
343                   PDesc.Profile.Pprf + PDesc.Profile.N,
344                    EssenceSubDescriptor.J2KProfile.get().begin());
345
346           EssenceSubDescriptor.J2KProfile.set_has_value();
347   }
348
349   // Corresponding profile
350
351   if (PDesc.CorrespondingProfile.N == 0) {
352         
353           EssenceSubDescriptor.J2KCorrespondingProfile.set_has_value(false);
354   
355   } else {
356           EssenceSubDescriptor.J2KCorrespondingProfile.get().resize(PDesc.CorrespondingProfile.N);
357
358           std::copy(PDesc.CorrespondingProfile.Pcpf,
359                   PDesc.CorrespondingProfile.Pcpf + PDesc.CorrespondingProfile.N,
360                   EssenceSubDescriptor.J2KCorrespondingProfile.get().begin());
361
362           EssenceSubDescriptor.J2KCorrespondingProfile.set_has_value();
363   }
364
365   // Extended capabilities
366
367   if (PDesc.ExtendedCapabilities.N == JP2K::NoExtendedCapabilitiesSignaled) {
368
369           /* No extended capabilities are signaled */
370
371           EssenceSubDescriptor.J2KExtendedCapabilities.set_has_value(false);
372
373   } else {
374
375           EssenceSubDescriptor.J2KExtendedCapabilities.get().Pcap = PDesc.ExtendedCapabilities.Pcap;
376
377           EssenceSubDescriptor.J2KExtendedCapabilities.get().Ccap.resize(PDesc.ExtendedCapabilities.N);
378
379           std::copy(PDesc.ExtendedCapabilities.Ccap,
380                   PDesc.ExtendedCapabilities.Ccap + PDesc.ExtendedCapabilities.N,
381                   EssenceSubDescriptor.J2KExtendedCapabilities.get().Ccap.begin());
382
383           EssenceSubDescriptor.J2KExtendedCapabilities.set_has_value(true);
384
385   }
386
387   return RESULT_OK;
388 }
389
390
391 //
392 ASDCP::Result_t
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)
397 {
398   memset(&PDesc, 0, sizeof(PDesc));
399
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;
407
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;
418
419   // PictureComponentSizing
420   ui32_t tmp_size = EssenceSubDescriptor.PictureComponentSizing.const_get().Length();
421
422   if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
423     {
424       memcpy(&PDesc.ImageComponents, EssenceSubDescriptor.PictureComponentSizing.const_get().RoData() + 8, tmp_size - 8);
425     }
426   else
427     {
428       DefaultLogSink().Warn("Unexpected PictureComponentSizing size: %u, should be 17.\n", tmp_size);
429     }
430
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());
436
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());
442   
443   PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1;
444
445   // Profile
446
447   std::fill(PDesc.Profile.Pprf, PDesc.Profile.Pprf + JP2K::MaxPRFN, 0);
448
449   if (EssenceSubDescriptor.J2KProfile.empty() ||
450           EssenceSubDescriptor.J2KProfile.const_get().size() == 0) {
451
452           PDesc.Profile.N = 0;
453
454   } else {
455
456           PDesc.Profile.N = EssenceSubDescriptor.J2KProfile.const_get().size();
457
458           std::copy(EssenceSubDescriptor.J2KProfile.const_get().begin(),
459                   EssenceSubDescriptor.J2KProfile.const_get().end(),
460                   PDesc.Profile.Pprf);
461
462   }
463
464   // Corresponding profile
465
466   std::fill(PDesc.CorrespondingProfile.Pcpf, PDesc.CorrespondingProfile.Pcpf + JP2K::MaxCPFN, 0);
467
468   if (EssenceSubDescriptor.J2KCorrespondingProfile.empty() ||
469           EssenceSubDescriptor.J2KCorrespondingProfile.const_get().size() == 0) {
470
471           PDesc.CorrespondingProfile.N = 0;
472
473   }
474   else {
475
476           PDesc.CorrespondingProfile.N = EssenceSubDescriptor.J2KCorrespondingProfile.const_get().size();
477
478           std::copy(EssenceSubDescriptor.J2KCorrespondingProfile.const_get().begin(),
479                   EssenceSubDescriptor.J2KCorrespondingProfile.const_get().end(),
480                   PDesc.CorrespondingProfile.Pcpf);
481
482   }
483
484   // Extended capabilities
485
486   std::fill(PDesc.ExtendedCapabilities.Ccap, PDesc.ExtendedCapabilities.Ccap + JP2K::MaxCapabilities, 0);
487
488   if (EssenceSubDescriptor.J2KExtendedCapabilities.empty()) {
489
490           PDesc.ExtendedCapabilities.Pcap = 0;
491           PDesc.ExtendedCapabilities.N = JP2K::NoExtendedCapabilitiesSignaled;
492
493   }
494   else {
495
496           PDesc.ExtendedCapabilities.Pcap = EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Pcap;
497           PDesc.ExtendedCapabilities.N = EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Ccap.size();
498
499           std::copy(EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Ccap.begin(),
500                   EssenceSubDescriptor.J2KExtendedCapabilities.const_get().Ccap.end(),
501                   PDesc.ExtendedCapabilities.Ccap);
502
503   }
504
505   return RESULT_OK;
506 }
507
508
509 //------------------------------------------------------------------------------------------
510 //
511 // hidden, internal implementation of JPEG 2000 reader
512
513
514 class lh__Reader : public ASDCP::h__ASDCPReader
515 {
516   RGBAEssenceDescriptor*        m_EssenceDescriptor;
517   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
518   ASDCP::Rational               m_EditRate;
519   ASDCP::Rational               m_SampleRate;
520   EssenceType_t                 m_Format;
521
522   ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
523
524 public:
525   PictureDescriptor m_PDesc;        // codestream parameter list
526
527   lh__Reader(const Dictionary& d) :
528     ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
529
530   virtual ~lh__Reader() {}
531
532   Result_t    OpenRead(const std::string&, EssenceType_t);
533   Result_t    ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
534 };
535
536
537 //
538 //
539 ASDCP::Result_t
540 lh__Reader::OpenRead(const std::string& filename, EssenceType_t type)
541 {
542   Result_t result = OpenMXFRead(filename);
543
544   if( ASDCP_SUCCESS(result) )
545     {
546       InterchangeObject* tmp_iobj = 0;
547       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
548       m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
549
550       if ( m_EssenceDescriptor == 0 )
551         {
552           DefaultLogSink().Error("RGBAEssenceDescriptor object not found.\n");
553           return RESULT_FORMAT;
554         }
555
556       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
557       m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
558
559       if ( m_EssenceSubDescriptor == 0 )
560         {
561           m_EssenceDescriptor = 0;
562           DefaultLogSink().Error("JPEG2000PictureSubDescriptor object not found.\n");
563           return RESULT_FORMAT;
564         }
565
566       std::list<InterchangeObject*> ObjectList;
567       m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
568
569       if ( ObjectList.empty() )
570         {
571           DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
572           return RESULT_FORMAT;
573         }
574
575       m_EditRate = ((Track*)ObjectList.front())->EditRate;
576       m_SampleRate = m_EssenceDescriptor->SampleRate;
577
578       if ( type == ASDCP::ESS_JPEG_2000 )
579         {
580           if ( m_EditRate != m_SampleRate )
581             {
582               DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
583                                     m_EditRate.Quotient(), m_SampleRate.Quotient());
584               
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 ) )
594                 {
595                   DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
596                   return RESULT_SFORMAT;
597                 }
598
599               return RESULT_FORMAT;
600             }
601         }
602       else if ( type == ASDCP::ESS_JPEG_2000_S )
603         {
604           if ( m_EditRate == EditRate_24 )
605             {
606               if ( m_SampleRate != EditRate_48 )
607                 {
608                   DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
609                   return RESULT_FORMAT;
610                 }
611             }
612           else if ( m_EditRate == EditRate_25 )
613             {
614               if ( m_SampleRate != EditRate_50 )
615                 {
616                   DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
617                   return RESULT_FORMAT;
618                 }
619             }
620           else if ( m_EditRate == EditRate_30 )
621             {
622               if ( m_SampleRate != EditRate_60 )
623                 {
624                   DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
625                   return RESULT_FORMAT;
626                 }
627             }
628           else if ( m_EditRate == EditRate_48 )
629             {
630               if ( m_SampleRate != EditRate_96 )
631                 {
632                   DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
633                   return RESULT_FORMAT;
634                 }
635             }
636           else if ( m_EditRate == EditRate_50 )
637             {
638               if ( m_SampleRate != EditRate_100 )
639                 {
640                   DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
641                   return RESULT_FORMAT;
642                 }
643             }
644           else if ( m_EditRate == EditRate_60 )
645             {
646               if ( m_SampleRate != EditRate_120 )
647                 {
648                   DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
649                   return RESULT_FORMAT;
650                 }
651             }
652           else if ( m_EditRate == EditRate_96 )
653             {
654               if ( m_SampleRate != EditRate_192 )
655                 {
656                   DefaultLogSink().Error("EditRate and SampleRate not correct for 96/192 stereoscopic essence.\n");
657                   return RESULT_FORMAT;
658                 }
659             }
660           else if ( m_EditRate == EditRate_100 )
661             {
662               if ( m_SampleRate != EditRate_200 )
663                 {
664                   DefaultLogSink().Error("EditRate and SampleRate not correct for 100/200 stereoscopic essence.\n");
665                   return RESULT_FORMAT;
666                 }
667             }
668           else if ( m_EditRate == EditRate_120 )
669             {
670               if ( m_SampleRate != EditRate_240 )
671                 {
672                   DefaultLogSink().Error("EditRate and SampleRate not correct for 120/240 stereoscopic essence.\n");
673                   return RESULT_FORMAT;
674                 }
675             }
676           else
677             {
678               DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
679                                      m_EditRate.Numerator, m_EditRate.Denominator);
680               return RESULT_FORMAT;
681             }
682         }
683       else
684         {
685           DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
686           return RESULT_STATE;
687         }
688
689       result = MD_to_JP2K_PDesc(*m_EssenceDescriptor, *m_EssenceSubDescriptor, m_EditRate, m_SampleRate, m_PDesc);
690     }
691
692   return result;
693 }
694
695 //
696 //
697 ASDCP::Result_t
698 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
699                       AESDecContext* Ctx, HMACContext* HMAC)
700 {
701   if ( ! m_File.IsOpen() )
702     return RESULT_INIT;
703
704   assert(m_Dict);
705   return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
706 }
707
708
709 //
710 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
711 {
712   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
713   h__Reader();
714
715 public:
716   h__Reader(const Dictionary& d) : lh__Reader(d) {}
717 };
718
719
720
721 //------------------------------------------------------------------------------------------
722
723
724 //
725 void
726 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
727 {
728   if ( stream == 0 )
729     stream = stderr;
730
731   fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
732   
733   fputc('\n', stream);
734
735   if ( dump_len > 0 )
736     Kumu::hexdump(m_Data, dump_len, stream);
737 }
738
739
740 //------------------------------------------------------------------------------------------
741
742 ASDCP::JP2K::MXFReader::MXFReader()
743 {
744   m_Reader = new h__Reader(DefaultCompositeDict());
745 }
746
747
748 ASDCP::JP2K::MXFReader::~MXFReader()
749 {
750   if ( m_Reader && m_Reader->m_File.IsOpen() )
751     m_Reader->Close();
752 }
753
754 // Warning: direct manipulation of MXF structures can interfere
755 // with the normal operation of the wrapper.  Caveat emptor!
756 //
757 ASDCP::MXF::OP1aHeader&
758 ASDCP::JP2K::MXFReader::OP1aHeader()
759 {
760   if ( m_Reader.empty() )
761     {
762       assert(g_OP1aHeader);
763       return *g_OP1aHeader;
764     }
765
766   return m_Reader->m_HeaderPart;
767 }
768
769 // Warning: direct manipulation of MXF structures can interfere
770 // with the normal operation of the wrapper.  Caveat emptor!
771 //
772 ASDCP::MXF::OPAtomIndexFooter&
773 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
774 {
775   if ( m_Reader.empty() )
776     {
777       assert(g_OPAtomIndexFooter);
778       return *g_OPAtomIndexFooter;
779     }
780
781   return m_Reader->m_IndexAccess;
782 }
783
784 // Warning: direct manipulation of MXF structures can interfere
785 // with the normal operation of the wrapper.  Caveat emptor!
786 //
787 ASDCP::MXF::RIP&
788 ASDCP::JP2K::MXFReader::RIP()
789 {
790   if ( m_Reader.empty() )
791     {
792       assert(g_RIP);
793       return *g_RIP;
794     }
795
796   return m_Reader->m_RIP;
797 }
798
799 // Open the file for reading. The file must exist. Returns error if the
800 // operation cannot be completed.
801 ASDCP::Result_t
802 ASDCP::JP2K::MXFReader::OpenRead(const std::string& filename) const
803 {
804   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
805 }
806
807 //
808 ASDCP::Result_t
809 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
810                                    AESDecContext* Ctx, HMACContext* HMAC) const
811 {
812   if ( m_Reader && m_Reader->m_File.IsOpen() )
813     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
814
815   return RESULT_INIT;
816 }
817
818 ASDCP::Result_t
819 ASDCP::JP2K::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
820 {
821     return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
822 }
823
824
825 // Fill the struct with the values from the file's header.
826 // Returns RESULT_INIT if the file is not open.
827 ASDCP::Result_t
828 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
829 {
830   if ( m_Reader && m_Reader->m_File.IsOpen() )
831     {
832       PDesc = m_Reader->m_PDesc;
833       return RESULT_OK;
834     }
835
836   return RESULT_INIT;
837 }
838
839
840 // Fill the struct with the values from the file's header.
841 // Returns RESULT_INIT if the file is not open.
842 ASDCP::Result_t
843 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
844 {
845   if ( m_Reader && m_Reader->m_File.IsOpen() )
846     {
847       Info = m_Reader->m_Info;
848       return RESULT_OK;
849     }
850
851   return RESULT_INIT;
852 }
853
854 //
855 void
856 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
857 {
858   if ( m_Reader->m_File.IsOpen() )
859     m_Reader->m_HeaderPart.Dump(stream);
860 }
861
862
863 //
864 void
865 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
866 {
867   if ( m_Reader->m_File.IsOpen() )
868     m_Reader->m_IndexAccess.Dump(stream);
869 }
870
871 //
872 ASDCP::Result_t
873 ASDCP::JP2K::MXFReader::Close() const
874 {
875   if ( m_Reader && m_Reader->m_File.IsOpen() )
876     {
877       m_Reader->Close();
878       return RESULT_OK;
879     }
880
881   return RESULT_INIT;
882 }
883
884
885 //------------------------------------------------------------------------------------------
886
887
888 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
889 {
890   ui32_t m_StereoFrameReady;
891
892 public:
893   h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
894
895   //
896   Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
897                      AESDecContext* Ctx, HMACContext* HMAC)
898   {
899     // look up frame index node
900     IndexTableSegment::IndexEntry TmpEntry;
901
902     if ( ASDCP_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
903       {
904         return RESULT_RANGE;
905       }
906
907     // get frame position
908     Kumu::fpos_t FilePosition = m_HeaderPart.BodyOffset + TmpEntry.StreamOffset;
909     Result_t result = RESULT_OK;
910
911     if ( phase == SP_LEFT )
912       {    
913         if ( FilePosition != m_LastPosition )
914           {
915             m_LastPosition = FilePosition;
916             result = m_File.Seek(FilePosition);
917           }
918
919         // the call to ReadEKLVPacket() will leave the file on an R frame
920         m_StereoFrameReady = FrameNum;
921       }
922     else if ( phase == SP_RIGHT )
923       {
924         if ( m_StereoFrameReady != FrameNum )
925           {
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 )
929               {
930                 m_LastPosition = FilePosition;
931                 result = m_File.Seek(FilePosition);
932               }
933
934             KLReader Reader;
935             result = Reader.ReadKLFromFile(m_File);
936
937             if ( ASDCP_SUCCESS(result) )
938               {
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);
942               }
943           }
944
945         // the call to ReadEKLVPacket() will leave the file not on an R frame
946         m_StereoFrameReady = 0xffffffff;
947       }
948     else
949       {
950         DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
951         return RESULT_STATE;
952       }
953
954     if( ASDCP_SUCCESS(result) )
955       {
956         ui32_t SequenceNum = FrameNum * 2;
957         SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
958         assert(m_Dict);
959         result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
960       }
961
962     return result;
963   }
964 };
965
966
967
968 ASDCP::JP2K::MXFSReader::MXFSReader()
969 {
970   m_Reader = new h__SReader(DefaultCompositeDict());
971 }
972
973
974 ASDCP::JP2K::MXFSReader::~MXFSReader()
975 {
976   if ( m_Reader && m_Reader->m_File.IsOpen() )
977     m_Reader->Close();
978 }
979
980 // Warning: direct manipulation of MXF structures can interfere
981 // with the normal operation of the wrapper.  Caveat emptor!
982 //
983 ASDCP::MXF::OP1aHeader&
984 ASDCP::JP2K::MXFSReader::OP1aHeader()
985 {
986   if ( m_Reader.empty() )
987     {
988       assert(g_OP1aHeader);
989       return *g_OP1aHeader;
990     }
991
992   return m_Reader->m_HeaderPart;
993 }
994
995 // Warning: direct manipulation of MXF structures can interfere
996 // with the normal operation of the wrapper.  Caveat emptor!
997 //
998 ASDCP::MXF::OPAtomIndexFooter&
999 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
1000 {
1001   if ( m_Reader.empty() )
1002     {
1003       assert(g_OPAtomIndexFooter);
1004       return *g_OPAtomIndexFooter;
1005     }
1006
1007   return m_Reader->m_IndexAccess;
1008 }
1009
1010 // Warning: direct manipulation of MXF structures can interfere
1011 // with the normal operation of the wrapper.  Caveat emptor!
1012 //
1013 ASDCP::MXF::RIP&
1014 ASDCP::JP2K::MXFSReader::RIP()
1015 {
1016   if ( m_Reader.empty() )
1017     {
1018       assert(g_RIP);
1019       return *g_RIP;
1020     }
1021
1022   return m_Reader->m_RIP;
1023 }
1024
1025 // Open the file for reading. The file must exist. Returns error if the
1026 // operation cannot be completed.
1027 ASDCP::Result_t
1028 ASDCP::JP2K::MXFSReader::OpenRead(const std::string& filename) const
1029 {
1030   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
1031 }
1032
1033 //
1034 ASDCP::Result_t
1035 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
1036 {
1037   Result_t result = RESULT_INIT;
1038
1039   if ( m_Reader && m_Reader->m_File.IsOpen() )
1040     {
1041       result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
1042
1043       if ( ASDCP_SUCCESS(result) )
1044         result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
1045     }
1046
1047   return result;
1048 }
1049
1050 //
1051 ASDCP::Result_t
1052 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
1053                                    AESDecContext* Ctx, HMACContext* HMAC) const
1054 {
1055   if ( m_Reader && m_Reader->m_File.IsOpen() )
1056     return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
1057
1058   return RESULT_INIT;
1059 }
1060
1061 ASDCP::Result_t
1062 ASDCP::JP2K::MXFSReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
1063 {
1064     return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
1065 }
1066
1067 // Fill the struct with the values from the file's header.
1068 // Returns RESULT_INIT if the file is not open.
1069 ASDCP::Result_t
1070 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
1071 {
1072   if ( m_Reader && m_Reader->m_File.IsOpen() )
1073     {
1074       PDesc = m_Reader->m_PDesc;
1075       return RESULT_OK;
1076     }
1077
1078   return RESULT_INIT;
1079 }
1080
1081
1082 // Fill the struct with the values from the file's header.
1083 // Returns RESULT_INIT if the file is not open.
1084 ASDCP::Result_t
1085 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
1086 {
1087   if ( m_Reader && m_Reader->m_File.IsOpen() )
1088     {
1089       Info = m_Reader->m_Info;
1090       return RESULT_OK;
1091     }
1092
1093   return RESULT_INIT;
1094 }
1095
1096 //
1097 void
1098 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
1099 {
1100   if ( m_Reader->m_File.IsOpen() )
1101     m_Reader->m_HeaderPart.Dump(stream);
1102 }
1103
1104
1105 //
1106 void
1107 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
1108 {
1109   if ( m_Reader->m_File.IsOpen() )
1110     m_Reader->m_IndexAccess.Dump(stream);
1111 }
1112
1113 //
1114 ASDCP::Result_t
1115 ASDCP::JP2K::MXFSReader::Close() const
1116 {
1117   if ( m_Reader && m_Reader->m_File.IsOpen() )
1118     {
1119       m_Reader->Close();
1120       return RESULT_OK;
1121     }
1122
1123   return RESULT_INIT;
1124 }
1125
1126
1127 //------------------------------------------------------------------------------------------
1128
1129
1130 //
1131 class lh__Writer : public ASDCP::h__ASDCPWriter
1132 {
1133   ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
1134   lh__Writer();
1135
1136   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
1137
1138 public:
1139   PictureDescriptor m_PDesc;
1140   byte_t            m_EssenceUL[SMPTE_UL_LENGTH];
1141
1142   lh__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_EssenceSubDescriptor(0) {
1143     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
1144   }
1145
1146   virtual ~lh__Writer(){}
1147
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();
1153 };
1154
1155 // Open the file for writing. The file must not exist. Returns error if
1156 // the operation cannot be completed.
1157 ASDCP::Result_t
1158 lh__Writer::OpenWrite(const std::string& filename, EssenceType_t type, ui32_t HeaderSize)
1159 {
1160   if ( ! m_State.Test_BEGIN() )
1161     return RESULT_STATE;
1162
1163   Result_t result = m_File.OpenWrite(filename);
1164
1165   if ( ASDCP_SUCCESS(result) )
1166     {
1167       m_HeaderSize = HeaderSize;
1168       RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
1169       tmp_rgba->ComponentMaxRef = 4095;
1170       tmp_rgba->ComponentMinRef = 0;
1171
1172       m_EssenceDescriptor = tmp_rgba;
1173       m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
1174       m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
1175
1176       GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
1177       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
1178
1179       if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
1180         {
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);
1185         }
1186
1187       result = m_State.Goto_INIT();
1188     }
1189
1190   return result;
1191 }
1192
1193 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
1194 ASDCP::Result_t
1195 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
1196 {
1197   assert(m_Dict);
1198   if ( ! m_State.Test_INIT() )
1199     return RESULT_STATE;
1200
1201   if ( LocalEditRate == ASDCP::Rational(0,0) )
1202     LocalEditRate = PDesc.EditRate;
1203
1204   m_PDesc = PDesc;
1205   assert(m_Dict);
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);
1211
1212   if ( ASDCP_SUCCESS(result) )
1213     {
1214       if ( PDesc.StoredWidth < 2049 )
1215         {
1216           static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
1217           m_EssenceSubDescriptor->Rsize = 3;
1218         }
1219       else
1220         {
1221           static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
1222           m_EssenceSubDescriptor->Rsize = 4;
1223         }
1224
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();
1228     }
1229
1230   if ( ASDCP_SUCCESS(result) )
1231     {
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));
1235     }
1236
1237   return result;
1238 }
1239
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
1243 // error occurs.
1244 //
1245 ASDCP::Result_t
1246 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
1247                        AESEncContext* Ctx, HMACContext* HMAC)
1248 {
1249   Result_t result = RESULT_OK;
1250
1251   if ( m_State.Test_READY() )
1252     result = m_State.Goto_RUNNING(); // first time through
1253  
1254   ui64_t StreamOffset = m_StreamOffset;
1255
1256   if ( ASDCP_SUCCESS(result) )
1257     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, MXF_BER_LENGTH, Ctx, HMAC);
1258
1259   if ( ASDCP_SUCCESS(result) && add_index )
1260     {  
1261       IndexTableSegment::IndexEntry Entry;
1262       Entry.StreamOffset = StreamOffset;
1263       m_FooterPart.PushIndexEntry(Entry);
1264     }
1265
1266   m_FramesWritten++;
1267   return result;
1268 }
1269
1270
1271 // Closes the MXF file, writing the index and other closing information.
1272 //
1273 ASDCP::Result_t
1274 lh__Writer::Finalize()
1275 {
1276   if ( ! m_State.Test_RUNNING() )
1277     return RESULT_STATE;
1278
1279   m_State.Goto_FINAL();
1280
1281   return WriteASDCPFooter();
1282 }
1283
1284
1285 //
1286 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1287 {
1288   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1289   h__Writer();
1290
1291 public:
1292   h__Writer(const Dictionary& d) : lh__Writer(d) {}
1293 };
1294
1295
1296 //------------------------------------------------------------------------------------------
1297
1298
1299
1300 ASDCP::JP2K::MXFWriter::MXFWriter()
1301 {
1302 }
1303
1304 ASDCP::JP2K::MXFWriter::~MXFWriter()
1305 {
1306 }
1307
1308 // Warning: direct manipulation of MXF structures can interfere
1309 // with the normal operation of the wrapper.  Caveat emptor!
1310 //
1311 ASDCP::MXF::OP1aHeader&
1312 ASDCP::JP2K::MXFWriter::OP1aHeader()
1313 {
1314   if ( m_Writer.empty() )
1315     {
1316       assert(g_OP1aHeader);
1317       return *g_OP1aHeader;
1318     }
1319
1320   return m_Writer->m_HeaderPart;
1321 }
1322
1323 // Warning: direct manipulation of MXF structures can interfere
1324 // with the normal operation of the wrapper.  Caveat emptor!
1325 //
1326 ASDCP::MXF::OPAtomIndexFooter&
1327 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1328 {
1329   if ( m_Writer.empty() )
1330     {
1331       assert(g_OPAtomIndexFooter);
1332       return *g_OPAtomIndexFooter;
1333     }
1334
1335   return m_Writer->m_FooterPart;
1336 }
1337
1338 // Warning: direct manipulation of MXF structures can interfere
1339 // with the normal operation of the wrapper.  Caveat emptor!
1340 //
1341 ASDCP::MXF::RIP&
1342 ASDCP::JP2K::MXFWriter::RIP()
1343 {
1344   if ( m_Writer.empty() )
1345     {
1346       assert(g_RIP);
1347       return *g_RIP;
1348     }
1349
1350   return m_Writer->m_RIP;
1351 }
1352
1353 // Open the file for writing. The file must not exist. Returns error if
1354 // the operation cannot be completed.
1355 ASDCP::Result_t
1356 ASDCP::JP2K::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
1357                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
1358 {
1359   if ( Info.LabelSetType == LS_MXF_SMPTE )
1360     m_Writer = new h__Writer(DefaultSMPTEDict());
1361   else
1362     m_Writer = new h__Writer(DefaultInteropDict());
1363
1364   m_Writer->m_Info = Info;
1365
1366   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1367
1368   if ( ASDCP_SUCCESS(result) )
1369     result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1370
1371   if ( ASDCP_FAILURE(result) )
1372     m_Writer.release();
1373
1374   return result;
1375 }
1376
1377
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
1381 // error occurs.
1382 ASDCP::Result_t
1383 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1384 {
1385   if ( m_Writer.empty() )
1386     return RESULT_INIT;
1387
1388   return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1389 }
1390
1391 // Closes the MXF file, writing the index and other closing information.
1392 ASDCP::Result_t
1393 ASDCP::JP2K::MXFWriter::Finalize()
1394 {
1395   if ( m_Writer.empty() )
1396     return RESULT_INIT;
1397
1398   return m_Writer->Finalize();
1399 }
1400
1401
1402 //------------------------------------------------------------------------------------------
1403 //
1404
1405 //
1406 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1407 {
1408   ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1409   h__SWriter();
1410   StereoscopicPhase_t m_NextPhase;
1411
1412 public:
1413   h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1414
1415   //
1416   Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1417                       AESEncContext* Ctx, HMACContext* HMAC)
1418   {
1419     if ( m_NextPhase != phase )
1420       return RESULT_SPHASE;
1421
1422     if ( phase == SP_LEFT )
1423       {
1424         m_NextPhase = SP_RIGHT;
1425         return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1426       }
1427
1428     m_NextPhase = SP_LEFT;
1429     return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1430   }
1431
1432   //
1433   Result_t Finalize()
1434   {
1435     if ( m_NextPhase != SP_LEFT )
1436       return RESULT_SPHASE;
1437
1438     assert( m_FramesWritten % 2 == 0 );
1439     m_FramesWritten /= 2;
1440     return lh__Writer::Finalize();
1441   }
1442 };
1443
1444
1445 //
1446 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1447 {
1448 }
1449
1450 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1451 {
1452 }
1453
1454 // Warning: direct manipulation of MXF structures can interfere
1455 // with the normal operation of the wrapper.  Caveat emptor!
1456 //
1457 ASDCP::MXF::OP1aHeader&
1458 ASDCP::JP2K::MXFSWriter::OP1aHeader()
1459 {
1460   if ( m_Writer.empty() )
1461     {
1462       assert(g_OP1aHeader);
1463       return *g_OP1aHeader;
1464     }
1465
1466   return m_Writer->m_HeaderPart;
1467 }
1468
1469 // Warning: direct manipulation of MXF structures can interfere
1470 // with the normal operation of the wrapper.  Caveat emptor!
1471 //
1472 ASDCP::MXF::OPAtomIndexFooter&
1473 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1474 {
1475   if ( m_Writer.empty() )
1476     {
1477       assert(g_OPAtomIndexFooter);
1478       return *g_OPAtomIndexFooter;
1479     }
1480
1481   return m_Writer->m_FooterPart;
1482 }
1483
1484 // Warning: direct manipulation of MXF structures can interfere
1485 // with the normal operation of the wrapper.  Caveat emptor!
1486 //
1487 ASDCP::MXF::RIP&
1488 ASDCP::JP2K::MXFSWriter::RIP()
1489 {
1490   if ( m_Writer.empty() )
1491     {
1492       assert(g_RIP);
1493       return *g_RIP;
1494     }
1495
1496   return m_Writer->m_RIP;
1497 }
1498
1499 // Open the file for writing. The file must not exist. Returns error if
1500 // the operation cannot be completed.
1501 ASDCP::Result_t
1502 ASDCP::JP2K::MXFSWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
1503                                    const PictureDescriptor& PDesc, ui32_t HeaderSize)
1504 {
1505   if ( Info.LabelSetType == LS_MXF_SMPTE )
1506     m_Writer = new h__SWriter(DefaultSMPTEDict());
1507   else
1508     m_Writer = new h__SWriter(DefaultInteropDict());
1509
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 )
1516     {
1517       DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1518       return RESULT_FORMAT;
1519     }
1520
1521   if ( PDesc.StoredWidth > 2048 )
1522     DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1523
1524   m_Writer->m_Info = Info;
1525
1526   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1527
1528   if ( ASDCP_SUCCESS(result) )
1529     {
1530       PictureDescriptor TmpPDesc = PDesc;
1531
1532       if ( PDesc.EditRate == ASDCP::EditRate_24 )
1533         TmpPDesc.EditRate = ASDCP::EditRate_48;
1534
1535       else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1536         TmpPDesc.EditRate = ASDCP::EditRate_50;
1537
1538       else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1539         TmpPDesc.EditRate = ASDCP::EditRate_60;
1540
1541       else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1542         TmpPDesc.EditRate = ASDCP::EditRate_96;
1543
1544       else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1545         TmpPDesc.EditRate = ASDCP::EditRate_100;
1546
1547       else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1548         TmpPDesc.EditRate = ASDCP::EditRate_120;
1549
1550       else if ( PDesc.EditRate == ASDCP::EditRate_96 )
1551         TmpPDesc.EditRate = ASDCP::EditRate_192;
1552
1553       else if ( PDesc.EditRate == ASDCP::EditRate_100 )
1554         TmpPDesc.EditRate = ASDCP::EditRate_200;
1555
1556       else if ( PDesc.EditRate == ASDCP::EditRate_120 )
1557         TmpPDesc.EditRate = ASDCP::EditRate_240;
1558
1559       result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1560     }
1561
1562   if ( ASDCP_FAILURE(result) )
1563     m_Writer.release();
1564
1565   return result;
1566 }
1567
1568 ASDCP::Result_t
1569 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1570 {
1571   if ( m_Writer.empty() )
1572     return RESULT_INIT;
1573
1574   Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1575
1576   if ( ASDCP_SUCCESS(result) )
1577     result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1578
1579   return result;
1580 }
1581
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
1585 // error occurs.
1586 ASDCP::Result_t
1587 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1588                                     AESEncContext* Ctx, HMACContext* HMAC)
1589 {
1590   if ( m_Writer.empty() )
1591     return RESULT_INIT;
1592
1593   return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1594 }
1595
1596 // Closes the MXF file, writing the index and other closing information.
1597 ASDCP::Result_t
1598 ASDCP::JP2K::MXFSWriter::Finalize()
1599 {
1600   if ( m_Writer.empty() )
1601     return RESULT_INIT;
1602
1603   return m_Writer->Finalize();
1604 }
1605
1606 //
1607 // end AS_DCP_JP2K.cpp
1608 //