cf30869c3cb94e2345e29fa0b54c8247ddb8d0d6
[asdcplib.git] / src / AS_DCP_JP2K.cpp
1 /*
2 Copyright (c) 2004-2013, 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
36 using namespace ASDCP::JP2K;
37 using Kumu::GenRandomValue;
38
39 //------------------------------------------------------------------------------------------
40
41 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
42 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
43 static std::string PICT_DEF_LABEL = "Picture Track";
44
45 int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
46
47 //
48 std::ostream&
49 ASDCP::JP2K::operator << (std::ostream& strm, const PictureDescriptor& PDesc)
50 {
51   strm << "       AspectRatio: " << PDesc.AspectRatio.Numerator << "/" << PDesc.AspectRatio.Denominator << std::endl;
52   strm << "          EditRate: " << PDesc.EditRate.Numerator << "/" << PDesc.EditRate.Denominator << std::endl;
53   strm << "        SampleRate: " << PDesc.SampleRate.Numerator << "/" << PDesc.SampleRate.Denominator << std::endl;
54   strm << "       StoredWidth: " << (unsigned) PDesc.StoredWidth << std::endl;
55   strm << "      StoredHeight: " << (unsigned) PDesc.StoredHeight << std::endl;
56   strm << "             Rsize: " << (unsigned) PDesc.Rsize << std::endl;
57   strm << "             Xsize: " << (unsigned) PDesc.Xsize << std::endl;
58   strm << "             Ysize: " << (unsigned) PDesc.Ysize << std::endl;
59   strm << "            XOsize: " << (unsigned) PDesc.XOsize << std::endl;
60   strm << "            YOsize: " << (unsigned) PDesc.YOsize << std::endl;
61   strm << "            XTsize: " << (unsigned) PDesc.XTsize << std::endl;
62   strm << "            YTsize: " << (unsigned) PDesc.YTsize << std::endl;
63   strm << "           XTOsize: " << (unsigned) PDesc.XTOsize << std::endl;
64   strm << "           YTOsize: " << (unsigned) PDesc.YTOsize << std::endl;
65   strm << " ContainerDuration: " << (unsigned) PDesc.ContainerDuration << std::endl;
66
67   strm << "-- JPEG 2000 Metadata --" << std::endl;
68   strm << "    ImageComponents:" << std::endl;
69   strm << "  bits  h-sep v-sep" << std::endl;
70
71   ui32_t i;
72   for ( i = 0; i < PDesc.Csize; i++ )
73     {
74       strm << "  " << std::setw(4) << PDesc.ImageComponents[i].Ssize + 1 /* See ISO 15444-1, Table A11, for the origin of '+1' */
75            << "  " << std::setw(5) << PDesc.ImageComponents[i].XRsize
76            << " " << std::setw(5) << PDesc.ImageComponents[i].YRsize
77            << std::endl;
78     }
79
80   strm << "               Scod: " << (short) PDesc.CodingStyleDefault.Scod << std::endl;
81   strm << "   ProgressionOrder: " << (short) PDesc.CodingStyleDefault.SGcod.ProgressionOrder << std::endl;
82   strm << "     NumberOfLayers: " << (short) KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)) << std::endl;
83   strm << " MultiCompTransform: " << (short) PDesc.CodingStyleDefault.SGcod.MultiCompTransform << std::endl;
84   strm << "DecompositionLevels: " << (short) PDesc.CodingStyleDefault.SPcod.DecompositionLevels << std::endl;
85   strm << "     CodeblockWidth: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockWidth << std::endl;
86   strm << "    CodeblockHeight: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockHeight << std::endl;
87   strm << "     CodeblockStyle: " << (short) PDesc.CodingStyleDefault.SPcod.CodeblockStyle << std::endl;
88   strm << "     Transformation: " << (short) PDesc.CodingStyleDefault.SPcod.Transformation << std::endl;
89
90
91   ui32_t precinct_set_size = 0;
92
93   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
94     precinct_set_size++;
95
96   strm << "          Precincts: " << (short) precinct_set_size << std::endl;
97   strm << "precinct dimensions:" << std::endl;
98
99   for ( i = 0; i < precinct_set_size; i++ )
100     strm << "    " << i + 1 << ": " << s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f] << " x "
101          << s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] << std::endl;
102
103   strm << "               Sqcd: " << (short) PDesc.QuantizationDefault.Sqcd << std::endl;
104
105   char tmp_buf[MaxDefaults*2];
106   strm << "              SPqcd: " << Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength, tmp_buf, MaxDefaults*2)
107        << std::endl;
108
109   return strm;
110 }
111
112 //
113 void
114 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
115 {
116   if ( stream == 0 )
117     stream = stderr;
118
119   fprintf(stream, "\
120        AspectRatio: %d/%d\n\
121           EditRate: %d/%d\n\
122         SampleRate: %d/%d\n\
123        StoredWidth: %u\n\
124       StoredHeight: %u\n\
125              Rsize: %u\n\
126              Xsize: %u\n\
127              Ysize: %u\n\
128             XOsize: %u\n\
129             YOsize: %u\n\
130             XTsize: %u\n\
131             YTsize: %u\n\
132            XTOsize: %u\n\
133            YTOsize: %u\n\
134  ContainerDuration: %u\n",
135           PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
136           PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
137           PDesc.SampleRate.Numerator, PDesc.SampleRate.Denominator,
138           PDesc.StoredWidth,
139           PDesc.StoredHeight,
140           PDesc.Rsize,
141           PDesc.Xsize,
142           PDesc.Ysize,
143           PDesc.XOsize,
144           PDesc.YOsize,
145           PDesc.XTsize,
146           PDesc.YTsize,
147           PDesc.XTOsize,
148           PDesc.YTOsize,
149           PDesc.ContainerDuration
150           );
151
152   fprintf(stream, "-- JPEG 2000 Metadata --\n");
153   fprintf(stream, "    ImageComponents:\n");
154   fprintf(stream, "  bits  h-sep v-sep\n");
155
156   ui32_t i;
157   for ( i = 0; i < PDesc.Csize; i++ )
158     {
159       fprintf(stream, "  %4d  %5d %5d\n",
160               PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
161               PDesc.ImageComponents[i].XRsize,
162               PDesc.ImageComponents[i].YRsize
163               );
164     }
165   
166   fprintf(stream, "               Scod: %hd\n", PDesc.CodingStyleDefault.Scod);
167   fprintf(stream, "   ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
168   fprintf(stream, "     NumberOfLayers: %hd\n",
169           KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
170
171   fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
172   fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
173   fprintf(stream, "     CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
174   fprintf(stream, "    CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
175   fprintf(stream, "     CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
176   fprintf(stream, "     Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
177
178
179   ui32_t precinct_set_size = 0;
180
181   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
182     precinct_set_size++;
183
184   fprintf(stream, "          Precincts: %hd\n", precinct_set_size);
185   fprintf(stream, "precinct dimensions:\n");
186
187   for ( i = 0; i < precinct_set_size; i++ )
188     fprintf(stream, "    %d: %d x %d\n", i + 1,
189             s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
190             s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
191             );
192
193   fprintf(stream, "               Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd);
194
195   char tmp_buf[MaxDefaults*2];
196   fprintf(stream, "              SPqcd: %s\n",
197           Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
198                         tmp_buf, MaxDefaults*2)
199           );
200 }
201
202
203 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
204 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
205 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
206
207 //
208 ASDCP::Result_t
209 ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc,
210                         const ASDCP::Dictionary& dict,
211                         ASDCP::MXF::RGBAEssenceDescriptor *EssenceDescriptor,
212                         ASDCP::MXF::JPEG2000PictureSubDescriptor *EssenceSubDescriptor)
213 {
214   if ( EssenceDescriptor == 0 || EssenceSubDescriptor == 0 )
215     return RESULT_PTR;
216
217   EssenceDescriptor->ContainerDuration = PDesc.ContainerDuration;
218   EssenceDescriptor->SampleRate = PDesc.EditRate;
219   EssenceDescriptor->FrameLayout = 0;
220   EssenceDescriptor->StoredWidth = PDesc.StoredWidth;
221   EssenceDescriptor->StoredHeight = PDesc.StoredHeight;
222   EssenceDescriptor->AspectRatio = PDesc.AspectRatio;
223
224   //  if ( m_Info.LabelSetType == LS_MXF_SMPTE )
225   //    {
226   // PictureEssenceCoding UL = 
227   // Video Line Map       ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
228   // CaptureGamma         UL = 
229   // ComponentMaxRef      ui32_t = 4095
230   // ComponentMinRef      ui32_t = 0
231   // PixelLayout          byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
232   //    }
233
234   if ( PDesc.StoredWidth < 2049 )
235     {
236       EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_2K));
237       EssenceSubDescriptor->Rsize = 3;
238     }
239   else
240     {
241       EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_4K));
242       EssenceSubDescriptor->Rsize = 4;
243     }
244
245   EssenceSubDescriptor->Xsize = PDesc.Xsize;
246   EssenceSubDescriptor->Ysize = PDesc.Ysize;
247   EssenceSubDescriptor->XOsize = PDesc.XOsize;
248   EssenceSubDescriptor->YOsize = PDesc.YOsize;
249   EssenceSubDescriptor->XTsize = PDesc.XTsize;
250   EssenceSubDescriptor->YTsize = PDesc.YTsize;
251   EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
252   EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
253   EssenceSubDescriptor->Csize = PDesc.Csize;
254
255   const ui32_t tmp_buffer_len = 1024;
256   byte_t tmp_buffer[tmp_buffer_len];
257
258   *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
259   *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
260   memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
261
262   const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
263   memcpy(EssenceSubDescriptor->PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size);
264   EssenceSubDescriptor->PictureComponentSizing.get().Length(pcomp_size);
265
266   ui32_t precinct_set_size = 0, i;
267   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
268     precinct_set_size++;
269
270   ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
271   memcpy(EssenceSubDescriptor->CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size);
272   EssenceSubDescriptor->CodingStyleDefault.get().Length(csd_size);
273
274   ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
275   memcpy(EssenceSubDescriptor->QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size);
276   EssenceSubDescriptor->QuantizationDefault.get().Length(qdflt_size);
277
278   return RESULT_OK;
279 }
280
281
282 //
283 ASDCP::Result_t
284 ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::RGBAEssenceDescriptor&  EssenceDescriptor,
285                         const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
286                         const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
287                         ASDCP::JP2K::PictureDescriptor& PDesc)
288 {
289   memset(&PDesc, 0, sizeof(PDesc));
290
291   PDesc.EditRate           = EditRate;
292   PDesc.SampleRate         = SampleRate;
293   assert(EssenceDescriptor.ContainerDuration.const_get() <= 0xFFFFFFFFL);
294   PDesc.ContainerDuration  = static_cast<ui32_t>(EssenceDescriptor.ContainerDuration.const_get());
295   PDesc.StoredWidth        = EssenceDescriptor.StoredWidth;
296   PDesc.StoredHeight       = EssenceDescriptor.StoredHeight;
297   PDesc.AspectRatio        = EssenceDescriptor.AspectRatio;
298
299   PDesc.Rsize   = EssenceSubDescriptor.Rsize;
300   PDesc.Xsize   = EssenceSubDescriptor.Xsize;
301   PDesc.Ysize   = EssenceSubDescriptor.Ysize;
302   PDesc.XOsize  = EssenceSubDescriptor.XOsize;
303   PDesc.YOsize  = EssenceSubDescriptor.YOsize;
304   PDesc.XTsize  = EssenceSubDescriptor.XTsize;
305   PDesc.YTsize  = EssenceSubDescriptor.YTsize;
306   PDesc.XTOsize = EssenceSubDescriptor.XTOsize;
307   PDesc.YTOsize = EssenceSubDescriptor.YTOsize;
308   PDesc.Csize   = EssenceSubDescriptor.Csize;
309
310   // PictureComponentSizing
311   ui32_t tmp_size = EssenceSubDescriptor.PictureComponentSizing.const_get().Length();
312
313   if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
314     {
315       memcpy(&PDesc.ImageComponents, EssenceSubDescriptor.PictureComponentSizing.const_get().RoData() + 8, tmp_size - 8);
316     }
317   else
318     {
319       DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
320     }
321
322   // CodingStyleDefault
323   memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
324   memcpy(&PDesc.CodingStyleDefault,
325          EssenceSubDescriptor.CodingStyleDefault.const_get().RoData(),
326          EssenceSubDescriptor.CodingStyleDefault.const_get().Length());
327
328   // QuantizationDefault
329   memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
330   memcpy(&PDesc.QuantizationDefault,
331          EssenceSubDescriptor.QuantizationDefault.const_get().RoData(),
332          EssenceSubDescriptor.QuantizationDefault.const_get().Length());
333   
334   PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1;
335   return RESULT_OK;
336 }
337
338 //
339 ASDCP::Result_t
340 ASDCP::JP2K_PDesc_to_MD(const JP2K::PictureDescriptor& PDesc,
341                         const ASDCP::Dictionary& dict,
342                         ASDCP::MXF::CDCIEssenceDescriptor *EssenceDescriptor,
343                         ASDCP::MXF::JPEG2000PictureSubDescriptor *EssenceSubDescriptor)
344 {
345   if ( EssenceDescriptor == 0 || EssenceSubDescriptor == 0 )
346     return RESULT_PTR;
347
348   EssenceDescriptor->ContainerDuration = PDesc.ContainerDuration;
349   EssenceDescriptor->SampleRate = PDesc.EditRate;
350   EssenceDescriptor->FrameLayout = 0;
351   EssenceDescriptor->StoredWidth = PDesc.StoredWidth;
352   EssenceDescriptor->StoredHeight = PDesc.StoredHeight;
353   EssenceDescriptor->AspectRatio = PDesc.AspectRatio;
354
355   //  if ( m_Info.LabelSetType == LS_MXF_SMPTE )
356   //    {
357   // PictureEssenceCoding UL = 
358   // Video Line Map       ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
359   // CaptureGamma         UL = 
360   // ComponentMaxRef      ui32_t = 4095
361   // ComponentMinRef      ui32_t = 0
362   // PixelLayout          byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
363   //    }
364
365   if ( PDesc.StoredWidth < 2049 )
366     {
367       EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_2K));
368       EssenceSubDescriptor->Rsize = 3;
369     }
370   else
371     {
372       EssenceDescriptor->PictureEssenceCoding.Set(dict.ul(MDD_JP2KEssenceCompression_4K));
373       EssenceSubDescriptor->Rsize = 4;
374     }
375
376   EssenceSubDescriptor->Xsize = PDesc.Xsize;
377   EssenceSubDescriptor->Ysize = PDesc.Ysize;
378   EssenceSubDescriptor->XOsize = PDesc.XOsize;
379   EssenceSubDescriptor->YOsize = PDesc.YOsize;
380   EssenceSubDescriptor->XTsize = PDesc.XTsize;
381   EssenceSubDescriptor->YTsize = PDesc.YTsize;
382   EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
383   EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
384   EssenceSubDescriptor->Csize = PDesc.Csize;
385
386   const ui32_t tmp_buffer_len = 1024;
387   byte_t tmp_buffer[tmp_buffer_len];
388
389   *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
390   *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
391   memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
392
393   const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
394   memcpy(EssenceSubDescriptor->PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size);
395   EssenceSubDescriptor->PictureComponentSizing.get().Length(pcomp_size);
396
397   ui32_t precinct_set_size = 0, i;
398   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
399     precinct_set_size++;
400
401   ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
402   memcpy(EssenceSubDescriptor->CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size);
403   EssenceSubDescriptor->CodingStyleDefault.get().Length(csd_size);
404
405   ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
406   memcpy(EssenceSubDescriptor->QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size);
407   EssenceSubDescriptor->QuantizationDefault.get().Length(qdflt_size);
408
409   return RESULT_OK;
410 }
411
412
413 //
414 ASDCP::Result_t
415 ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::CDCIEssenceDescriptor&  EssenceDescriptor,
416                         const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
417                         const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
418                         ASDCP::JP2K::PictureDescriptor& PDesc)
419 {
420   memset(&PDesc, 0, sizeof(PDesc));
421
422   PDesc.EditRate           = EditRate;
423   PDesc.SampleRate         = SampleRate;
424   assert(EssenceDescriptor.ContainerDuration.const_get() <= 0xFFFFFFFFL);
425   PDesc.ContainerDuration  = static_cast<ui32_t>(EssenceDescriptor.ContainerDuration.const_get());
426   PDesc.StoredWidth        = EssenceDescriptor.StoredWidth;
427   PDesc.StoredHeight       = EssenceDescriptor.StoredHeight;
428   PDesc.AspectRatio        = EssenceDescriptor.AspectRatio;
429
430   PDesc.Rsize   = EssenceSubDescriptor.Rsize;
431   PDesc.Xsize   = EssenceSubDescriptor.Xsize;
432   PDesc.Ysize   = EssenceSubDescriptor.Ysize;
433   PDesc.XOsize  = EssenceSubDescriptor.XOsize;
434   PDesc.YOsize  = EssenceSubDescriptor.YOsize;
435   PDesc.XTsize  = EssenceSubDescriptor.XTsize;
436   PDesc.YTsize  = EssenceSubDescriptor.YTsize;
437   PDesc.XTOsize = EssenceSubDescriptor.XTOsize;
438   PDesc.YTOsize = EssenceSubDescriptor.YTOsize;
439   PDesc.Csize   = EssenceSubDescriptor.Csize;
440
441   // PictureComponentSizing
442   ui32_t tmp_size = EssenceSubDescriptor.PictureComponentSizing.const_get().Length();
443
444   if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
445     {
446       memcpy(&PDesc.ImageComponents, EssenceSubDescriptor.PictureComponentSizing.const_get().RoData() + 8, tmp_size - 8);
447     }
448   else
449     {
450       DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
451     }
452
453   // CodingStyleDefault
454   memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
455   memcpy(&PDesc.CodingStyleDefault,
456          EssenceSubDescriptor.CodingStyleDefault.const_get().RoData(),
457          EssenceSubDescriptor.CodingStyleDefault.const_get().Length());
458
459   // QuantizationDefault
460   memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
461   memcpy(&PDesc.QuantizationDefault,
462          EssenceSubDescriptor.QuantizationDefault.const_get().RoData(),
463          EssenceSubDescriptor.QuantizationDefault.const_get().Length());
464   
465   PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1;
466   return RESULT_OK;
467 }
468
469 // Compares the actual floating point value of the rates.
470 // This allows, for example, {300000,1001} and {2997,100) to be considered equivalent.
471 // to 29.97.
472 bool 
473 epsilon_compare(const ASDCP::Rational& left, const ASDCP::Rational& right, double epsilon = 0.001)
474 {
475   bool result = false;
476   double difference = left.Quotient() - right.Quotient();
477
478   if (fabs(difference) < epsilon)
479     result = true;
480
481   return result;
482 }
483 // end DOLBY
484
485
486 //------------------------------------------------------------------------------------------
487 //
488 // hidden, internal implementation of JPEG 2000 reader
489
490
491 class lh__Reader : public ASDCP::h__ASDCPReader
492 {
493   RGBAEssenceDescriptor*        m_EssenceDescriptor;
494   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
495   ASDCP::Rational               m_EditRate;
496   ASDCP::Rational               m_SampleRate;
497   EssenceType_t                 m_Format;
498
499   ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
500
501 public:
502   PictureDescriptor m_PDesc;        // codestream parameter list
503
504   lh__Reader(const Dictionary& d) :
505     ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
506
507   virtual ~lh__Reader() {}
508
509   Result_t    OpenRead(const char*, EssenceType_t);
510   Result_t    ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
511 };
512
513
514 //
515 //
516 ASDCP::Result_t
517 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
518 {
519   Result_t result = OpenMXFRead(filename);
520
521   if( ASDCP_SUCCESS(result) )
522     {
523       InterchangeObject* tmp_iobj = 0;
524       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
525       m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
526
527       if ( m_EssenceDescriptor == 0 )
528         {
529           DefaultLogSink().Error("RGBAEssenceDescriptor object not found.\n");
530           return RESULT_FORMAT;
531         }
532
533       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
534       m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
535
536       if ( m_EssenceSubDescriptor == 0 )
537         {
538           m_EssenceDescriptor = 0;
539           DefaultLogSink().Error("JPEG2000PictureSubDescriptor object not found.\n");
540           return RESULT_FORMAT;
541         }
542
543       std::list<InterchangeObject*> ObjectList;
544       m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
545
546       if ( ObjectList.empty() )
547         {
548           DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
549           return RESULT_FORMAT;
550         }
551
552       m_EditRate = ((Track*)ObjectList.front())->EditRate;
553       m_SampleRate = m_EssenceDescriptor->SampleRate;
554
555       if ( type == ASDCP::ESS_JPEG_2000 )
556         {
557           if ( m_EditRate != m_SampleRate )
558             {
559               DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
560                                     m_EditRate.Quotient(), m_SampleRate.Quotient());
561               
562               if ( m_EditRate == EditRate_24 && m_SampleRate == EditRate_48 ||
563                    m_EditRate == EditRate_25 && m_SampleRate == EditRate_50 ||
564                    m_EditRate == EditRate_30 && m_SampleRate == EditRate_60 ||
565                    m_EditRate == EditRate_48 && m_SampleRate == EditRate_96 ||
566                    m_EditRate == EditRate_50 && m_SampleRate == EditRate_100 ||
567                    m_EditRate == EditRate_60 && m_SampleRate == EditRate_120 )
568                 {
569                   DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
570                   return RESULT_SFORMAT;
571                 }
572
573               return RESULT_FORMAT;
574             }
575         }
576       else if ( type == ASDCP::ESS_JPEG_2000_S )
577         {
578           if ( m_EditRate == EditRate_24 )
579             {
580               if ( m_SampleRate != EditRate_48 )
581                 {
582                   DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
583                   return RESULT_FORMAT;
584                 }
585             }
586           else if ( m_EditRate == EditRate_25 )
587             {
588               if ( m_SampleRate != EditRate_50 )
589                 {
590                   DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
591                   return RESULT_FORMAT;
592                 }
593             }
594           else if ( m_EditRate == EditRate_30 )
595             {
596               if ( m_SampleRate != EditRate_60 )
597                 {
598                   DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
599                   return RESULT_FORMAT;
600                 }
601             }
602           else if ( m_EditRate == EditRate_48 )
603             {
604               if ( m_SampleRate != EditRate_96 )
605                 {
606                   DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
607                   return RESULT_FORMAT;
608                 }
609             }
610           else if ( m_EditRate == EditRate_50 )
611             {
612               if ( m_SampleRate != EditRate_100 )
613                 {
614                   DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
615                   return RESULT_FORMAT;
616                 }
617             }
618           else if ( m_EditRate == EditRate_60 )
619             {
620               if ( m_SampleRate != EditRate_120 )
621                 {
622                   DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
623                   return RESULT_FORMAT;
624                 }
625             }
626           else
627             {
628               DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
629                                      m_EditRate.Numerator, m_EditRate.Denominator);
630               return RESULT_FORMAT;
631             }
632         }
633       else
634         {
635           DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
636           return RESULT_STATE;
637         }
638
639       result = MD_to_JP2K_PDesc(*m_EssenceDescriptor, *m_EssenceSubDescriptor, m_EditRate, m_SampleRate, m_PDesc);
640     }
641
642   return result;
643 }
644
645 //
646 //
647 ASDCP::Result_t
648 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
649                       AESDecContext* Ctx, HMACContext* HMAC)
650 {
651   if ( ! m_File.IsOpen() )
652     return RESULT_INIT;
653
654   assert(m_Dict);
655   return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
656 }
657
658
659 //
660 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
661 {
662   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
663   h__Reader();
664
665 public:
666   h__Reader(const Dictionary& d) : lh__Reader(d) {}
667 };
668
669
670
671 //------------------------------------------------------------------------------------------
672
673
674 //
675 void
676 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
677 {
678   if ( stream == 0 )
679     stream = stderr;
680
681   fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
682   
683   fputc('\n', stream);
684
685   if ( dump_len > 0 )
686     Kumu::hexdump(m_Data, dump_len, stream);
687 }
688
689
690 //------------------------------------------------------------------------------------------
691
692 ASDCP::JP2K::MXFReader::MXFReader()
693 {
694   m_Reader = new h__Reader(DefaultCompositeDict());
695 }
696
697
698 ASDCP::JP2K::MXFReader::~MXFReader()
699 {
700   if ( m_Reader && m_Reader->m_File.IsOpen() )
701     m_Reader->Close();
702 }
703
704 // Warning: direct manipulation of MXF structures can interfere
705 // with the normal operation of the wrapper.  Caveat emptor!
706 //
707 ASDCP::MXF::OP1aHeader&
708 ASDCP::JP2K::MXFReader::OP1aHeader()
709 {
710   if ( m_Reader.empty() )
711     {
712       assert(g_OP1aHeader);
713       return *g_OP1aHeader;
714     }
715
716   return m_Reader->m_HeaderPart;
717 }
718
719 // Warning: direct manipulation of MXF structures can interfere
720 // with the normal operation of the wrapper.  Caveat emptor!
721 //
722 ASDCP::MXF::OPAtomIndexFooter&
723 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
724 {
725   if ( m_Reader.empty() )
726     {
727       assert(g_OPAtomIndexFooter);
728       return *g_OPAtomIndexFooter;
729     }
730
731   return m_Reader->m_IndexAccess;
732 }
733
734 // Warning: direct manipulation of MXF structures can interfere
735 // with the normal operation of the wrapper.  Caveat emptor!
736 //
737 ASDCP::MXF::RIP&
738 ASDCP::JP2K::MXFReader::RIP()
739 {
740   if ( m_Reader.empty() )
741     {
742       assert(g_RIP);
743       return *g_RIP;
744     }
745
746   return m_Reader->m_RIP;
747 }
748
749 // Open the file for reading. The file must exist. Returns error if the
750 // operation cannot be completed.
751 ASDCP::Result_t
752 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
753 {
754   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
755 }
756
757 //
758 ASDCP::Result_t
759 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
760                                    AESDecContext* Ctx, HMACContext* HMAC) const
761 {
762   if ( m_Reader && m_Reader->m_File.IsOpen() )
763     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
764
765   return RESULT_INIT;
766 }
767
768 ASDCP::Result_t
769 ASDCP::JP2K::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
770 {
771     return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
772 }
773
774
775 // Fill the struct with the values from the file's header.
776 // Returns RESULT_INIT if the file is not open.
777 ASDCP::Result_t
778 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
779 {
780   if ( m_Reader && m_Reader->m_File.IsOpen() )
781     {
782       PDesc = m_Reader->m_PDesc;
783       return RESULT_OK;
784     }
785
786   return RESULT_INIT;
787 }
788
789
790 // Fill the struct with the values from the file's header.
791 // Returns RESULT_INIT if the file is not open.
792 ASDCP::Result_t
793 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
794 {
795   if ( m_Reader && m_Reader->m_File.IsOpen() )
796     {
797       Info = m_Reader->m_Info;
798       return RESULT_OK;
799     }
800
801   return RESULT_INIT;
802 }
803
804 //
805 void
806 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
807 {
808   if ( m_Reader->m_File.IsOpen() )
809     m_Reader->m_HeaderPart.Dump(stream);
810 }
811
812
813 //
814 void
815 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
816 {
817   if ( m_Reader->m_File.IsOpen() )
818     m_Reader->m_IndexAccess.Dump(stream);
819 }
820
821 //
822 ASDCP::Result_t
823 ASDCP::JP2K::MXFReader::Close() const
824 {
825   if ( m_Reader && m_Reader->m_File.IsOpen() )
826     {
827       m_Reader->Close();
828       return RESULT_OK;
829     }
830
831   return RESULT_INIT;
832 }
833
834
835 //------------------------------------------------------------------------------------------
836
837
838 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
839 {
840   ui32_t m_StereoFrameReady;
841
842 public:
843   h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
844
845   //
846   Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
847                      AESDecContext* Ctx, HMACContext* HMAC)
848   {
849     // look up frame index node
850     IndexTableSegment::IndexEntry TmpEntry;
851
852     if ( ASDCP_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
853       {
854         DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
855         return RESULT_RANGE;
856       }
857
858     // get frame position
859     Kumu::fpos_t FilePosition = m_HeaderPart.BodyOffset + TmpEntry.StreamOffset;
860     Result_t result = RESULT_OK;
861
862     if ( phase == SP_LEFT )
863       {    
864         if ( FilePosition != m_LastPosition )
865           {
866             m_LastPosition = FilePosition;
867             result = m_File.Seek(FilePosition);
868           }
869
870         // the call to ReadEKLVPacket() will leave the file on an R frame
871         m_StereoFrameReady = FrameNum;
872       }
873     else if ( phase == SP_RIGHT )
874       {
875         if ( m_StereoFrameReady != FrameNum )
876           {
877             // the file is not already positioned, we must do some work
878             // seek to the companion SP_LEFT frame and read the frame's key and length
879             if ( FilePosition != m_LastPosition )
880               {
881                 m_LastPosition = FilePosition;
882                 result = m_File.Seek(FilePosition);
883               }
884
885             KLReader Reader;
886             result = Reader.ReadKLFromFile(m_File);
887
888             if ( ASDCP_SUCCESS(result) )
889               {
890                 // skip over the companion SP_LEFT frame
891                 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
892                 result = m_File.Seek(new_pos);
893               }
894           }
895
896         // the call to ReadEKLVPacket() will leave the file not on an R frame
897         m_StereoFrameReady = 0xffffffff;
898       }
899     else
900       {
901         DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
902         return RESULT_STATE;
903       }
904
905     if( ASDCP_SUCCESS(result) )
906       {
907         ui32_t SequenceNum = FrameNum * 2;
908         SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
909         assert(m_Dict);
910         result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
911       }
912
913     return result;
914   }
915 };
916
917
918
919 ASDCP::JP2K::MXFSReader::MXFSReader()
920 {
921   m_Reader = new h__SReader(DefaultCompositeDict());
922 }
923
924
925 ASDCP::JP2K::MXFSReader::~MXFSReader()
926 {
927   if ( m_Reader && m_Reader->m_File.IsOpen() )
928     m_Reader->Close();
929 }
930
931 // Warning: direct manipulation of MXF structures can interfere
932 // with the normal operation of the wrapper.  Caveat emptor!
933 //
934 ASDCP::MXF::OP1aHeader&
935 ASDCP::JP2K::MXFSReader::OP1aHeader()
936 {
937   if ( m_Reader.empty() )
938     {
939       assert(g_OP1aHeader);
940       return *g_OP1aHeader;
941     }
942
943   return m_Reader->m_HeaderPart;
944 }
945
946 // Warning: direct manipulation of MXF structures can interfere
947 // with the normal operation of the wrapper.  Caveat emptor!
948 //
949 ASDCP::MXF::OPAtomIndexFooter&
950 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
951 {
952   if ( m_Reader.empty() )
953     {
954       assert(g_OPAtomIndexFooter);
955       return *g_OPAtomIndexFooter;
956     }
957
958   return m_Reader->m_IndexAccess;
959 }
960
961 // Warning: direct manipulation of MXF structures can interfere
962 // with the normal operation of the wrapper.  Caveat emptor!
963 //
964 ASDCP::MXF::RIP&
965 ASDCP::JP2K::MXFSReader::RIP()
966 {
967   if ( m_Reader.empty() )
968     {
969       assert(g_RIP);
970       return *g_RIP;
971     }
972
973   return m_Reader->m_RIP;
974 }
975
976 // Open the file for reading. The file must exist. Returns error if the
977 // operation cannot be completed.
978 ASDCP::Result_t
979 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
980 {
981   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
982 }
983
984 //
985 ASDCP::Result_t
986 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
987 {
988   Result_t result = RESULT_INIT;
989
990   if ( m_Reader && m_Reader->m_File.IsOpen() )
991     {
992       result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
993
994       if ( ASDCP_SUCCESS(result) )
995         result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
996     }
997
998   return result;
999 }
1000
1001 //
1002 ASDCP::Result_t
1003 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
1004                                    AESDecContext* Ctx, HMACContext* HMAC) const
1005 {
1006   if ( m_Reader && m_Reader->m_File.IsOpen() )
1007     return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
1008
1009   return RESULT_INIT;
1010 }
1011
1012 ASDCP::Result_t
1013 ASDCP::JP2K::MXFSReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
1014 {
1015     return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
1016 }
1017
1018 // Fill the struct with the values from the file's header.
1019 // Returns RESULT_INIT if the file is not open.
1020 ASDCP::Result_t
1021 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
1022 {
1023   if ( m_Reader && m_Reader->m_File.IsOpen() )
1024     {
1025       PDesc = m_Reader->m_PDesc;
1026       return RESULT_OK;
1027     }
1028
1029   return RESULT_INIT;
1030 }
1031
1032
1033 // Fill the struct with the values from the file's header.
1034 // Returns RESULT_INIT if the file is not open.
1035 ASDCP::Result_t
1036 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
1037 {
1038   if ( m_Reader && m_Reader->m_File.IsOpen() )
1039     {
1040       Info = m_Reader->m_Info;
1041       return RESULT_OK;
1042     }
1043
1044   return RESULT_INIT;
1045 }
1046
1047 //
1048 void
1049 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
1050 {
1051   if ( m_Reader->m_File.IsOpen() )
1052     m_Reader->m_HeaderPart.Dump(stream);
1053 }
1054
1055
1056 //
1057 void
1058 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
1059 {
1060   if ( m_Reader->m_File.IsOpen() )
1061     m_Reader->m_IndexAccess.Dump(stream);
1062 }
1063
1064 //
1065 ASDCP::Result_t
1066 ASDCP::JP2K::MXFSReader::Close() const
1067 {
1068   if ( m_Reader && m_Reader->m_File.IsOpen() )
1069     {
1070       m_Reader->Close();
1071       return RESULT_OK;
1072     }
1073
1074   return RESULT_INIT;
1075 }
1076
1077
1078 //------------------------------------------------------------------------------------------
1079
1080
1081 //
1082 class lh__Writer : public ASDCP::h__ASDCPWriter
1083 {
1084   ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
1085   lh__Writer();
1086
1087   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
1088
1089 public:
1090   PictureDescriptor m_PDesc;
1091   byte_t            m_EssenceUL[SMPTE_UL_LENGTH];
1092
1093   lh__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_EssenceSubDescriptor(0) {
1094     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
1095   }
1096
1097   virtual ~lh__Writer(){}
1098
1099   Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
1100   Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
1101                            ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
1102   Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
1103   Result_t Finalize();
1104 };
1105
1106 // Open the file for writing. The file must not exist. Returns error if
1107 // the operation cannot be completed.
1108 ASDCP::Result_t
1109 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
1110 {
1111   if ( ! m_State.Test_BEGIN() )
1112     return RESULT_STATE;
1113
1114   Result_t result = m_File.OpenWrite(filename);
1115
1116   if ( ASDCP_SUCCESS(result) )
1117     {
1118       m_HeaderSize = HeaderSize;
1119       RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
1120       tmp_rgba->ComponentMaxRef = 4095;
1121       tmp_rgba->ComponentMinRef = 0;
1122
1123       m_EssenceDescriptor = tmp_rgba;
1124       m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
1125       m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
1126
1127       GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
1128       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
1129
1130       if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
1131         {
1132           InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
1133           m_EssenceSubDescriptorList.push_back(StereoSubDesc);
1134           GenRandomValue(StereoSubDesc->InstanceUID);
1135           m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
1136         }
1137
1138       result = m_State.Goto_INIT();
1139     }
1140
1141   return result;
1142 }
1143
1144 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
1145 ASDCP::Result_t
1146 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
1147 {
1148   assert(m_Dict);
1149   if ( ! m_State.Test_INIT() )
1150     return RESULT_STATE;
1151
1152   if ( LocalEditRate == ASDCP::Rational(0,0) )
1153     LocalEditRate = PDesc.EditRate;
1154
1155   m_PDesc = PDesc;
1156   assert(m_Dict);
1157   Result_t result = JP2K_PDesc_to_MD(m_PDesc, *m_Dict,
1158                                      (ASDCP::MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor,
1159                                      m_EssenceSubDescriptor);
1160
1161   if ( ASDCP_SUCCESS(result) )
1162     {
1163       memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
1164       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
1165       result = m_State.Goto_READY();
1166     }
1167
1168   if ( ASDCP_SUCCESS(result) )
1169     {
1170       result = WriteASDCPHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
1171                                 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
1172                                 LocalEditRate, derive_timecode_rate_from_edit_rate(m_PDesc.EditRate));
1173     }
1174
1175   return result;
1176 }
1177
1178 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1179 // argument is present, the essence is encrypted prior to writing.
1180 // Fails if the file is not open, is finalized, or an operating system
1181 // error occurs.
1182 //
1183 ASDCP::Result_t
1184 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
1185                        AESEncContext* Ctx, HMACContext* HMAC)
1186 {
1187   Result_t result = RESULT_OK;
1188
1189   if ( m_State.Test_READY() )
1190     result = m_State.Goto_RUNNING(); // first time through
1191  
1192   ui64_t StreamOffset = m_StreamOffset;
1193
1194   if ( ASDCP_SUCCESS(result) )
1195     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
1196
1197   if ( ASDCP_SUCCESS(result) && add_index )
1198     {  
1199       IndexTableSegment::IndexEntry Entry;
1200       Entry.StreamOffset = StreamOffset;
1201       m_FooterPart.PushIndexEntry(Entry);
1202     }
1203
1204   m_FramesWritten++;
1205   return result;
1206 }
1207
1208
1209 // Closes the MXF file, writing the index and other closing information.
1210 //
1211 ASDCP::Result_t
1212 lh__Writer::Finalize()
1213 {
1214   if ( ! m_State.Test_RUNNING() )
1215     return RESULT_STATE;
1216
1217   m_State.Goto_FINAL();
1218
1219   return WriteASDCPFooter();
1220 }
1221
1222
1223 //
1224 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1225 {
1226   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1227   h__Writer();
1228
1229 public:
1230   h__Writer(const Dictionary& d) : lh__Writer(d) {}
1231 };
1232
1233
1234 //------------------------------------------------------------------------------------------
1235
1236
1237
1238 ASDCP::JP2K::MXFWriter::MXFWriter()
1239 {
1240 }
1241
1242 ASDCP::JP2K::MXFWriter::~MXFWriter()
1243 {
1244 }
1245
1246 // Warning: direct manipulation of MXF structures can interfere
1247 // with the normal operation of the wrapper.  Caveat emptor!
1248 //
1249 ASDCP::MXF::OP1aHeader&
1250 ASDCP::JP2K::MXFWriter::OP1aHeader()
1251 {
1252   if ( m_Writer.empty() )
1253     {
1254       assert(g_OP1aHeader);
1255       return *g_OP1aHeader;
1256     }
1257
1258   return m_Writer->m_HeaderPart;
1259 }
1260
1261 // Warning: direct manipulation of MXF structures can interfere
1262 // with the normal operation of the wrapper.  Caveat emptor!
1263 //
1264 ASDCP::MXF::OPAtomIndexFooter&
1265 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1266 {
1267   if ( m_Writer.empty() )
1268     {
1269       assert(g_OPAtomIndexFooter);
1270       return *g_OPAtomIndexFooter;
1271     }
1272
1273   return m_Writer->m_FooterPart;
1274 }
1275
1276 // Warning: direct manipulation of MXF structures can interfere
1277 // with the normal operation of the wrapper.  Caveat emptor!
1278 //
1279 ASDCP::MXF::RIP&
1280 ASDCP::JP2K::MXFWriter::RIP()
1281 {
1282   if ( m_Writer.empty() )
1283     {
1284       assert(g_RIP);
1285       return *g_RIP;
1286     }
1287
1288   return m_Writer->m_RIP;
1289 }
1290
1291 // Open the file for writing. The file must not exist. Returns error if
1292 // the operation cannot be completed.
1293 ASDCP::Result_t
1294 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1295                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
1296 {
1297   if ( Info.LabelSetType == LS_MXF_SMPTE )
1298     m_Writer = new h__Writer(DefaultSMPTEDict());
1299   else
1300     m_Writer = new h__Writer(DefaultInteropDict());
1301
1302   m_Writer->m_Info = Info;
1303
1304   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1305
1306   if ( ASDCP_SUCCESS(result) )
1307     result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1308
1309   if ( ASDCP_FAILURE(result) )
1310     m_Writer.release();
1311
1312   return result;
1313 }
1314
1315
1316 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1317 // argument is present, the essence is encrypted prior to writing.
1318 // Fails if the file is not open, is finalized, or an operating system
1319 // error occurs.
1320 ASDCP::Result_t
1321 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1322 {
1323   if ( m_Writer.empty() )
1324     return RESULT_INIT;
1325
1326   return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1327 }
1328
1329 // Closes the MXF file, writing the index and other closing information.
1330 ASDCP::Result_t
1331 ASDCP::JP2K::MXFWriter::Finalize()
1332 {
1333   if ( m_Writer.empty() )
1334     return RESULT_INIT;
1335
1336   return m_Writer->Finalize();
1337 }
1338
1339
1340 //------------------------------------------------------------------------------------------
1341 //
1342
1343 //
1344 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1345 {
1346   ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1347   h__SWriter();
1348   StereoscopicPhase_t m_NextPhase;
1349
1350 public:
1351   h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1352
1353   //
1354   Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1355                       AESEncContext* Ctx, HMACContext* HMAC)
1356   {
1357     if ( m_NextPhase != phase )
1358       return RESULT_SPHASE;
1359
1360     if ( phase == SP_LEFT )
1361       {
1362         m_NextPhase = SP_RIGHT;
1363         return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1364       }
1365
1366     m_NextPhase = SP_LEFT;
1367     return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1368   }
1369
1370   //
1371   Result_t Finalize()
1372   {
1373     if ( m_NextPhase != SP_LEFT )
1374       return RESULT_SPHASE;
1375
1376     assert( m_FramesWritten % 2 == 0 );
1377     m_FramesWritten /= 2;
1378     return lh__Writer::Finalize();
1379   }
1380 };
1381
1382
1383 //
1384 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1385 {
1386 }
1387
1388 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1389 {
1390 }
1391
1392 // Warning: direct manipulation of MXF structures can interfere
1393 // with the normal operation of the wrapper.  Caveat emptor!
1394 //
1395 ASDCP::MXF::OP1aHeader&
1396 ASDCP::JP2K::MXFSWriter::OP1aHeader()
1397 {
1398   if ( m_Writer.empty() )
1399     {
1400       assert(g_OP1aHeader);
1401       return *g_OP1aHeader;
1402     }
1403
1404   return m_Writer->m_HeaderPart;
1405 }
1406
1407 // Warning: direct manipulation of MXF structures can interfere
1408 // with the normal operation of the wrapper.  Caveat emptor!
1409 //
1410 ASDCP::MXF::OPAtomIndexFooter&
1411 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1412 {
1413   if ( m_Writer.empty() )
1414     {
1415       assert(g_OPAtomIndexFooter);
1416       return *g_OPAtomIndexFooter;
1417     }
1418
1419   return m_Writer->m_FooterPart;
1420 }
1421
1422 // Warning: direct manipulation of MXF structures can interfere
1423 // with the normal operation of the wrapper.  Caveat emptor!
1424 //
1425 ASDCP::MXF::RIP&
1426 ASDCP::JP2K::MXFSWriter::RIP()
1427 {
1428   if ( m_Writer.empty() )
1429     {
1430       assert(g_RIP);
1431       return *g_RIP;
1432     }
1433
1434   return m_Writer->m_RIP;
1435 }
1436
1437 // Open the file for writing. The file must not exist. Returns error if
1438 // the operation cannot be completed.
1439 ASDCP::Result_t
1440 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1441                                    const PictureDescriptor& PDesc, ui32_t HeaderSize)
1442 {
1443   if ( Info.LabelSetType == LS_MXF_SMPTE )
1444     m_Writer = new h__SWriter(DefaultSMPTEDict());
1445   else
1446     m_Writer = new h__SWriter(DefaultInteropDict());
1447
1448   if ( PDesc.EditRate != ASDCP::EditRate_24
1449        && PDesc.EditRate != ASDCP::EditRate_25
1450        && PDesc.EditRate != ASDCP::EditRate_30
1451        && PDesc.EditRate != ASDCP::EditRate_48
1452        && PDesc.EditRate != ASDCP::EditRate_50
1453        && PDesc.EditRate != ASDCP::EditRate_60 )
1454     {
1455       DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1456       return RESULT_FORMAT;
1457     }
1458
1459   if ( PDesc.StoredWidth > 2048 )
1460     DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1461
1462   m_Writer->m_Info = Info;
1463
1464   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1465
1466   if ( ASDCP_SUCCESS(result) )
1467     {
1468       PictureDescriptor TmpPDesc = PDesc;
1469
1470       if ( PDesc.EditRate == ASDCP::EditRate_24 )
1471         TmpPDesc.EditRate = ASDCP::EditRate_48;
1472
1473       else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1474         TmpPDesc.EditRate = ASDCP::EditRate_50;
1475
1476       else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1477         TmpPDesc.EditRate = ASDCP::EditRate_60;
1478
1479       else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1480         TmpPDesc.EditRate = ASDCP::EditRate_96;
1481
1482       else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1483         TmpPDesc.EditRate = ASDCP::EditRate_100;
1484
1485       else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1486         TmpPDesc.EditRate = ASDCP::EditRate_120;
1487
1488       result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1489     }
1490
1491   if ( ASDCP_FAILURE(result) )
1492     m_Writer.release();
1493
1494   return result;
1495 }
1496
1497 ASDCP::Result_t
1498 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1499 {
1500   if ( m_Writer.empty() )
1501     return RESULT_INIT;
1502
1503   Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1504
1505   if ( ASDCP_SUCCESS(result) )
1506     result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1507
1508   return result;
1509 }
1510
1511 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1512 // argument is present, the essence is encrypted prior to writing.
1513 // Fails if the file is not open, is finalized, or an operating system
1514 // error occurs.
1515 ASDCP::Result_t
1516 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1517                                     AESEncContext* Ctx, HMACContext* HMAC)
1518 {
1519   if ( m_Writer.empty() )
1520     return RESULT_INIT;
1521
1522   return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1523 }
1524
1525 // Closes the MXF file, writing the index and other closing information.
1526 ASDCP::Result_t
1527 ASDCP::JP2K::MXFSWriter::Finalize()
1528 {
1529   if ( m_Writer.empty() )
1530     return RESULT_INIT;
1531
1532   return m_Writer->Finalize();
1533 }
1534
1535 //
1536 // end AS_DCP_JP2K.cpp
1537 //