2 Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic 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.
11 DCP-o-matic 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.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
22 #include "dcpomatic_assert.h"
23 #include "dcpomatic_socket.h"
25 #include "j2k_image_proxy.h"
26 #include <dcp/colour_conversion.h>
27 #include <dcp/j2k_transcode.h>
28 #include <dcp/mono_picture_frame.h>
29 #include <dcp/openjpeg_image.h>
30 #include <dcp/raw_convert.h>
31 #include <dcp/rgb_xyz.h>
32 #include <dcp/stereo_picture_frame.h>
33 #include <dcp/warnings.h>
34 #include <libcxml/cxml.h>
35 LIBDCP_DISABLE_WARNINGS
36 #include <libxml++/libxml++.h>
37 LIBDCP_ENABLE_WARNINGS
44 using std::dynamic_pointer_cast;
45 using std::make_shared;
47 using std::shared_ptr;
49 using boost::optional;
51 using dcp::raw_convert;
54 /** Construct a J2KImageProxy from a JPEG2000 file */
55 J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPixelFormat pixel_format)
56 : _data (new dcp::ArrayData(path))
58 , _pixel_format (pixel_format)
61 /* ::image assumes 16bpp */
62 DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
66 J2KImageProxy::J2KImageProxy (
67 shared_ptr<const dcp::MonoPictureFrame> frame,
69 AVPixelFormat pixel_format,
70 optional<int> forced_reduction
74 , _pixel_format (pixel_format)
75 , _forced_reduction (forced_reduction)
78 /* ::image assumes 16bpp */
79 DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
83 J2KImageProxy::J2KImageProxy (
84 shared_ptr<const dcp::StereoPictureFrame> frame,
87 AVPixelFormat pixel_format,
88 optional<int> forced_reduction
90 : _data (eye == dcp::Eye::LEFT ? frame->left() : frame->right())
93 , _pixel_format (pixel_format)
94 , _forced_reduction (forced_reduction)
97 /* ::image assumes 16bpp */
98 DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
102 J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
105 _size = dcp::Size (xml->number_child<int>("Width"), xml->number_child<int>("Height"));
106 if (xml->optional_number_child<int>("Eye")) {
107 _eye = static_cast<dcp::Eye>(xml->number_child<int>("Eye"));
109 auto data = make_shared<ArrayData>(xml->number_child<int>("Size"));
110 /* This only matters when we are using J2KImageProxy for the preview, which
111 will never use this constructor (which is only used for passing data to
112 encode servers). So we can put anything in here. It's a bit of a hack.
114 _pixel_format = AV_PIX_FMT_XYZ12LE;
115 socket->read (data->data(), data->size());
121 J2KImageProxy::prepare (Image::Alignment alignment, optional<dcp::Size> target_size) const
123 boost::mutex::scoped_lock lm (_mutex);
125 if (_image && target_size == _target_size) {
126 DCPOMATIC_ASSERT (_reduce);
132 if (_forced_reduction) {
133 reduce = *_forced_reduction;
135 while (target_size && (_size.width / pow(2, reduce)) > target_size->width && (_size.height / pow(2, reduce)) > target_size->height) {
140 reduce = max (0, reduce);
144 /* XXX: should check that potentially trashing _data here doesn't matter */
145 auto decompressed = dcp::decompress_j2k (const_cast<uint8_t*>(_data->data()), _data->size(), reduce);
146 _image = make_shared<Image>(_pixel_format, decompressed->size(), alignment);
148 int const shift = 16 - decompressed->precision (0);
150 /* Copy data in whatever format (sRGB or XYZ) into our Image; I'm assuming
151 the data is 12-bit either way.
154 int const width = decompressed->size().width;
157 int* decomp_0 = decompressed->data (0);
158 int* decomp_1 = decompressed->data (1);
159 int* decomp_2 = decompressed->data (2);
160 for (int y = 0; y < decompressed->size().height; ++y) {
161 auto q = reinterpret_cast<uint16_t *>(_image->data()[0] + y * _image->stride()[0]);
162 for (int x = 0; x < width; ++x) {
163 *q++ = decomp_0[p] << shift;
164 *q++ = decomp_1[p] << shift;
165 *q++ = decomp_2[p] << shift;
169 } catch (dcp::J2KDecompressionError& e) {
170 _image = make_shared<Image>(_pixel_format, _size, alignment);
171 _image->make_black ();
175 _target_size = target_size;
183 J2KImageProxy::image (Image::Alignment alignment, optional<dcp::Size> target_size) const
185 int const r = prepare (alignment, target_size);
187 /* I think this is safe without a lock on mutex. _image is guaranteed to be
188 set up when prepare() has happened.
190 return Result (_image, r, _error);
195 J2KImageProxy::add_metadata (xmlpp::Node* node) const
197 node->add_child("Type")->add_child_text(N_("J2K"));
198 node->add_child("Width")->add_child_text(raw_convert<string>(_size.width));
199 node->add_child("Height")->add_child_text(raw_convert<string>(_size.height));
201 node->add_child("Eye")->add_child_text(raw_convert<string>(static_cast<int>(_eye.get())));
203 node->add_child("Size")->add_child_text(raw_convert<string>(_data->size()));
208 J2KImageProxy::write_to_socket (shared_ptr<Socket> socket) const
210 socket->write (_data->data(), _data->size());
215 J2KImageProxy::same (shared_ptr<const ImageProxy> other) const
217 auto jp = dynamic_pointer_cast<const J2KImageProxy>(other);
222 return *_data == *jp->_data;
226 J2KImageProxy::J2KImageProxy (ArrayData data, dcp::Size size, AVPixelFormat pixel_format)
227 : _data (new ArrayData(data))
229 , _pixel_format (pixel_format)
232 /* ::image assumes 16bpp */
233 DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
238 J2KImageProxy::memory_used () const
240 size_t m = _data->size();
242 /* 3 components, 16-bits per pixel */
243 m += 3 * 2 * _image->size().width * _image->size().height;