harder than it looks
[asdcplib.git] / src / AS_DCP_JP2K.cpp
1 /*
2 Copyright (c) 2004-2009, 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 //------------------------------------------------------------------------------------------
204 //
205 // hidden, internal implementation of JPEG 2000 reader
206
207
208 class lh__Reader : public ASDCP::h__Reader
209 {
210   RGBAEssenceDescriptor*        m_EssenceDescriptor;
211   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
212   ASDCP::Rational               m_EditRate;
213   ASDCP::Rational               m_SampleRate;
214   EssenceType_t                 m_Format;
215
216   ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
217
218 public:
219   PictureDescriptor m_PDesc;        // codestream parameter list
220
221   lh__Reader(const Dictionary& d) :
222     ASDCP::h__Reader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
223   Result_t    OpenRead(const char*, EssenceType_t);
224   Result_t    ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
225   Result_t    MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
226 };
227
228 //
229 ASDCP::Result_t
230 lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
231 {
232   memset(&PDesc, 0, sizeof(PDesc));
233   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
234
235   PDesc.EditRate           = m_EditRate;
236   PDesc.SampleRate         = m_SampleRate;
237   assert(PDescObj->ContainerDuration <= 0xFFFFFFFFL);
238   PDesc.ContainerDuration  = (ui32_t) PDescObj->ContainerDuration;
239   PDesc.StoredWidth        = PDescObj->StoredWidth;
240   PDesc.StoredHeight       = PDescObj->StoredHeight;
241   PDesc.AspectRatio        = PDescObj->AspectRatio;
242
243   if ( m_EssenceSubDescriptor != 0 )
244     {
245       PDesc.Rsize   = m_EssenceSubDescriptor->Rsize;
246       PDesc.Xsize   = m_EssenceSubDescriptor->Xsize;
247       PDesc.Ysize   = m_EssenceSubDescriptor->Ysize;
248       PDesc.XOsize  = m_EssenceSubDescriptor->XOsize;
249       PDesc.YOsize  = m_EssenceSubDescriptor->YOsize;
250       PDesc.XTsize  = m_EssenceSubDescriptor->XTsize;
251       PDesc.YTsize  = m_EssenceSubDescriptor->YTsize;
252       PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
253       PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
254       PDesc.Csize   = m_EssenceSubDescriptor->Csize;
255
256       // PictureComponentSizing
257       ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
258
259       if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
260         memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
261
262       else
263         DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
264
265       // CodingStyleDefault
266       memset(&m_PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
267       memcpy(&m_PDesc.CodingStyleDefault,
268              m_EssenceSubDescriptor->CodingStyleDefault.RoData(),
269              m_EssenceSubDescriptor->CodingStyleDefault.Length());
270
271       // QuantizationDefault
272       memset(&m_PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
273       memcpy(&m_PDesc.QuantizationDefault,
274              m_EssenceSubDescriptor->QuantizationDefault.RoData(),
275              m_EssenceSubDescriptor->QuantizationDefault.Length());
276
277       m_PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1;
278     }
279
280   return RESULT_OK;
281 }
282
283 //
284 //
285 ASDCP::Result_t
286 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
287 {
288   Result_t result = OpenMXFRead(filename);
289
290   if( ASDCP_SUCCESS(result) )
291     {
292       InterchangeObject* tmp_iobj = 0;
293       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
294       m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
295
296       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
297       m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
298
299       std::list<InterchangeObject*> ObjectList;
300       m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
301
302       if ( ObjectList.empty() )
303         {
304           DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
305           return RESULT_FORMAT;
306         }
307
308       m_EditRate = ((Track*)ObjectList.front())->EditRate;
309       m_SampleRate = m_EssenceDescriptor->SampleRate;
310
311       if ( type == ASDCP::ESS_JPEG_2000 )
312         {
313           if ( m_EditRate != m_SampleRate )
314             {
315               DefaultLogSink().Error("EditRate and SampleRate do not match (%.03f, %.03f).\n",
316                                      m_EditRate.Quotient(), m_SampleRate.Quotient());
317               
318               if ( m_EditRate == EditRate_24 && m_SampleRate == EditRate_48 )
319                 {
320                   DefaultLogSink().Debug("File may contain JPEG Interop stereoscopic images.\n");
321                   return RESULT_SFORMAT;
322                 }
323
324               return RESULT_FORMAT;
325             }
326         }
327       else if ( type == ASDCP::ESS_JPEG_2000_S )
328         {
329           if ( ! ( m_EditRate == EditRate_24 && m_SampleRate == EditRate_48 ) )
330             {
331               DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
332               return RESULT_FORMAT;
333             }
334         }
335       else
336         {
337           DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
338           return RESULT_STATE;
339         }
340
341       result = MD_to_JP2K_PDesc(m_PDesc);
342     }
343
344   if( ASDCP_SUCCESS(result) )
345     result = InitMXFIndex();
346
347   if( ASDCP_SUCCESS(result) )
348     result = InitInfo();
349
350   return result;
351 }
352
353 //
354 //
355 ASDCP::Result_t
356 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
357                       AESDecContext* Ctx, HMACContext* HMAC)
358 {
359   if ( ! m_File.IsOpen() )
360     return RESULT_INIT;
361
362   assert(m_Dict);
363   return ReadEKLVFrame(FrameNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
364 }
365
366
367 //
368 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
369 {
370   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
371   h__Reader();
372
373 public:
374   h__Reader(const Dictionary& d) : lh__Reader(d) {}
375 };
376
377
378
379 //------------------------------------------------------------------------------------------
380
381
382 //
383 void
384 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
385 {
386   if ( stream == 0 )
387     stream = stderr;
388
389   fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
390   
391   fputc('\n', stream);
392
393   if ( dump_len > 0 )
394     Kumu::hexdump(m_Data, dump_len, stream);
395 }
396
397
398 //------------------------------------------------------------------------------------------
399
400 ASDCP::JP2K::MXFReader::MXFReader()
401 {
402   m_Reader = new h__Reader(DefaultCompositeDict());
403 }
404
405
406 ASDCP::JP2K::MXFReader::~MXFReader()
407 {
408 }
409
410 // Open the file for reading. The file must exist. Returns error if the
411 // operation cannot be completed.
412 ASDCP::Result_t
413 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
414 {
415   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
416 }
417
418 //
419 ASDCP::Result_t
420 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
421                                    AESDecContext* Ctx, HMACContext* HMAC) const
422 {
423   if ( m_Reader && m_Reader->m_File.IsOpen() )
424     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
425
426   return RESULT_INIT;
427 }
428
429
430 // Fill the struct with the values from the file's header.
431 // Returns RESULT_INIT if the file is not open.
432 ASDCP::Result_t
433 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
434 {
435   if ( m_Reader && m_Reader->m_File.IsOpen() )
436     {
437       PDesc = m_Reader->m_PDesc;
438       return RESULT_OK;
439     }
440
441   return RESULT_INIT;
442 }
443
444
445 // Fill the struct with the values from the file's header.
446 // Returns RESULT_INIT if the file is not open.
447 ASDCP::Result_t
448 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
449 {
450   if ( m_Reader && m_Reader->m_File.IsOpen() )
451     {
452       Info = m_Reader->m_Info;
453       return RESULT_OK;
454     }
455
456   return RESULT_INIT;
457 }
458
459 //
460 void
461 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
462 {
463   if ( m_Reader->m_File.IsOpen() )
464     m_Reader->m_HeaderPart.Dump(stream);
465 }
466
467
468 //
469 void
470 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
471 {
472   if ( m_Reader->m_File.IsOpen() )
473     m_Reader->m_FooterPart.Dump(stream);
474 }
475
476
477 //------------------------------------------------------------------------------------------
478
479
480 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
481 {
482   ui32_t m_StereoFrameReady;
483
484 public:
485   h__SReader(const Dictionary& d) : lh__Reader(d), m_StereoFrameReady(0xffffffff) {}
486
487   //
488   Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
489                      AESDecContext* Ctx, HMACContext* HMAC)
490   {
491     // look up frame index node
492     IndexTableSegment::IndexEntry TmpEntry;
493
494     if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
495       {
496         DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
497         return RESULT_RANGE;
498       }
499
500     // get frame position
501     Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
502     Result_t result = RESULT_OK;
503
504     if ( phase == SP_LEFT )
505       {    
506         if ( FilePosition != m_LastPosition )
507           {
508             m_LastPosition = FilePosition;
509             result = m_File.Seek(FilePosition);
510           }
511
512         // the call to ReadEKLVPacket() will leave the file on an R frame
513         m_StereoFrameReady = FrameNum;
514       }
515     else if ( phase == SP_RIGHT )
516       {
517         if ( m_StereoFrameReady != FrameNum )
518           {
519             // the file is not already positioned, we must do some work
520             // seek to the companion SP_LEFT frame and read the frame's key and length
521             if ( FilePosition != m_LastPosition )
522               {
523                 m_LastPosition = FilePosition;
524                 result = m_File.Seek(FilePosition);
525               }
526
527             KLReader Reader;
528             result = Reader.ReadKLFromFile(m_File);
529
530             if ( ASDCP_SUCCESS(result) )
531               {
532                 // skip over the companion SP_LEFT frame
533                 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
534                 result = m_File.Seek(new_pos);
535               }
536           }
537
538         // the call to ReadEKLVPacket() will leave the file not on an R frame
539         m_StereoFrameReady = 0xffffffff;
540       }
541     else
542       {
543         DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
544         return RESULT_STATE;
545       }
546
547     if( ASDCP_SUCCESS(result) )
548       {
549         ui32_t SequenceNum = FrameNum * 2;
550         SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
551         assert(m_Dict);
552         result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, m_Dict->ul(MDD_JPEG2000Essence), Ctx, HMAC);
553       }
554
555     return result;
556   }
557 };
558
559
560
561 ASDCP::JP2K::MXFSReader::MXFSReader()
562 {
563   m_Reader = new h__SReader(DefaultCompositeDict());
564 }
565
566
567 ASDCP::JP2K::MXFSReader::~MXFSReader()
568 {
569 }
570
571 // Open the file for reading. The file must exist. Returns error if the
572 // operation cannot be completed.
573 ASDCP::Result_t
574 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
575 {
576   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
577 }
578
579 //
580 ASDCP::Result_t
581 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
582 {
583   Result_t result = RESULT_INIT;
584
585   if ( m_Reader && m_Reader->m_File.IsOpen() )
586     {
587       result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
588
589       if ( ASDCP_SUCCESS(result) )
590         result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
591     }
592
593   return result;
594 }
595
596 //
597 ASDCP::Result_t
598 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
599                                    AESDecContext* Ctx, HMACContext* HMAC) const
600 {
601   if ( m_Reader && m_Reader->m_File.IsOpen() )
602     return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
603
604   return RESULT_INIT;
605 }
606
607 // Fill the struct with the values from the file's header.
608 // Returns RESULT_INIT if the file is not open.
609 ASDCP::Result_t
610 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
611 {
612   if ( m_Reader && m_Reader->m_File.IsOpen() )
613     {
614       PDesc = m_Reader->m_PDesc;
615       return RESULT_OK;
616     }
617
618   return RESULT_INIT;
619 }
620
621
622 // Fill the struct with the values from the file's header.
623 // Returns RESULT_INIT if the file is not open.
624 ASDCP::Result_t
625 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
626 {
627   if ( m_Reader && m_Reader->m_File.IsOpen() )
628     {
629       Info = m_Reader->m_Info;
630       return RESULT_OK;
631     }
632
633   return RESULT_INIT;
634 }
635
636 //
637 void
638 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
639 {
640   if ( m_Reader->m_File.IsOpen() )
641     m_Reader->m_HeaderPart.Dump(stream);
642 }
643
644
645 //
646 void
647 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
648 {
649   if ( m_Reader->m_File.IsOpen() )
650     m_Reader->m_FooterPart.Dump(stream);
651 }
652
653 //------------------------------------------------------------------------------------------
654
655
656 //
657 class lh__Writer : public ASDCP::h__Writer
658 {
659   ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
660   lh__Writer();
661
662   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
663
664 public:
665   PictureDescriptor m_PDesc;
666   byte_t            m_EssenceUL[SMPTE_UL_LENGTH];
667
668   lh__Writer(const Dictionary& d) : ASDCP::h__Writer(d), m_EssenceSubDescriptor(0) {
669     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
670   }
671
672   ~lh__Writer(){}
673
674   Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
675   Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
676                            ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
677   Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
678   Result_t Finalize();
679   Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
680 };
681
682 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
683 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
684 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
685
686 //
687 ASDCP::Result_t
688 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
689 {
690   assert(m_EssenceDescriptor);
691   assert(m_EssenceSubDescriptor);
692   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
693
694   PDescObj->ContainerDuration = PDesc.ContainerDuration;
695   PDescObj->SampleRate = PDesc.EditRate;
696   PDescObj->FrameLayout = 0;
697   PDescObj->StoredWidth = PDesc.StoredWidth;
698   PDescObj->StoredHeight = PDesc.StoredHeight;
699   PDescObj->AspectRatio = PDesc.AspectRatio;
700
701   //  if ( m_Info.LabelSetType == LS_MXF_SMPTE )
702   //    {
703   // PictureEssenceCoding UL = 
704   // Video Line Map       ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
705   // CaptureGamma         UL = 
706   // ComponentMaxRef      ui32_t = 4095
707   // ComponentMinRef      ui32_t = 0
708   // PixelLayout          byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
709   //    }
710
711   assert(m_Dict);
712   if ( PDesc.StoredWidth < 2049 )
713     {
714       PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_2K));
715       m_EssenceSubDescriptor->Rsize = 3;
716     }
717   else
718     {
719       PDescObj->PictureEssenceCoding.Set(m_Dict->ul(MDD_JP2KEssenceCompression_4K));
720       m_EssenceSubDescriptor->Rsize = 4;
721     }
722
723   m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
724   m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
725   m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
726   m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
727   m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
728   m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
729   m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
730   m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
731   m_EssenceSubDescriptor->Csize = PDesc.Csize;
732
733   const ui32_t tmp_buffer_len = 1024;
734   byte_t tmp_buffer[tmp_buffer_len];
735
736   *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
737   *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
738   memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
739
740   const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
741   memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
742   m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
743
744   ui32_t precinct_set_size = 0, i;
745   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
746     precinct_set_size++;
747
748   ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
749   memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
750   m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
751
752   ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
753   memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
754   m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
755
756   return RESULT_OK;
757 }
758
759
760 // Open the file for writing. The file must not exist. Returns error if
761 // the operation cannot be completed.
762 ASDCP::Result_t
763 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
764 {
765   if ( ! m_State.Test_BEGIN() )
766     return RESULT_STATE;
767
768   Result_t result = m_File.OpenWrite(filename);
769
770   if ( ASDCP_SUCCESS(result) )
771     {
772       m_HeaderSize = HeaderSize;
773       RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor(m_Dict);
774       tmp_rgba->ComponentMaxRef = 4095;
775       tmp_rgba->ComponentMinRef = 0;
776
777       m_EssenceDescriptor = tmp_rgba;
778       m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor(m_Dict);
779       m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
780
781       GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
782       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
783
784       if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
785         {
786           InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor(m_Dict);
787           m_EssenceSubDescriptorList.push_back(StereoSubDesc);
788           GenRandomValue(StereoSubDesc->InstanceUID);
789           m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
790         }
791
792       result = m_State.Goto_INIT();
793     }
794
795   return result;
796 }
797
798 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
799 ASDCP::Result_t
800 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
801 {
802   assert(m_Dict);
803   if ( ! m_State.Test_INIT() )
804     return RESULT_STATE;
805
806   if ( LocalEditRate == ASDCP::Rational(0,0) )
807     LocalEditRate = PDesc.EditRate;
808
809   m_PDesc = PDesc;
810   Result_t result = JP2K_PDesc_to_MD(m_PDesc);
811
812   if ( ASDCP_SUCCESS(result) )
813       result = WriteMXFHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
814                               PICT_DEF_LABEL,     UL(m_Dict->ul(MDD_PictureDataDef)),
815                               LocalEditRate, 24 /* TCFrameRate */);
816
817   if ( ASDCP_SUCCESS(result) )
818     {
819       memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
820       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
821       result = m_State.Goto_READY();
822     }
823
824   return result;
825 }
826
827 // Writes a frame of essence to the MXF file. If the optional AESEncContext
828 // argument is present, the essence is encrypted prior to writing.
829 // Fails if the file is not open, is finalized, or an operating system
830 // error occurs.
831 //
832 ASDCP::Result_t
833 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
834                        AESEncContext* Ctx, HMACContext* HMAC)
835 {
836   Result_t result = RESULT_OK;
837
838   if ( m_State.Test_READY() )
839     result = m_State.Goto_RUNNING(); // first time through
840  
841   ui64_t StreamOffset = m_StreamOffset;
842
843   if ( ASDCP_SUCCESS(result) )
844     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
845
846   if ( ASDCP_SUCCESS(result) && add_index )
847     {  
848       IndexTableSegment::IndexEntry Entry;
849       Entry.StreamOffset = StreamOffset;
850       m_FooterPart.PushIndexEntry(Entry);
851     }
852
853   m_FramesWritten++;
854   return result;
855 }
856
857
858 // Closes the MXF file, writing the index and other closing information.
859 //
860 ASDCP::Result_t
861 lh__Writer::Finalize()
862 {
863   if ( ! m_State.Test_RUNNING() )
864     return RESULT_STATE;
865
866   m_State.Goto_FINAL();
867
868   return WriteMXFFooter();
869 }
870
871
872 //
873 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
874 {
875   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
876   h__Writer();
877
878 public:
879   h__Writer(const Dictionary& d) : lh__Writer(d) {}
880 };
881
882
883 //------------------------------------------------------------------------------------------
884
885
886
887 ASDCP::JP2K::MXFWriter::MXFWriter()
888 {
889 }
890
891 ASDCP::JP2K::MXFWriter::~MXFWriter()
892 {
893 }
894
895
896 // Open the file for writing. The file must not exist. Returns error if
897 // the operation cannot be completed.
898 ASDCP::Result_t
899 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
900                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
901 {
902   if ( Info.LabelSetType == LS_MXF_SMPTE )
903     m_Writer = new h__Writer(DefaultSMPTEDict());
904   else
905     m_Writer = new h__Writer(DefaultInteropDict());
906
907   m_Writer->m_Info = Info;
908
909   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
910
911   if ( ASDCP_SUCCESS(result) )
912     result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
913
914   if ( ASDCP_FAILURE(result) )
915     m_Writer.release();
916
917   return result;
918 }
919
920
921 // Writes a frame of essence to the MXF file. If the optional AESEncContext
922 // argument is present, the essence is encrypted prior to writing.
923 // Fails if the file is not open, is finalized, or an operating system
924 // error occurs.
925 ASDCP::Result_t
926 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
927 {
928   if ( m_Writer.empty() )
929     return RESULT_INIT;
930
931   return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
932 }
933
934 // Closes the MXF file, writing the index and other closing information.
935 ASDCP::Result_t
936 ASDCP::JP2K::MXFWriter::Finalize()
937 {
938   if ( m_Writer.empty() )
939     return RESULT_INIT;
940
941   return m_Writer->Finalize();
942 }
943
944
945 //------------------------------------------------------------------------------------------
946 //
947
948 //
949 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
950 {
951   ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
952   h__SWriter();
953   StereoscopicPhase_t m_NextPhase;
954
955 public:
956   h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
957
958   //
959   Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
960                       AESEncContext* Ctx, HMACContext* HMAC)
961   {
962     if ( m_NextPhase != phase )
963       return RESULT_SPHASE;
964
965     if ( phase == SP_LEFT )
966       {
967         m_NextPhase = SP_RIGHT;
968         return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
969       }
970
971     m_NextPhase = SP_LEFT;
972     return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
973   }
974
975   //
976   Result_t Finalize()
977   {
978     if ( m_NextPhase != SP_LEFT )
979       return RESULT_SPHASE;
980
981     assert( m_FramesWritten % 2 == 0 );
982     m_FramesWritten /= 2;
983     return lh__Writer::Finalize();
984   }
985 };
986
987
988 //
989 ASDCP::JP2K::MXFSWriter::MXFSWriter()
990 {
991 }
992
993 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
994 {
995 }
996
997
998 // Open the file for writing. The file must not exist. Returns error if
999 // the operation cannot be completed.
1000 ASDCP::Result_t
1001 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1002                                    const PictureDescriptor& PDesc, ui32_t HeaderSize)
1003 {
1004   if ( Info.LabelSetType == LS_MXF_SMPTE )
1005     m_Writer = new h__SWriter(DefaultSMPTEDict());
1006   else
1007     m_Writer = new h__SWriter(DefaultInteropDict());
1008
1009   if ( PDesc.EditRate != ASDCP::EditRate_24 )
1010     {
1011       DefaultLogSink().Error("Stereoscopic wrapping requires 24 fps input streams.\n");
1012       return RESULT_FORMAT;
1013     }
1014
1015   if ( PDesc.StoredWidth > 2048 )
1016     DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1017
1018   m_Writer->m_Info = Info;
1019
1020   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1021
1022   if ( ASDCP_SUCCESS(result) )
1023     {
1024       PictureDescriptor TmpPDesc = PDesc;
1025       TmpPDesc.EditRate = ASDCP::EditRate_48;
1026
1027       result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, ASDCP::EditRate_24);
1028     }
1029
1030   if ( ASDCP_FAILURE(result) )
1031     m_Writer.release();
1032
1033   return result;
1034 }
1035
1036 ASDCP::Result_t
1037 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1038 {
1039   if ( m_Writer.empty() )
1040     return RESULT_INIT;
1041
1042   Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1043
1044   if ( ASDCP_SUCCESS(result) )
1045     result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1046
1047   return result;
1048 }
1049
1050 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1051 // argument is present, the essence is encrypted prior to writing.
1052 // Fails if the file is not open, is finalized, or an operating system
1053 // error occurs.
1054 ASDCP::Result_t
1055 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1056                                     AESEncContext* Ctx, HMACContext* HMAC)
1057 {
1058   if ( m_Writer.empty() )
1059     return RESULT_INIT;
1060
1061   return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1062 }
1063
1064 // Closes the MXF file, writing the index and other closing information.
1065 ASDCP::Result_t
1066 ASDCP::JP2K::MXFSWriter::Finalize()
1067 {
1068   if ( m_Writer.empty() )
1069     return RESULT_INIT;
1070
1071   return m_Writer->Finalize();
1072 }
1073
1074 //
1075 // end AS_DCP_JP2K.cpp
1076 //