Add a nice note for general MXF errors.
[libdcp.git] / src / j2k_transcode.cc
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
35 /** @file  src/j2k_transcode.cc
36  *  @brief Methods to encode and decode JPEG2000
37  */
38
39
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 class ReadBuffer
74 {
75 public:
76         ReadBuffer (uint8_t const * data, int64_t size)
77                 : _data (data)
78                 , _size (size)
79                 , _offset (0)
80         {}
81
82         OPJ_SIZE_T read (void* buffer, OPJ_SIZE_T nb_bytes)
83         {
84                 int64_t N = min (nb_bytes, _size - _offset);
85                 memcpy (buffer, _data + _offset, N);
86                 _offset += N;
87                 return N;
88         }
89
90 private:
91         uint8_t const * _data;
92         OPJ_SIZE_T _size;
93         OPJ_SIZE_T _offset;
94 };
95
96
97 static OPJ_SIZE_T
98 read_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
99 {
100         return reinterpret_cast<ReadBuffer*>(data)->read (buffer, nb_bytes);
101 }
102
103
104 static void
105 read_free_function (void* data)
106 {
107         delete reinterpret_cast<ReadBuffer*>(data);
108 }
109
110
111 static void
112 decompress_error_callback (char const * msg, void *)
113 {
114         throw J2KDecompressionError (msg);
115 }
116
117
118 static void
119 compress_error_callback (char const * msg, void *)
120 {
121         throw MiscError (msg);
122 }
123
124
125 shared_ptr<dcp::OpenJPEGImage>
126 dcp::decompress_j2k (uint8_t const * data, int64_t size, int reduce)
127 {
128         DCP_ASSERT (reduce >= 0);
129
130         uint8_t const jp2_magic[] = {
131                 0x00,
132                 0x00,
133                 0x00,
134                 0x0c,
135                 'j',
136                 'P',
137                 0x20,
138                 0x20
139         };
140
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;
144         }
145
146         auto decoder = opj_create_decompress (format);
147         if (!decoder) {
148                 boost::throw_exception (ReadError ("could not create JPEG2000 decompresser"));
149         }
150         opj_dparameters_t parameters;
151         opj_set_default_decoder_parameters (&parameters);
152         parameters.cp_reduce = reduce;
153         opj_setup_decoder (decoder, &parameters);
154
155         auto stream = opj_stream_default_create (OPJ_TRUE);
156         if (!stream) {
157                 throw MiscError ("could not create JPEG2000 stream");
158         }
159
160         opj_set_error_handler(decoder, decompress_error_callback, 00);
161
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);
166
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)));
174                 } else {
175                         boost::throw_exception (ReadError (String::compose ("could not decode JP2 file of %1 bytes.", size)));
176                 }
177         }
178
179         opj_destroy_codec (decoder);
180         opj_stream_destroy (stream);
181
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);
185 }
186
187
188 class WriteBuffer
189 {
190 public:
191 /* XXX: is there a better strategy for this? */
192 #define MAX_J2K_SIZE (1024 * 1024 * 2)
193         WriteBuffer ()
194                 : _data (shared_array<uint8_t>(new uint8_t[MAX_J2K_SIZE]), MAX_J2K_SIZE)
195                 , _offset (0)
196         {
197                 _data.set_size (0);
198         }
199
200         OPJ_SIZE_T write (void* buffer, OPJ_SIZE_T nb_bytes)
201         {
202                 DCP_ASSERT ((_offset + nb_bytes) < MAX_J2K_SIZE);
203                 memcpy (_data.data() + _offset, buffer, nb_bytes);
204                 _offset += nb_bytes;
205                 if (_offset > OPJ_SIZE_T(_data.size())) {
206                         _data.set_size (_offset);
207                 }
208                 return nb_bytes;
209         }
210
211         OPJ_BOOL seek (OPJ_SIZE_T nb_bytes)
212         {
213                 _offset = nb_bytes;
214                 return OPJ_TRUE;
215         }
216
217         ArrayData data () const
218         {
219                 return _data;
220         }
221
222 private:
223         ArrayData _data;
224         OPJ_SIZE_T _offset;
225 };
226
227
228 static OPJ_SIZE_T
229 write_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
230 {
231         return reinterpret_cast<WriteBuffer*>(data)->write(buffer, nb_bytes);
232 }
233
234
235 static void
236 write_free_function (void* data)
237 {
238         delete reinterpret_cast<WriteBuffer*>(data);
239 }
240
241
242 static OPJ_BOOL
243 seek_function (OPJ_OFF_T nb_bytes, void* data)
244 {
245         return reinterpret_cast<WriteBuffer*>(data)->seek(nb_bytes);
246
247 }
248
249
250 ArrayData
251 dcp::compress_j2k (shared_ptr<const OpenJPEGImage> xyz, int bandwidth, int frames_per_second, bool threed, bool fourk, string comment)
252 {
253         /* get a J2K compressor handle */
254         auto encoder = opj_create_compress (OPJ_CODEC_J2K);
255         if (encoder == nullptr) {
256                 throw MiscError ("could not create JPEG2000 encoder");
257         }
258
259         if (comment.empty()) {
260                 /* asdcplib complains with "Illegal data size" when reading frames encoded with an empty comment */
261                 throw MiscError("compress_j2k comment can not be an empty string");
262         }
263
264         opj_set_error_handler (encoder, compress_error_callback, 0);
265
266         /* Set encoding parameters to default values */
267         opj_cparameters_t parameters;
268         opj_set_default_encoder_parameters (&parameters);
269         if (fourk) {
270                 parameters.numresolution = 7;
271         }
272         parameters.rsiz = fourk ? OPJ_PROFILE_CINEMA_4K : OPJ_PROFILE_CINEMA_2K;
273         parameters.cp_comment = strdup (comment.c_str());
274
275         /* set max image */
276         parameters.max_cs_size = (bandwidth / 8) / frames_per_second;
277         if (threed) {
278                 /* In 3D we have only half the normal bandwidth per eye */
279                 parameters.max_cs_size /= 2;
280         }
281         parameters.max_comp_size = parameters.max_cs_size / 1.25;
282         parameters.tcp_numlayers = 1;
283         parameters.tcp_mct = 1;
284 #ifdef LIBDCP_HAVE_NUMGBITS
285         parameters.numgbits = fourk ? 2 : 1;
286 #endif
287
288         /* Setup the encoder parameters using the current image and user parameters */
289         opj_setup_encoder (encoder, &parameters, xyz->opj_image());
290
291 #ifndef LIBDCP_HAVE_NUMGBITS
292         string numgbits = String::compose("GUARD_BITS=%1", fourk ? 2 : 1);
293         char const* extra_options[] = { numgbits.c_str(), nullptr };
294         opj_encoder_set_extra_options(encoder, extra_options);
295 #endif
296
297         auto stream = opj_stream_default_create (OPJ_FALSE);
298         if (!stream) {
299                 opj_destroy_codec (encoder);
300                 free (parameters.cp_comment);
301                 throw MiscError ("could not create JPEG2000 stream");
302         }
303
304         opj_stream_set_write_function (stream, write_function);
305         opj_stream_set_seek_function (stream, seek_function);
306         WriteBuffer* buffer = new WriteBuffer ();
307         opj_stream_set_user_data (stream, buffer, write_free_function);
308
309         if (!opj_start_compress (encoder, xyz->opj_image(), stream)) {
310                 opj_stream_destroy (stream);
311                 opj_destroy_codec (encoder);
312                 free (parameters.cp_comment);
313                 if ((errno & 0x61500) == 0x61500) {
314                         /* We've had one of the magic error codes from our patched openjpeg */
315                         boost::throw_exception (StartCompressionError (errno & 0xff));
316                 } else {
317                         boost::throw_exception (StartCompressionError ());
318                 }
319         }
320
321         if (!opj_encode (encoder, stream)) {
322                 opj_stream_destroy (stream);
323                 opj_destroy_codec (encoder);
324                 free (parameters.cp_comment);
325                 throw MiscError ("JPEG2000 encoding failed");
326         }
327
328         if (!opj_end_compress (encoder, stream)) {
329                 opj_stream_destroy (stream);
330                 opj_destroy_codec (encoder);
331                 free (parameters.cp_comment);
332                 throw MiscError ("could not end JPEG2000 encoding");
333         }
334
335         ArrayData enc (buffer->data ());
336
337         opj_stream_destroy (stream);
338         opj_destroy_codec (encoder);
339         free (parameters.cp_comment);
340
341         return enc;
342 }
343