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