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