45 #include "compose.hpp"
54 using std::shared_ptr;
55 using boost::shared_array;
59 shared_ptr<dcp::OpenJPEGImage>
66 shared_ptr<dcp::OpenJPEGImage>
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)
112 decompress_error_callback (
char const * msg,
void *)
119 compress_error_callback (
char const * msg,
void *)
125 shared_ptr<dcp::OpenJPEGImage>
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);
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)
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)
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)
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()) {
252 throw MiscError(
"compress_j2k comment can not be an empty string");
255 opj_set_error_handler (encoder, compress_error_callback, 0);
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;
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;
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);
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) {
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");
328 opj_stream_destroy (stream);
329 opj_destroy_codec (encoder);
330 free (parameters.cp_comment);
Class to hold an arbitrary block of data.
An error that occurs during decompression of JPEG2000 data.
A miscellaneous exception.
Any error that occurs when reading data from a DCP.
Exceptions thrown by libdcp.
Methods to encode and decode JPEG2000.
Namespace for everything in libdcp.
std::shared_ptr< OpenJPEGImage > decompress_j2k(uint8_t const *data, int64_t size, int reduce)
ArrayData compress_j2k(std::shared_ptr< const OpenJPEGImage >, int bandwidth, int frames_per_second, bool threed, bool fourk, std::string comment="libdcp")