libdcp
j2k_transcode.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
3 
4  This file is part of libdcp.
5 
6  libdcp is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  libdcp is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with libdcp. If not, see <http://www.gnu.org/licenses/>.
18 
19  In addition, as a special exception, the copyright holders give
20  permission to link the code of portions of this program with the
21  OpenSSL library under certain conditions as described in each
22  individual source file, and distribute linked combinations
23  including the two.
24 
25  You must obey the GNU General Public License in all respects
26  for all of the code used other than OpenSSL. If you modify
27  file(s) with this exception, you may extend this exception to your
28  version of the file(s), but you are not obligated to do so. If you
29  do not wish to do so, delete this exception statement from your
30  version. If you delete this exception statement from all source
31  files in the program, then also delete it here.
32 */
33 
34 
40 #include "array_data.h"
41 #include "j2k_transcode.h"
42 #include "exceptions.h"
43 #include "openjpeg_image.h"
44 #include "dcp_assert.h"
45 #include "compose.hpp"
46 #include <openjpeg.h>
47 #include <cmath>
48 #include <iostream>
49 
50 
51 using std::min;
52 using std::pow;
53 using std::string;
54 using std::shared_ptr;
55 using boost::shared_array;
56 using namespace dcp;
57 
58 
59 shared_ptr<dcp::OpenJPEGImage>
60 dcp::decompress_j2k (Data const& data, int reduce)
61 {
62  return dcp::decompress_j2k (data.data(), data.size(), reduce);
63 }
64 
65 
66 shared_ptr<dcp::OpenJPEGImage>
67 dcp::decompress_j2k (shared_ptr<const Data> data, int reduce)
68 {
69  return dcp::decompress_j2k (data->data(), data->size(), reduce);
70 }
71 
72 
73 #ifdef LIBDCP_OPENJPEG2
74 
75 class ReadBuffer
76 {
77 public:
78  ReadBuffer (uint8_t const * data, int64_t size)
79  : _data (data)
80  , _size (size)
81  , _offset (0)
82  {}
83 
84  OPJ_SIZE_T read (void* buffer, OPJ_SIZE_T nb_bytes)
85  {
86  int64_t N = min (nb_bytes, _size - _offset);
87  memcpy (buffer, _data + _offset, N);
88  _offset += N;
89  return N;
90  }
91 
92 private:
93  uint8_t const * _data;
94  OPJ_SIZE_T _size;
95  OPJ_SIZE_T _offset;
96 };
97 
98 
99 static OPJ_SIZE_T
100 read_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
101 {
102  return reinterpret_cast<ReadBuffer*>(data)->read (buffer, nb_bytes);
103 }
104 
105 
106 static void
107 read_free_function (void* data)
108 {
109  delete reinterpret_cast<ReadBuffer*>(data);
110 }
111 
112 
113 static void
114 decompress_error_callback (char const * msg, void *)
115 {
116  throw J2KDecompressionError (msg);
117 }
118 
119 
120 static void
121 compress_error_callback (char const * msg, void *)
122 {
123  throw MiscError (msg);
124 }
125 
126 
127 shared_ptr<dcp::OpenJPEGImage>
128 dcp::decompress_j2k (uint8_t const * data, int64_t size, int reduce)
129 {
130  DCP_ASSERT (reduce >= 0);
131 
132  uint8_t const jp2_magic[] = {
133  0x00,
134  0x00,
135  0x00,
136  0x0c,
137  'j',
138  'P',
139  0x20,
140  0x20
141  };
142 
143  auto format = OPJ_CODEC_J2K;
144  if (size >= int (sizeof (jp2_magic)) && memcmp (data, jp2_magic, sizeof (jp2_magic)) == 0) {
145  format = OPJ_CODEC_JP2;
146  }
147 
148  auto decoder = opj_create_decompress (format);
149  if (!decoder) {
150  boost::throw_exception (ReadError ("could not create JPEG2000 decompresser"));
151  }
152  opj_dparameters_t parameters;
153  opj_set_default_decoder_parameters (&parameters);
154  parameters.cp_reduce = reduce;
155  opj_setup_decoder (decoder, &parameters);
156 
157  auto stream = opj_stream_default_create (OPJ_TRUE);
158  if (!stream) {
159  throw MiscError ("could not create JPEG2000 stream");
160  }
161 
162  opj_set_error_handler(decoder, decompress_error_callback, 00);
163 
164  opj_stream_set_read_function (stream, read_function);
165  auto buffer = new ReadBuffer (data, size);
166  opj_stream_set_user_data (stream, buffer, read_free_function);
167  opj_stream_set_user_data_length (stream, size);
168 
169  opj_image_t* image = 0;
170  opj_read_header (stream, decoder, &image);
171  if (opj_decode (decoder, stream, image) == OPJ_FALSE) {
172  opj_destroy_codec (decoder);
173  opj_stream_destroy (stream);
174  if (format == OPJ_CODEC_J2K) {
175  boost::throw_exception (ReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
176  } else {
177  boost::throw_exception (ReadError (String::compose ("could not decode JP2 file of %1 bytes.", size)));
178  }
179  }
180 
181  opj_destroy_codec (decoder);
182  opj_stream_destroy (stream);
183 
184  image->x1 = rint (float(image->x1) / pow (2.0f, reduce));
185  image->y1 = rint (float(image->y1) / pow (2.0f, reduce));
186  return shared_ptr<OpenJPEGImage> (new OpenJPEGImage (image));
187 }
188 
189 #endif
190 
191 
192 #ifdef LIBDCP_OPENJPEG1
193 
194 shared_ptr<dcp::OpenJPEGImage>
195 dcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
196 {
197  auto decoder = opj_create_decompress (CODEC_J2K);
198  opj_dparameters_t parameters;
199  opj_set_default_decoder_parameters (&parameters);
200  parameters.cp_reduce = reduce;
201  opj_setup_decoder (decoder, &parameters);
202  auto cio = opj_cio_open ((opj_common_ptr) decoder, data, size);
203  auto image = opj_decode (decoder, cio);
204  if (!image) {
205  opj_destroy_decompress (decoder);
206  opj_cio_close (cio);
207  boost::throw_exception (ReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
208  }
209 
210  opj_destroy_decompress (decoder);
211  opj_cio_close (cio);
212 
213  image->x1 = rint (float(image->x1) / pow (2, reduce));
214  image->y1 = rint (float(image->y1) / pow (2, reduce));
215  return shared_ptr<OpenJPEGImage> (new OpenJPEGImage (image));
216 }
217 #endif
218 
219 
220 #ifdef LIBDCP_OPENJPEG2
221 
222 class WriteBuffer
223 {
224 public:
225 /* XXX: is there a better strategy for this? */
226 #define MAX_J2K_SIZE (1024 * 1024 * 2)
227  WriteBuffer ()
228  : _data (shared_array<uint8_t>(new uint8_t[MAX_J2K_SIZE]), MAX_J2K_SIZE)
229  , _offset (0)
230  {
231  _data.set_size (0);
232  }
233 
234  OPJ_SIZE_T write (void* buffer, OPJ_SIZE_T nb_bytes)
235  {
236  DCP_ASSERT ((_offset + nb_bytes) < MAX_J2K_SIZE);
237  memcpy (_data.data() + _offset, buffer, nb_bytes);
238  _offset += nb_bytes;
239  if (_offset > OPJ_SIZE_T(_data.size())) {
240  _data.set_size (_offset);
241  }
242  return nb_bytes;
243  }
244 
245  OPJ_BOOL seek (OPJ_SIZE_T nb_bytes)
246  {
247  _offset = nb_bytes;
248  return OPJ_TRUE;
249  }
250 
251  ArrayData data () const
252  {
253  return _data;
254  }
255 
256 private:
257  ArrayData _data;
258  OPJ_SIZE_T _offset;
259 };
260 
261 
262 static OPJ_SIZE_T
263 write_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
264 {
265  return reinterpret_cast<WriteBuffer*>(data)->write(buffer, nb_bytes);
266 }
267 
268 
269 static void
270 write_free_function (void* data)
271 {
272  delete reinterpret_cast<WriteBuffer*>(data);
273 }
274 
275 
276 static OPJ_BOOL
277 seek_function (OPJ_OFF_T nb_bytes, void* data)
278 {
279  return reinterpret_cast<WriteBuffer*>(data)->seek(nb_bytes);
280 
281 }
282 
283 
284 ArrayData
285 dcp::compress_j2k (shared_ptr<const OpenJPEGImage> xyz, int bandwidth, int frames_per_second, bool threed, bool fourk, string comment)
286 {
287  /* get a J2K compressor handle */
288  auto encoder = opj_create_compress (OPJ_CODEC_J2K);
289  if (encoder == nullptr) {
290  throw MiscError ("could not create JPEG2000 encoder");
291  }
292 
293  if (comment.empty()) {
294  /* asdcplib complains with "Illegal data size" when reading frames encoded with an empty comment */
295  throw MiscError("compress_j2k comment can not be an empty string");
296  }
297 
298  opj_set_error_handler (encoder, compress_error_callback, 0);
299 
300  /* Set encoding parameters to default values */
301  opj_cparameters_t parameters;
302  opj_set_default_encoder_parameters (&parameters);
303  if (fourk) {
304  parameters.numresolution = 7;
305  }
306  parameters.rsiz = fourk ? OPJ_PROFILE_CINEMA_4K : OPJ_PROFILE_CINEMA_2K;
307  parameters.cp_comment = strdup (comment.c_str());
308 
309  /* set max image */
310  parameters.max_cs_size = (bandwidth / 8) / frames_per_second;
311  if (threed) {
312  /* In 3D we have only half the normal bandwidth per eye */
313  parameters.max_cs_size /= 2;
314  }
315  parameters.max_comp_size = parameters.max_cs_size / 1.25;
316  parameters.tcp_numlayers = 1;
317  parameters.tcp_mct = 1;
318  parameters.numgbits = fourk ? 2 : 1;
319 
320  /* Setup the encoder parameters using the current image and user parameters */
321  opj_setup_encoder (encoder, &parameters, xyz->opj_image());
322 
323  auto stream = opj_stream_default_create (OPJ_FALSE);
324  if (!stream) {
325  opj_destroy_codec (encoder);
326  free (parameters.cp_comment);
327  throw MiscError ("could not create JPEG2000 stream");
328  }
329 
330  opj_stream_set_write_function (stream, write_function);
331  opj_stream_set_seek_function (stream, seek_function);
332  WriteBuffer* buffer = new WriteBuffer ();
333  opj_stream_set_user_data (stream, buffer, write_free_function);
334 
335  if (!opj_start_compress (encoder, xyz->opj_image(), stream)) {
336  opj_stream_destroy (stream);
337  opj_destroy_codec (encoder);
338  free (parameters.cp_comment);
339  if ((errno & 0x61500) == 0x61500) {
340  /* We've had one of the magic error codes from our patched openjpeg */
341  boost::throw_exception (StartCompressionError (errno & 0xff));
342  } else {
343  boost::throw_exception (StartCompressionError ());
344  }
345  }
346 
347  if (!opj_encode (encoder, stream)) {
348  opj_stream_destroy (stream);
349  opj_destroy_codec (encoder);
350  free (parameters.cp_comment);
351  throw MiscError ("JPEG2000 encoding failed");
352  }
353 
354  if (!opj_end_compress (encoder, stream)) {
355  opj_stream_destroy (stream);
356  opj_destroy_codec (encoder);
357  free (parameters.cp_comment);
358  throw MiscError ("could not end JPEG2000 encoding");
359  }
360 
361  ArrayData enc (buffer->data ());
362 
363  opj_stream_destroy (stream);
364  opj_destroy_codec (encoder);
365  free (parameters.cp_comment);
366 
367  return enc;
368 }
369 
370 #endif
371 
372 
373 #ifdef LIBDCP_OPENJPEG1
374 
375 ArrayData
376 dcp::compress_j2k (shared_ptr<const OpenJPEGImage> xyz, int bandwidth, int frames_per_second, bool threed, bool fourk)
377 {
378  /* Set the max image and component sizes based on frame_rate */
379  int max_cs_len = ((float) bandwidth) / 8 / frames_per_second;
380  if (threed) {
381  /* In 3D we have only half the normal bandwidth per eye */
382  max_cs_len /= 2;
383  }
384  int const max_comp_size = max_cs_len / 1.25;
385 
386  /* get a J2K compressor handle */
387  auto cinfo = opj_create_compress (CODEC_J2K);
388  if (cinfo == nullptr) {
389  throw MiscError ("could not create JPEG2000 encoder");
390  }
391 
392  /* Set encoding parameters to default values */
393  opj_cparameters_t parameters;
394  opj_set_default_encoder_parameters (&parameters);
395  if (fourk) {
396  parameters.numresolution = 7;
397  }
398 
399  /* Set default cinema parameters */
400  parameters.tile_size_on = false;
401  parameters.cp_tdx = 1;
402  parameters.cp_tdy = 1;
403 
404  /* Tile part */
405  parameters.tp_flag = 'C';
406  parameters.tp_on = 1;
407 
408  /* Tile and Image shall be at (0,0) */
409  parameters.cp_tx0 = 0;
410  parameters.cp_ty0 = 0;
411  parameters.image_offset_x0 = 0;
412  parameters.image_offset_y0 = 0;
413 
414  /* Codeblock size = 32x32 */
415  parameters.cblockw_init = 32;
416  parameters.cblockh_init = 32;
417  parameters.csty |= 0x01;
418 
419  /* The progression order shall be CPRL */
420  parameters.prog_order = CPRL;
421 
422  /* No ROI */
423  parameters.roi_compno = -1;
424 
425  parameters.subsampling_dx = 1;
426  parameters.subsampling_dy = 1;
427 
428  /* 9-7 transform */
429  parameters.irreversible = 1;
430 
431  parameters.tcp_rates[0] = 0;
432  parameters.tcp_numlayers++;
433  parameters.cp_disto_alloc = 1;
434  parameters.cp_rsiz = fourk ? CINEMA4K : CINEMA2K;
435  if (fourk) {
436  parameters.numpocs = 2;
437  parameters.POC[0].tile = 1;
438  parameters.POC[0].resno0 = 0;
439  parameters.POC[0].compno0 = 0;
440  parameters.POC[0].layno1 = 1;
441  parameters.POC[0].resno1 = parameters.numresolution - 1;
442  parameters.POC[0].compno1 = 3;
443  parameters.POC[0].prg1 = CPRL;
444  parameters.POC[1].tile = 1;
445  parameters.POC[1].resno0 = parameters.numresolution - 1;
446  parameters.POC[1].compno0 = 0;
447  parameters.POC[1].layno1 = 1;
448  parameters.POC[1].resno1 = parameters.numresolution;
449  parameters.POC[1].compno1 = 3;
450  parameters.POC[1].prg1 = CPRL;
451  }
452 
453  parameters.cp_comment = strdup ("libdcp");
454  parameters.cp_cinema = fourk ? CINEMA4K_24 : CINEMA2K_24;
455 
456  /* 3 components, so use MCT */
457  parameters.tcp_mct = 1;
458 
459  /* set max image */
460  parameters.max_comp_size = max_comp_size;
461  parameters.tcp_rates[0] = ((float) (3 * xyz->size().width * xyz->size().height * 12)) / (max_cs_len * 8);
462 
463  /* Set event manager to null (openjpeg 1.3 bug) */
464  cinfo->event_mgr = 0;
465 
466  /* Setup the encoder parameters using the current image and user parameters */
467  opj_setup_encoder (cinfo, &parameters, xyz->opj_image());
468 
469  auto cio = opj_cio_open ((opj_common_ptr) cinfo, 0, 0);
470  if (cio == nullptr) {
471  opj_destroy_compress (cinfo);
472  throw MiscError ("could not open JPEG2000 stream");
473  }
474 
475  int const r = opj_encode (cinfo, cio, xyz->opj_image(), 0);
476  if (r == 0) {
477  opj_cio_close (cio);
478  opj_destroy_compress (cinfo);
479  throw MiscError ("JPEG2000 encoding failed");
480  }
481 
482  ArrayData enc (cio->buffer, cio_tell (cio));
483 
484  opj_cio_close (cio);
485  free (parameters.cp_comment);
486  opj_destroy_compress (cinfo);
487 
488  return enc;
489 }
490 
491 #endif
ArrayData class.
Class to hold an arbitrary block of data.
Definition: array_data.h:55
Definition: data.h:52
An error that occurs during decompression of JPEG2000 data.
Definition: exceptions.h:135
A miscellaneous exception.
Definition: exceptions.h:94
A wrapper of libopenjpeg's opj_image_t.
Any error that occurs when reading data from a DCP.
Definition: exceptions.h:106
DCP_ASSERT macro.
Exceptions thrown by libdcp.
Methods to encode and decode JPEG2000.
Namespace for everything in libdcp.
Definition: array_data.h:50
ArrayData compress_j2k(std::shared_ptr< const OpenJPEGImage >, int bandwith, int frames_per_second, bool threed, bool fourk, std::string comment="libdcp")
std::shared_ptr< OpenJPEGImage > decompress_j2k(uint8_t const *data, int64_t size, int reduce)
OpenJPEGImage class.