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