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