09d1981460df3077d9cc7378c5772d31f2297812
[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 429-4 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_EssenceSubDescriptorList.push_back((FileDescriptor*)m_EssenceSubDescriptor);
402
403       GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
404       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
405
406       result = m_State.Goto_INIT();
407     }
408
409   return result;
410 }
411
412 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
413 ASDCP::Result_t
414 ASDCP::JP2K::MXFWriter::h__Writer::SetSourceStream(const PictureDescriptor& PDesc)
415 {
416   if ( ! m_State.Test_INIT() )
417     return RESULT_STATE;
418
419   m_PDesc = PDesc;
420   Result_t result = JP2K_PDesc_to_MD(m_PDesc);
421
422   if ( ASDCP_SUCCESS(result) )
423       result = WriteMXFHeader(JP2K_PACKAGE_LABEL, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
424                               PICT_DEF_LABEL,     UL(Dict::ul(MDD_PictureDataDef)),
425                               m_PDesc.EditRate, 24 /* TCFrameRate */);
426
427   if ( ASDCP_SUCCESS(result) )
428     {
429       memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
430       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
431       result = m_State.Goto_READY();
432     }
433
434   return result;
435 }
436
437 // Writes a frame of essence to the MXF file. If the optional AESEncContext
438 // argument is present, the essence is encrypted prior to writing.
439 // Fails if the file is not open, is finalized, or an operating system
440 // error occurs.
441 //
442 ASDCP::Result_t
443 ASDCP::JP2K::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
444                                                HMACContext* HMAC)
445 {
446   Result_t result = RESULT_OK;
447
448   if ( m_State.Test_READY() )
449     result = m_State.Goto_RUNNING(); // first time through
450  
451   IndexTableSegment::IndexEntry Entry;
452   Entry.StreamOffset = m_StreamOffset;
453
454   if ( ASDCP_SUCCESS(result) )
455     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
456
457   if ( ASDCP_SUCCESS(result) )
458     {  
459       m_FooterPart.PushIndexEntry(Entry);
460       m_FramesWritten++;
461     }
462
463   return result;
464 }
465
466
467 // Closes the MXF file, writing the index and other closing information.
468 //
469 ASDCP::Result_t
470 ASDCP::JP2K::MXFWriter::h__Writer::Finalize()
471 {
472   if ( ! m_State.Test_RUNNING() )
473     return RESULT_STATE;
474
475   m_State.Goto_FINAL();
476
477   return WriteMXFFooter();
478 }
479
480
481 //------------------------------------------------------------------------------------------
482
483
484
485 ASDCP::JP2K::MXFWriter::MXFWriter()
486 {
487 }
488
489 ASDCP::JP2K::MXFWriter::~MXFWriter()
490 {
491 }
492
493
494 // Open the file for writing. The file must not exist. Returns error if
495 // the operation cannot be completed.
496 ASDCP::Result_t
497 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
498                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
499 {
500   m_Writer = new h__Writer;
501   
502   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
503
504   if ( ASDCP_SUCCESS(result) )
505     {
506       m_Writer->m_Info = Info;
507       result = m_Writer->SetSourceStream(PDesc);
508     }
509
510   if ( ASDCP_FAILURE(result) )
511     m_Writer.release();
512
513   return result;
514 }
515
516
517 // Writes a frame of essence to the MXF file. If the optional AESEncContext
518 // argument is present, the essence is encrypted prior to writing.
519 // Fails if the file is not open, is finalized, or an operating system
520 // error occurs.
521 ASDCP::Result_t
522 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
523 {
524   if ( m_Writer.empty() )
525     return RESULT_INIT;
526
527   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
528 }
529
530 // Closes the MXF file, writing the index and other closing information.
531 ASDCP::Result_t
532 ASDCP::JP2K::MXFWriter::Finalize()
533 {
534   if ( m_Writer.empty() )
535     return RESULT_INIT;
536
537   return m_Writer->Finalize();
538 }
539
540
541 //
542 // end AS_DCP_JP2K.cpp
543 //