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.
35 /** @file src/j2k_transcode.cc
36 * @brief Methods to encode and decode JPEG2000
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"
54 using std::shared_ptr;
55 using boost::shared_array;
59 shared_ptr<dcp::OpenJPEGImage>
60 dcp::decompress_j2k (Data const& data, int reduce)
62 return dcp::decompress_j2k (data.data(), data.size(), reduce);
66 shared_ptr<dcp::OpenJPEGImage>
67 dcp::decompress_j2k (shared_ptr<const Data> data, int reduce)
69 return dcp::decompress_j2k (data->data(), data->size(), reduce);
76 ReadBuffer (uint8_t const * data, int64_t size)
82 OPJ_SIZE_T read (void* buffer, OPJ_SIZE_T nb_bytes)
84 int64_t N = min (nb_bytes, _size - _offset);
85 memcpy (buffer, _data + _offset, N);
91 uint8_t const * _data;
98 read_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
100 return reinterpret_cast<ReadBuffer*>(data)->read (buffer, nb_bytes);
105 read_free_function (void* data)
107 delete reinterpret_cast<ReadBuffer*>(data);
112 decompress_error_callback (char const * msg, void *)
114 throw J2KDecompressionError (msg);
119 compress_error_callback (char const * msg, void *)
121 throw MiscError (msg);
125 shared_ptr<dcp::OpenJPEGImage>
126 dcp::decompress_j2k (uint8_t const * data, int64_t size, int reduce)
128 DCP_ASSERT (reduce >= 0);
130 uint8_t const jp2_magic[] = {
141 auto format = OPJ_CODEC_J2K;
142 if (size >= int (sizeof (jp2_magic)) && memcmp (data, jp2_magic, sizeof (jp2_magic)) == 0) {
143 format = OPJ_CODEC_JP2;
146 auto decoder = opj_create_decompress (format);
148 boost::throw_exception(ReadError("could not create JPEG2000 decompressor"));
150 opj_dparameters_t parameters;
151 opj_set_default_decoder_parameters (¶meters);
152 parameters.cp_reduce = reduce;
153 opj_setup_decoder (decoder, ¶meters);
155 auto stream = opj_stream_default_create (OPJ_TRUE);
157 throw MiscError ("could not create JPEG2000 stream");
160 opj_set_error_handler(decoder, decompress_error_callback, 00);
162 opj_stream_set_read_function (stream, read_function);
163 auto buffer = new ReadBuffer (data, size);
164 opj_stream_set_user_data (stream, buffer, read_free_function);
165 opj_stream_set_user_data_length (stream, size);
167 opj_image_t* image = 0;
168 opj_read_header (stream, decoder, &image);
169 if (opj_decode (decoder, stream, image) == OPJ_FALSE) {
170 opj_destroy_codec (decoder);
171 opj_stream_destroy (stream);
172 if (format == OPJ_CODEC_J2K) {
173 boost::throw_exception (ReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
175 boost::throw_exception (ReadError (String::compose ("could not decode JP2 file of %1 bytes.", size)));
179 opj_destroy_codec (decoder);
180 opj_stream_destroy (stream);
182 image->x1 = rint (float(image->x1) / pow (2.0f, reduce));
183 image->y1 = rint (float(image->y1) / pow (2.0f, reduce));
184 return std::make_shared<OpenJPEGImage>(image);
191 OPJ_SIZE_T write (void* buffer, OPJ_SIZE_T nb_bytes)
193 auto const new_offset = _offset + nb_bytes;
194 if (new_offset > OPJ_SIZE_T(_data.size())) {
195 _data.set_size(new_offset);
197 memcpy(_data.data() + _offset, buffer, nb_bytes);
198 _offset = new_offset;
202 OPJ_BOOL seek (OPJ_SIZE_T nb_bytes)
208 ArrayData data () const
215 OPJ_SIZE_T _offset = 0;
220 write_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
222 return reinterpret_cast<WriteBuffer*>(data)->write(buffer, nb_bytes);
227 write_free_function (void* data)
229 delete reinterpret_cast<WriteBuffer*>(data);
234 seek_function (OPJ_OFF_T nb_bytes, void* data)
236 return reinterpret_cast<WriteBuffer*>(data)->seek(nb_bytes);
242 dcp::compress_j2k (shared_ptr<const OpenJPEGImage> xyz, int bandwidth, int frames_per_second, bool threed, bool fourk, string comment)
244 /* get a J2K compressor handle */
245 auto encoder = opj_create_compress (OPJ_CODEC_J2K);
246 if (encoder == nullptr) {
247 throw MiscError ("could not create JPEG2000 encoder");
250 if (comment.empty()) {
251 /* asdcplib complains with "Illegal data size" when reading frames encoded with an empty comment */
252 throw MiscError("compress_j2k comment can not be an empty string");
255 opj_set_error_handler (encoder, compress_error_callback, 0);
257 /* Set encoding parameters to default values */
258 opj_cparameters_t parameters;
259 opj_set_default_encoder_parameters (¶meters);
261 parameters.numresolution = 7;
263 parameters.rsiz = fourk ? OPJ_PROFILE_CINEMA_4K : OPJ_PROFILE_CINEMA_2K;
264 parameters.cp_comment = strdup (comment.c_str());
267 parameters.max_cs_size = (bandwidth / 8) / frames_per_second;
269 /* In 3D we have only half the normal bandwidth per eye */
270 parameters.max_cs_size /= 2;
272 parameters.max_comp_size = parameters.max_cs_size / 1.25;
273 parameters.tcp_numlayers = 1;
274 parameters.tcp_mct = 1;
275 #ifdef LIBDCP_HAVE_NUMGBITS
276 parameters.numgbits = fourk ? 2 : 1;
279 /* Setup the encoder parameters using the current image and user parameters */
280 opj_setup_encoder (encoder, ¶meters, xyz->opj_image());
282 #ifndef LIBDCP_HAVE_NUMGBITS
283 string numgbits = String::compose("GUARD_BITS=%1", fourk ? 2 : 1);
284 char const* extra_options[] = { numgbits.c_str(), nullptr };
285 opj_encoder_set_extra_options(encoder, extra_options);
288 auto stream = opj_stream_default_create (OPJ_FALSE);
290 opj_destroy_codec (encoder);
291 free (parameters.cp_comment);
292 throw MiscError ("could not create JPEG2000 stream");
295 opj_stream_set_write_function (stream, write_function);
296 opj_stream_set_seek_function (stream, seek_function);
297 WriteBuffer* buffer = new WriteBuffer ();
298 opj_stream_set_user_data (stream, buffer, write_free_function);
300 if (!opj_start_compress (encoder, xyz->opj_image(), stream)) {
301 opj_stream_destroy (stream);
302 opj_destroy_codec (encoder);
303 free (parameters.cp_comment);
304 if ((errno & 0x61500) == 0x61500) {
305 /* We've had one of the magic error codes from our patched openjpeg */
306 boost::throw_exception (StartCompressionError (errno & 0xff));
308 boost::throw_exception (StartCompressionError ());
312 if (!opj_encode (encoder, stream)) {
313 opj_stream_destroy (stream);
314 opj_destroy_codec (encoder);
315 free (parameters.cp_comment);
316 throw MiscError ("JPEG2000 encoding failed");
319 if (!opj_end_compress (encoder, stream)) {
320 opj_stream_destroy (stream);
321 opj_destroy_codec (encoder);
322 free (parameters.cp_comment);
323 throw MiscError ("could not end JPEG2000 encoding");
326 ArrayData enc (buffer->data ());
328 opj_stream_destroy (stream);
329 opj_destroy_codec (encoder);
330 free (parameters.cp_comment);