Add OpenSSL licence exception.
[libdcp.git] / src / j2k.cc
1 /*
2     Copyright (C) 2012-2015 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 #include "j2k.h"
35 #include "exceptions.h"
36 #include "openjpeg_image.h"
37 #include "data.h"
38 #include "dcp_assert.h"
39 #include "compose.hpp"
40 #include <openjpeg.h>
41 #include <cmath>
42 #include <iostream>
43
44 using std::min;
45 using std::pow;
46 using boost::shared_ptr;
47 using boost::shared_array;
48 using namespace dcp;
49
50 shared_ptr<dcp::OpenJPEGImage>
51 dcp::decompress_j2k (Data data, int reduce)
52 {
53         return dcp::decompress_j2k (data.data().get(), data.size(), reduce);
54 }
55
56 class ReadBuffer
57 {
58 public:
59         ReadBuffer (uint8_t* data, int64_t size)
60                 : _data (data)
61                 , _size (size)
62                 , _offset (0)
63         {}
64
65         OPJ_SIZE_T read (void* buffer, OPJ_SIZE_T nb_bytes)
66         {
67                 int64_t N = min (nb_bytes, _size - _offset);
68                 memcpy (buffer, _data + _offset, N);
69                 _offset += N;
70                 return N;
71         }
72
73 private:
74         uint8_t* _data;
75         OPJ_SIZE_T _size;
76         OPJ_SIZE_T _offset;
77 };
78
79 static OPJ_SIZE_T
80 read_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
81 {
82         return reinterpret_cast<ReadBuffer*>(data)->read (buffer, nb_bytes);
83 }
84
85 static void
86 read_free_function (void* data)
87 {
88         delete reinterpret_cast<ReadBuffer*>(data);
89 }
90
91 /** Decompress a JPEG2000 image to a bitmap.
92  *  @param data JPEG2000 data.
93  *  @param size Size of data in bytes.
94  *  @param reduce A power of 2 by which to reduce the size of the decoded image;
95  *  e.g. 0 reduces by (2^0 == 1), ie keeping the same size.
96  *       1 reduces by (2^1 == 2), ie halving the size of the image.
97  *  This is useful for scaling 4K DCP images down to 2K.
98  *  @return OpenJPEGImage.
99  */
100 shared_ptr<dcp::OpenJPEGImage>
101 dcp::decompress_j2k (uint8_t* data, int64_t size, int reduce)
102 {
103         uint8_t const jp2_magic[] = {
104                 0x00,
105                 0x00,
106                 0x00,
107                 0x0c,
108                 'j',
109                 'P',
110                 0x20,
111                 0x20
112         };
113
114         OPJ_CODEC_FORMAT format = OPJ_CODEC_J2K;
115         if (size >= int (sizeof (jp2_magic)) && memcmp (data, jp2_magic, sizeof (jp2_magic)) == 0) {
116                 format = OPJ_CODEC_JP2;
117         }
118
119         opj_codec_t* decoder = opj_create_decompress (format);
120         if (!decoder) {
121                 boost::throw_exception (DCPReadError ("could not create JPEG2000 decompresser"));
122         }
123         opj_dparameters_t parameters;
124         opj_set_default_decoder_parameters (&parameters);
125         parameters.cp_reduce = reduce;
126         opj_setup_decoder (decoder, &parameters);
127
128         opj_stream_t* stream = opj_stream_default_create (OPJ_TRUE);
129         if (!stream) {
130                 throw MiscError ("could not create JPEG2000 stream");
131         }
132
133         opj_stream_set_read_function (stream, read_function);
134         ReadBuffer* buffer = new ReadBuffer (data, size);
135         opj_stream_set_user_data (stream, buffer, read_free_function);
136         opj_stream_set_user_data_length (stream, size);
137
138         opj_image_t* image = 0;
139         opj_read_header (stream, decoder, &image);
140         if (opj_decode (decoder, stream, image) == OPJ_FALSE) {
141                 opj_destroy_codec (decoder);
142                 opj_stream_destroy (stream);
143                 if (format == OPJ_CODEC_J2K) {
144                         boost::throw_exception (DCPReadError (String::compose ("could not decode JPEG2000 codestream of %1 bytes.", size)));
145                 } else {
146                         boost::throw_exception (DCPReadError (String::compose ("could not decode JP2 file of %1 bytes.", size)));
147                 }
148         }
149
150         opj_destroy_codec (decoder);
151         opj_stream_destroy (stream);
152
153         image->x1 = rint (float(image->x1) / pow (2.0f, reduce));
154         image->y1 = rint (float(image->y1) / pow (2.0f, reduce));
155         return shared_ptr<OpenJPEGImage> (new OpenJPEGImage (image));
156 }
157
158 class WriteBuffer
159 {
160 public:
161 /* XXX: is there a better strategy for this? */
162 #define MAX_J2K_SIZE (1024 * 1024 * 2)
163         WriteBuffer ()
164                 : _data (shared_array<uint8_t> (new uint8_t[MAX_J2K_SIZE]), MAX_J2K_SIZE)
165                 , _offset (0)
166         {
167                 _data.set_size (0);
168         }
169
170         OPJ_SIZE_T write (void* buffer, OPJ_SIZE_T nb_bytes)
171         {
172                 DCP_ASSERT ((_offset + nb_bytes) < MAX_J2K_SIZE);
173                 memcpy (_data.data().get() + _offset, buffer, nb_bytes);
174                 _offset += nb_bytes;
175                 if (_offset > OPJ_SIZE_T (_data.size())) {
176                         _data.set_size (_offset);
177                 }
178                 return nb_bytes;
179         }
180
181         OPJ_BOOL seek (OPJ_SIZE_T nb_bytes)
182         {
183                 _offset = nb_bytes;
184                 return OPJ_TRUE;
185         }
186
187         Data data () const
188         {
189                 return _data;
190         }
191
192 private:
193         Data _data;
194         OPJ_SIZE_T _offset;
195 };
196
197 static OPJ_SIZE_T
198 write_function (void* buffer, OPJ_SIZE_T nb_bytes, void* data)
199 {
200         return reinterpret_cast<WriteBuffer*>(data)->write (buffer, nb_bytes);
201 }
202
203 static void
204 write_free_function (void* data)
205 {
206         delete reinterpret_cast<WriteBuffer*>(data);
207 }
208
209 static OPJ_BOOL
210 seek_function (OPJ_OFF_T nb_bytes, void* data)
211 {
212         return reinterpret_cast<WriteBuffer*>(data)->seek (nb_bytes);
213 }
214
215 static void
216 error_callback (char const * msg, void *)
217 {
218         throw MiscError (msg);
219 }
220
221 Data
222 dcp::compress_j2k (shared_ptr<const OpenJPEGImage> xyz, int bandwidth, int frames_per_second, bool threed, bool fourk)
223 {
224         /* get a J2K compressor handle */
225         opj_codec_t* encoder = opj_create_compress (OPJ_CODEC_J2K);
226         if (encoder == 0) {
227                 throw MiscError ("could not create JPEG2000 encoder");
228         }
229
230         opj_set_error_handler (encoder, error_callback, 0);
231
232         /* Set encoding parameters to default values */
233         opj_cparameters_t parameters;
234         opj_set_default_encoder_parameters (&parameters);
235         parameters.rsiz = fourk ? OPJ_PROFILE_CINEMA_4K : OPJ_PROFILE_CINEMA_2K;
236         parameters.cp_comment = strdup ("libdcp");
237
238         /* set max image */
239         parameters.max_cs_size = (bandwidth / 8) / frames_per_second;
240         if (threed) {
241                 /* In 3D we have only half the normal bandwidth per eye */
242                 parameters.max_cs_size /= 2;
243         }
244         parameters.max_comp_size = parameters.max_cs_size / 1.25;
245         parameters.tcp_numlayers = 1;
246         parameters.tcp_mct = 1;
247
248         /* Setup the encoder parameters using the current image and user parameters */
249         opj_setup_encoder (encoder, &parameters, xyz->opj_image());
250
251         opj_stream_t* stream = opj_stream_default_create (OPJ_FALSE);
252         if (!stream) {
253                 throw MiscError ("could not create JPEG2000 stream");
254         }
255
256         opj_stream_set_write_function (stream, write_function);
257         opj_stream_set_seek_function (stream, seek_function);
258         WriteBuffer* buffer = new WriteBuffer ();
259         opj_stream_set_user_data (stream, buffer, write_free_function);
260
261         if (!opj_start_compress (encoder, xyz->opj_image(), stream)) {
262                 throw MiscError ("could not start JPEG2000 encoding");
263         }
264
265         if (!opj_encode (encoder, stream)) {
266                 opj_destroy_codec (encoder);
267                 opj_stream_destroy (stream);
268                 throw MiscError ("JPEG2000 encoding failed");
269         }
270
271         if (!opj_end_compress (encoder, stream)) {
272                 opj_destroy_codec (encoder);
273                 opj_stream_destroy (stream);
274                 throw MiscError ("could not end JPEG2000 encoding");
275         }
276
277         Data enc (buffer->data ());
278
279         free (parameters.cp_comment);
280         opj_destroy_codec (encoder);
281         opj_stream_destroy (stream);
282
283         return enc;
284 }