added aiff reader
[asdcplib.git] / src / AS_DCP_JP2K.cpp
1 /*
2 Copyright (c) 2004-2006, 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 XXXM frame wrapping of JPEG 2000 codestreams";
38 static std::string PICT_DEF_LABEL = "Picture Track";
39
40 //
41 void
42 ASDCP::JP2K::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
43 {
44   if ( stream == 0 )
45     stream = stderr;
46
47   fprintf(stream, "\
48       AspectRatio: %lu/%lu\n\
49          EditRate: %lu/%lu\n\
50       StoredWidth: %lu\n\
51      StoredHeight: %lu\n\
52             Rsize: %lu\n\
53             Xsize: %lu\n\
54             Ysize: %lu\n\
55            XOsize: %lu\n\
56            YOsize: %lu\n\
57            XTsize: %lu\n\
58            YTsize: %lu\n\
59           XTOsize: %lu\n\
60           YTOsize: %lu\n\
61 ContainerDuration: %lu\n",
62           PDesc.AspectRatio.Numerator ,PDesc.AspectRatio.Denominator,
63           PDesc.EditRate.Numerator ,PDesc.EditRate.Denominator,
64           PDesc.StoredWidth,
65           PDesc.StoredHeight,
66           PDesc.Rsize,
67           PDesc.Xsize,
68           PDesc.Ysize,
69           PDesc.XOsize,
70           PDesc.YOsize,
71           PDesc.XTsize,
72           PDesc.YTsize,
73           PDesc.XTOsize,
74           PDesc.YTOsize,
75           PDesc.ContainerDuration
76           );
77
78   fprintf(stream, "Color Components:\n");
79
80   for ( ui32_t i = 0; i < PDesc.Csize; i++ )
81     {
82       fprintf(stream, "  %lu.%lu.%lu\n",
83               PDesc.ImageComponents[i].Ssize,
84               PDesc.ImageComponents[i].XRsize,
85               PDesc.ImageComponents[i].YRsize
86               );
87     }
88
89   const ui32_t tmp_buf_len = 256;
90   char tmp_buf[tmp_buf_len];
91
92   if ( PDesc.CodingStyleLength )
93     fprintf(stream, "Default Coding (%lu): %s\n",
94             PDesc.CodingStyleLength,
95             bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength,
96                     tmp_buf, tmp_buf_len)
97             );
98
99   if ( PDesc.QuantDefaultLength )
100     fprintf(stream, "Quantization Default (%lu): %s\n",
101             PDesc.QuantDefaultLength,
102             bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength,
103                     tmp_buf, tmp_buf_len)
104             );
105 }
106
107 //------------------------------------------------------------------------------------------
108 //
109 // hidden, internal implementation of JPEG 2000 reader
110
111 class ASDCP::JP2K::MXFReader::h__Reader : public ASDCP::h__Reader
112 {
113   RGBAEssenceDescriptor*        m_EssenceDescriptor;
114   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
115
116   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
117
118 public:
119   PictureDescriptor m_PDesc;        // codestream parameter list
120
121   h__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0) {}
122   Result_t    OpenRead(const char*);
123   Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
124   Result_t    ReadFrameGOPStart(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
125   Result_t    MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc);
126 };
127
128 //
129 ASDCP::Result_t
130 ASDCP::JP2K::MXFReader::h__Reader::MD_to_JP2K_PDesc(JP2K::PictureDescriptor& PDesc)
131 {
132   memset(&PDesc, 0, sizeof(PDesc));
133   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
134
135   PDesc.EditRate           = PDescObj->SampleRate;
136   PDesc.ContainerDuration  = PDescObj->ContainerDuration;
137   PDesc.StoredWidth        = PDescObj->StoredWidth;
138   PDesc.StoredHeight       = PDescObj->StoredHeight;
139   PDesc.AspectRatio        = PDescObj->AspectRatio;
140
141   if ( m_EssenceSubDescriptor != 0 )
142     {
143       PDesc.Rsize   = m_EssenceSubDescriptor->Rsize;
144       PDesc.Xsize   = m_EssenceSubDescriptor->Xsize;
145       PDesc.Ysize   = m_EssenceSubDescriptor->Ysize;
146       PDesc.XOsize  = m_EssenceSubDescriptor->XOsize;
147       PDesc.YOsize  = m_EssenceSubDescriptor->YOsize;
148       PDesc.XTsize  = m_EssenceSubDescriptor->XTsize;
149       PDesc.YTsize  = m_EssenceSubDescriptor->YTsize;
150       PDesc.XTOsize = m_EssenceSubDescriptor->XTOsize;
151       PDesc.YTOsize = m_EssenceSubDescriptor->YTOsize;
152       PDesc.Csize   = m_EssenceSubDescriptor->Csize;
153
154       // PictureComponentSizing
155       ui32_t tmp_size = m_EssenceSubDescriptor->PictureComponentSizing.Size();
156
157       if ( tmp_size == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
158         memcpy(&PDesc.ImageComponents, m_EssenceSubDescriptor->PictureComponentSizing.RoData() + 8, tmp_size - 8);
159
160       else
161         DefaultLogSink().Error("Unexpected PictureComponentSizing size: %lu, should be 17\n", tmp_size);
162
163       // CodingStyleDefault
164       if ( ( PDesc.CodingStyleLength = m_EssenceSubDescriptor->CodingStyleDefault.Size() ) != 0 )
165         memcpy(PDesc.CodingStyle, m_EssenceSubDescriptor->CodingStyleDefault.RoData(), PDesc.CodingStyleLength);
166
167       // QuantizationDefault
168       if ( ( PDesc.QuantDefaultLength = m_EssenceSubDescriptor->QuantizationDefault.Size() ) != 0 )
169         memcpy(PDesc.QuantDefault, m_EssenceSubDescriptor->QuantizationDefault.RoData(), PDesc.QuantDefaultLength);
170     }
171
172   return RESULT_OK;
173 }
174
175 //
176 //
177 ASDCP::Result_t
178 ASDCP::JP2K::MXFReader::h__Reader::OpenRead(const char* filename)
179 {
180   Result_t result = OpenMXFRead(filename);
181
182   if( ASDCP_SUCCESS(result) )
183     {
184       if ( m_EssenceDescriptor == 0 )
185         {
186           m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(RGBAEssenceDescriptor), (InterchangeObject**)&m_EssenceDescriptor);
187           m_HeaderPart.GetMDObjectByType(OBJ_TYPE_ARGS(JPEG2000PictureSubDescriptor), (InterchangeObject**)&m_EssenceSubDescriptor);
188         }
189
190       result = MD_to_JP2K_PDesc(m_PDesc);
191     }
192
193   if( ASDCP_SUCCESS(result) )
194     result = InitMXFIndex();
195
196   if( ASDCP_SUCCESS(result) )
197     result = InitInfo(m_Info);
198
199   return result;
200 }
201
202 //
203 //
204 ASDCP::Result_t
205 ASDCP::JP2K::MXFReader::h__Reader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
206                                               AESDecContext* Ctx, HMACContext* HMAC)
207 {
208   if ( ! m_File.IsOpen() )
209     return RESULT_INIT;
210
211   return ReadEKLVPacket(FrameNum, FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
212 }
213
214 //------------------------------------------------------------------------------------------
215
216
217 //
218 void
219 ASDCP::JP2K::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
220 {
221   if ( stream == 0 )
222     stream = stderr;
223
224   fprintf(stream, "Frame: %06lu, %7lu bytes", m_FrameNumber, m_Size);
225   
226   fputc('\n', stream);
227
228   if ( dump_len > 0 )
229     hexdump(m_Data, dump_len, stream);
230 }
231
232
233 //------------------------------------------------------------------------------------------
234
235 ASDCP::JP2K::MXFReader::MXFReader()
236 {
237   m_Reader = new h__Reader;
238 }
239
240
241 ASDCP::JP2K::MXFReader::~MXFReader()
242 {
243 }
244
245 // Open the file for reading. The file must exist. Returns error if the
246 // operation cannot be completed.
247 ASDCP::Result_t
248 ASDCP::JP2K::MXFReader::OpenRead(const char* filename) const
249 {
250   return m_Reader->OpenRead(filename);
251 }
252
253 //
254 ASDCP::Result_t
255 ASDCP::JP2K::MXFReader::ReadFrame(ui32_t FrameNum, FrameBuffer& FrameBuf,
256                                    AESDecContext* Ctx, HMACContext* HMAC) const
257 {
258   if ( m_Reader && m_Reader->m_File.IsOpen() )
259     return m_Reader->ReadFrame(FrameNum, FrameBuf, Ctx, HMAC);
260
261   return RESULT_INIT;
262 }
263
264
265 // Fill the struct with the values from the file's header.
266 // Returns RESULT_INIT if the file is not open.
267 ASDCP::Result_t
268 ASDCP::JP2K::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
269 {
270   if ( m_Reader && m_Reader->m_File.IsOpen() )
271     {
272       PDesc = m_Reader->m_PDesc;
273       return RESULT_OK;
274     }
275
276   return RESULT_INIT;
277 }
278
279
280 // Fill the struct with the values from the file's header.
281 // Returns RESULT_INIT if the file is not open.
282 ASDCP::Result_t
283 ASDCP::JP2K::MXFReader::FillWriterInfo(WriterInfo& Info) const
284 {
285   if ( m_Reader && m_Reader->m_File.IsOpen() )
286     {
287       Info = m_Reader->m_Info;
288       return RESULT_OK;
289     }
290
291   return RESULT_INIT;
292 }
293
294 //
295 void
296 ASDCP::JP2K::MXFReader::DumpHeaderMetadata(FILE* stream) const
297 {
298   if ( m_Reader->m_File.IsOpen() )
299     m_Reader->m_HeaderPart.Dump(stream);
300 }
301
302
303 //
304 void
305 ASDCP::JP2K::MXFReader::DumpIndex(FILE* stream) const
306 {
307   if ( m_Reader->m_File.IsOpen() )
308     m_Reader->m_FooterPart.Dump(stream);
309 }
310
311
312 //------------------------------------------------------------------------------------------
313
314
315
316 //
317 class ASDCP::JP2K::MXFWriter::h__Writer : public ASDCP::h__Writer
318 {
319   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
320
321 public:
322   PictureDescriptor m_PDesc;
323
324   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
325
326   h__Writer() : m_EssenceSubDescriptor(0) {}
327   ~h__Writer(){}
328
329   Result_t OpenWrite(const char*, ui32_t HeaderSize);
330   Result_t SetSourceStream(const PictureDescriptor&);
331   Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
332   Result_t Finalize();
333   Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
334 };
335
336
337 //
338 ASDCP::Result_t
339 ASDCP::JP2K::MXFWriter::h__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
340 {
341   assert(m_EssenceDescriptor);
342   assert(m_EssenceSubDescriptor);
343   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
344
345   PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression));
346   PDescObj->SampleRate = PDesc.EditRate;
347   PDescObj->ContainerDuration = PDesc.ContainerDuration;
348   PDescObj->StoredWidth = PDesc.StoredWidth;
349   PDescObj->StoredHeight = PDesc.StoredHeight;
350   PDescObj->AspectRatio = PDesc.AspectRatio;
351   PDescObj->FrameLayout = 0;
352
353   m_EssenceSubDescriptor->Rsize = PDesc.Rsize;
354   m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
355   m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
356   m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
357   m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
358   m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
359   m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
360   m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
361   m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
362   m_EssenceSubDescriptor->Csize = PDesc.Csize;
363
364   const ui32_t tmp_buffer_len = 64;
365   byte_t tmp_buffer[tmp_buffer_len];
366
367   *(ui32_t*)tmp_buffer = ASDCP_i32_BE(3L); // three components
368   *(ui32_t*)(tmp_buffer+4) = ASDCP_i32_BE(3L);
369   memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
370
371   memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, 17);
372   m_EssenceSubDescriptor->PictureComponentSizing.Size(17);
373
374   memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), PDesc.CodingStyle, PDesc.CodingStyleLength);
375   m_EssenceSubDescriptor->CodingStyleDefault.Size(PDesc.CodingStyleLength);
376
377   memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), PDesc.QuantDefault, PDesc.QuantDefaultLength);
378   m_EssenceSubDescriptor->QuantizationDefault.Size(PDesc.QuantDefaultLength);
379
380   return RESULT_OK;
381 }
382
383
384 // Open the file for writing. The file must not exist. Returns error if
385 // the operation cannot be completed.
386 ASDCP::Result_t
387 ASDCP::JP2K::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
388 {
389   if ( ! m_State.Test_BEGIN() )
390     return RESULT_STATE;
391
392   Result_t result = m_File.OpenWrite(filename);
393
394   if ( ASDCP_SUCCESS(result) )
395     {
396       m_HeaderSize = HeaderSize;
397       m_EssenceDescriptor = new RGBAEssenceDescriptor;
398       m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
399       m_HeaderPart.AddChildObject(m_EssenceSubDescriptor);
400       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
401       result = m_State.Goto_INIT();
402     }
403
404   return result;
405 }
406
407 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
408 ASDCP::Result_t
409 ASDCP::JP2K::MXFWriter::h__Writer::SetSourceStream(const PictureDescriptor& PDesc)
410 {
411   if ( ! m_State.Test_INIT() )
412     return RESULT_STATE;
413
414   m_PDesc = PDesc;
415   Result_t result = JP2K_PDesc_to_MD(m_PDesc);
416
417   if ( ASDCP_SUCCESS(result) )
418       result = WriteMXFHeader(JP2K_PACKAGE_LABEL, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
419                               PICT_DEF_LABEL,     UL(Dict::ul(MDD_PictureDataDef)),
420                               m_PDesc.EditRate, 24 /* TCFrameRate */);
421
422   if ( ASDCP_SUCCESS(result) )
423     result = m_State.Goto_READY();
424
425   return result;
426 }
427
428 // Writes a frame of essence to the MXF file. If the optional AESEncContext
429 // argument is present, the essence is encrypted prior to writing.
430 // Fails if the file is not open, is finalized, or an operating system
431 // error occurs.
432 //
433 ASDCP::Result_t
434 ASDCP::JP2K::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
435                                                HMACContext* HMAC)
436 {
437   Result_t result = RESULT_OK;
438
439   if ( m_State.Test_READY() )
440     result = m_State.Goto_RUNNING(); // first time through
441  
442   IndexTableSegment::IndexEntry Entry;
443   Entry.StreamOffset = m_StreamOffset;
444
445   if ( ASDCP_SUCCESS(result) )
446     result = WriteEKLVPacket(FrameBuf, Dict::ul(MDD_JPEG2000Essence), Ctx, HMAC);
447
448   if ( ASDCP_SUCCESS(result) )
449     {  
450       m_FooterPart.PushIndexEntry(Entry);
451       m_FramesWritten++;
452     }
453
454   return result;
455 }
456
457
458 // Closes the MXF file, writing the index and other closing information.
459 //
460 ASDCP::Result_t
461 ASDCP::JP2K::MXFWriter::h__Writer::Finalize()
462 {
463   if ( ! m_State.Test_RUNNING() )
464     return RESULT_STATE;
465
466   m_State.Goto_FINAL();
467
468   return WriteMXFFooter();
469 }
470
471
472 //------------------------------------------------------------------------------------------
473
474
475
476 ASDCP::JP2K::MXFWriter::MXFWriter()
477 {
478 }
479
480 ASDCP::JP2K::MXFWriter::~MXFWriter()
481 {
482 }
483
484
485 // Open the file for writing. The file must not exist. Returns error if
486 // the operation cannot be completed.
487 ASDCP::Result_t
488 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
489                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
490 {
491   m_Writer = new h__Writer;
492   
493   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
494
495   if ( ASDCP_SUCCESS(result) )
496     {
497       m_Writer->m_Info = Info;
498       result = m_Writer->SetSourceStream(PDesc);
499     }
500
501   if ( ASDCP_FAILURE(result) )
502     m_Writer.release();
503
504   return result;
505 }
506
507
508 // Writes a frame of essence to the MXF file. If the optional AESEncContext
509 // argument is present, the essence is encrypted prior to writing.
510 // Fails if the file is not open, is finalized, or an operating system
511 // error occurs.
512 ASDCP::Result_t
513 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
514 {
515   if ( m_Writer.empty() )
516     return RESULT_INIT;
517
518   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
519 }
520
521 // Closes the MXF file, writing the index and other closing information.
522 ASDCP::Result_t
523 ASDCP::JP2K::MXFWriter::Finalize()
524 {
525   if ( m_Writer.empty() )
526     return RESULT_INIT;
527
528   return m_Writer->Finalize();
529 }
530
531
532 //
533 // end AS_DCP_JP2K.cpp
534 //