a0e84631a3a96875d2be8ca1b7f787608ea2d4cb
[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
35 //------------------------------------------------------------------------------------------
36
37 static std::string JP2K_PACKAGE_LABEL = "File Package: SMPTE 429-4 frame wrapping of JPEG 2000 codestreams";
38 static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG 2000 codestreams";
39 static std::string PICT_DEF_LABEL = "Picture Track";
40
41 //
42 void
43 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
44 {
45   if ( stream == 0 )
46     stream = stderr;
47
48   fprintf(stream, "\
49        AspectRatio: %d/%d\n\
50           EditRate: %d/%d\n\
51        StoredWidth: %u\n\
52       StoredHeight: %u\n\
53              Rsize: %u\n\
54              Xsize: %u\n\
55              Ysize: %u\n\
56             XOsize: %u\n\
57             YOsize: %u\n\
58             XTsize: %u\n\
59             YTsize: %u\n\
60            XTOsize: %u\n\
61            YTOsize: %u\n\
62  ContainerDuration: %u\n",
63           PDesc.AspectRatio.Numerator ,PDesc.AspectRatio.Denominator,
64           PDesc.EditRate.Numerator ,PDesc.EditRate.Denominator,
65           PDesc.StoredWidth,
66           PDesc.StoredHeight,
67           PDesc.Rsize,
68           PDesc.Xsize,
69           PDesc.Ysize,
70           PDesc.XOsize,
71           PDesc.YOsize,
72           PDesc.XTsize,
73           PDesc.YTsize,
74           PDesc.XTOsize,
75           PDesc.YTOsize,
76           PDesc.ContainerDuration
77           );
78
79   fprintf(stream, "Color Components:\n");
80
81   for ( ui32_t i = 0; i < PDesc.Csize; i++ )
82     {
83       fprintf(stream, "  %u.%u.%u\n",
84               PDesc.ImageComponents[i].Ssize,
85               PDesc.ImageComponents[i].XRsize,
86               PDesc.ImageComponents[i].YRsize
87               );
88     }
89
90   const ui32_t tmp_buf_len = 256;
91   char tmp_buf[tmp_buf_len];
92
93   if ( PDesc.CodingStyleLength )
94     fprintf(stream, "Default Coding (%u): %s\n",
95             PDesc.CodingStyleLength,
96             Kumu::bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength, tmp_buf, tmp_buf_len)
97             );
98
99   if ( PDesc.QuantDefaultLength )
100     fprintf(stream, "Quantization Default (%u): %s\n",
101             PDesc.QuantDefaultLength,
102             Kumu::bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength, tmp_buf, tmp_buf_len)
103             );
104 }
105
106 //------------------------------------------------------------------------------------------
107 //
108 // hidden, internal implementation of JPEG 2000 reader
109
110 class ASDCP::JP2K::MXFReader::h__Reader : public ASDCP::h__Reader
111 {
112   RGBAEssenceDescriptor*        m_EssenceDescriptor;
113   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
114
115   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
116
117 public:
118   PictureDescriptor m_PDesc;        // codestream parameter list
119
120   h__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0) {}
121   Result_t    OpenRead(const char*);
122   Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
123   Result_t    MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
124 };
125
126 //
127 ASDCP::Result_t
128 ASDCP::JP2K::MXFReader::h__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
129 {
130   memset(&PDesc, 0, sizeof(PDesc));
131   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
132
133   PDesc.EditRate           = PDescObj->SampleRate;
134   PDesc.ContainerDuration  = PDescObj->ContainerDuration;
135   PDesc.StoredWidth        = PDescObj->StoredWidth;
136   PDesc.StoredHeight       = PDescObj->StoredHeight;
137   PDesc.AspectRatio        = PDescObj->AspectRatio;
138
139   if ( m_EssenceSubDescriptor != 0 )
140     {
141       PDesc.Rsize   = m_EssenceSubDescriptor->Rsize;
142       PDesc.Xsize   = m_EssenceSubDescriptor->Xsize;
143       PDesc.Ysize   = m_EssenceSubDescriptor->Ysize;
144       PDesc.XOsize  = m_EssenceSubDescriptor->XOsize;
145       PDesc.YOsize  = m_EssenceSubDescriptor->YOsize;
146       PDesc.XTsize  = m_EssenceSubDescriptor->XTsize;
147       PDesc.YTsize  = m_EssenceSubDescriptor->YTsize;
148       PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
149       PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
150       PDesc.Csize   = m_EssenceSubDescriptor->Csize;
151
152       // PictureComponentSizing
153       ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Length();
154
155       if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
156         memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
157
158       else
159         DefaultLogSink().Error("Unexpected PictureComponentSizing size: %u, should be 17\n", tmp_size);
160
161       // CodingStyleDefault
162       if ( ( PDesc.CodingStyleLength = m_EssenceSubDescriptor->CodingStyleDefault.Length() ) != 0 )
163         memcpy(PDesc.CodingStyle, m_EssenceSubDescriptor->CodingStyleDefault.RoData(), PDesc.CodingStyleLength);
164
165       // QuantizationDefault
166       if ( ( PDesc.QuantDefaultLength = m_EssenceSubDescriptor->QuantizationDefault.Length() ) != 0 )
167         memcpy(PDesc.QuantDefault, m_EssenceSubDescriptor->QuantizationDefault.RoData(), PDesc.QuantDefaultLength);
168     }
169
170   return RESULT_OK;
171 }
172
173 //
174 //
175 ASDCP::Result_t
176 ASDCP::JP2K::MXFReader::h__Reader::OpenRead(const char* filename)
177 {
178   Result_t result = OpenMXFRead(filename);
179
180   if( ASDCP_SUCCESS(result) )
181     {
182       if ( m_EssenceDescriptor == 0 )
183         {
184           m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), (InterchangeObject**)&m_EssenceDescriptor);
185           m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), (InterchangeObject**)&m_EssenceSubDescriptor);
186         }
187
188       result = MD_to_JP2K_PDesc(m_PDesc);
189     }
190
191   if( ASDCP_SUCCESS(result) )
192     result = InitMXFIndex();
193
194   if( ASDCP_SUCCESS(result) )
195     result = InitInfo();
196
197   return result;
198 }
199
200 //
201 //
202 ASDCP::Result_t
203 ASDCP::JP2K::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
204                                               AESDecContext* Ctx, HMACContext* HMAC)
205 {
206   if ( ! m_File.IsOpen() )
207     return RESULT_INIT;
208
209   return ReadEKLVFrame(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
210 }
211
212 //------------------------------------------------------------------------------------------
213
214
215 //
216 void
217 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
218 {
219   if ( stream == 0 )
220     stream = stderr;
221
222   fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
223   
224   fputc('\n', stream);
225
226   if ( dump_len > 0 )
227     Kumu::hexdump(m_Data, dump_len, stream);
228 }
229
230
231 //------------------------------------------------------------------------------------------
232
233 ASDCP::JP2K::MXFReader::MXFReader()
234 {
235   m_Reader = new h__Reader;
236 }
237
238
239 ASDCP::JP2K::MXFReader::~MXFReader()
240 {
241 }
242
243 // Open the file for reading. The file must exist. Returns error if the
244 // operation cannot be completed.
245 ASDCP::Result_t
246 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
247 {
248   return m_Reader->OpenRead(filename);
249 }
250
251 //
252 ASDCP::Result_t
253 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
254                                    AESDecContext* Ctx, HMACContext* HMAC) const
255 {
256   if ( m_Reader && m_Reader->m_File.IsOpen() )
257     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
258
259   return RESULT_INIT;
260 }
261
262
263 // Fill the struct with the values from the file's header.
264 // Returns RESULT_INIT if the file is not open.
265 ASDCP::Result_t
266 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
267 {
268   if ( m_Reader && m_Reader->m_File.IsOpen() )
269     {
270       PDesc = m_Reader->m_PDesc;
271       return RESULT_OK;
272     }
273
274   return RESULT_INIT;
275 }
276
277
278 // Fill the struct with the values from the file's header.
279 // Returns RESULT_INIT if the file is not open.
280 ASDCP::Result_t
281 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
282 {
283   if ( m_Reader && m_Reader->m_File.IsOpen() )
284     {
285       Info = m_Reader->m_Info;
286       return RESULT_OK;
287     }
288
289   return RESULT_INIT;
290 }
291
292 //
293 void
294 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
295 {
296   if ( m_Reader->m_File.IsOpen() )
297     m_Reader->m_HeaderPart.Dump(stream);
298 }
299
300
301 //
302 void
303 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
304 {
305   if ( m_Reader->m_File.IsOpen() )
306     m_Reader->m_FooterPart.Dump(stream);
307 }
308
309
310 //------------------------------------------------------------------------------------------
311
312
313 using namespace ASDCP::JP2K;
314
315 //
316 class lh__Writer : public ASDCP::h__Writer
317 {
318   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
319
320 public:
321   PictureDescriptor m_PDesc;
322   byte_t            m_EssenceUL[SMPTE_UL_LENGTH];
323
324   ASDCP_NO_COPY_CONSTRUCT(lh__Writer);
325
326   lh__Writer() : m_EssenceSubDescriptor(0) {
327     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
328   }
329
330   ~lh__Writer(){}
331
332   Result_t OpenWrite(const char*, ui32_t HeaderSize);
333   Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
334                            ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
335   Result_t WriteFrame(const JP2K::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
336   Result_t Finalize();
337   Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
338 };
339
340
341 //
342 ASDCP::Result_t
343 lh__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
344 {
345   assert(m_EssenceDescriptor);
346   assert(m_EssenceSubDescriptor);
347   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
348
349   PDescObj->SampleRate = PDesc.EditRate;
350   PDescObj->ContainerDuration = PDesc.ContainerDuration;
351   PDescObj->StoredWidth = PDesc.StoredWidth;
352   PDescObj->StoredHeight = PDesc.StoredHeight;
353   PDescObj->AspectRatio = PDesc.AspectRatio;
354   PDescObj->FrameLayout = 0;
355
356   if ( PDesc.StoredWidth < 2049 )
357     {
358       PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression_2K));
359       m_EssenceSubDescriptor->Rsize = 3;
360     }
361   else
362     {
363       PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression_4K));
364       m_EssenceSubDescriptor->Rsize = 4;
365     }
366
367   m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
368   m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
369   m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
370   m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
371   m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
372   m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
373   m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
374   m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
375   m_EssenceSubDescriptor->Csize = PDesc.Csize;
376
377   const ui32_t tmp_buffer_len = 64;
378   byte_t tmp_buffer[tmp_buffer_len];
379
380   *(ui32_t*)tmp_buffer = KM_i32_BE(3L); // three components
381   *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(3L);
382   memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
383
384   memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, 17);
385   m_EssenceSubDescriptor->PictureComponentSizing.Length(17);
386
387   memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), PDesc.CodingStyle, PDesc.CodingStyleLength);
388   m_EssenceSubDescriptor->CodingStyleDefault.Length(PDesc.CodingStyleLength);
389
390   memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), PDesc.QuantDefault, PDesc.QuantDefaultLength);
391   m_EssenceSubDescriptor->QuantizationDefault.Length(PDesc.QuantDefaultLength);
392
393   return RESULT_OK;
394 }
395
396
397 // Open the file for writing. The file must not exist. Returns error if
398 // the operation cannot be completed.
399 ASDCP::Result_t
400 lh__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
401 {
402   if ( ! m_State.Test_BEGIN() )
403     return RESULT_STATE;
404
405   Result_t result = m_File.OpenWrite(filename);
406
407   if ( ASDCP_SUCCESS(result) )
408     {
409       m_HeaderSize = HeaderSize;
410       RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor;
411       tmp_rgba->ComponentMaxRef = 4095;
412       tmp_rgba->ComponentMinRef = 0;
413
414       m_EssenceDescriptor = tmp_rgba;
415       m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
416       m_EssenceSubDescriptorList.push_back((FileDescriptor*)m_EssenceSubDescriptor);
417
418       GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
419       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
420
421       result = m_State.Goto_INIT();
422     }
423
424   return result;
425 }
426
427 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
428 ASDCP::Result_t
429 lh__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
430 {
431   if ( ! m_State.Test_INIT() )
432     return RESULT_STATE;
433
434   if ( LocalEditRate == ASDCP::Rational(0,0) )
435     LocalEditRate = m_PDesc.EditRate;
436
437   m_PDesc = PDesc;
438   Result_t result = JP2K_PDesc_to_MD(m_PDesc);
439
440   if ( ASDCP_SUCCESS(result) )
441       result = WriteMXFHeader(label, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
442                               PICT_DEF_LABEL,     UL(Dict::ul(MDD_PictureDataDef)),
443                               LocalEditRate, 24 /* TCFrameRate */);
444
445   if ( ASDCP_SUCCESS(result) )
446     {
447       memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
448       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
449       result = m_State.Goto_READY();
450     }
451
452   return result;
453 }
454
455 // Writes a frame of essence to the MXF file. If the optional AESEncContext
456 // argument is present, the essence is encrypted prior to writing.
457 // Fails if the file is not open, is finalized, or an operating system
458 // error occurs.
459 //
460 ASDCP::Result_t
461 lh__Writer::WriteFrame(const JP2K::FrameBuffer& FrameBuf, bool add_index,
462                        AESEncContext* Ctx, HMACContext* HMAC)
463 {
464   Result_t result = RESULT_OK;
465
466   if ( m_State.Test_READY() )
467     result = m_State.Goto_RUNNING(); // first time through
468  
469   ui64_t StreamOffset = m_StreamOffset;
470
471   if ( ASDCP_SUCCESS(result) )
472     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
473
474   if ( ASDCP_SUCCESS(result) && add_index )
475     {  
476       IndexTableSegment::IndexEntry Entry;
477       Entry.StreamOffset = StreamOffset;
478       m_FooterPart.PushIndexEntry(Entry);
479       m_FramesWritten++;
480     }
481
482   return result;
483 }
484
485
486 // Closes the MXF file, writing the index and other closing information.
487 //
488 ASDCP::Result_t
489 lh__Writer::Finalize()
490 {
491   if ( ! m_State.Test_RUNNING() )
492     return RESULT_STATE;
493
494   m_State.Goto_FINAL();
495
496   return WriteMXFFooter();
497 }
498
499
500 //
501 class ASDCP::JP2K::MXFWriter::h__Writer : public lh__Writer
502 {
503 };
504
505
506 //------------------------------------------------------------------------------------------
507
508
509
510 ASDCP::JP2K::MXFWriter::MXFWriter()
511 {
512 }
513
514 ASDCP::JP2K::MXFWriter::~MXFWriter()
515 {
516 }
517
518
519 // Open the file for writing. The file must not exist. Returns error if
520 // the operation cannot be completed.
521 ASDCP::Result_t
522 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
523                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
524 {
525   m_Writer = new h__Writer;
526   
527   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
528
529   if ( ASDCP_SUCCESS(result) )
530     {
531       m_Writer->m_Info = Info;
532       result = m_Writer->SetSourceStream(PDesc, JP2K_PACKAGE_LABEL);
533     }
534
535   if ( ASDCP_FAILURE(result) )
536     m_Writer.release();
537
538   return result;
539 }
540
541
542 // Writes a frame of essence to the MXF file. If the optional AESEncContext
543 // argument is present, the essence is encrypted prior to writing.
544 // Fails if the file is not open, is finalized, or an operating system
545 // error occurs.
546 ASDCP::Result_t
547 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
548 {
549   if ( m_Writer.empty() )
550     return RESULT_INIT;
551
552   return m_Writer->WriteFrame(FrameBuf, true, Ctx, HMAC);
553 }
554
555 // Closes the MXF file, writing the index and other closing information.
556 ASDCP::Result_t
557 ASDCP::JP2K::MXFWriter::Finalize()
558 {
559   if ( m_Writer.empty() )
560     return RESULT_INIT;
561
562   return m_Writer->Finalize();
563 }
564
565
566 //------------------------------------------------------------------------------------------
567 //
568
569 //
570 class ASDCP::JP2K::MXFSWriter::h__SWriter : public lh__Writer
571 {
572   StereoscopicPhase_t m_NextPhase;
573
574 public:
575   h__SWriter() : m_NextPhase(SP_LEFT) {}
576
577   //
578   Result_t WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
579                       AESEncContext* Ctx, HMACContext* HMAC)
580   {
581     if ( m_NextPhase != phase )
582       return RESULT_SPHASE;
583
584     if ( phase == SP_LEFT )
585       {
586         m_NextPhase = SP_RIGHT;
587         return lh__Writer::WriteFrame(FrameBuf, true, Ctx, HMAC);
588       }
589
590     m_NextPhase = SP_LEFT;
591     return lh__Writer::WriteFrame(FrameBuf, false, Ctx, HMAC);
592   }
593
594   //
595   Result_t Finalize()
596   {
597     if ( m_NextPhase != SP_LEFT )
598       return RESULT_SPHASE;
599
600     return lh__Writer::Finalize();
601   }
602 };
603
604
605 //
606 ASDCP::JP2K::MXFSWriter::MXFSWriter()
607 {
608 }
609
610 ASDCP::JP2K::MXFSWriter::~MXFSWriter()
611 {
612 }
613
614
615 // Open the file for writing. The file must not exist. Returns error if
616 // the operation cannot be completed.
617 ASDCP::Result_t
618 ASDCP::JP2K::MXFSWriter::OpenWrite(const char* filename, const WriterInfo& Info,
619                                    const PictureDescriptor& PDesc, ui32_t HeaderSize)
620 {
621   m_Writer = new h__SWriter;
622   
623   if ( PDesc.EditRate != ASDCP::EditRate_24 )
624     {
625       DefaultLogSink().Error("Stereoscopic wrapping requires 24 fps input streams.\n");
626       return RESULT_FORMAT;
627     }
628
629   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
630
631   if ( ASDCP_SUCCESS(result) )
632     {
633       m_Writer->m_Info = Info;
634       PictureDescriptor TmpPDesc = PDesc;
635       TmpPDesc.EditRate = ASDCP::EditRate_48;
636
637       result = m_Writer->SetSourceStream(TmpPDesc, JP2K_S_PACKAGE_LABEL, ASDCP::EditRate_24);
638     }
639
640   if ( ASDCP_FAILURE(result) )
641     m_Writer.release();
642
643   return result;
644 }
645
646
647 // Writes a frame of essence to the MXF file. If the optional AESEncContext
648 // argument is present, the essence is encrypted prior to writing.
649 // Fails if the file is not open, is finalized, or an operating system
650 // error occurs.
651 ASDCP::Result_t
652 ASDCP::JP2K::MXFSWriter::WriteFrame(const FrameBuffer& FrameBuf, StereoscopicPhase_t phase,
653                                     AESEncContext* Ctx, HMACContext* HMAC)
654 {
655   if ( m_Writer.empty() )
656     return RESULT_INIT;
657
658   return m_Writer->WriteFrame(FrameBuf, phase, Ctx, HMAC);
659 }
660
661 // Closes the MXF file, writing the index and other closing information.
662 ASDCP::Result_t
663 ASDCP::JP2K::MXFSWriter::Finalize()
664 {
665   if ( m_Writer.empty() )
666     return RESULT_INIT;
667
668   return m_Writer->Finalize();
669 }
670
671 //
672 // end AS_DCP_JP2K.cpp
673 //