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