Commit a bunch of portability fixes (64- vs. 32-bit types).
[asdcplib.git] / src / AS_DCP_JP2K.cpp
1 /*
2 Copyright (c) 2004-2008, 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
34 using namespace ASDCP::JP2K;
35 using Kumu::GenRandomValue;
36
37 //------------------------------------------------------------------------------------------
38
39 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
40 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
41 static std::string PICT_DEF_LABEL = "Picture Track";
42
43 int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
44
45 //
46 void
47 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
48 {
49   if ( stream == 0 )
50     stream = stderr;
51
52   fprintf(stream, "\
53        AspectRatio: %d/%d\n\
54           EditRate: %d/%d\n\
55        StoredWidth: %u\n\
56       StoredHeight: %u\n\
57              Rsize: %u\n\
58              Xsize: %u\n\
59              Ysize: %u\n\
60             XOsize: %u\n\
61             YOsize: %u\n\
62             XTsize: %u\n\
63             YTsize: %u\n\
64            XTOsize: %u\n\
65            YTOsize: %u\n\
66  ContainerDuration: %u\n",
67           PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
68           PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
69           PDesc.StoredWidth,
70           PDesc.StoredHeight,
71           PDesc.Rsize,
72           PDesc.Xsize,
73           PDesc.Ysize,
74           PDesc.XOsize,
75           PDesc.YOsize,
76           PDesc.XTsize,
77           PDesc.YTsize,
78           PDesc.XTOsize,
79           PDesc.YTOsize,
80           PDesc.ContainerDuration
81           );
82
83   fprintf(stream, "-- JPEG 2000 Metadata --\n");
84   fprintf(stream, "    ImageComponents:\n");
85   fprintf(stream, "  bits  h-sep v-sep\n");
86
87   ui32_t i;
88   for ( i = 0; i < PDesc.Csize; i++ )
89     {
90       fprintf(stream, "  %4d  %5d %5d\n",
91               PDesc.ImageComponents[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
92               PDesc.ImageComponents[i].XRsize,
93               PDesc.ImageComponents[i].YRsize
94               );
95     }
96   
97   fprintf(stream, "               Scod: %hd\n", PDesc.CodingStyleDefault.Scod);
98   fprintf(stream, "   ProgressionOrder: %hd\n", PDesc.CodingStyleDefault.SGcod.ProgressionOrder);
99   fprintf(stream, "     NumberOfLayers: %hd\n",
100           KM_i16_BE(Kumu::cp2i<ui16_t>(PDesc.CodingStyleDefault.SGcod.NumberOfLayers)));
101
102   fprintf(stream, " MultiCompTransform: %hd\n", PDesc.CodingStyleDefault.SGcod.MultiCompTransform);
103   fprintf(stream, "DecompositionLevels: %hd\n", PDesc.CodingStyleDefault.SPcod.DecompositionLevels);
104   fprintf(stream, "     CodeblockWidth: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockWidth);
105   fprintf(stream, "    CodeblockHeight: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockHeight);
106   fprintf(stream, "     CodeblockStyle: %hd\n", PDesc.CodingStyleDefault.SPcod.CodeblockStyle);
107   fprintf(stream, "     Transformation: %hd\n", PDesc.CodingStyleDefault.SPcod.Transformation);
108
109
110   ui32_t precinct_set_size = 0;
111
112   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
113     precinct_set_size++;
114
115   fprintf(stream, "          Precincts: %hd\n", precinct_set_size);
116   fprintf(stream, "precinct dimensions:\n");
117
118   for ( i = 0; i < precinct_set_size; i++ )
119     fprintf(stream, "    %d: %d x %d\n", i + 1,
120             s_exp_lookup[PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]&0x0f],
121             s_exp_lookup[(PDesc.CodingStyleDefault.SPcod.PrecinctSize[i]>>4)&0x0f]
122             );
123
124   fprintf(stream, "               Sqcd: %hd\n", PDesc.QuantizationDefault.Sqcd);
125
126   char tmp_buf[MaxDefaults*2];
127   fprintf(stream, "              SPqcd: %s\n",
128           Kumu::bin2hex(PDesc.QuantizationDefault.SPqcd, PDesc.QuantizationDefault.SPqcdLength,
129                         tmp_buf, MaxDefaults*2)
130           );
131 }
132
133 //------------------------------------------------------------------------------------------
134 //
135 // hidden, internal implementation of JPEG 2000 reader
136
137 class lh__Reader : public ASDCP::h__Reader
138 {
139   RGBAEssenceDescriptor*        m_EssenceDescriptor;
140   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
141   ASDCP::Rational               m_EditRate;
142   EssenceType_t                 m_Format;
143
144   ASDCP_NO_COPY_CONSTRUCT(lh__Reader);
145
146 public:
147   PictureDescriptor m_PDesc;        // codestream parameter list
148
149   lh__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
150   Result_t    OpenRead(const char*, EssenceType_t);
151   Result_t    ReadFrame(ui32_t, JP2K::FrameBuffer&, AESDecContext*, HMACContext*);
152   Result_t    MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
153 };
154
155 //
156 ASDCP::Result_t
157 lh__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
158 {
159   memset(&PDesc, 0, sizeof(PDesc));
160   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
161
162   PDesc.EditRate           = m_EditRate;
163   assert(PDescObj->ContainerDuration <= 0xFFFFFFFFL);
164   PDesc.ContainerDuration  = (ui32_t) PDescObj->ContainerDuration;
165   PDesc.StoredWidth        = PDescObj->StoredWidth;
166   PDesc.StoredHeight       = PDescObj->StoredHeight;
167   PDesc.AspectRatio        = PDescObj->AspectRatio;
168
169   if ( m_EssenceSubDescriptor != 0 )
170     {
171       PDesc.Rsize   = m_EssenceSubDescriptor->Rsize;
172       PDesc.Xsize   = m_EssenceSubDescriptor->Xsize;
173       PDesc.Ysize   = m_EssenceSubDescriptor->Ysize;
174       PDesc.XOsize  = m_EssenceSubDescriptor->XOsize;
175       PDesc.YOsize  = m_EssenceSubDescriptor->YOsize;
176       PDesc.XTsize  = m_EssenceSubDescriptor->XTsize;
177       PDesc.YTsize  = m_EssenceSubDescriptor->YTsize;
178       PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
179       PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
180       PDesc.Csize   = m_EssenceSubDescriptor->Csize;
181
182       // PictureComponentSizing
183       ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
184
185       if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
186         memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
187
188       else
189         DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
190
191       // CodingStyleDefault
192       memset(&m_PDesc.CodingStyleDefault, 0, sizeof(CodingStyleDefault_t));
193       memcpy(&m_PDesc.CodingStyleDefault,
194              m_EssenceSubDescriptor->CodingStyleDefault.RoData(),
195              m_EssenceSubDescriptor->CodingStyleDefault.Length());
196
197       // QuantizationDefault
198       memset(&m_PDesc.QuantizationDefault, 0, sizeof(QuantizationDefault_t));
199       memcpy(&m_PDesc.QuantizationDefault,
200              m_EssenceSubDescriptor->QuantizationDefault.RoData(),
201              m_EssenceSubDescriptor->QuantizationDefault.Length());
202
203       m_PDesc.QuantizationDefault.SPqcdLength = m_EssenceSubDescriptor->QuantizationDefault.Length() - 1;
204     }
205
206   return RESULT_OK;
207 }
208
209 //
210 //
211 ASDCP::Result_t
212 lh__Reader::OpenRead(const char* filename, EssenceType_t type)
213 {
214   Result_t result = OpenMXFRead(filename);
215
216   if( ASDCP_SUCCESS(result) )
217     {
218       InterchangeObject* tmp_iobj = 0;
219       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), &tmp_iobj);
220       m_EssenceDescriptor = static_cast<RGBAEssenceDescriptor*>(tmp_iobj);
221
222       m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), &tmp_iobj);
223       m_EssenceSubDescriptor = static_cast<JPEG2000PictureSubDescriptor*>(tmp_iobj);
224
225       std::list<InterchangeObject*> ObjectList;
226       m_HeaderPart.GetMDObjectsByType(OBJ_TYPE_ARGS(Track), ObjectList);
227
228       if ( ObjectList.empty() )
229         {
230           DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
231           return RESULT_FORMAT;
232         }
233
234       m_EditRate = ((Track*)ObjectList.front())->EditRate;
235
236       if ( type == ASDCP::ESS_JPEG_2000 )
237         {
238           if ( m_EditRate != m_EssenceDescriptor->SampleRate )
239             {
240               DefaultLogSink().Error("EditRate and SampleRate do not match (%.03f, %.03f).\n",
241                                      m_EditRate.Quotient(), m_EssenceDescriptor->SampleRate.Quotient());
242               
243               if ( m_EditRate == EditRate_24 && m_EssenceDescriptor->SampleRate == EditRate_48 )
244                 {
245                   DefaultLogSink().Error("File may contain JPEG Interop stereoscopic images.\n");
246                   return RESULT_SFORMAT;
247                 }
248
249               return RESULT_FORMAT;
250             }
251         }
252       else if ( type == ASDCP::ESS_JPEG_2000_S )
253         {
254           if ( ! ( m_EditRate == EditRate_24 && m_EssenceDescriptor->SampleRate == EditRate_48 ) )
255             {
256               DefaultLogSink().Error("EditRate and SampleRate not correct for 24/48 stereoscopic essence.\n");
257               return RESULT_FORMAT;
258             }
259         }
260       else
261         {
262           DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
263           return RESULT_STATE;
264         }
265
266       result = MD_to_JP2K_PDesc(m_PDesc);
267     }
268
269   if( ASDCP_SUCCESS(result) )
270     result = InitMXFIndex();
271
272   if( ASDCP_SUCCESS(result) )
273     result = InitInfo();
274
275   return result;
276 }
277
278 //
279 //
280 ASDCP::Result_t
281 lh__Reader::ReadFrame(ui32_t FrameNum, JP2K::FrameBuffer& FrameBuf,
282                       AESDecContext* Ctx, HMACContext* HMAC)
283 {
284   if ( ! m_File.IsOpen() )
285     return RESULT_INIT;
286
287   return ReadEKLVFrame(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
288 }
289
290
291 //
292 class ASDCP::JP2K::MXFReader::h__Reader : public lh__Reader
293 {
294 };
295
296
297
298 //------------------------------------------------------------------------------------------
299
300
301 //
302 void
303 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
304 {
305   if ( stream == 0 )
306     stream = stderr;
307
308   fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
309   
310   fputc('\n', stream);
311
312   if ( dump_len > 0 )
313     Kumu::hexdump(m_Data, dump_len, stream);
314 }
315
316
317 //------------------------------------------------------------------------------------------
318
319 ASDCP::JP2K::MXFReader::MXFReader()
320 {
321   m_Reader = new h__Reader;
322 }
323
324
325 ASDCP::JP2K::MXFReader::~MXFReader()
326 {
327 }
328
329 // Open the file for reading. The file must exist. Returns error if the
330 // operation cannot be completed.
331 ASDCP::Result_t
332 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
333 {
334   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000);
335 }
336
337 //
338 ASDCP::Result_t
339 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
340                                    AESDecContext* Ctx, HMACContext* HMAC) const
341 {
342   if ( m_Reader && m_Reader->m_File.IsOpen() )
343     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
344
345   return RESULT_INIT;
346 }
347
348
349 // Fill the struct with the values from the file's header.
350 // Returns RESULT_INIT if the file is not open.
351 ASDCP::Result_t
352 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
353 {
354   if ( m_Reader && m_Reader->m_File.IsOpen() )
355     {
356       PDesc = m_Reader->m_PDesc;
357       return RESULT_OK;
358     }
359
360   return RESULT_INIT;
361 }
362
363
364 // Fill the struct with the values from the file's header.
365 // Returns RESULT_INIT if the file is not open.
366 ASDCP::Result_t
367 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
368 {
369   if ( m_Reader && m_Reader->m_File.IsOpen() )
370     {
371       Info = m_Reader->m_Info;
372       return RESULT_OK;
373     }
374
375   return RESULT_INIT;
376 }
377
378 //
379 void
380 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
381 {
382   if ( m_Reader->m_File.IsOpen() )
383     m_Reader->m_HeaderPart.Dump(stream);
384 }
385
386
387 //
388 void
389 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
390 {
391   if ( m_Reader->m_File.IsOpen() )
392     m_Reader->m_FooterPart.Dump(stream);
393 }
394
395
396 //------------------------------------------------------------------------------------------
397
398 class ASDCP::JP2K::MXFSReader::h__SReader : public lh__Reader
399 {
400   ui32_t m_StereoFrameReady;
401
402 public:
403   h__SReader() : m_StereoFrameReady(0xffffffff) {}
404
405   //
406   Result_t ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
407                      AESDecContext* Ctx, HMACContext* HMAC)
408   {
409     // look up frame index node
410     IndexTableSegment::IndexEntry TmpEntry;
411
412     if ( ASDCP_FAILURE(m_FooterPart.Lookup(FrameNum, TmpEntry)) )
413       {
414         DefaultLogSink().Error("Frame value out of range: %u\n", FrameNum);
415         return RESULT_RANGE;
416       }
417
418     // get frame position
419     Kumu::fpos_t FilePosition = m_EssenceStart + TmpEntry.StreamOffset;
420     Result_t result = RESULT_OK;
421
422     if ( phase == SP_LEFT )
423       {    
424         if ( FilePosition != m_LastPosition )
425           {
426             m_LastPosition = FilePosition;
427             result = m_File.Seek(FilePosition);
428           }
429
430         // the call to ReadEKLVPacket() will leave the file on an R frame
431         m_StereoFrameReady = FrameNum;
432       }
433     else if ( phase == SP_RIGHT )
434       {
435         if ( m_StereoFrameReady != FrameNum )
436           {
437             // the file is not already positioned, we must do some work
438             // seek to the companion SP_LEFT frame and read the frame's key and length
439             if ( FilePosition != m_LastPosition )
440               {
441                 m_LastPosition = FilePosition;
442                 result = m_File.Seek(FilePosition);
443               }
444
445             KLReader Reader;
446             result = Reader.ReadKLFromFile(m_File);
447
448             if ( ASDCP_SUCCESS(result) )
449               {
450                 // skip over the companion SP_LEFT frame
451                 Kumu::fpos_t new_pos = FilePosition + SMPTE_UL_LENGTH + Reader.KLLength() + Reader.Length();
452                 result = m_File.Seek(new_pos);
453               }
454           }
455
456         // the call to ReadEKLVPacket() will leave the file not on an R frame
457         m_StereoFrameReady = 0xffffffff;
458       }
459     else
460       {
461         DefaultLogSink().Error("Unexpected stereoscopic phase value: %u\n", phase);
462         return RESULT_STATE;
463       }
464
465     if( ASDCP_SUCCESS(result) )
466       {
467         ui32_t SequenceNum = FrameNum * 2;
468         SequenceNum += ( phase == SP_RIGHT ) ? 2 : 1;
469         result = ReadEKLVPacket(FrameNum, SequenceNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
470       }
471
472     return result;
473   }
474 };
475
476
477
478 ASDCP::JP2K::MXFSReader::MXFSReader()
479 {
480   m_Reader = new h__SReader;
481 }
482
483
484 ASDCP::JP2K::MXFSReader::~MXFSReader()
485 {
486 }
487
488 // Open the file for reading. The file must exist. Returns error if the
489 // operation cannot be completed.
490 ASDCP::Result_t
491 ASDCP::JP2K::MXFSReader::OpenRead(const char* filename) const
492 {
493   return m_Reader->OpenRead(filename, ASDCP::ESS_JPEG_2000_S);
494 }
495
496 //
497 ASDCP::Result_t
498 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, SFrameBuffer& FrameBuf, AESDecContext* Ctx, HMACContext* HMAC) const
499 {
500   Result_t result = RESULT_INIT;
501
502   if ( m_Reader && m_Reader->m_File.IsOpen() )
503     {
504       result = m_Reader->ReadFrame(FrameNum, SP_LEFT, FrameBuf.Left, Ctx, HMAC);
505
506       if ( ASDCP_SUCCESS(result) )
507         result = m_Reader->ReadFrame(FrameNum, SP_RIGHT, FrameBuf.Right, Ctx, HMAC);
508     }
509
510   return result;
511 }
512
513 //
514 ASDCP::Result_t
515 ASDCP::JP2K::MXFSReader::ReadFrame(ui32_t FrameNum, StereoscopicPhase_t phase, FrameBuffer& FrameBuf,
516                                    AESDecContext* Ctx, HMACContext* HMAC) const
517 {
518   if ( m_Reader && m_Reader->m_File.IsOpen() )
519     return m_Reader->ReadFrame(FrameNum, phase, FrameBuf, Ctx, HMAC);
520
521   return RESULT_INIT;
522 }
523
524 // Fill the struct with the values from the file's header.
525 // Returns RESULT_INIT if the file is not open.
526 ASDCP::Result_t
527 ASDCP::JP2K::MXFSReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
528 {
529   if ( m_Reader && m_Reader->m_File.IsOpen() )
530     {
531       PDesc = m_Reader->m_PDesc;
532       return RESULT_OK;
533     }
534
535   return RESULT_INIT;
536 }
537
538
539 // Fill the struct with the values from the file's header.
540 // Returns RESULT_INIT if the file is not open.
541 ASDCP::Result_t
542 ASDCP::JP2K::MXFSReader::FillWriterInfo(WriterInfo& Info) const
543 {
544   if ( m_Reader && m_Reader->m_File.IsOpen() )
545     {
546       Info = m_Reader->m_Info;
547       return RESULT_OK;
548     }
549
550   return RESULT_INIT;
551 }
552
553 //
554 void
555 ASDCP::JP2K::MXFSReader::DumpHeaderMetadata(FILE* stream) const
556 {
557   if ( m_Reader->m_File.IsOpen() )
558     m_Reader->m_HeaderPart.Dump(stream);
559 }
560
561
562 //
563 void
564 ASDCP::JP2K::MXFSReader::DumpIndex(FILE* stream) const
565 {
566   if ( m_Reader->m_File.IsOpen() )
567     m_Reader->m_FooterPart.Dump(stream);
568 }
569
570 //------------------------------------------------------------------------------------------
571
572
573 //
574 class lh__Writer : public ASDCP::h__Writer
575 {
576   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
577
578 public:
579   PictureDescriptor m_PDesc;
580   byte_t            m_EssenceUL[SMPTE_UL_LENGTH];
581
582   ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
583
584   lh__Writer() : m_EssenceSubDescriptor(0) {
585     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
586   }
587
588   ~lh__Writer(){}
589
590   Result_t OpenWrite(const char*, EssenceType_t type, ui32_t HeaderSize);
591   Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
592                            ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
593   Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
594   Result_t Finalize();
595   Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
596 };
597
598 const int VideoLineMapSize = 16; // See SMPTE 377M D.2.1
599 const int PixelLayoutSize = 8*2; // See SMPTE 377M D.2.3
600 static const byte_t s_PixelLayoutXYZ[PixelLayoutSize] = { 0xd8, 0x0c, 0xd9, 0x0c, 0xda, 0x0c, 0x00 };
601
602 //
603 ASDCP::Result_t
604 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
605 {
606   assert(m_EssenceDescriptor);
607   assert(m_EssenceSubDescriptor);
608   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
609
610   PDescObj->ContainerDuration = PDesc.ContainerDuration;
611   PDescObj->SampleRate = PDesc.EditRate;
612   PDescObj->FrameLayout = 0;
613   PDescObj->StoredWidth = PDesc.StoredWidth;
614   PDescObj->StoredHeight = PDesc.StoredHeight;
615   PDescObj->AspectRatio = PDesc.AspectRatio;
616
617   //  if ( m_Info.LabelSetType == LS_MXF_SMPTE )
618   //    {
619   // PictureEssenceCoding UL = 
620   // Video Line Map       ui32_t[VideoLineMapSize] = { 2, 4, 0, 0 }
621   // CaptureGamma         UL = 
622   // ComponentMaxRef      ui32_t = 4095
623   // ComponentMinRef      ui32_t = 0
624   // PixelLayout          byte_t[PixelLayoutSize] = s_PixelLayoutXYZ
625   //    }
626
627   if ( PDesc.StoredWidth < 2049 )
628     {
629       PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_2K));
630       m_EssenceSubDescriptor->Rsize = 3;
631     }
632   else
633     {
634       PDescObj->PictureEssenceCoding.Set(Dict::ul(MDD_JP2KEssenceCompression_4K));
635       m_EssenceSubDescriptor->Rsize = 4;
636     }
637
638   m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
639   m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
640   m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
641   m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
642   m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
643   m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
644   m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
645   m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
646   m_EssenceSubDescriptor->Csize = PDesc.Csize;
647
648   const ui32_t tmp_buffer_len = 1024;
649   byte_t tmp_buffer[tmp_buffer_len];
650
651   *(ui32_t*)tmp_buffer = KM_i32_BE(MaxComponents); // three components
652   *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(sizeof(ASDCP::JP2K::ImageComponent_t));
653   memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
654
655   const ui32_t pcomp_size = (sizeof(int) * 2) + (sizeof(ASDCP::JP2K::ImageComponent_t) * MaxComponents);
656   memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, pcomp_size);
657   m_EssenceSubDescriptor->PictureComponentSizing.Length(pcomp_size);
658
659   ui32_t precinct_set_size = 0, i;
660   for ( i = 0; PDesc.CodingStyleDefault.SPcod.PrecinctSize[i] != 0 && i < MaxPrecincts; i++ )
661     precinct_set_size++;
662
663   ui32_t csd_size = sizeof(CodingStyleDefault_t) - MaxPrecincts + precinct_set_size;
664   memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), &PDesc.CodingStyleDefault, csd_size);
665   m_EssenceSubDescriptor->CodingStyleDefault.Length(csd_size);
666
667   ui32_t qdflt_size = PDesc.QuantizationDefault.SPqcdLength + 1;
668   memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), &PDesc.QuantizationDefault, qdflt_size);
669   m_EssenceSubDescriptor->QuantizationDefault.Length(qdflt_size);
670
671   return RESULT_OK;
672 }
673
674
675 // Open the file for writing. The file must not exist. Returns error if
676 // the operation cannot be completed.
677 ASDCP::Result_t
678 lh__Writer::OpenWrite(const char* filename, EssenceType_t type, ui32_t HeaderSize)
679 {
680   if ( ! m_State.Test_BEGIN() )
681     return RESULT_STATE;
682
683   Result_t result = m_File.OpenWrite(filename);
684
685   if ( ASDCP_SUCCESS(result) )
686     {
687       m_HeaderSize = HeaderSize;
688       RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor;
689       tmp_rgba->ComponentMaxRef = 4095;
690       tmp_rgba->ComponentMinRef = 0;
691
692       m_EssenceDescriptor = tmp_rgba;
693       m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
694       m_EssenceSubDescriptorList.push_back((InterchangeObject*)m_EssenceSubDescriptor);
695
696       GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
697       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
698
699       if ( type == ASDCP::ESS_JPEG_2000_S && m_Info.LabelSetType == LS_MXF_SMPTE )
700         {
701           InterchangeObject* StereoSubDesc = new StereoscopicPictureSubDescriptor;
702           m_EssenceSubDescriptorList.push_back(StereoSubDesc);
703           GenRandomValue(StereoSubDesc->InstanceUID);
704           m_EssenceDescriptor->SubDescriptors.push_back(StereoSubDesc->InstanceUID);
705         }
706
707       result = m_State.Goto_INIT();
708     }
709
710   return result;
711 }
712
713 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
714 ASDCP::Result_t
715 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
716 {
717   if ( ! m_State.Test_INIT() )
718     return RESULT_STATE;
719
720   if ( LocalEditRate == ASDCP::Rational(0,0) )
721     LocalEditRate = PDesc.EditRate;
722
723   m_PDesc = PDesc;
724   Result_t result = JP2K_PDesc_to_MD(m_PDesc);
725
726   if ( ASDCP_SUCCESS(result) )
727       result = WriteMXFHeader(label, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
728                               PICT_DEF_LABEL,     UL(Dict::ul(MDD_PictureDataDef)),
729                               LocalEditRate, 24 /* TCFrameRate */);
730
731   if ( ASDCP_SUCCESS(result) )
732     {
733       memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
734       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
735       result = m_State.Goto_READY();
736     }
737
738   return result;
739 }
740
741 // Writes a frame of essence to the MXF file. If the optional AESEncContext
742 // argument is present, the essence is encrypted prior to writing.
743 // Fails if the file is not open, is finalized, or an operating system
744 // error occurs.
745 //
746 ASDCP::Result_t
747 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
748                        AESEncContext* Ctx, HMACContext* HMAC)
749 {
750   Result_t result = RESULT_OK;
751
752   if ( m_State.Test_READY() )
753     result = m_State.Goto_RUNNING(); // first time through
754  
755   ui64_t StreamOffset = m_StreamOffset;
756
757   if ( ASDCP_SUCCESS(result) )
758     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
759
760   if ( ASDCP_SUCCESS(result) && add_index )
761     {  
762       IndexTableSegment::IndexEntry Entry;
763       Entry.StreamOffset = StreamOffset;
764       m_FooterPart.PushIndexEntry(Entry);
765     }
766
767   m_FramesWritten++;
768   return result;
769 }
770
771
772 // Closes the MXF file, writing the index and other closing information.
773 //
774 ASDCP::Result_t
775 lh__Writer::Finalize()
776 {
777   if ( ! m_State.Test_RUNNING() )
778     return RESULT_STATE;
779
780   m_State.Goto_FINAL();
781
782   return WriteMXFFooter();
783 }
784
785
786 //
787 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
788 {
789 };
790
791
792 //------------------------------------------------------------------------------------------
793
794
795
796 ASDCP::JP2K::MXFWriter::MXFWriter()
797 {
798 }
799
800 ASDCP::JP2K::MXFWriter::~MXFWriter()
801 {
802 }
803
804
805 // Open the file for writing. The file must not exist. Returns error if
806 // the operation cannot be completed.
807 ASDCP::Result_t
808 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
809                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
810 {
811   m_Writer = new h__Writer;
812   m_Writer->m_Info = Info;
813
814   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000, HeaderSize);
815
816   if ( ASDCP_SUCCESS(result) )
817     result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
818
819   if ( ASDCP_FAILURE(result) )
820     m_Writer.release();
821
822   return result;
823 }
824
825
826 // Writes a frame of essence to the MXF file. If the optional AESEncContext
827 // argument is present, the essence is encrypted prior to writing.
828 // Fails if the file is not open, is finalized, or an operating system
829 // error occurs.
830 ASDCP::Result_t
831 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
832 {
833   if ( m_Writer.empty() )
834     return RESULT_INIT;
835
836   return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
837 }
838
839 // Closes the MXF file, writing the index and other closing information.
840 ASDCP::Result_t
841 ASDCP::JP2K::MXFWriter::Finalize()
842 {
843   if ( m_Writer.empty() )
844     return RESULT_INIT;
845
846   return m_Writer->Finalize();
847 }
848
849
850 //------------------------------------------------------------------------------------------
851 //
852
853 //
854 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
855 {
856   StereoscopicPhase_t m_NextPhase;
857
858 public:
859   h__SWriter() : m_NextPhase(SP_LEFT) {}
860
861   //
862   Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
863                       AESEncContext* Ctx, HMACContext* HMAC)
864   {
865     if ( m_NextPhase != phase )
866       return RESULT_SPHASE;
867
868     if ( phase == SP_LEFT )
869       {
870         m_NextPhase = SP_RIGHT;
871         return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
872       }
873
874     m_NextPhase = SP_LEFT;
875     return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
876   }
877
878   //
879   Result_t Finalize()
880   {
881     if ( m_NextPhase != SP_LEFT )
882       return RESULT_SPHASE;
883
884     assert( m_FramesWritten % 2 == 0 );
885     m_FramesWritten /= 2;
886     return lh__Writer::Finalize();
887   }
888 };
889
890
891 //
892 ASDCP::JP2K::MXFSWriter::MXFSWriter()
893 {
894 }
895
896 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
897 {
898 }
899
900
901 // Open the file for writing. The file must not exist. Returns error if
902 // the operation cannot be completed.
903 ASDCP::Result_t
904 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
905                                    const PictureDescriptor& PDesc, ui32_t HeaderSize)
906 {
907   m_Writer = new h__SWriter;
908   
909   if ( PDesc.EditRate != ASDCP::EditRate_24 )
910     {
911       DefaultLogSink().Error("Stereoscopic wrapping requires 24 fps input streams.\n");
912       return RESULT_FORMAT;
913     }
914
915   if ( PDesc.StoredWidth > 2048 )
916     DefaultLogSink().Warn("Wrapping non-standard 4K stereoscopic content. I hope you know what you are doing!\n");
917
918   m_Writer->m_Info = Info;
919
920   Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_2000_S, HeaderSize);
921
922   if ( ASDCP_SUCCESS(result) )
923     {
924       PictureDescriptor TmpPDesc = PDesc;
925       TmpPDesc.EditRate = ASDCP::EditRate_48;
926
927       result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, ASDCP::EditRate_24);
928     }
929
930   if ( ASDCP_FAILURE(result) )
931     m_Writer.release();
932
933   return result;
934 }
935
936 ASDCP::Result_t
937 ASDCP::JP2K::MXFSWriter::WriteFrame(const SFrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
938 {
939   if ( m_Writer.empty() )
940     return RESULT_INIT;
941
942   Result_t result = m_Writer->WriteFrame(FrameBuf.Left, SP_LEFT, Ctx, HMAC);
943
944   if ( ASDCP_SUCCESS(result) )
945     result = m_Writer->WriteFrame(FrameBuf.Right, SP_RIGHT, Ctx, HMAC);
946
947   return result;
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::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
956                                     AESEncContext* Ctx, HMACContext* HMAC)
957 {
958   if ( m_Writer.empty() )
959     return RESULT_INIT;
960
961   return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
962 }
963
964 // Closes the MXF file, writing the index and other closing information.
965 ASDCP::Result_t
966 ASDCP::JP2K::MXFSWriter::Finalize()
967 {
968   if ( m_Writer.empty() )
969     return RESULT_INIT;
970
971   return m_Writer->Finalize();
972 }
973
974 //
975 // end AS_DCP_JP2K.cpp
976 //