Account for J2K decoding at lower-than-maximum resolution when cropping
[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 <Magick++.h>
35 #include <iostream>
36
37 #include "i18n.h"
38
39 using std::string;
40 using std::cout;
41 using std::max;
42 using std::pair;
43 using std::make_pair;
44 using boost::shared_ptr;
45 using boost::optional;
46 using boost::dynamic_pointer_cast;
47 using dcp::Data;
48 using dcp::raw_convert;
49
50 /** Construct a J2KImageProxy from a JPEG2000 file */
51 J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPixelFormat pixel_format)
52         : _data (path)
53         , _size (size)
54         , _pixel_format (pixel_format)
55 {
56
57 }
58
59 J2KImageProxy::J2KImageProxy (
60         shared_ptr<const dcp::MonoPictureFrame> frame,
61         dcp::Size size,
62         AVPixelFormat pixel_format,
63         optional<int> forced_reduction
64         )
65         : _data (frame->j2k_size ())
66         , _size (size)
67         , _pixel_format (pixel_format)
68         , _forced_reduction (forced_reduction)
69 {
70         memcpy (_data.data().get(), frame->j2k_data(), _data.size ());
71 }
72
73 J2KImageProxy::J2KImageProxy (
74         shared_ptr<const dcp::StereoPictureFrame> frame,
75         dcp::Size size,
76         dcp::Eye eye,
77         AVPixelFormat pixel_format,
78         optional<int> forced_reduction
79         )
80         : _size (size)
81         , _eye (eye)
82         , _pixel_format (pixel_format)
83         , _forced_reduction (forced_reduction)
84 {
85         switch (eye) {
86         case dcp::EYE_LEFT:
87                 _data = Data (frame->left_j2k_size ());
88                 memcpy (_data.data().get(), frame->left_j2k_data(), _data.size ());
89                 break;
90         case dcp::EYE_RIGHT:
91                 _data = Data (frame->right_j2k_size ());
92                 memcpy (_data.data().get(), frame->right_j2k_data(), _data.size ());
93                 break;
94         }
95 }
96
97 J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
98 {
99         _size = dcp::Size (xml->number_child<int> ("Width"), xml->number_child<int> ("Height"));
100         if (xml->optional_number_child<int> ("Eye")) {
101                 _eye = static_cast<dcp::Eye> (xml->number_child<int> ("Eye"));
102         }
103         _data = Data (xml->number_child<int> ("Size"));
104         /* This only matters when we are using J2KImageProxy for the preview, which
105            will never use this constructor (which is only used for passing data to
106            encode servers).  So we can put anything in here.  It's a bit of a hack.
107         */
108         _pixel_format = AV_PIX_FMT_XYZ12LE;
109         socket->read (_data.data().get (), _data.size ());
110 }
111
112 int
113 J2KImageProxy::prepare (optional<dcp::Size> target_size) const
114 {
115         boost::mutex::scoped_lock lm (_mutex);
116
117         if (_decompressed && target_size == _target_size) {
118                 DCPOMATIC_ASSERT (_reduce);
119                 return *_reduce;
120         }
121
122         int reduce = 0;
123
124         if (_forced_reduction) {
125                 reduce = *_forced_reduction;
126         } else {
127                 while (target_size && (_size.width / pow(2, reduce)) > target_size->width && (_size.height / pow(2, reduce)) > target_size->height) {
128                         ++reduce;
129                 }
130
131                 --reduce;
132                 reduce = max (0, reduce);
133         }
134
135         _decompressed = dcp::decompress_j2k (const_cast<uint8_t*> (_data.data().get()), _data.size (), reduce);
136
137         if (_decompressed->precision(0) < 12) {
138                 int const shift = 12 - _decompressed->precision (0);
139                 for (int c = 0; c < 3; ++c) {
140                         int* p = _decompressed->data (c);
141                         for (int y = 0; y < _decompressed->size().height; ++y) {
142                                 for (int x = 0; x < _decompressed->size().width; ++x) {
143                                         *p++ <<= shift;
144                                 }
145                         }
146                 }
147         }
148
149         _target_size = target_size;
150         _reduce = reduce;
151
152         return reduce;
153 }
154
155 pair<shared_ptr<Image>, int>
156 J2KImageProxy::image (optional<dcp::NoteHandler>, optional<dcp::Size> target_size) const
157 {
158         int const reduce = prepare (target_size);
159
160         shared_ptr<Image> image (new Image (_pixel_format, _decompressed->size(), true));
161
162         /* Copy data in whatever format (sRGB or XYZ) into our Image; I'm assuming
163            the data is 12-bit either way.
164         */
165
166         int const width = _decompressed->size().width;
167
168         int p = 0;
169         for (int y = 0; y < _decompressed->size().height; ++y) {
170                 uint16_t* q = (uint16_t *) (image->data()[0] + y * image->stride()[0]);
171                 for (int x = 0; x < width; ++x) {
172                         for (int c = 0; c < 3; ++c) {
173                                 *q++ = _decompressed->data(c)[p] << 4;
174                         }
175                         ++p;
176                 }
177         }
178
179         return make_pair (image, reduce);
180 }
181
182 void
183 J2KImageProxy::add_metadata (xmlpp::Node* node) const
184 {
185         node->add_child("Type")->add_child_text (N_("J2K"));
186         node->add_child("Width")->add_child_text (raw_convert<string> (_size.width));
187         node->add_child("Height")->add_child_text (raw_convert<string> (_size.height));
188         if (_eye) {
189                 node->add_child("Eye")->add_child_text (raw_convert<string> (static_cast<int> (_eye.get ())));
190         }
191         node->add_child("Size")->add_child_text (raw_convert<string> (_data.size ()));
192 }
193
194 void
195 J2KImageProxy::send_binary (shared_ptr<Socket> socket) const
196 {
197         socket->write (_data.data().get(), _data.size());
198 }
199
200 bool
201 J2KImageProxy::same (shared_ptr<const ImageProxy> other) const
202 {
203         shared_ptr<const J2KImageProxy> jp = dynamic_pointer_cast<const J2KImageProxy> (other);
204         if (!jp) {
205                 return false;
206         }
207
208         if (_data.size() != jp->_data.size()) {
209                 return false;
210         }
211
212         return memcmp (_data.data().get(), jp->_data.data().get(), _data.size()) == 0;
213 }
214
215 J2KImageProxy::J2KImageProxy (Data data, dcp::Size size, AVPixelFormat pixel_format)
216         : _data (data)
217         , _size (size)
218         , _pixel_format (pixel_format)
219 {
220
221 }
222
223 size_t
224 J2KImageProxy::memory_used () const
225 {
226         size_t m = _data.size();
227         if (_decompressed) {
228                 /* 3 components, 16-bits per pixel */
229                 m += 3 * 2 * _decompressed->size().width * _decompressed->size().height;
230         }
231         return m;
232 }