more printf format fixes
[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: %d/%d\n\
49           EditRate: %d/%d\n\
50        StoredWidth: %u\n\
51       StoredHeight: %u\n\
52              Rsize: %u\n\
53              Xsize: %u\n\
54              Ysize: %u\n\
55             XOsize: %u\n\
56             YOsize: %u\n\
57             XTsize: %u\n\
58             YTsize: %u\n\
59            XTOsize: %u\n\
60            YTOsize: %u\n\
61  ContainerDuration: %u\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, "  %u.%u.%u\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 (%u): %s\n",
94             PDesc.CodingStyleLength,
95             Kumu::bin2hex(PDesc.CodingStyle, PDesc.CodingStyleLength, tmp_buf, tmp_buf_len)
96             );
97
98   if ( PDesc.QuantDefaultLength )
99     fprintf(stream, "Quantization Default (%u): %s\n",
100             PDesc.QuantDefaultLength,
101             Kumu::bin2hex(PDesc.QuantDefault, PDesc.QuantDefaultLength, tmp_buf, tmp_buf_len)
102             );
103 }
104
105 //------------------------------------------------------------------------------------------
106 //
107 // hidden, internal implementation of JPEG 2000 reader
108
109 class ASDCP::JP2K::MXFReader::h__Reader : public ASDCP::h__Reader
110 {
111   RGBAEssenceDescriptor*        m_EssenceDescriptor;
112   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
113
114   ASDCP_NO_COPY_CONSTRUCT(h__Reader);
115
116 public:
117   PictureDescriptor m_PDesc;        // codestream parameter list
118
119   h__Reader() : m_EssenceDescriptor(0), m_EssenceSubDescriptor(0) {}
120   Result_t    OpenRead(const char*);
121   Result_t    ReadFrame(ui32_t, FrameBuffer&, AESDecContext*, HMACContext*);
122   Result_t    ReadFrameGOPStart(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 ReadEKLVPacket(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
314 //
315 class ASDCP::JP2K::MXFWriter::h__Writer : public ASDCP::h__Writer
316 {
317   JPEG2000PictureSubDescriptor* m_EssenceSubDescriptor;
318
319 public:
320   PictureDescriptor m_PDesc;
321   byte_t            m_EssenceUL[SMPTE_UL_LENGTH];
322
323   ASDCP_NO_COPY_CONSTRUCT(h__Writer);
324
325   h__Writer() : m_EssenceSubDescriptor(0) {
326     memset(m_EssenceUL, 0, SMPTE_UL_LENGTH);
327   }
328
329   ~h__Writer(){}
330
331   Result_t OpenWrite(const char*, ui32_t HeaderSize);
332   Result_t SetSourceStream(const PictureDescriptor&);
333   Result_t WriteFrame(const FrameBuffer&, AESEncContext* = 0, HMACContext* = 0);
334   Result_t Finalize();
335   Result_t JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc);
336 };
337
338
339 //
340 ASDCP::Result_t
341 ASDCP::JP2K::MXFWriter::h__Writer::JP2K_PDesc_to_MD(JP2K::PictureDescriptor& PDesc)
342 {
343   assert(m_EssenceDescriptor);
344   assert(m_EssenceSubDescriptor);
345   MXF::RGBAEssenceDescriptor* PDescObj = (MXF::RGBAEssenceDescriptor*)m_EssenceDescriptor;
346
347   PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression));
348   PDescObj->SampleRate = PDesc.EditRate;
349   PDescObj->ContainerDuration = PDesc.ContainerDuration;
350   PDescObj->StoredWidth = PDesc.StoredWidth;
351   PDescObj->StoredHeight = PDesc.StoredHeight;
352   PDescObj->AspectRatio = PDesc.AspectRatio;
353   PDescObj->FrameLayout = 0;
354
355   m_EssenceSubDescriptor->Rsize = PDesc.Rsize;
356   m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
357   m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
358   m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
359   m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
360   m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
361   m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
362   m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
363   m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
364   m_EssenceSubDescriptor->Csize = PDesc.Csize;
365
366   const ui32_t tmp_buffer_len = 64;
367   byte_t tmp_buffer[tmp_buffer_len];
368
369   *(ui32_t*)tmp_buffer = KM_i32_BE(3L); // three components
370   *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(3L);
371   memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
372
373   memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, 17);
374   m_EssenceSubDescriptor->PictureComponentSizing.Length(17);
375
376   memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), PDesc.CodingStyle, PDesc.CodingStyleLength);
377   m_EssenceSubDescriptor->CodingStyleDefault.Length(PDesc.CodingStyleLength);
378
379   memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), PDesc.QuantDefault, PDesc.QuantDefaultLength);
380   m_EssenceSubDescriptor->QuantizationDefault.Length(PDesc.QuantDefaultLength);
381
382   return RESULT_OK;
383 }
384
385
386 // Open the file for writing. The file must not exist. Returns error if
387 // the operation cannot be completed.
388 ASDCP::Result_t
389 ASDCP::JP2K::MXFWriter::h__Writer::OpenWrite(const char* filename, ui32_t HeaderSize)
390 {
391   if ( ! m_State.Test_BEGIN() )
392     return RESULT_STATE;
393
394   Result_t result = m_File.OpenWrite(filename);
395
396   if ( ASDCP_SUCCESS(result) )
397     {
398       m_HeaderSize = HeaderSize;
399       m_EssenceDescriptor = new RGBAEssenceDescriptor;
400       m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
401       m_HeaderPart.AddChildObject(m_EssenceSubDescriptor);
402       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
403       result = m_State.Goto_INIT();
404     }
405
406   return result;
407 }
408
409 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
410 ASDCP::Result_t
411 ASDCP::JP2K::MXFWriter::h__Writer::SetSourceStream(const PictureDescriptor& PDesc)
412 {
413   if ( ! m_State.Test_INIT() )
414     return RESULT_STATE;
415
416   m_PDesc = PDesc;
417   Result_t result = JP2K_PDesc_to_MD(m_PDesc);
418
419   if ( ASDCP_SUCCESS(result) )
420       result = WriteMXFHeader(JP2K_PACKAGE_LABEL, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
421                               PICT_DEF_LABEL,     UL(Dict::ul(MDD_PictureDataDef)),
422                               m_PDesc.EditRate, 24 /* TCFrameRate */);
423
424   if ( ASDCP_SUCCESS(result) )
425     {
426       memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
427       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
428       result = m_State.Goto_READY();
429     }
430
431   return result;
432 }
433
434 // Writes a frame of essence to the MXF file. If the optional AESEncContext
435 // argument is present, the essence is encrypted prior to writing.
436 // Fails if the file is not open, is finalized, or an operating system
437 // error occurs.
438 //
439 ASDCP::Result_t
440 ASDCP::JP2K::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
441                                                HMACContext* HMAC)
442 {
443   Result_t result = RESULT_OK;
444
445   if ( m_State.Test_READY() )
446     result = m_State.Goto_RUNNING(); // first time through
447  
448   IndexTableSegment::IndexEntry Entry;
449   Entry.StreamOffset = m_StreamOffset;
450
451   if ( ASDCP_SUCCESS(result) )
452     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
453
454   if ( ASDCP_SUCCESS(result) )
455     {  
456       m_FooterPart.PushIndexEntry(Entry);
457       m_FramesWritten++;
458     }
459
460   return result;
461 }
462
463
464 // Closes the MXF file, writing the index and other closing information.
465 //
466 ASDCP::Result_t
467 ASDCP::JP2K::MXFWriter::h__Writer::Finalize()
468 {
469   if ( ! m_State.Test_RUNNING() )
470     return RESULT_STATE;
471
472   m_State.Goto_FINAL();
473
474   return WriteMXFFooter();
475 }
476
477
478 //------------------------------------------------------------------------------------------
479
480
481
482 ASDCP::JP2K::MXFWriter::MXFWriter()
483 {
484 }
485
486 ASDCP::JP2K::MXFWriter::~MXFWriter()
487 {
488 }
489
490
491 // Open the file for writing. The file must not exist. Returns error if
492 // the operation cannot be completed.
493 ASDCP::Result_t
494 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
495                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
496 {
497   m_Writer = new h__Writer;
498   
499   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
500
501   if ( ASDCP_SUCCESS(result) )
502     {
503       m_Writer->m_Info = Info;
504       result = m_Writer->SetSourceStream(PDesc);
505     }
506
507   if ( ASDCP_FAILURE(result) )
508     m_Writer.release();
509
510   return result;
511 }
512
513
514 // Writes a frame of essence to the MXF file. If the optional AESEncContext
515 // argument is present, the essence is encrypted prior to writing.
516 // Fails if the file is not open, is finalized, or an operating system
517 // error occurs.
518 ASDCP::Result_t
519 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
520 {
521   if ( m_Writer.empty() )
522     return RESULT_INIT;
523
524   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
525 }
526
527 // Closes the MXF file, writing the index and other closing information.
528 ASDCP::Result_t
529 ASDCP::JP2K::MXFWriter::Finalize()
530 {
531   if ( m_Writer.empty() )
532     return RESULT_INIT;
533
534   return m_Writer->Finalize();
535 }
536
537
538 //
539 // end AS_DCP_JP2K.cpp
540 //