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