2 Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of libdcp.
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.
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.
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/>.
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
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.
36 * @brief Methods to encode and decode JPEG2000
40 #include "array_data.h"
42 #include "exceptions.h"
43 #include "openjpeg_image.h"
44 #include "dcp_assert.h"
45 #include "compose.hpp"
54 using std::shared_ptr;
55 using boost::shared_array;
59 shared_ptr<dcp::OpenJPEGImage>
60 dcp::decompress_j2k (ArrayData data, int reduce)
62 return dcp::decompress_j2k (data.data(), data.size(), reduce);
66 #ifdef LIBDCP_OPENJPEG2
71 ReadBuffer (uint8_t* data, int64_t size)
77 OPJ_SIZE_T read (void* buffer, OPJ_SIZE_T nb_bytes)
79 int64_t N = min (nb_bytes, _size - _offset);
80 memcpy (buffer, _data + _offset, N);
93 read_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
95 return reinterpret_cast<ReadBuffer*>(data)->read (buffer, nb_bytes);
100 read_free_function (void* data)
102 delete reinterpret_cast<ReadBuffer*>(data);
107 decompress_error_callback (char const * msg, void *)
109 throw J2KDecompressionError (msg);
114 compress_error_callback (char const * msg, void *)
116 throw MiscError (msg);
120 shared_ptr<dcp::OpenJPEGImage>
121 dcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
123 DCP_ASSERT (reduce >= 0);
125 uint8_t const jp2_magic[] = {
136 auto format = OPJ_CODEC_J2K;
137 if (size >= int (sizeof (jp2_magic)) && memcmp (data, jp2_magic, sizeof (jp2_magic)) == 0) {
138 format = OPJ_CODEC_JP2;
141 auto decoder = opj_create_decompress (format);
143 boost::throw_exception (ReadError ("could not create JPEG2000 decompresser"));
145 opj_dparameters_t parameters;
146 opj_set_default_decoder_parameters (¶meters);
147 parameters.cp_reduce = reduce;
148 opj_setup_decoder (decoder, ¶meters);
150 auto stream = opj_stream_default_create (OPJ_TRUE);
152 throw MiscError ("could not create JPEG2000 stream");
155 opj_set_error_handler(decoder, decompress_error_callback, 00);
157 opj_stream_set_read_function (stream, read_function);
158 auto buffer = new ReadBuffer (data, size);
159 opj_stream_set_user_data (stream, buffer, read_free_function);
160 opj_stream_set_user_data_length (stream, size);
162 opj_image_t* image = 0;
163 opj_read_header (stream, decoder, &image);
164 if (opj_decode (decoder, stream, image) == OPJ_FALSE) {
165 opj_destroy_codec (decoder);
166 opj_stream_destroy (stream);
167 if (format == OPJ_CODEC_J2K) {
168 boost::throw_exception (ReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
170 boost::throw_exception (ReadError (String::compose ("could not decode JP2 file of %1 bytes.", size)));
174 opj_destroy_codec (decoder);
175 opj_stream_destroy (stream);
177 image->x1 = rint (float(image->x1) / pow (2.0f, reduce));
178 image->y1 = rint (float(image->y1) / pow (2.0f, reduce));
179 return shared_ptr<OpenJPEGImage> (new OpenJPEGImage (image));
185 #ifdef LIBDCP_OPENJPEG1
187 shared_ptr<dcp::OpenJPEGImage>
188 dcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
190 auto decoder = opj_create_decompress (CODEC_J2K);
191 opj_dparameters_t parameters;
192 opj_set_default_decoder_parameters (¶meters);
193 parameters.cp_reduce = reduce;
194 opj_setup_decoder (decoder, ¶meters);
195 auto cio = opj_cio_open ((opj_common_ptr) decoder, data, size);
196 auto image = opj_decode (decoder, cio);
198 opj_destroy_decompress (decoder);
200 boost::throw_exception (ReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
203 opj_destroy_decompress (decoder);
206 image->x1 = rint (float(image->x1) / pow (2, reduce));
207 image->y1 = rint (float(image->y1) / pow (2, reduce));
208 return shared_ptr<OpenJPEGImage> (new OpenJPEGImage (image));
213 #ifdef LIBDCP_OPENJPEG2
218 /* XXX: is there a better strategy for this? */
219 #define MAX_J2K_SIZE (1024 * 1024 * 2)
221 : _data (shared_array<uint8_t>(new uint8_t[MAX_J2K_SIZE]), MAX_J2K_SIZE)
227 OPJ_SIZE_T write (void* buffer, OPJ_SIZE_T nb_bytes)
229 DCP_ASSERT ((_offset + nb_bytes) < MAX_J2K_SIZE);
230 memcpy (_data.data() + _offset, buffer, nb_bytes);
232 if (_offset > OPJ_SIZE_T(_data.size())) {
233 _data.set_size (_offset);
238 OPJ_BOOL seek (OPJ_SIZE_T nb_bytes)
244 ArrayData data () const
256 write_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
258 return reinterpret_cast<WriteBuffer*>(data)->write(buffer, nb_bytes);
263 write_free_function (void* data)
265 delete reinterpret_cast<WriteBuffer*>(data);
270 seek_function (OPJ_OFF_T nb_bytes, void* data)
272 return reinterpret_cast<WriteBuffer*>(data)->seek(nb_bytes);
278 dcp::compress_j2k (shared_ptr<const OpenJPEGImage> xyz, int bandwidth, int frames_per_second, bool threed, bool fourk, string comment)
280 /* get a J2K compressor handle */
281 auto encoder = opj_create_compress (OPJ_CODEC_J2K);
282 if (encoder == nullptr) {
283 throw MiscError ("could not create JPEG2000 encoder");
286 if (comment.empty()) {
287 /* asdcplib complains with "Illegal data size" when reading frames encoded with an empty comment */
288 throw MiscError("compress_j2k comment can not be an empty string");
291 opj_set_error_handler (encoder, compress_error_callback, 0);
293 /* Set encoding parameters to default values */
294 opj_cparameters_t parameters;
295 opj_set_default_encoder_parameters (¶meters);
297 parameters.numresolution = 7;
299 parameters.rsiz = fourk ? OPJ_PROFILE_CINEMA_4K : OPJ_PROFILE_CINEMA_2K;
300 parameters.cp_comment = strdup (comment.c_str());
303 parameters.max_cs_size = (bandwidth / 8) / frames_per_second;
305 /* In 3D we have only half the normal bandwidth per eye */
306 parameters.max_cs_size /= 2;
308 parameters.max_comp_size = parameters.max_cs_size / 1.25;
309 parameters.tcp_numlayers = 1;
310 parameters.tcp_mct = 1;
312 /* Setup the encoder parameters using the current image and user parameters */
313 opj_setup_encoder (encoder, ¶meters, xyz->opj_image());
315 auto stream = opj_stream_default_create (OPJ_FALSE);
317 opj_destroy_codec (encoder);
318 free (parameters.cp_comment);
319 throw MiscError ("could not create JPEG2000 stream");
322 opj_stream_set_write_function (stream, write_function);
323 opj_stream_set_seek_function (stream, seek_function);
324 WriteBuffer* buffer = new WriteBuffer ();
325 opj_stream_set_user_data (stream, buffer, write_free_function);
327 if (!opj_start_compress (encoder, xyz->opj_image(), stream)) {
328 opj_stream_destroy (stream);
329 opj_destroy_codec (encoder);
330 free (parameters.cp_comment);
331 if ((errno & 0x61500) == 0x61500) {
332 /* We've had one of the magic error codes from our patched openjpeg */
333 boost::throw_exception (StartCompressionError (errno & 0xff));
335 boost::throw_exception (StartCompressionError ());
339 if (!opj_encode (encoder, stream)) {
340 opj_stream_destroy (stream);
341 opj_destroy_codec (encoder);
342 free (parameters.cp_comment);
343 throw MiscError ("JPEG2000 encoding failed");
346 if (!opj_end_compress (encoder, stream)) {
347 opj_stream_destroy (stream);
348 opj_destroy_codec (encoder);
349 free (parameters.cp_comment);
350 throw MiscError ("could not end JPEG2000 encoding");
353 ArrayData enc (buffer->data ());
355 opj_stream_destroy (stream);
356 opj_destroy_codec (encoder);
357 free (parameters.cp_comment);
365 #ifdef LIBDCP_OPENJPEG1
368 dcp::compress_j2k (shared_ptr<const OpenJPEGImage> xyz, int bandwidth, int frames_per_second, bool threed, bool fourk)
370 /* Set the max image and component sizes based on frame_rate */
371 int max_cs_len = ((float) bandwidth) / 8 / frames_per_second;
373 /* In 3D we have only half the normal bandwidth per eye */
376 int const max_comp_size = max_cs_len / 1.25;
378 /* get a J2K compressor handle */
379 auto cinfo = opj_create_compress (CODEC_J2K);
380 if (cinfo == nullptr) {
381 throw MiscError ("could not create JPEG2000 encoder");
384 /* Set encoding parameters to default values */
385 opj_cparameters_t parameters;
386 opj_set_default_encoder_parameters (¶meters);
388 parameters.numresolution = 7;
391 /* Set default cinema parameters */
392 parameters.tile_size_on = false;
393 parameters.cp_tdx = 1;
394 parameters.cp_tdy = 1;
397 parameters.tp_flag = 'C';
398 parameters.tp_on = 1;
400 /* Tile and Image shall be at (0,0) */
401 parameters.cp_tx0 = 0;
402 parameters.cp_ty0 = 0;
403 parameters.image_offset_x0 = 0;
404 parameters.image_offset_y0 = 0;
406 /* Codeblock size = 32x32 */
407 parameters.cblockw_init = 32;
408 parameters.cblockh_init = 32;
409 parameters.csty |= 0x01;
411 /* The progression order shall be CPRL */
412 parameters.prog_order = CPRL;
415 parameters.roi_compno = -1;
417 parameters.subsampling_dx = 1;
418 parameters.subsampling_dy = 1;
421 parameters.irreversible = 1;
423 parameters.tcp_rates[0] = 0;
424 parameters.tcp_numlayers++;
425 parameters.cp_disto_alloc = 1;
426 parameters.cp_rsiz = fourk ? CINEMA4K : CINEMA2K;
428 parameters.numpocs = 2;
429 parameters.POC[0].tile = 1;
430 parameters.POC[0].resno0 = 0;
431 parameters.POC[0].compno0 = 0;
432 parameters.POC[0].layno1 = 1;
433 parameters.POC[0].resno1 = parameters.numresolution - 1;
434 parameters.POC[0].compno1 = 3;
435 parameters.POC[0].prg1 = CPRL;
436 parameters.POC[1].tile = 1;
437 parameters.POC[1].resno0 = parameters.numresolution - 1;
438 parameters.POC[1].compno0 = 0;
439 parameters.POC[1].layno1 = 1;
440 parameters.POC[1].resno1 = parameters.numresolution;
441 parameters.POC[1].compno1 = 3;
442 parameters.POC[1].prg1 = CPRL;
445 parameters.cp_comment = strdup ("libdcp");
446 parameters.cp_cinema = fourk ? CINEMA4K_24 : CINEMA2K_24;
448 /* 3 components, so use MCT */
449 parameters.tcp_mct = 1;
452 parameters.max_comp_size = max_comp_size;
453 parameters.tcp_rates[0] = ((float) (3 * xyz->size().width * xyz->size().height * 12)) / (max_cs_len * 8);
455 /* Set event manager to null (openjpeg 1.3 bug) */
456 cinfo->event_mgr = 0;
458 /* Setup the encoder parameters using the current image and user parameters */
459 opj_setup_encoder (cinfo, ¶meters, xyz->opj_image());
461 auto cio = opj_cio_open ((opj_common_ptr) cinfo, 0, 0);
462 if (cio == nullptr) {
463 opj_destroy_compress (cinfo);
464 throw MiscError ("could not open JPEG2000 stream");
467 int const r = opj_encode (cinfo, cio, xyz->opj_image(), 0);
470 opj_destroy_compress (cinfo);
471 throw MiscError ("JPEG2000 encoding failed");
474 ArrayData enc (cio->buffer, cio_tell (cio));
477 free (parameters.cp_comment);
478 opj_destroy_compress (cinfo);