2 Copyright (C) 2014-2015 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/>.
21 #include "j2k_image_proxy.h"
22 #include "dcpomatic_socket.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>
32 #include <libcxml/cxml.h>
33 #include <libxml++/libxml++.h>
44 using boost::shared_ptr;
45 using boost::optional;
46 using boost::dynamic_pointer_cast;
48 using dcp::raw_convert;
50 /** Construct a J2KImageProxy from a JPEG2000 file */
51 J2KImageProxy::J2KImageProxy (boost::filesystem::path path, dcp::Size size, AVPixelFormat pixel_format)
54 , _pixel_format (pixel_format)
59 J2KImageProxy::J2KImageProxy (
60 shared_ptr<const dcp::MonoPictureFrame> frame,
62 AVPixelFormat pixel_format,
63 optional<int> forced_reduction
65 : _data (frame->j2k_size ())
67 , _pixel_format (pixel_format)
68 , _forced_reduction (forced_reduction)
70 memcpy (_data.data().get(), frame->j2k_data(), _data.size ());
73 J2KImageProxy::J2KImageProxy (
74 shared_ptr<const dcp::StereoPictureFrame> frame,
77 AVPixelFormat pixel_format,
78 optional<int> forced_reduction
82 , _pixel_format (pixel_format)
83 , _forced_reduction (forced_reduction)
87 _data = Data (frame->left_j2k_size ());
88 memcpy (_data.data().get(), frame->left_j2k_data(), _data.size ());
91 _data = Data (frame->right_j2k_size ());
92 memcpy (_data.data().get(), frame->right_j2k_data(), _data.size ());
97 J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
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"));
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.
108 _pixel_format = AV_PIX_FMT_XYZ12LE;
109 socket->read (_data.data().get (), _data.size ());
113 J2KImageProxy::prepare (optional<dcp::Size> target_size) const
115 boost::mutex::scoped_lock lm (_mutex);
117 if (_decompressed && target_size == _target_size) {
118 DCPOMATIC_ASSERT (_reduce);
124 if (_forced_reduction) {
125 reduce = *_forced_reduction;
127 while (target_size && (_size.width / pow(2, reduce)) > target_size->width && (_size.height / pow(2, reduce)) > target_size->height) {
132 reduce = max (0, reduce);
135 _decompressed = dcp::decompress_j2k (const_cast<uint8_t*> (_data.data().get()), _data.size (), reduce);
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) {
149 _target_size = target_size;
155 pair<shared_ptr<Image>, int>
156 J2KImageProxy::image (optional<dcp::NoteHandler>, optional<dcp::Size> target_size) const
158 int const reduce = prepare (target_size);
160 shared_ptr<Image> image (new Image (_pixel_format, _decompressed->size(), true));
162 /* Copy data in whatever format (sRGB or XYZ) into our Image; I'm assuming
163 the data is 12-bit either way.
166 int const width = _decompressed->size().width;
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;
179 return make_pair (image, reduce);
183 J2KImageProxy::add_metadata (xmlpp::Node* node) const
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));
189 node->add_child("Eye")->add_child_text (raw_convert<string> (static_cast<int> (_eye.get ())));
191 node->add_child("Size")->add_child_text (raw_convert<string> (_data.size ()));
195 J2KImageProxy::send_binary (shared_ptr<Socket> socket) const
197 socket->write (_data.data().get(), _data.size());
201 J2KImageProxy::same (shared_ptr<const ImageProxy> other) const
203 shared_ptr<const J2KImageProxy> jp = dynamic_pointer_cast<const J2KImageProxy> (other);
208 if (_data.size() != jp->_data.size()) {
212 return memcmp (_data.data().get(), jp->_data.data().get(), _data.size()) == 0;
215 J2KImageProxy::J2KImageProxy (Data data, dcp::Size size, AVPixelFormat pixel_format)
218 , _pixel_format (pixel_format)
224 J2KImageProxy::memory_used () const
226 size_t m = _data.size();
228 /* 3 components, 16-bits per pixel */
229 m += 3 * 2 * _decompressed->size().width * _decompressed->size().height;