2K.4K switching
[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->SampleRate = PDesc.EditRate;
348   PDescObj->ContainerDuration = PDesc.ContainerDuration;
349   PDescObj->StoredWidth = PDesc.StoredWidth;
350   PDescObj->StoredHeight = PDesc.StoredHeight;
351   PDescObj->AspectRatio = PDesc.AspectRatio;
352   PDescObj->FrameLayout = 0;
353
354   if ( PDesc.StoredWidth < 2049 )
355     {
356       PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression_2K));
357       m_EssenceSubDescriptor->Rsize = 3;
358     }
359   else
360     {
361       PDescObj->Codec.Set(Dict::ul(MDD_JP2KEssenceCompression_4K));
362       m_EssenceSubDescriptor->Rsize = 4;
363     }
364
365   m_EssenceSubDescriptor->Xsize = PDesc.Xsize;
366   m_EssenceSubDescriptor->Ysize = PDesc.Ysize;
367   m_EssenceSubDescriptor->XOsize = PDesc.XOsize;
368   m_EssenceSubDescriptor->YOsize = PDesc.YOsize;
369   m_EssenceSubDescriptor->XTsize = PDesc.XTsize;
370   m_EssenceSubDescriptor->YTsize = PDesc.YTsize;
371   m_EssenceSubDescriptor->XTOsize = PDesc.XTOsize;
372   m_EssenceSubDescriptor->YTOsize = PDesc.YTOsize;
373   m_EssenceSubDescriptor->Csize = PDesc.Csize;
374
375   const ui32_t tmp_buffer_len = 64;
376   byte_t tmp_buffer[tmp_buffer_len];
377
378   *(ui32_t*)tmp_buffer = KM_i32_BE(3L); // three components
379   *(ui32_t*)(tmp_buffer+4) = KM_i32_BE(3L);
380   memcpy(tmp_buffer + 8, &PDesc.ImageComponents, sizeof(ASDCP::JP2K::ImageComponent) * 3L);
381
382   memcpy(m_EssenceSubDescriptor->PictureComponentSizing.Data(), tmp_buffer, 17);
383   m_EssenceSubDescriptor->PictureComponentSizing.Length(17);
384
385   memcpy(m_EssenceSubDescriptor->CodingStyleDefault.Data(), PDesc.CodingStyle, PDesc.CodingStyleLength);
386   m_EssenceSubDescriptor->CodingStyleDefault.Length(PDesc.CodingStyleLength);
387
388   memcpy(m_EssenceSubDescriptor->QuantizationDefault.Data(), PDesc.QuantDefault, PDesc.QuantDefaultLength);
389   m_EssenceSubDescriptor->QuantizationDefault.Length(PDesc.QuantDefaultLength);
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       m_HeaderSize = HeaderSize;
408       RGBAEssenceDescriptor* tmp_rgba = new RGBAEssenceDescriptor;
409       tmp_rgba->ComponentMaxRef = 4095;
410       tmp_rgba->ComponentMinRef = 0;
411
412       m_EssenceDescriptor = tmp_rgba;
413       m_EssenceSubDescriptor = new JPEG2000PictureSubDescriptor;
414       m_EssenceSubDescriptorList.push_back((FileDescriptor*)m_EssenceSubDescriptor);
415
416       GenRandomValue(m_EssenceSubDescriptor->InstanceUID);
417       m_EssenceDescriptor->SubDescriptors.push_back(m_EssenceSubDescriptor->InstanceUID);
418
419       result = m_State.Goto_INIT();
420     }
421
422   return result;
423 }
424
425 // Automatically sets the MXF file's metadata from the first jpeg codestream stream.
426 ASDCP::Result_t
427 ASDCP::JP2K::MXFWriter::h__Writer::SetSourceStream(const PictureDescriptor& PDesc)
428 {
429   if ( ! m_State.Test_INIT() )
430     return RESULT_STATE;
431
432   m_PDesc = PDesc;
433   Result_t result = JP2K_PDesc_to_MD(m_PDesc);
434
435   if ( ASDCP_SUCCESS(result) )
436       result = WriteMXFHeader(JP2K_PACKAGE_LABEL, UL(Dict::ul(MDD_JPEG_2000Wrapping)),
437                               PICT_DEF_LABEL,     UL(Dict::ul(MDD_PictureDataDef)),
438                               m_PDesc.EditRate, 24 /* TCFrameRate */);
439
440   if ( ASDCP_SUCCESS(result) )
441     {
442       memcpy(m_EssenceUL, Dict::ul(MDD_JPEG2000Essence), SMPTE_UL_LENGTH);
443       m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
444       result = m_State.Goto_READY();
445     }
446
447   return result;
448 }
449
450 // Writes a frame of essence to the MXF file. If the optional AESEncContext
451 // argument is present, the essence is encrypted prior to writing.
452 // Fails if the file is not open, is finalized, or an operating system
453 // error occurs.
454 //
455 ASDCP::Result_t
456 ASDCP::JP2K::MXFWriter::h__Writer::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx,
457                                                HMACContext* HMAC)
458 {
459   Result_t result = RESULT_OK;
460
461   if ( m_State.Test_READY() )
462     result = m_State.Goto_RUNNING(); // first time through
463  
464   IndexTableSegment::IndexEntry Entry;
465   Entry.StreamOffset = m_StreamOffset;
466
467   if ( ASDCP_SUCCESS(result) )
468     result = WriteEKLVPacket(FrameBuf, m_EssenceUL, Ctx, HMAC);
469
470   if ( ASDCP_SUCCESS(result) )
471     {  
472       m_FooterPart.PushIndexEntry(Entry);
473       m_FramesWritten++;
474     }
475
476   return result;
477 }
478
479
480 // Closes the MXF file, writing the index and other closing information.
481 //
482 ASDCP::Result_t
483 ASDCP::JP2K::MXFWriter::h__Writer::Finalize()
484 {
485   if ( ! m_State.Test_RUNNING() )
486     return RESULT_STATE;
487
488   m_State.Goto_FINAL();
489
490   return WriteMXFFooter();
491 }
492
493
494 //------------------------------------------------------------------------------------------
495
496
497
498 ASDCP::JP2K::MXFWriter::MXFWriter()
499 {
500 }
501
502 ASDCP::JP2K::MXFWriter::~MXFWriter()
503 {
504 }
505
506
507 // Open the file for writing. The file must not exist. Returns error if
508 // the operation cannot be completed.
509 ASDCP::Result_t
510 ASDCP::JP2K::MXFWriter::OpenWrite(const char* filename, const WriterInfo& Info,
511                                   const PictureDescriptor& PDesc, ui32_t HeaderSize)
512 {
513   m_Writer = new h__Writer;
514   
515   Result_t result = m_Writer->OpenWrite(filename, HeaderSize);
516
517   if ( ASDCP_SUCCESS(result) )
518     {
519       m_Writer->m_Info = Info;
520       result = m_Writer->SetSourceStream(PDesc);
521     }
522
523   if ( ASDCP_FAILURE(result) )
524     m_Writer.release();
525
526   return result;
527 }
528
529
530 // Writes a frame of essence to the MXF file. If the optional AESEncContext
531 // argument is present, the essence is encrypted prior to writing.
532 // Fails if the file is not open, is finalized, or an operating system
533 // error occurs.
534 ASDCP::Result_t
535 ASDCP::JP2K::MXFWriter::WriteFrame(const FrameBuffer& FrameBuf, AESEncContext* Ctx, HMACContext* HMAC)
536 {
537   if ( m_Writer.empty() )
538     return RESULT_INIT;
539
540   return m_Writer->WriteFrame(FrameBuf, Ctx, HMAC);
541 }
542
543 // Closes the MXF file, writing the index and other closing information.
544 ASDCP::Result_t
545 ASDCP::JP2K::MXFWriter::Finalize()
546 {
547   if ( m_Writer.empty() )
548     return RESULT_INIT;
549
550   return m_Writer->Finalize();
551 }
552
553
554 //
555 // end AS_DCP_JP2K.cpp
556 //