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)
56 /* ::image assumes 16bpp */
57 DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
60 J2KImageProxy::J2KImageProxy (
61 shared_ptr<const dcp::MonoPictureFrame> frame,
63 AVPixelFormat pixel_format,
64 optional<int> forced_reduction
66 : _data (frame->j2k_size ())
68 , _pixel_format (pixel_format)
69 , _forced_reduction (forced_reduction)
71 /* ::image assumes 16bpp */
72 DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
73 memcpy (_data.data().get(), frame->j2k_data(), _data.size ());
76 J2KImageProxy::J2KImageProxy (
77 shared_ptr<const dcp::StereoPictureFrame> frame,
80 AVPixelFormat pixel_format,
81 optional<int> forced_reduction
85 , _pixel_format (pixel_format)
86 , _forced_reduction (forced_reduction)
88 /* ::image assumes 16bpp */
89 DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
92 _data = Data (frame->left_j2k_size ());
93 memcpy (_data.data().get(), frame->left_j2k_data(), _data.size ());
96 _data = Data (frame->right_j2k_size ());
97 memcpy (_data.data().get(), frame->right_j2k_data(), _data.size ());
102 J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> socket)
104 _size = dcp::Size (xml->number_child<int> ("Width"), xml->number_child<int> ("Height"));
105 if (xml->optional_number_child<int> ("Eye")) {
106 _eye = static_cast<dcp::Eye> (xml->number_child<int> ("Eye"));
108 _data = Data (xml->number_child<int> ("Size"));
109 /* This only matters when we are using J2KImageProxy for the preview, which
110 will never use this constructor (which is only used for passing data to
111 encode servers). So we can put anything in here. It's a bit of a hack.
113 _pixel_format = AV_PIX_FMT_XYZ12LE;
114 socket->read (_data.data().get (), _data.size ());
118 J2KImageProxy::prepare (optional<dcp::Size> target_size) const
120 boost::mutex::scoped_lock lm (_mutex);
122 if (_decompressed && target_size == _target_size) {
123 DCPOMATIC_ASSERT (_reduce);
129 if (_forced_reduction) {
130 reduce = *_forced_reduction;
132 while (target_size && (_size.width / pow(2, reduce)) > target_size->width && (_size.height / pow(2, reduce)) > target_size->height) {
137 reduce = max (0, reduce);
140 _decompressed = dcp::decompress_j2k (const_cast<uint8_t*> (_data.data().get()), _data.size (), reduce);
142 if (_decompressed->precision(0) < 12) {
143 int const shift = 12 - _decompressed->precision (0);
144 for (int c = 0; c < 3; ++c) {
145 int* p = _decompressed->data (c);
146 for (int y = 0; y < _decompressed->size().height; ++y) {
147 for (int x = 0; x < _decompressed->size().width; ++x) {
154 _target_size = target_size;
160 pair<shared_ptr<Image>, int>
161 J2KImageProxy::image (optional<dcp::NoteHandler>, optional<dcp::Size> target_size) const
163 int const reduce = prepare (target_size);
165 shared_ptr<Image> image (new Image (_pixel_format, _decompressed->size(), true));
167 /* Copy data in whatever format (sRGB or XYZ) into our Image; I'm assuming
168 the data is 12-bit either way.
171 int const width = _decompressed->size().width;
174 for (int y = 0; y < _decompressed->size().height; ++y) {
175 uint16_t* q = (uint16_t *) (image->data()[0] + y * image->stride()[0]);
176 for (int x = 0; x < width; ++x) {
177 for (int c = 0; c < 3; ++c) {
178 *q++ = _decompressed->data(c)[p] << 4;
184 return make_pair (image, reduce);
188 J2KImageProxy::add_metadata (xmlpp::Node* node) const
190 node->add_child("Type")->add_child_text (N_("J2K"));
191 node->add_child("Width")->add_child_text (raw_convert<string> (_size.width));
192 node->add_child("Height")->add_child_text (raw_convert<string> (_size.height));
194 node->add_child("Eye")->add_child_text (raw_convert<string> (static_cast<int> (_eye.get ())));
196 node->add_child("Size")->add_child_text (raw_convert<string> (_data.size ()));
200 J2KImageProxy::send_binary (shared_ptr<Socket> socket) const
202 socket->write (_data.data().get(), _data.size());
206 J2KImageProxy::same (shared_ptr<const ImageProxy> other) const
208 shared_ptr<const J2KImageProxy> jp = dynamic_pointer_cast<const J2KImageProxy> (other);
213 if (_data.size() != jp->_data.size()) {
217 return memcmp (_data.data().get(), jp->_data.data().get(), _data.size()) == 0;
220 J2KImageProxy::J2KImageProxy (Data data, dcp::Size size, AVPixelFormat pixel_format)
223 , _pixel_format (pixel_format)
225 /* ::image assumes 16bpp */
226 DCPOMATIC_ASSERT (_pixel_format == AV_PIX_FMT_RGB48 || _pixel_format == AV_PIX_FMT_XYZ12LE);
230 J2KImageProxy::memory_used () const
232 size_t m = _data.size();
234 /* 3 components, 16-bits per pixel */
235 m += 3 * 2 * _decompressed->size().width * _decompressed->size().height;