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