Use dcp::file_to_string().
[dcpomatic.git] / src / lib / j2k_image_proxy.cc
1 /*
2     Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
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.
10
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.
15
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/>.
18
19 */
20
21
22 #include "j2k_image_proxy.h"
23 #include "dcpomatic_socket.h"
24 #include "image.h"
25 #include "dcpomatic_assert.h"
26 #include "warnings.h"
27 #include <dcp/raw_convert.h>
28 #include <dcp/openjpeg_image.h>
29 #include <dcp/mono_picture_frame.h>
30 #include <dcp/stereo_picture_frame.h>
31 #include <dcp/colour_conversion.h>
32 #include <dcp/rgb_xyz.h>
33 #include <dcp/j2k_transcode.h>
34 #include <libcxml/cxml.h>
35 DCPOMATIC_DISABLE_WARNINGS
36 #include <libxml++/libxml++.h>
37 DCPOMATIC_ENABLE_WARNINGS
38 #include <iostream>
39
40 #include "i18n.h"
41
42
43 using std::cout;
44 using std::dynamic_pointer_cast;
45 using std::make_pair;
46 using std::make_shared;
47 using std::max;
48 using std::pair;
49 using std::shared_ptr;
50 using std::string;
51 using boost::optional;
52 using dcp::ArrayData;
53 using dcp::raw_convert;
54
55
56 /** Construct a J2KImageProxy from a JPEG2000 file */
57 J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPixelFormat pixel_format)
58         : _data (new dcp::ArrayData(path))
59         , _size (size)
60         , _pixel_format (pixel_format)
61         , _error (false)
62 {
63         /* ::image assumes 16bpp */
64         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
65 }
66
67
68 J2KImageProxy::J2KImageProxy (
69         shared_ptr<const dcp::MonoPictureFrame> frame,
70         dcp::Size size,
71         AVPixelFormat pixel_format,
72         optional<int> forced_reduction
73         )
74         : _data (frame)
75         , _size (size)
76         , _pixel_format (pixel_format)
77         , _forced_reduction (forced_reduction)
78         , _error (false)
79 {
80         /* ::image assumes 16bpp */
81         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
82 }
83
84
85 J2KImageProxy::J2KImageProxy (
86         shared_ptr<const dcp::StereoPictureFrame> frame,
87         dcp::Size size,
88         dcp::Eye eye,
89         AVPixelFormat pixel_format,
90         optional<int> forced_reduction
91         )
92         : _data (eye == dcp::Eye::LEFT ? frame->left() : frame->right())
93         , _size (size)
94         , _eye (eye)
95         , _pixel_format (pixel_format)
96         , _forced_reduction (forced_reduction)
97         , _error (false)
98 {
99         /* ::image assumes 16bpp */
100         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
101 }
102
103
104 J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
105         : _error (false)
106 {
107         _size = dcp::Size (xml->number_child<int>("Width"), xml->number_child<int>("Height"));
108         if (xml->optional_number_child<int>("Eye")) {
109                 _eye = static_cast<dcp::Eye>(xml->number_child<int>("Eye"));
110         }
111         shared_ptr<ArrayData> data(new ArrayData(xml->number_child<int>("Size")));
112         /* This only matters when we are using J2KImageProxy for the preview, which
113            will never use this constructor (which is only used for passing data to
114            encode servers).  So we can put anything in here.  It's a bit of a hack.
115         */
116         _pixel_format = AV_PIX_FMT_XYZ12LE;
117         socket->read (data->data(), data->size());
118         _data = data;
119 }
120
121
122 int
123 J2KImageProxy::prepare (optional<dcp::Size> target_size) const
124 {
125         boost::mutex::scoped_lock lm (_mutex);
126
127         if (_image && target_size == _target_size) {
128                 DCPOMATIC_ASSERT (_reduce);
129                 return *_reduce;
130         }
131
132         int reduce = 0;
133
134         if (_forced_reduction) {
135                 reduce = *_forced_reduction;
136         } else {
137                 while (target_size && (_size.width / pow(2, reduce)) > target_size->width && (_size.height / pow(2, reduce)) > target_size->height) {
138                         ++reduce;
139                 }
140
141                 --reduce;
142                 reduce = max (0, reduce);
143         }
144
145         try {
146                 /* XXX: should check that potentially trashing _data here doesn't matter */
147                 auto decompressed = dcp::decompress_j2k (const_cast<uint8_t*>(_data->data()), _data->size(), reduce);
148                 _image.reset (new Image (_pixel_format, decompressed->size(), true));
149
150                 int const shift = 16 - decompressed->precision (0);
151
152                 /* Copy data in whatever format (sRGB or XYZ) into our Image; I'm assuming
153                    the data is 12-bit either way.
154                    */
155
156                 int const width = decompressed->size().width;
157
158                 int p = 0;
159                 int* decomp_0 = decompressed->data (0);
160                 int* decomp_1 = decompressed->data (1);
161                 int* decomp_2 = decompressed->data (2);
162                 for (int y = 0; y < decompressed->size().height; ++y) {
163                         auto q = reinterpret_cast<uint16_t *>(_image->data()[0] + y * _image->stride()[0]);
164                         for (int x = 0; x < width; ++x) {
165                                 *q++ = decomp_0[p] << shift;
166                                 *q++ = decomp_1[p] << shift;
167                                 *q++ = decomp_2[p] << shift;
168                                 ++p;
169                         }
170                 }
171         } catch (dcp::J2KDecompressionError& e) {
172                 _image = make_shared<Image>(_pixel_format, _size, true);
173                 _image->make_black ();
174                 _error = true;
175         }
176
177         _target_size = target_size;
178         _reduce = reduce;
179
180         return reduce;
181 }
182
183
184 ImageProxy::Result
185 J2KImageProxy::image (optional<dcp::Size> target_size) const
186 {
187         int const r = prepare (target_size);
188
189         /* I think this is safe without a lock on mutex.  _image is guaranteed to be
190            set up when prepare() has happened.
191         */
192         return Result (_image, r, _error);
193 }
194
195
196 void
197 J2KImageProxy::add_metadata (xmlpp::Node* node) const
198 {
199         node->add_child("Type")->add_child_text(N_("J2K"));
200         node->add_child("Width")->add_child_text(raw_convert<string>(_size.width));
201         node->add_child("Height")->add_child_text(raw_convert<string>(_size.height));
202         if (_eye) {
203                 node->add_child("Eye")->add_child_text(raw_convert<string>(static_cast<int>(_eye.get())));
204         }
205         node->add_child("Size")->add_child_text(raw_convert<string>(_data->size()));
206 }
207
208
209 void
210 J2KImageProxy::write_to_socket (shared_ptr<Socket> socket) const
211 {
212         socket->write (_data->data(), _data->size());
213 }
214
215
216 bool
217 J2KImageProxy::same (shared_ptr<const ImageProxy> other) const
218 {
219         auto jp = dynamic_pointer_cast<const J2KImageProxy>(other);
220         if (!jp) {
221                 return false;
222         }
223
224         return *_data == *jp->_data;
225 }
226
227
228 J2KImageProxy::J2KImageProxy (ArrayData data, dcp::Size size, AVPixelFormat pixel_format)
229         : _data (new ArrayData(data))
230         , _size (size)
231         , _pixel_format (pixel_format)
232         , _error (false)
233 {
234         /* ::image assumes 16bpp */
235         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
236 }
237
238
239 size_t
240 J2KImageProxy::memory_used () const
241 {
242         size_t m = _data->size();
243         if (_image) {
244                 /* 3 components, 16-bits per pixel */
245                 m += 3 * 2 * _image->size().width * _image->size().height;
246         }
247         return m;
248 }