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