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