Extract common code out into kdm_for_screen()
[dcpomatic.git] / src / lib / j2k_image_proxy.cc
1 /*
2     Copyright (C) 2014-2015 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 #include "j2k_image_proxy.h"
22 #include "dcpomatic_socket.h"
23 #include "image.h"
24 #include "dcpomatic_assert.h"
25 #include <dcp/raw_convert.h>
26 #include <dcp/openjpeg_image.h>
27 #include <dcp/mono_picture_frame.h>
28 #include <dcp/stereo_picture_frame.h>
29 #include <dcp/colour_conversion.h>
30 #include <dcp/rgb_xyz.h>
31 #include <dcp/j2k.h>
32 #include <libcxml/cxml.h>
33 #include <libxml++/libxml++.h>
34 #include <iostream>
35
36 #include "i18n.h"
37
38 using std::string;
39 using std::cout;
40 using std::max;
41 using std::pair;
42 using std::make_pair;
43 using boost::shared_ptr;
44 using boost::optional;
45 using boost::dynamic_pointer_cast;
46 using dcp::Data;
47 using dcp::raw_convert;
48
49 /** Construct a J2KImageProxy from a JPEG2000 file */
50 J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPixelFormat pixel_format)
51         : _data (path)
52         , _size (size)
53         , _pixel_format (pixel_format)
54         , _error (false)
55 {
56         /* ::image assumes 16bpp */
57         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
58 }
59
60 J2KImageProxy::J2KImageProxy (
61         shared_ptr<const dcp::MonoPictureFrame> frame,
62         dcp::Size size,
63         AVPixelFormat pixel_format,
64         optional<int> forced_reduction
65         )
66         : _data (frame->j2k_size ())
67         , _size (size)
68         , _pixel_format (pixel_format)
69         , _forced_reduction (forced_reduction)
70         , _error (false)
71 {
72         /* ::image assumes 16bpp */
73         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
74         memcpy (_data.data().get(), frame->j2k_data(), _data.size ());
75 }
76
77 J2KImageProxy::J2KImageProxy (
78         shared_ptr<const dcp::StereoPictureFrame> frame,
79         dcp::Size size,
80         dcp::Eye eye,
81         AVPixelFormat pixel_format,
82         optional<int> forced_reduction
83         )
84         : _size (size)
85         , _eye (eye)
86         , _pixel_format (pixel_format)
87         , _forced_reduction (forced_reduction)
88         , _error (false)
89 {
90         /* ::image assumes 16bpp */
91         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
92         switch (eye) {
93         case dcp::EYE_LEFT:
94                 _data = Data (frame->left_j2k_size ());
95                 memcpy (_data.data().get(), frame->left_j2k_data(), _data.size ());
96                 break;
97         case dcp::EYE_RIGHT:
98                 _data = Data (frame->right_j2k_size ());
99                 memcpy (_data.data().get(), frame->right_j2k_data(), _data.size ());
100                 break;
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         _data = Data (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().get (), _data.size ());
118 }
119
120 int
121 J2KImageProxy::prepare (optional<dcp::Size> target_size) const
122 {
123         boost::mutex::scoped_lock lm (_mutex);
124
125         if (_image && target_size == _target_size) {
126                 DCPOMATIC_ASSERT (_reduce);
127                 return *_reduce;
128         }
129
130         int reduce = 0;
131
132         if (_forced_reduction) {
133                 reduce = *_forced_reduction;
134         } else {
135                 while (target_size && (_size.width / pow(2, reduce)) > target_size->width && (_size.height / pow(2, reduce)) > target_size->height) {
136                         ++reduce;
137                 }
138
139                 --reduce;
140                 reduce = max (0, reduce);
141         }
142
143         try {
144                 shared_ptr<dcp::OpenJPEGImage> decompressed = dcp::decompress_j2k (const_cast<uint8_t*> (_data.data().get()), _data.size (), reduce);
145                 _image.reset (new Image (_pixel_format, decompressed->size(), true));
146
147                 int const shift = 16 - decompressed->precision (0);
148
149                 /* Copy data in whatever format (sRGB or XYZ) into our Image; I'm assuming
150                    the data is 12-bit either way.
151                    */
152
153                 int const width = decompressed->size().width;
154
155                 int p = 0;
156                 int* decomp_0 = decompressed->data (0);
157                 int* decomp_1 = decompressed->data (1);
158                 int* decomp_2 = decompressed->data (2);
159                 for (int y = 0; y < decompressed->size().height; ++y) {
160                         uint16_t* q = (uint16_t *) (_image->data()[0] + y * _image->stride()[0]);
161                         for (int x = 0; x < width; ++x) {
162                                 *q++ = decomp_0[p] << shift;
163                                 *q++ = decomp_1[p] << shift;
164                                 *q++ = decomp_2[p] << shift;
165                                 ++p;
166                         }
167                 }
168         } catch (dcp::J2KDecompressionError& e) {
169                 _image.reset (new Image (_pixel_format, _size, true));
170                 _image->make_black ();
171                 _error = true;
172         }
173
174         _target_size = target_size;
175         _reduce = reduce;
176
177         return reduce;
178 }
179
180
181 ImageProxy::Result
182 J2KImageProxy::image (optional<dcp::Size> target_size) const
183 {
184         int const r = prepare (target_size);
185
186         /* I think this is safe without a lock on mutex.  _image is guaranteed to be
187            set up when prepare() has happened.
188         */
189         return Result (_image, r, _error);
190 }
191
192
193 void
194 J2KImageProxy::add_metadata (xmlpp::Node* node) const
195 {
196         node->add_child("Type")->add_child_text (N_("J2K"));
197         node->add_child("Width")->add_child_text (raw_convert<string> (_size.width));
198         node->add_child("Height")->add_child_text (raw_convert<string> (_size.height));
199         if (_eye) {
200                 node->add_child("Eye")->add_child_text (raw_convert<string> (static_cast<int> (_eye.get ())));
201         }
202         node->add_child("Size")->add_child_text (raw_convert<string> (_data.size ()));
203 }
204
205 void
206 J2KImageProxy::write_to_socket (shared_ptr<Socket> socket) const
207 {
208         socket->write (_data.data().get(), _data.size());
209 }
210
211 bool
212 J2KImageProxy::same (shared_ptr<const ImageProxy> other) const
213 {
214         shared_ptr<const J2KImageProxy> jp = dynamic_pointer_cast<const J2KImageProxy> (other);
215         if (!jp) {
216                 return false;
217         }
218
219         if (_data.size() != jp->_data.size()) {
220                 return false;
221         }
222
223         return memcmp (_data.data().get(), jp->_data.data().get(), _data.size()) == 0;
224 }
225
226 J2KImageProxy::J2KImageProxy (Data data, dcp::Size size, AVPixelFormat pixel_format)
227         : _data (data)
228         , _size (size)
229         , _pixel_format (pixel_format)
230 {
231         /* ::image assumes 16bpp */
232         DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
233 }
234
235 size_t
236 J2KImageProxy::memory_used () const
237 {
238         size_t m = _data.size();
239         if (_image) {
240                 /* 3 components, 16-bits per pixel */
241                 m += 3 * 2 * _image->size().width * _image->size().height;
242         }
243         return m;
244 }