Tidying.
[libdcp.git] / src / j2k.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.cc
36  *  @brief Methods to encode and decode JPEG2000
37  */
38
39
40 #include "array_data.h"
41 #include "j2k.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 (ArrayData data, int reduce)
61 {
62         return dcp::decompress_j2k (data.data(), data.size(), reduce);
63 }
64
65
66 #ifdef LIBDCP_OPENJPEG2
67
68 class ReadBuffer
69 {
70 public:
71         ReadBuffer (uint8_t* data, int64_t size)
72                 : _data (data)
73                 , _size (size)
74                 , _offset (0)
75         {}
76
77         OPJ_SIZE_T read (void* buffer, OPJ_SIZE_T nb_bytes)
78         {
79                 int64_t N = min (nb_bytes, _size - _offset);
80                 memcpy (buffer, _data + _offset, N);
81                 _offset += N;
82                 return N;
83         }
84
85 private:
86         uint8_t* _data;
87         OPJ_SIZE_T _size;
88         OPJ_SIZE_T _offset;
89 };
90
91
92 static OPJ_SIZE_T
93 read_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
94 {
95         return reinterpret_cast<ReadBuffer*>(data)->read (buffer, nb_bytes);
96 }
97
98
99 static void
100 read_free_function (void* data)
101 {
102         delete reinterpret_cast<ReadBuffer*>(data);
103 }
104
105
106 static void
107 decompress_error_callback (char const * msg, void *)
108 {
109         throw J2KDecompressionError (msg);
110 }
111
112
113 static void
114 compress_error_callback (char const * msg, void *)
115 {
116         throw MiscError (msg);
117 }
118
119
120 shared_ptr<dcp::OpenJPEGImage>
121 dcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
122 {
123         DCP_ASSERT (reduce >= 0);
124
125         uint8_t const jp2_magic[] = {
126                 0x00,
127                 0x00,
128                 0x00,
129                 0x0c,
130                 'j',
131                 'P',
132                 0x20,
133                 0x20
134         };
135
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;
139         }
140
141         auto decoder = opj_create_decompress (format);
142         if (!decoder) {
143                 boost::throw_exception (ReadError ("could not create JPEG2000 decompresser"));
144         }
145         opj_dparameters_t parameters;
146         opj_set_default_decoder_parameters (&parameters);
147         parameters.cp_reduce = reduce;
148         opj_setup_decoder (decoder, &parameters);
149
150         auto stream = opj_stream_default_create (OPJ_TRUE);
151         if (!stream) {
152                 throw MiscError ("could not create JPEG2000 stream");
153         }
154
155         opj_set_error_handler(decoder, decompress_error_callback, 00);
156
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);
161
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)));
169                 } else {
170                         boost::throw_exception (ReadError (String::compose ("could not decode JP2 file of %1 bytes.", size)));
171                 }
172         }
173
174         opj_destroy_codec (decoder);
175         opj_stream_destroy (stream);
176
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));
180 }
181
182 #endif
183
184
185 #ifdef LIBDCP_OPENJPEG1
186
187 shared_ptr<dcp::OpenJPEGImage>
188 dcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
189 {
190         auto decoder = opj_create_decompress (CODEC_J2K);
191         opj_dparameters_t parameters;
192         opj_set_default_decoder_parameters (&parameters);
193         parameters.cp_reduce = reduce;
194         opj_setup_decoder (decoder, &parameters);
195         auto cio = opj_cio_open ((opj_common_ptr) decoder, data, size);
196         auto image = opj_decode (decoder, cio);
197         if (!image) {
198                 opj_destroy_decompress (decoder);
199                 opj_cio_close (cio);
200                 boost::throw_exception (ReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
201         }
202
203         opj_destroy_decompress (decoder);
204         opj_cio_close (cio);
205
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));
209 }
210 #endif
211
212
213 #ifdef LIBDCP_OPENJPEG2
214
215 class WriteBuffer
216 {
217 public:
218 /* XXX: is there a better strategy for this? */
219 #define MAX_J2K_SIZE (1024 * 1024 * 2)
220         WriteBuffer ()
221                 : _data (shared_array<uint8_t>(new uint8_t[MAX_J2K_SIZE]), MAX_J2K_SIZE)
222                 , _offset (0)
223         {
224                 _data.set_size (0);
225         }
226
227         OPJ_SIZE_T write (void* buffer, OPJ_SIZE_T nb_bytes)
228         {
229                 DCP_ASSERT ((_offset + nb_bytes) < MAX_J2K_SIZE);
230                 memcpy (_data.data() + _offset, buffer, nb_bytes);
231                 _offset += nb_bytes;
232                 if (_offset > OPJ_SIZE_T(_data.size())) {
233                         _data.set_size (_offset);
234                 }
235                 return nb_bytes;
236         }
237
238         OPJ_BOOL seek (OPJ_SIZE_T nb_bytes)
239         {
240                 _offset = nb_bytes;
241                 return OPJ_TRUE;
242         }
243
244         ArrayData data () const
245         {
246                 return _data;
247         }
248
249 private:
250         ArrayData _data;
251         OPJ_SIZE_T _offset;
252 };
253
254
255 static OPJ_SIZE_T
256 write_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
257 {
258         return reinterpret_cast<WriteBuffer*>(data)->write(buffer, nb_bytes);
259 }
260
261
262 static void
263 write_free_function (void* data)
264 {
265         delete reinterpret_cast<WriteBuffer*>(data);
266 }
267
268
269 static OPJ_BOOL
270 seek_function (OPJ_OFF_T nb_bytes, void* data)
271 {
272         return reinterpret_cast<WriteBuffer*>(data)->seek(nb_bytes);
273
274 }
275
276
277 ArrayData
278 dcp::compress_j2k (shared_ptr<const OpenJPEGImage> xyz, int bandwidth, int frames_per_second, bool threed, bool fourk, string comment)
279 {
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");
284         }
285
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");
289         }
290
291         opj_set_error_handler (encoder, compress_error_callback, 0);
292
293         /* Set encoding parameters to default values */
294         opj_cparameters_t parameters;
295         opj_set_default_encoder_parameters (&parameters);
296         if (fourk) {
297                 parameters.numresolution = 7;
298         }
299         parameters.rsiz = fourk ? OPJ_PROFILE_CINEMA_4K : OPJ_PROFILE_CINEMA_2K;
300         parameters.cp_comment = strdup (comment.c_str());
301
302         /* set max image */
303         parameters.max_cs_size = (bandwidth / 8) / frames_per_second;
304         if (threed) {
305                 /* In 3D we have only half the normal bandwidth per eye */
306                 parameters.max_cs_size /= 2;
307         }
308         parameters.max_comp_size = parameters.max_cs_size / 1.25;
309         parameters.tcp_numlayers = 1;
310         parameters.tcp_mct = 1;
311
312         /* Setup the encoder parameters using the current image and user parameters */
313         opj_setup_encoder (encoder, &parameters, xyz->opj_image());
314
315         auto stream = opj_stream_default_create (OPJ_FALSE);
316         if (!stream) {
317                 opj_destroy_codec (encoder);
318                 free (parameters.cp_comment);
319                 throw MiscError ("could not create JPEG2000 stream");
320         }
321
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);
326
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));
334                 } else {
335                         boost::throw_exception (StartCompressionError ());
336                 }
337         }
338
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");
344         }
345
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");
351         }
352
353         ArrayData enc (buffer->data ());
354
355         opj_stream_destroy (stream);
356         opj_destroy_codec (encoder);
357         free (parameters.cp_comment);
358
359         return enc;
360 }
361
362 #endif
363
364
365 #ifdef LIBDCP_OPENJPEG1
366
367 ArrayData
368 dcp::compress_j2k (shared_ptr<const OpenJPEGImage> xyz, int bandwidth, int frames_per_second, bool threed, bool fourk)
369 {
370         /* Set the max image and component sizes based on frame_rate */
371         int max_cs_len = ((float) bandwidth) / 8 / frames_per_second;
372         if (threed) {
373                 /* In 3D we have only half the normal bandwidth per eye */
374                 max_cs_len /= 2;
375         }
376         int const max_comp_size = max_cs_len / 1.25;
377
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");
382         }
383
384         /* Set encoding parameters to default values */
385         opj_cparameters_t parameters;
386         opj_set_default_encoder_parameters (&parameters);
387         if (fourk) {
388                 parameters.numresolution = 7;
389         }
390
391         /* Set default cinema parameters */
392         parameters.tile_size_on = false;
393         parameters.cp_tdx = 1;
394         parameters.cp_tdy = 1;
395
396         /* Tile part */
397         parameters.tp_flag = 'C';
398         parameters.tp_on = 1;
399
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;
405
406         /* Codeblock size = 32x32 */
407         parameters.cblockw_init = 32;
408         parameters.cblockh_init = 32;
409         parameters.csty |= 0x01;
410
411         /* The progression order shall be CPRL */
412         parameters.prog_order = CPRL;
413
414         /* No ROI */
415         parameters.roi_compno = -1;
416
417         parameters.subsampling_dx = 1;
418         parameters.subsampling_dy = 1;
419
420         /* 9-7 transform */
421         parameters.irreversible = 1;
422
423         parameters.tcp_rates[0] = 0;
424         parameters.tcp_numlayers++;
425         parameters.cp_disto_alloc = 1;
426         parameters.cp_rsiz = fourk ? CINEMA4K : CINEMA2K;
427         if (fourk) {
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;
443         }
444
445         parameters.cp_comment = strdup ("libdcp");
446         parameters.cp_cinema = fourk ? CINEMA4K_24 : CINEMA2K_24;
447
448         /* 3 components, so use MCT */
449         parameters.tcp_mct = 1;
450
451         /* set max image */
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);
454
455         /* Set event manager to null (openjpeg 1.3 bug) */
456         cinfo->event_mgr = 0;
457
458         /* Setup the encoder parameters using the current image and user parameters */
459         opj_setup_encoder (cinfo, &parameters, xyz->opj_image());
460
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");
465         }
466
467         int const r = opj_encode (cinfo, cio, xyz->opj_image(), 0);
468         if (r == 0) {
469                 opj_cio_close (cio);
470                 opj_destroy_compress (cinfo);
471                 throw MiscError ("JPEG2000 encoding failed");
472         }
473
474         ArrayData enc (cio->buffer, cio_tell (cio));
475
476         opj_cio_close (cio);
477         free (parameters.cp_comment);
478         opj_destroy_compress (cinfo);
479
480         return enc;
481 }
482
483 #endif