release candidate
[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(&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().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       result = WriteMXFHeader(label, UL(m_Dict->ul(MDD_JPEG_2000Wrapping)),
846                               PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
847                               LocalEditRate, 24 /* TCFrameRate */);
848
849   return result;
850 }
851
852 // Writes a frame of essence to the MXF file. If the optional AESEncContext
853 // argument is present, the essence is encrypted prior to writing.
854 // Fails if the file is not open, is finalized, or an operating system
855 // error occurs.
856 //
857 ASDCP::Result_t
858 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
859                        AESEncContext* Ctx, HMACContext* HMAC)
860 {
861   Result_t result = RESULT_OK;
862
863   if ( m_State.Test_READY() )
864     result = m_State.Goto_RUNNING(); // first time through
865  
866   ui64_t StreamOffset = m_StreamOffset;
867
868   if ( ASDCP_SUCCESS(result) )
869     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
870
871   if ( ASDCP_SUCCESS(result) && add_index )
872     {  
873       IndexTableSegment::IndexEntry Entry;
874       Entry.StreamOffset = StreamOffset;
875       m_FooterPart.PushIndexEntry(Entry);
876     }
877
878   m_FramesWritten++;
879   return result;
880 }
881
882
883 // Closes the MXF file, writing the index and other closing information.
884 //
885 ASDCP::Result_t
886 lh__Writer::Finalize()
887 {
888   if ( ! m_State.Test_RUNNING() )
889     return RESULT_STATE;
890
891   m_State.Goto_FINAL();
892
893   return WriteMXFFooter();
894 }
895
896
897 //
898 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
899 {
900   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
901   h__Writer();
902
903 public:
904   h__Writer(const Dictionary& d) : lh__Writer(d) {}
905 };
906
907
908 //------------------------------------------------------------------------------------------
909
910
911
912 ASDCP::JP2K::MXFWriter::MXFWriter()
913 {
914 }
915
916 ASDCP::JP2K::MXFWriter::~MXFWriter()
917 {
918 }
919
920
921 // Open the file for writing. The file must not exist. Returns error if
922 // the operation cannot be completed.
923 ASDCP::Result_t
924 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
925                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
926 {
927   if ( Info.LabelSetType == LS_MXF_SMPTE )
928     m_Writer = new h__Writer(DefaultSMPTEDict());
929   else
930     m_Writer = new h__Writer(DefaultInteropDict());
931
932   m_Writer->m_Info = Info;
933
934   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
935
936   if ( ASDCP_SUCCESS(result) )
937     result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
938
939   if ( ASDCP_FAILURE(result) )
940     m_Writer.release();
941
942   return result;
943 }
944
945
946 // Writes a frame of essence to the MXF file. If the optional AESEncContext
947 // argument is present, the essence is encrypted prior to writing.
948 // Fails if the file is not open, is finalized, or an operating system
949 // error occurs.
950 ASDCP::Result_t
951 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
952 {
953   if ( m_Writer.empty() )
954     return RESULT_INIT;
955
956   return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
957 }
958
959 // Closes the MXF file, writing the index and other closing information.
960 ASDCP::Result_t
961 ASDCP::JP2K::MXFWriter::Finalize()
962 {
963   if ( m_Writer.empty() )
964     return RESULT_INIT;
965
966   return m_Writer->Finalize();
967 }
968
969
970 //------------------------------------------------------------------------------------------
971 //
972
973 //
974 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
975 {
976   ASDCP_NO_COPY_CONSTRUCT(h__SWriter);
977   h__SWriter();
978   StereoscopicPhase_t m_NextPhase;
979
980 public:
981   h__SWriter(const Dictionary& d) : lh__Writer(d), m_NextPhase(SP_LEFT) {}
982
983   //
984   Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
985                       AESEncContext* Ctx, HMACContext* HMAC)
986   {
987     if ( m_NextPhase != phase )
988       return RESULT_SPHASE;
989
990     if ( phase == SP_LEFT )
991       {
992         m_NextPhase = SP_RIGHT;
993         return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
994       }
995
996     m_NextPhase = SP_LEFT;
997     return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
998   }
999
1000   //
1001   Result_t Finalize()
1002   {
1003     if ( m_NextPhase != SP_LEFT )
1004       return RESULT_SPHASE;
1005
1006     assert( m_FramesWritten % 2 == 0 );
1007     m_FramesWritten /= 2;
1008     return lh__Writer::Finalize();
1009   }
1010 };
1011
1012
1013 //
1014 ASDCP::JP2K::MXFSWriter::MXFSWriter()
1015 {
1016 }
1017
1018 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
1019 {
1020 }
1021
1022
1023 // Open the file for writing. The file must not exist. Returns error if
1024 // the operation cannot be completed.
1025 ASDCP::Result_t
1026 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
1027                                    const PictureDescriptor& PDesc, ui32_t HeaderSize)
1028 {
1029   if ( Info.LabelSetType == LS_MXF_SMPTE )
1030     m_Writer = new h__SWriter(DefaultSMPTEDict());
1031   else
1032     m_Writer = new h__SWriter(DefaultInteropDict());
1033
1034   if ( PDesc.EditRate != ASDCP::EditRate_24
1035        && PDesc.EditRate != ASDCP::EditRate_25
1036        && PDesc.EditRate != ASDCP::EditRate_30 )
1037     {
1038       DefaultLogSink().Error("Stereoscopic wrapping requires 24, 25 or 30 fps input streams.\n");
1039       return RESULT_FORMAT;
1040     }
1041
1042   if ( PDesc.StoredWidth > 2048 )
1043     DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
1044
1045   m_Writer->m_Info = Info;
1046
1047   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
1048
1049   if ( ASDCP_SUCCESS(result) )
1050     {
1051       PictureDescriptor TmpPDesc = PDesc;
1052
1053       if ( PDesc.EditRate == ASDCP::EditRate_24 )
1054         TmpPDesc.EditRate = ASDCP::EditRate_48;
1055
1056       else if ( PDesc.EditRate == ASDCP::EditRate_25 )
1057         TmpPDesc.EditRate = ASDCP::EditRate_50;
1058
1059       else if ( PDesc.EditRate == ASDCP::EditRate_30 )
1060         TmpPDesc.EditRate = ASDCP::EditRate_60;
1061
1062       result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, PDesc.EditRate);
1063     }
1064
1065   if ( ASDCP_FAILURE(result) )
1066     m_Writer.release();
1067
1068   return result;
1069 }
1070
1071 ASDCP::Result_t
1072 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
1073 {
1074   if ( m_Writer.empty() )
1075     return RESULT_INIT;
1076
1077   Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
1078
1079   if ( ASDCP_SUCCESS(result) )
1080     result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
1081
1082   return result;
1083 }
1084
1085 // Writes a frame of essence to the MXF file. If the optional AESEncContext
1086 // argument is present, the essence is encrypted prior to writing.
1087 // Fails if the file is not open, is finalized, or an operating system
1088 // error occurs.
1089 ASDCP::Result_t
1090 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
1091                                     AESEncContext* Ctx, HMACContext* HMAC)
1092 {
1093   if ( m_Writer.empty() )
1094     return RESULT_INIT;
1095
1096   return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
1097 }
1098
1099 // Closes the MXF file, writing the index and other closing information.
1100 ASDCP::Result_t
1101 ASDCP::JP2K::MXFSWriter::Finalize()
1102 {
1103   if ( m_Writer.empty() )
1104     return RESULT_INIT;
1105
1106   return m_Writer->Finalize();
1107 }
1108
1109 //
1110 // end AS_DCP_JP2K.cpp
1111 //