635eae5ae2c60200fc7942571204152bc58ef86a
[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 < MaxComponents; ++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 < MaxPrecincts; ++i )
100     strm << "    " << i + 1 << ": " << s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f] << " x "
101          << s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f] << std::endl;
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 < MaxComponents; 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 < MaxPrecincts; i++ )
188     fprintf(stream, "    %d: %d x %d\n", i + 1,
189             s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
190             s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
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::GenericPictureEssenceDescriptor& EssenceDescriptor,
212                         ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor)
213 {
214   EssenceDescriptor.ContainerDuration = PDesc.ContainerDuration;
215   EssenceDescriptor.SampleRate = PDesc.EditRate;
216   EssenceDescriptor.FrameLayout = 0;
217   EssenceDescriptor.StoredWidth = PDesc.StoredWidth;
218   EssenceDescriptor.StoredHeight = PDesc.StoredHeight;
219   EssenceDescriptor.AspectRatio = PDesc.AspectRatio;
220
221   EssenceSubDescriptor.Rsize = PDesc.Rsize;
222   EssenceSubDescriptor.Xsize = PDesc.Xsize;
223   EssenceSubDescriptor.Ysize = PDesc.Ysize;
224   EssenceSubDescriptor.XOsize = PDesc.XOsize;
225   EssenceSubDescriptor.YOsize = PDesc.YOsize;
226   EssenceSubDescriptor.XTsize = PDesc.XTsize;
227   EssenceSubDescriptor.YTsize = PDesc.YTsize;
228   EssenceSubDescriptor.XTOsize = PDesc.XTOsize;
229   EssenceSubDescriptor.YTOsize = PDesc.YTOsize;
230   EssenceSubDescriptor.Csize = PDesc.Csize;
231
232   const ui32_t tmp_buffer_len = 1024;
233   byte_t tmp_buffer[tmp_buffer_len];
234
235   *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
236   *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
237   memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
238
239   const ui32_t pcomp_size = (sizeof(ui32_t) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
240   memcpy(EssenceSubDescriptor.PictureComponentSizing.get().Data(), tmp_buffer, pcomp_size);
241   EssenceSubDescriptor.PictureComponentSizing.get().Length(pcomp_size);
242   EssenceSubDescriptor.PictureComponentSizing.set_has_value();
243
244   ui32_t precinct_set_size = 0;
245   for ( ui32_t i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; ++i )
246     precinct_set_size++;
247
248   ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
249   memcpy(EssenceSubDescriptor.CodingStyleDefault.get().Data(), &PDesc.CodingStyleDefault, csd_size);
250   EssenceSubDescriptor.CodingStyleDefault.get().Length(csd_size);
251   EssenceSubDescriptor.CodingStyleDefault.set_has_value();
252
253   ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
254   memcpy(EssenceSubDescriptor.QuantizationDefault.get().Data(), &PDesc.QuantizationDefault, qdflt_size);
255   EssenceSubDescriptor.QuantizationDefault.get().Length(qdflt_size);
256   EssenceSubDescriptor.QuantizationDefault.set_has_value();
257
258   return RESULT_OK;
259 }
260
261
262 //
263 ASDCP::Result_t
264 ASDCP::MD_to_JP2K_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor&  EssenceDescriptor,
265                         const ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor,
266                         const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
267                         ASDCP::JP2K::PictureDescriptor& PDesc)
268 {
269   memset(&PDesc, 0, sizeof(PDesc));
270
271   PDesc.EditRate           = EditRate;
272   PDesc.SampleRate         = SampleRate;
273   assert(EssenceDescriptor.ContainerDuration.const_get() <= 0xFFFFFFFFL);
274   PDesc.ContainerDuration  = static_cast<ui32_t>(EssenceDescriptor.ContainerDuration.const_get());
275   PDesc.StoredWidth        = EssenceDescriptor.StoredWidth;
276   PDesc.StoredHeight       = EssenceDescriptor.StoredHeight;
277   PDesc.AspectRatio        = EssenceDescriptor.AspectRatio;
278
279   PDesc.Rsize   = EssenceSubDescriptor.Rsize;
280   PDesc.Xsize   = EssenceSubDescriptor.Xsize;
281   PDesc.Ysize   = EssenceSubDescriptor.Ysize;
282   PDesc.XOsize  = EssenceSubDescriptor.XOsize;
283   PDesc.YOsize  = EssenceSubDescriptor.YOsize;
284   PDesc.XTsize  = EssenceSubDescriptor.XTsize;
285   PDesc.YTsize  = EssenceSubDescriptor.YTsize;
286   PDesc.XTOsize = EssenceSubDescriptor.XTOsize;
287   PDesc.YTOsize = EssenceSubDescriptor.YTOsize;
288   PDesc.Csize   = EssenceSubDescriptor.Csize;
289
290   // PictureComponentSizing
291   ui32_t tmp_size = EssenceSubDescriptor.PictureComponentSizing.const_get().Length();
292
293   if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
294     {
295       memcpy(&PDesc.ImageComponents, EssenceSubDescriptor.PictureComponentSizing.const_get().RoData() + 8, tmp_size - 8);
296     }
297   else
298     {
299       DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
300     }
301
302   // CodingStyleDefault
303   memset(&PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
304   memcpy(&PDesc.CodingStyleDefault,
305          EssenceSubDescriptor.CodingStyleDefault.const_get().RoData(),
306          EssenceSubDescriptor.CodingStyleDefault.const_get().Length());
307
308   // QuantizationDefault
309   memset(&PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
310   memcpy(&PDesc.QuantizationDefault,
311          EssenceSubDescriptor.QuantizationDefault.const_get().RoData(),
312          EssenceSubDescriptor.QuantizationDefault.const_get().Length());
313   
314   PDesc.QuantizationDefault.SPqcdLength = EssenceSubDescriptor.QuantizationDefault.const_get().Length() - 1;
315   return RESULT_OK;
316 }
317
318
319 //------------------------------------------------------------------------------------------
320 //
321 // hidden, internal implementation of JPEG 2000 reader
322
323
324 class lh__Reader : public ASDCP::h__ASDCPReader
325 {
326   RGBAEssenceDescriptor*        m_EssenceDescriptor;
327   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
328   ASDCP::Rational               m_EditRate;
329   ASDCP::Rational               m_SampleRate;
330   EssenceType_t                 m_Format;
331
332   ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
333
334 public:
335   PictureDescriptor m_PDesc;        // codestream parameter list
336
337   lh__Reader(const Dictionary& d) :
338     ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
339
340   virtual ~lh__Reader() {}
341
342   Result_t    OpenRead(const std::string&, EssenceType_t);
343   Result_t    ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
344 };
345
346
347 //
348 //
349 ASDCP::Result_t
350 lh__Reader::OpenRead(const std::string& filename, EssenceType_t type)
351 {
352   Result_t result = OpenMXFRead(filename);
353
354   if( ASDCP_SUCCESS(result) )
355     {
356       InterchangeObject* tmp_iobj = 0;
357       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
358       m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
359
360       if ( m_EssenceDescriptor == 0 )
361         {
362           DefaultLogSink().Error("RGBAEssenceDescriptor object not found.\n");
363           return RESULT_FORMAT;
364         }
365
366       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
367       m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
368
369       if ( m_EssenceSubDescriptor == 0 )
370         {
371           m_EssenceDescriptor = 0;
372           DefaultLogSink().Error("JPEG2000PictureSubDescriptor object not found.\n");
373           return RESULT_FORMAT;
374         }
375
376       std::list<InterchangeObject*> ObjectList;
377       m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
378
379       if ( ObjectList.empty() )
380         {
381           DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
382           return RESULT_FORMAT;
383         }
384
385       m_EditRate = ((Track*)ObjectList.front())->EditRate;
386       m_SampleRate = m_EssenceDescriptor->SampleRate;
387
388       if ( type == ASDCP::ESS_JPEG_2000 )
389         {
390           if ( m_EditRate != m_SampleRate )
391             {
392               DefaultLogSink().Warn("EditRate and SampleRate do not match (%.03f, %.03f).\n",
393                                     m_EditRate.Quotient(), m_SampleRate.Quotient());
394               
395               if ( m_EditRate == EditRate_24 && m_SampleRate == EditRate_48 ||
396                    m_EditRate == EditRate_25 && m_SampleRate == EditRate_50 ||
397                    m_EditRate == EditRate_30 && m_SampleRate == EditRate_60 ||
398                    m_EditRate == EditRate_48 && m_SampleRate == EditRate_96 ||
399                    m_EditRate == EditRate_50 && m_SampleRate == EditRate_100 ||
400                    m_EditRate == EditRate_60 && m_SampleRate == EditRate_120 )
401                 {
402                   DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
403                   return RESULT_SFORMAT;
404                 }
405
406               return RESULT_FORMAT;
407             }
408         }
409       else if ( type == ASDCP::ESS_JPEG_2000_S )
410         {
411           if ( m_EditRate == EditRate_24 )
412             {
413               if ( m_SampleRate != EditRate_48 )
414                 {
415                   DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
416                   return RESULT_FORMAT;
417                 }
418             }
419           else if ( m_EditRate == EditRate_25 )
420             {
421               if ( m_SampleRate != EditRate_50 )
422                 {
423                   DefaultLogSink().Error("EditRate and SampleRate not correct for 25/50 stereoscopic essence.\n");
424                   return RESULT_FORMAT;
425                 }
426             }
427           else if ( m_EditRate == EditRate_30 )
428             {
429               if ( m_SampleRate != EditRate_60 )
430                 {
431                   DefaultLogSink().Error("EditRate and SampleRate not correct for 30/60 stereoscopic essence.\n");
432                   return RESULT_FORMAT;
433                 }
434             }
435           else if ( m_EditRate == EditRate_48 )
436             {
437               if ( m_SampleRate != EditRate_96 )
438                 {
439                   DefaultLogSink().Error("EditRate and SampleRate not correct for 48/96 stereoscopic essence.\n");
440                   return RESULT_FORMAT;
441                 }
442             }
443           else if ( m_EditRate == EditRate_50 )
444             {
445               if ( m_SampleRate != EditRate_100 )
446                 {
447                   DefaultLogSink().Error("EditRate and SampleRate not correct for 50/100 stereoscopic essence.\n");
448                   return RESULT_FORMAT;
449                 }
450             }
451           else if ( m_EditRate == EditRate_60 )
452             {
453               if ( m_SampleRate != EditRate_120 )
454                 {
455                   DefaultLogSink().Error("EditRate and SampleRate not correct for 60/120 stereoscopic essence.\n");
456                   return RESULT_FORMAT;
457                 }
458             }
459           else
460             {
461               DefaultLogSink().Error("EditRate not correct for stereoscopic essence: %d/%d.\n",
462                                      m_EditRate.Numerator, m_EditRate.Denominator);
463               return RESULT_FORMAT;
464             }
465         }
466       else
467         {
468           DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
469           return RESULT_STATE;
470         }
471
472       result = MD_to_JP2K_PDesc(*m_EssenceDescriptor, *m_EssenceSubDescriptor, m_EditRate, m_SampleRate, m_PDesc);
473     }
474
475   return result;
476 }
477
478 //
479 //
480 ASDCP::Result_t
481 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
482                       AESDecContext* Ctx, HMACContext* HMAC)
483 {
484   if ( ! m_File.IsOpen() )
485     return RESULT_INIT;
486
487   assert(m_Dict);
488   return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
489 }
490
491
492 //
493 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
494 {
495   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
496   h__Reader();
497
498 public:
499   h__Reader(const Dictionary& d) : lh__Reader(d) {}
500 };
501
502
503
504 //------------------------------------------------------------------------------------------
505
506
507 //
508 void
509 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
510 {
511   if ( stream == 0 )
512     stream = stderr;
513
514   fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
515   
516   fputc('\n', stream);
517
518   if ( dump_len > 0 )
519     Kumu::hexdump(m_Data, dump_len, stream);
520 }
521
522
523 //------------------------------------------------------------------------------------------
524
525 ASDCP::JP2K::MXFReader::MXFReader()
526 {
527   m_Reader = new h__Reader(DefaultCompositeDict());
528 }
529
530
531 ASDCP::JP2K::MXFReader::~MXFReader()
532 {
533   if ( m_Reader && m_Reader->m_File.IsOpen() )
534     m_Reader->Close();
535 }
536
537 // Warning: direct manipulation of MXF structures can interfere
538 // with the normal operation of the wrapper.  Caveat emptor!
539 //
540 ASDCP::MXF::OP1aHeader&
541 ASDCP::JP2K::MXFReader::OP1aHeader()
542 {
543   if ( m_Reader.empty() )
544     {
545       assert(g_OP1aHeader);
546       return *g_OP1aHeader;
547     }
548
549   return m_Reader->m_HeaderPart;
550 }
551
552 // Warning: direct manipulation of MXF structures can interfere
553 // with the normal operation of the wrapper.  Caveat emptor!
554 //
555 ASDCP::MXF::OPAtomIndexFooter&
556 ASDCP::JP2K::MXFReader::OPAtomIndexFooter()
557 {
558   if ( m_Reader.empty() )
559     {
560       assert(g_OPAtomIndexFooter);
561       return *g_OPAtomIndexFooter;
562     }
563
564   return m_Reader->m_IndexAccess;
565 }
566
567 // Warning: direct manipulation of MXF structures can interfere
568 // with the normal operation of the wrapper.  Caveat emptor!
569 //
570 ASDCP::MXF::RIP&
571 ASDCP::JP2K::MXFReader::RIP()
572 {
573   if ( m_Reader.empty() )
574     {
575       assert(g_RIP);
576       return *g_RIP;
577     }
578
579   return m_Reader->m_RIP;
580 }
581
582 // Open the file for reading. The file must exist. Returns error if the
583 // operation cannot be completed.
584 ASDCP::Result_t
585 ASDCP::JP2K::MXFReader::OpenRead(const std::string& filename) const
586 {
587   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
588 }
589
590 //
591 ASDCP::Result_t
592 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
593                                    AESDecContext* Ctx, HMACContext* HMAC) const
594 {
595   if ( m_Reader && m_Reader->m_File.IsOpen() )
596     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
597
598   return RESULT_INIT;
599 }
600
601 ASDCP::Result_t
602 ASDCP::JP2K::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
603 {
604     return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
605 }
606
607
608 // Fill the struct with the values from the file's header.
609 // Returns RESULT_INIT if the file is not open.
610 ASDCP::Result_t
611 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
612 {
613   if ( m_Reader && m_Reader->m_File.IsOpen() )
614     {
615       PDesc = m_Reader->m_PDesc;
616       return RESULT_OK;
617     }
618
619   return RESULT_INIT;
620 }
621
622
623 // Fill the struct with the values from the file's header.
624 // Returns RESULT_INIT if the file is not open.
625 ASDCP::Result_t
626 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
627 {
628   if ( m_Reader && m_Reader->m_File.IsOpen() )
629     {
630       Info = m_Reader->m_Info;
631       return RESULT_OK;
632     }
633
634   return RESULT_INIT;
635 }
636
637 //
638 void
639 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
640 {
641   if ( m_Reader->m_File.IsOpen() )
642     m_Reader->m_HeaderPart.Dump(stream);
643 }
644
645
646 //
647 void
648 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
649 {
650   if ( m_Reader->m_File.IsOpen() )
651     m_Reader->m_IndexAccess.Dump(stream);
652 }
653
654 //
655 ASDCP::Result_t
656 ASDCP::JP2K::MXFReader::Close() const
657 {
658   if ( m_Reader && m_Reader->m_File.IsOpen() )
659     {
660       m_Reader->Close();
661       return RESULT_OK;
662     }
663
664   return RESULT_INIT;
665 }
666
667
668 //------------------------------------------------------------------------------------------
669
670
671 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
672 {
673   ui32_t m_StereoFrameReady;
674
675 public:
676   h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
677
678   //
679   Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
680                      AESDecContext* Ctx, HMACContext* HMAC)
681   {
682     // look up frame index node
683     IndexTableSegment::IndexEntry TmpEntry;
684
685     if ( ASDCP_FAILURE(m_IndexAccess.Lookup(FrameNum, TmpEntry)) )
686       {
687         DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
688         return RESULT_RANGE;
689       }
690
691     // get frame position
692     Kumu::fpos_t FilePosition = m_HeaderPart.BodyOffset + TmpEntry.StreamOffset;
693     Result_t result = RESULT_OK;
694
695     if ( phase == SP_LEFT )
696       {    
697         if ( FilePosition != m_LastPosition )
698           {
699             m_LastPosition = FilePosition;
700             result = m_File.Seek(FilePosition);
701           }
702
703         // the call to ReadEKLVPacket() will leave the file on an R frame
704         m_StereoFrameReady = FrameNum;
705       }
706     else if ( phase == SP_RIGHT )
707       {
708         if ( m_StereoFrameReady != FrameNum )
709           {
710             // the file is not already positioned, we must do some work
711             // seek to the companion SP_LEFT frame and read the frame's key and length
712             if ( FilePosition != m_LastPosition )
713               {
714                 m_LastPosition = FilePosition;
715                 result = m_File.Seek(FilePosition);
716               }
717
718             KLReader Reader;
719             result = Reader.ReadKLFromFile(m_File);
720
721             if ( ASDCP_SUCCESS(result) )
722               {
723                 // skip over the companion SP_LEFT frame
724                 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
725                 result = m_File.Seek(new_pos);
726               }
727           }
728
729         // the call to ReadEKLVPacket() will leave the file not on an R frame
730         m_StereoFrameReady = 0xffffffff;
731       }
732     else
733       {
734         DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
735         return RESULT_STATE;
736       }
737
738     if( ASDCP_SUCCESS(result) )
739       {
740         ui32_t SequenceNum = FrameNum * 2;
741         SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
742         assert(m_Dict);
743         result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
744       }
745
746     return result;
747   }
748 };
749
750
751
752 ASDCP::JP2K::MXFSReader::MXFSReader()
753 {
754   m_Reader = new h__SReader(DefaultCompositeDict());
755 }
756
757
758 ASDCP::JP2K::MXFSReader::~MXFSReader()
759 {
760   if ( m_Reader && m_Reader->m_File.IsOpen() )
761     m_Reader->Close();
762 }
763
764 // Warning: direct manipulation of MXF structures can interfere
765 // with the normal operation of the wrapper.  Caveat emptor!
766 //
767 ASDCP::MXF::OP1aHeader&
768 ASDCP::JP2K::MXFSReader::OP1aHeader()
769 {
770   if ( m_Reader.empty() )
771     {
772       assert(g_OP1aHeader);
773       return *g_OP1aHeader;
774     }
775
776   return m_Reader->m_HeaderPart;
777 }
778
779 // Warning: direct manipulation of MXF structures can interfere
780 // with the normal operation of the wrapper.  Caveat emptor!
781 //
782 ASDCP::MXF::OPAtomIndexFooter&
783 ASDCP::JP2K::MXFSReader::OPAtomIndexFooter()
784 {
785   if ( m_Reader.empty() )
786     {
787       assert(g_OPAtomIndexFooter);
788       return *g_OPAtomIndexFooter;
789     }
790
791   return m_Reader->m_IndexAccess;
792 }
793
794 // Warning: direct manipulation of MXF structures can interfere
795 // with the normal operation of the wrapper.  Caveat emptor!
796 //
797 ASDCP::MXF::RIP&
798 ASDCP::JP2K::MXFSReader::RIP()
799 {
800   if ( m_Reader.empty() )
801     {
802       assert(g_RIP);
803       return *g_RIP;
804     }
805
806   return m_Reader->m_RIP;
807 }
808
809 // Open the file for reading. The file must exist. Returns error if the
810 // operation cannot be completed.
811 ASDCP::Result_t
812 ASDCP::JP2K::MXFSReader::OpenRead(const std::string& filename) const
813 {
814   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
815 }
816
817 //
818 ASDCP::Result_t
819 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
820 {
821   Result_t result = RESULT_INIT;
822
823   if ( m_Reader && m_Reader->m_File.IsOpen() )
824     {
825       result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
826
827       if ( ASDCP_SUCCESS(result) )
828         result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
829     }
830
831   return result;
832 }
833
834 //
835 ASDCP::Result_t
836 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
837                                    AESDecContext* Ctx, HMACContext* HMAC) const
838 {
839   if ( m_Reader && m_Reader->m_File.IsOpen() )
840     return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
841
842   return RESULT_INIT;
843 }
844
845 ASDCP::Result_t
846 ASDCP::JP2K::MXFSReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset, i8_t& temporalOffset, i8_t& keyFrameOffset) const
847 {
848     return m_Reader->LocateFrame(FrameNum, streamOffset, temporalOffset, keyFrameOffset);
849 }
850
851 // Fill the struct with the values from the file's header.
852 // Returns RESULT_INIT if the file is not open.
853 ASDCP::Result_t
854 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
855 {
856   if ( m_Reader && m_Reader->m_File.IsOpen() )
857     {
858       PDesc = m_Reader->m_PDesc;
859       return RESULT_OK;
860     }
861
862   return RESULT_INIT;
863 }
864
865
866 // Fill the struct with the values from the file's header.
867 // Returns RESULT_INIT if the file is not open.
868 ASDCP::Result_t
869 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
870 {
871   if ( m_Reader && m_Reader->m_File.IsOpen() )
872     {
873       Info = m_Reader->m_Info;
874       return RESULT_OK;
875     }
876
877   return RESULT_INIT;
878 }
879
880 //
881 void
882 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
883 {
884   if ( m_Reader->m_File.IsOpen() )
885     m_Reader->m_HeaderPart.Dump(stream);
886 }
887
888
889 //
890 void
891 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
892 {
893   if ( m_Reader->m_File.IsOpen() )
894     m_Reader->m_IndexAccess.Dump(stream);
895 }
896
897 //
898 ASDCP::Result_t
899 ASDCP::JP2K::MXFSReader::Close() const
900 {
901   if ( m_Reader && m_Reader->m_File.IsOpen() )
902     {
903       m_Reader->Close();
904       return RESULT_OK;
905     }
906
907   return RESULT_INIT;
908 }
909
910
911 //------------------------------------------------------------------------------------------
912
913
914 //
915 class lh__Writer : public ASDCP::h__ASDCPWriter
916 {
917   ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
918   lh__Writer();
919
920   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
921
922 public:
923   PictureDescriptor m_PDesc;
924   byte_t            m_EssenceUL[SMPTE_UL_LENGTH];
925
926   lh__Writer(const Dictionary& d) : ASDCP::h__ASDCPWriter(d), m_EssenceSubDescriptor(0) {
927     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
928   }
929
930   virtual ~lh__Writer(){}
931
932   Result_t OpenWrite(const std::string&, EssenceType_t type, ui32_t HeaderSize);
933   Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
934                            ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
935   Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
936   Result_t Finalize();
937 };
938
939 // Open the file for writing. The file must not exist. Returns error if
940 // the operation cannot be completed.
941 ASDCP::Result_t
942 lh__Writer::OpenWrite(const std::string& filename, EssenceType_t type, ui32_t HeaderSize)
943 {
944   if ( ! m_State.Test_BEGIN() )
945     return RESULT_STATE;
946
947   Result_t result = m_File.OpenWrite(filename);
948
949   if ( ASDCP_SUCCESS(result) )
950     {
951       m_HeaderSize = HeaderSize;
952       RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
953       tmp_rgba->ComponentMaxRef = 4095;
954       tmp_rgba->ComponentMinRef = 0;
955
956       m_EssenceDescriptor = tmp_rgba;
957       m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
958       m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
959
960       GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
961       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
962
963       if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
964         {
965           InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
966           m_EssenceSubDescriptorList.push_back(StereoSubDesc);
967           GenRandomValue(StereoSubDesc->InstanceUID);
968           m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
969         }
970
971       result = m_State.Goto_INIT();
972     }
973
974   return result;
975 }
976
977 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
978 ASDCP::Result_t
979 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
980 {
981   assert(m_Dict);
982   if ( ! m_State.Test_INIT() )
983     return RESULT_STATE;
984
985   if ( LocalEditRate == ASDCP::Rational(0,0) )
986     LocalEditRate = PDesc.EditRate;
987
988   m_PDesc = PDesc;
989   assert(m_Dict);
990   assert(m_EssenceDescriptor);
991   assert(m_EssenceSubDescriptor);
992   Result_t result = JP2K_PDesc_to_MD(m_PDesc, *m_Dict,
993                                      *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(m_EssenceDescriptor),
994                                      *m_EssenceSubDescriptor);
995
996   if ( ASDCP_SUCCESS(result) )
997     {
998       if ( PDesc.StoredWidth < 2049 )
999         {
1000           static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
1001           m_EssenceSubDescriptor->Rsize = 3;
1002         }
1003       else
1004         {
1005           static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor)->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
1006           m_EssenceSubDescriptor->Rsize = 4;
1007         }
1008
1009       memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
1010       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
1011       result = m_State.Goto_READY();
1012     }
1013
1014   if ( ASDCP_SUCCESS(result) )
1015     {
1016       result = WriteASDCPHeader(label, UL(m_Dict->ul(MDD_JPEG_2000WrappingFrame)),
1017                                 PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
1018                                 LocalEditRate, derive_timecode_rate_from_edit_rate(m_PDesc.EditRate));
1019     }
1020
1021   return result;
1022 }
1023
1024 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1025 // argument is present, the essence is encrypted prior to writing.
1026 // Fails if the file is not open, is finalized, or an operating system
1027 // error occurs.
1028 //
1029 ASDCP::Result_t
1030 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
1031                        AESEncContext* Ctx, HMACContext* HMAC)
1032 {
1033   Result_t result = RESULT_OK;
1034
1035   if ( m_State.Test_READY() )
1036     result = m_State.Goto_RUNNING(); // first time through
1037  
1038   ui64_t StreamOffset = m_StreamOffset;
1039
1040   if ( ASDCP_SUCCESS(result) )
1041     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
1042
1043   if ( ASDCP_SUCCESS(result) && add_index )
1044     {  
1045       IndexTableSegment::IndexEntry Entry;
1046       Entry.StreamOffset = StreamOffset;
1047       m_FooterPart.PushIndexEntry(Entry);
1048     }
1049
1050   m_FramesWritten++;
1051   return result;
1052 }
1053
1054
1055 // Closes the MXF file, writing the index and other closing information.
1056 //
1057 ASDCP::Result_t
1058 lh__Writer::Finalize()
1059 {
1060   if ( ! m_State.Test_RUNNING() )
1061     return RESULT_STATE;
1062
1063   m_State.Goto_FINAL();
1064
1065   return WriteASDCPFooter();
1066 }
1067
1068
1069 //
1070 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
1071 {
1072   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
1073   h__Writer();
1074
1075 public:
1076   h__Writer(const Dictionary& d) : lh__Writer(d) {}
1077 };
1078
1079
1080 //------------------------------------------------------------------------------------------
1081
1082
1083
1084 ASDCP::JP2K::MXFWriter::MXFWriter()
1085 {
1086 }
1087
1088 ASDCP::JP2K::MXFWriter::~MXFWriter()
1089 {
1090 }
1091
1092 // Warning: direct manipulation of MXF structures can interfere
1093 // with the normal operation of the wrapper.  Caveat emptor!
1094 //
1095 ASDCP::MXF::OP1aHeader&
1096 ASDCP::JP2K::MXFWriter::OP1aHeader()
1097 {
1098   if ( m_Writer.empty() )
1099     {
1100       assert(g_OP1aHeader);
1101       return *g_OP1aHeader;
1102     }
1103
1104   return m_Writer->m_HeaderPart;
1105 }
1106
1107 // Warning: direct manipulation of MXF structures can interfere
1108 // with the normal operation of the wrapper.  Caveat emptor!
1109 //
1110 ASDCP::MXF::OPAtomIndexFooter&
1111 ASDCP::JP2K::MXFWriter::OPAtomIndexFooter()
1112 {
1113   if ( m_Writer.empty() )
1114     {
1115       assert(g_OPAtomIndexFooter);
1116       return *g_OPAtomIndexFooter;
1117     }
1118
1119   return m_Writer->m_FooterPart;
1120 }
1121
1122 // Warning: direct manipulation of MXF structures can interfere
1123 // with the normal operation of the wrapper.  Caveat emptor!
1124 //
1125 ASDCP::MXF::RIP&
1126 ASDCP::JP2K::MXFWriter::RIP()
1127 {
1128   if ( m_Writer.empty() )
1129     {
1130       assert(g_RIP);
1131       return *g_RIP;
1132     }
1133
1134   return m_Writer->m_RIP;
1135 }
1136
1137 // Open the file for writing. The file must not exist. Returns error if
1138 // the operation cannot be completed.
1139 ASDCP::Result_t
1140 ASDCP::JP2K::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
1141                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
1142 {
1143   if ( Info.LabelSetType == LS_MXF_SMPTE )
1144     m_Writer = new h__Writer(DefaultSMPTEDict());
1145   else
1146     m_Writer = new h__Writer(DefaultInteropDict());
1147
1148   m_Writer->m_Info = Info;
1149
1150   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
1151
1152   if ( ASDCP_SUCCESS(result) )
1153     result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
1154
1155   if ( ASDCP_FAILURE(result) )
1156     m_Writer.release();
1157
1158   return result;
1159 }
1160
1161
1162 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1163 // argument is present, the essence is encrypted prior to writing.
1164 // Fails if the file is not open, is finalized, or an operating system
1165 // error occurs.
1166 ASDCP::Result_t
1167 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1168 {
1169   if ( m_Writer.empty() )
1170     return RESULT_INIT;
1171
1172   return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
1173 }
1174
1175 // Closes the MXF file, writing the index and other closing information.
1176 ASDCP::Result_t
1177 ASDCP::JP2K::MXFWriter::Finalize()
1178 {
1179   if ( m_Writer.empty() )
1180     return RESULT_INIT;
1181
1182   return m_Writer->Finalize();
1183 }
1184
1185
1186 //------------------------------------------------------------------------------------------
1187 //
1188
1189 //
1190 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
1191 {
1192   ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
1193   h__SWriter();
1194   StereoscopicPhase_t m_NextPhase;
1195
1196 public:
1197   h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
1198
1199   //
1200   Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1201                       AESEncContext* Ctx, HMACContext* HMAC)
1202   {
1203     if ( m_NextPhase != phase )
1204       return RESULT_SPHASE;
1205
1206     if ( phase == SP_LEFT )
1207       {
1208         m_NextPhase = SP_RIGHT;
1209         return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
1210       }
1211
1212     m_NextPhase = SP_LEFT;
1213     return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
1214   }
1215
1216   //
1217   Result_t Finalize()
1218   {
1219     if ( m_NextPhase != SP_LEFT )
1220       return RESULT_SPHASE;
1221
1222     assert( m_FramesWritten % 2 == 0 );
1223     m_FramesWritten /= 2;
1224     return lh__Writer::Finalize();
1225   }
1226 };
1227
1228
1229 //
1230 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1231 {
1232 }
1233
1234 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1235 {
1236 }
1237
1238 // Warning: direct manipulation of MXF structures can interfere
1239 // with the normal operation of the wrapper.  Caveat emptor!
1240 //
1241 ASDCP::MXF::OP1aHeader&
1242 ASDCP::JP2K::MXFSWriter::OP1aHeader()
1243 {
1244   if ( m_Writer.empty() )
1245     {
1246       assert(g_OP1aHeader);
1247       return *g_OP1aHeader;
1248     }
1249
1250   return m_Writer->m_HeaderPart;
1251 }
1252
1253 // Warning: direct manipulation of MXF structures can interfere
1254 // with the normal operation of the wrapper.  Caveat emptor!
1255 //
1256 ASDCP::MXF::OPAtomIndexFooter&
1257 ASDCP::JP2K::MXFSWriter::OPAtomIndexFooter()
1258 {
1259   if ( m_Writer.empty() )
1260     {
1261       assert(g_OPAtomIndexFooter);
1262       return *g_OPAtomIndexFooter;
1263     }
1264
1265   return m_Writer->m_FooterPart;
1266 }
1267
1268 // Warning: direct manipulation of MXF structures can interfere
1269 // with the normal operation of the wrapper.  Caveat emptor!
1270 //
1271 ASDCP::MXF::RIP&
1272 ASDCP::JP2K::MXFSWriter::RIP()
1273 {
1274   if ( m_Writer.empty() )
1275     {
1276       assert(g_RIP);
1277       return *g_RIP;
1278     }
1279
1280   return m_Writer->m_RIP;
1281 }
1282
1283 // Open the file for writing. The file must not exist. Returns error if
1284 // the operation cannot be completed.
1285 ASDCP::Result_t
1286 ASDCP::JP2K::MXFSWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
1287                                    const PictureDescriptor& PDesc, ui32_t HeaderSize)
1288 {
1289   if ( Info.LabelSetType == LS_MXF_SMPTE )
1290     m_Writer = new h__SWriter(DefaultSMPTEDict());
1291   else
1292     m_Writer = new h__SWriter(DefaultInteropDict());
1293
1294   if ( PDesc.EditRate != ASDCP::EditRate_24
1295        && PDesc.EditRate != ASDCP::EditRate_25
1296        && PDesc.EditRate != ASDCP::EditRate_30
1297        && PDesc.EditRate != ASDCP::EditRate_48
1298        && PDesc.EditRate != ASDCP::EditRate_50
1299        && PDesc.EditRate != ASDCP::EditRate_60 )
1300     {
1301       DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25, 30, 48, 50 or 60 fps input streams.\n");
1302       return RESULT_FORMAT;
1303     }
1304
1305   if ( PDesc.StoredWidth > 2048 )
1306     DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1307
1308   m_Writer->m_Info = Info;
1309
1310   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1311
1312   if ( ASDCP_SUCCESS(result) )
1313     {
1314       PictureDescriptor TmpPDesc = PDesc;
1315
1316       if ( PDesc.EditRate == ASDCP::EditRate_24 )
1317         TmpPDesc.EditRate = ASDCP::EditRate_48;
1318
1319       else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1320         TmpPDesc.EditRate = ASDCP::EditRate_50;
1321
1322       else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1323         TmpPDesc.EditRate = ASDCP::EditRate_60;
1324
1325       else if ( PDesc.EditRate == ASDCP::EditRate_48 )
1326         TmpPDesc.EditRate = ASDCP::EditRate_96;
1327
1328       else if ( PDesc.EditRate == ASDCP::EditRate_50 )
1329         TmpPDesc.EditRate = ASDCP::EditRate_100;
1330
1331       else if ( PDesc.EditRate == ASDCP::EditRate_60 )
1332         TmpPDesc.EditRate = ASDCP::EditRate_120;
1333
1334       result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1335     }
1336
1337   if ( ASDCP_FAILURE(result) )
1338     m_Writer.release();
1339
1340   return result;
1341 }
1342
1343 ASDCP::Result_t
1344 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1345 {
1346   if ( m_Writer.empty() )
1347     return RESULT_INIT;
1348
1349   Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1350
1351   if ( ASDCP_SUCCESS(result) )
1352     result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1353
1354   return result;
1355 }
1356
1357 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1358 // argument is present, the essence is encrypted prior to writing.
1359 // Fails if the file is not open, is finalized, or an operating system
1360 // error occurs.
1361 ASDCP::Result_t
1362 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1363                                     AESEncContext* Ctx, HMACContext* HMAC)
1364 {
1365   if ( m_Writer.empty() )
1366     return RESULT_INIT;
1367
1368   return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1369 }
1370
1371 // Closes the MXF file, writing the index and other closing information.
1372 ASDCP::Result_t
1373 ASDCP::JP2K::MXFSWriter::Finalize()
1374 {
1375   if ( m_Writer.empty() )
1376     return RESULT_INIT;
1377
1378   return m_Writer->Finalize();
1379 }
1380
1381 //
1382 // end AS_DCP_JP2K.cpp
1383 //