Make similar changes to the previous commit for _xml_id.
[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 #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