Move things round a bit.
[dcpomatic.git] / src / lib / dcp_video_frame.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3     Taken from code Copyright (C) 2010-2011 Terrence Meiczinger
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 /** @file  src/dcp_video_frame.cc
22  *  @brief A single frame of video destined for a DCP.
23  *
24  *  Given an Image and some settings, this class knows how to encode
25  *  the image to J2K either on the local host or on a remote server.
26  *
27  *  Objects of this class are used for the queue that we keep
28  *  of images that require encoding.
29  */
30
31 #include <stdint.h>
32 #include <cstring>
33 #include <cstdlib>
34 #include <stdexcept>
35 #include <cstdio>
36 #include <iomanip>
37 #include <sstream>
38 #include <iostream>
39 #include <unistd.h>
40 #include <errno.h>
41 #include <netinet/in.h>
42 #include <netdb.h>
43 #include <boost/filesystem.hpp>
44 #include "film.h"
45 #include "dcp_video_frame.h"
46 #include "lut.h"
47 #include "config.h"
48 #include "film_state.h"
49 #include "options.h"
50 #include "exceptions.h"
51 #include "server.h"
52 #include "util.h"
53 #include "scaler.h"
54 #include "image.h"
55 #include "log.h"
56
57 #ifdef DEBUG_HASH
58 #include <mhash.h>
59 #endif
60
61 using namespace std;
62 using namespace boost;
63
64 /** Construct a DCP video frame.
65  *  @param input Input image.
66  *  @param out Required size of output, in pixels (including any padding).
67  *  @param s Scaler to use.
68  *  @param p Number of pixels of padding either side of the image.
69  *  @param f Index of the frame within the Film.
70  *  @param fps Frames per second of the Film.
71  *  @param pp FFmpeg post-processing string to use.
72  *  @param clut Colour look-up table to use (see Config::colour_lut_index ())
73  *  @param bw J2K bandwidth to use (see Config::j2k_bandwidth ())
74  *  @param l Log to write to.
75  */
76 DCPVideoFrame::DCPVideoFrame (
77         shared_ptr<Image> yuv, Size out, int p, Scaler const * s, int f, float fps, string pp, int clut, int bw, Log* l)
78         : _input (yuv)
79         , _out_size (out)
80         , _padding (p)
81         , _scaler (s)
82         , _frame (f)
83           /* we round here; not sure if this is right */
84         , _frames_per_second (rint (fps))
85         , _post_process (pp)
86         , _colour_lut_index (clut)
87         , _j2k_bandwidth (bw)
88         , _log (l)
89         , _image (0)
90         , _parameters (0)
91         , _cinfo (0)
92         , _cio (0)
93 {
94         
95 }
96
97 /** Create a libopenjpeg container suitable for our output image */
98 void
99 DCPVideoFrame::create_openjpeg_container ()
100 {
101         for (int i = 0; i < 3; ++i) {
102                 _cmptparm[i].dx = 1;
103                 _cmptparm[i].dy = 1;
104                 _cmptparm[i].w = _out_size.width;
105                 _cmptparm[i].h = _out_size.height;
106                 _cmptparm[i].x0 = 0;
107                 _cmptparm[i].y0 = 0;
108                 _cmptparm[i].prec = 12;
109                 _cmptparm[i].bpp = 12;
110                 _cmptparm[i].sgnd = 0;
111         }
112
113         _image = opj_image_create (3, &_cmptparm[0], CLRSPC_SRGB);
114         if (_image == 0) {
115                 throw EncodeError ("could not create libopenjpeg image");
116         }
117
118         _image->x0 = 0;
119         _image->y0 = 0;
120         _image->x1 = _out_size.width;
121         _image->y1 = _out_size.height;
122 }
123
124 DCPVideoFrame::~DCPVideoFrame ()
125 {
126         if (_image) {
127                 opj_image_destroy (_image);
128         }
129
130         if (_cio) {
131                 opj_cio_close (_cio);
132         }
133
134         if (_cinfo) {
135                 opj_destroy_compress (_cinfo);
136         }
137
138         if (_parameters) {
139                 free (_parameters->cp_comment);
140                 free (_parameters->cp_matrice);
141         }
142         
143         delete _parameters;
144 }
145
146 /** J2K-encode this frame on the local host.
147  *  @return Encoded data.
148  */
149 shared_ptr<EncodedData>
150 DCPVideoFrame::encode_locally ()
151 {
152         shared_ptr<Image> prepared = _input;
153         
154         if (!_post_process.empty ()) {
155                 prepared = prepared->post_process (_post_process);
156         }
157         
158         prepared = prepared->scale_and_convert_to_rgb (_out_size, _padding, _scaler);
159
160         create_openjpeg_container ();
161
162         int const size = _out_size.width * _out_size.height;
163
164         struct {
165                 double r, g, b;
166         } s;
167
168         struct {
169                 double x, y, z;
170         } d;
171
172         /* Copy our RGB into the openjpeg container, converting to XYZ in the process */
173
174         uint8_t* p = prepared->data()[0];
175         for (int i = 0; i < size; ++i) {
176                 /* In gamma LUT (converting 8-bit input to 12-bit) */
177                 s.r = lut_in[_colour_lut_index][*p++ << 4];
178                 s.g = lut_in[_colour_lut_index][*p++ << 4];
179                 s.b = lut_in[_colour_lut_index][*p++ << 4];
180
181                 /* RGB to XYZ Matrix */
182                 d.x = ((s.r * color_matrix[_colour_lut_index][0][0]) + (s.g * color_matrix[_colour_lut_index][0][1]) + (s.b * color_matrix[_colour_lut_index][0][2]));
183                 d.y = ((s.r * color_matrix[_colour_lut_index][1][0]) + (s.g * color_matrix[_colour_lut_index][1][1]) + (s.b * color_matrix[_colour_lut_index][1][2]));
184                 d.z = ((s.r * color_matrix[_colour_lut_index][2][0]) + (s.g * color_matrix[_colour_lut_index][2][1]) + (s.b * color_matrix[_colour_lut_index][2][2]));
185                                                                                              
186                 /* DCI companding */
187                 d.x = d.x * DCI_COEFFICENT * (DCI_LUT_SIZE - 1);
188                 d.y = d.y * DCI_COEFFICENT * (DCI_LUT_SIZE - 1);
189                 d.z = d.z * DCI_COEFFICENT * (DCI_LUT_SIZE - 1);
190
191                 /* Out gamma LUT */
192                 _image->comps[0].data[i] = lut_out[LO_DCI][(int) d.x];
193                 _image->comps[1].data[i] = lut_out[LO_DCI][(int) d.y];
194                 _image->comps[2].data[i] = lut_out[LO_DCI][(int) d.z];
195         }
196
197         /* Set the max image and component sizes based on frame_rate */
198         int const max_cs_len = ((float) _j2k_bandwidth) / 8 / _frames_per_second;
199         int const max_comp_size = max_cs_len / 1.25;
200
201         /* Set encoding parameters to default values */
202         _parameters = new opj_cparameters_t;
203         opj_set_default_encoder_parameters (_parameters);
204
205         /* Set default cinema parameters */
206         _parameters->tile_size_on = false;
207         _parameters->cp_tdx = 1;
208         _parameters->cp_tdy = 1;
209         
210         /* Tile part */
211         _parameters->tp_flag = 'C';
212         _parameters->tp_on = 1;
213         
214         /* Tile and Image shall be at (0,0) */
215         _parameters->cp_tx0 = 0;
216         _parameters->cp_ty0 = 0;
217         _parameters->image_offset_x0 = 0;
218         _parameters->image_offset_y0 = 0;
219
220         /* Codeblock size = 32x32 */
221         _parameters->cblockw_init = 32;
222         _parameters->cblockh_init = 32;
223         _parameters->csty |= 0x01;
224         
225         /* The progression order shall be CPRL */
226         _parameters->prog_order = CPRL;
227         
228         /* No ROI */
229         _parameters->roi_compno = -1;
230         
231         _parameters->subsampling_dx = 1;
232         _parameters->subsampling_dy = 1;
233         
234         /* 9-7 transform */
235         _parameters->irreversible = 1;
236         
237         _parameters->tcp_rates[0] = 0;
238         _parameters->tcp_numlayers++;
239         _parameters->cp_disto_alloc = 1;
240         _parameters->cp_rsiz = CINEMA2K;
241         _parameters->cp_comment = strdup ("OpenDCP");
242         _parameters->cp_cinema = CINEMA2K_24;
243
244         /* 3 components, so use MCT */
245         _parameters->tcp_mct = 1;
246         
247         /* set max image */
248         _parameters->max_comp_size = max_comp_size;
249         _parameters->tcp_rates[0] = ((float) (3 * _image->comps[0].w * _image->comps[0].h * _image->comps[0].prec)) / (max_cs_len * 8);
250
251         /* get a J2K compressor handle */
252         _cinfo = opj_create_compress (CODEC_J2K);
253
254         /* Set event manager to null (openjpeg 1.3 bug) */
255         _cinfo->event_mgr = 0;
256
257 #ifdef DEBUG_HASH
258         md5_data ("J2K in X", _image->comps[0].data, size * sizeof (int));
259         md5_data ("J2K in Y", _image->comps[1].data, size * sizeof (int));
260         md5_data ("J2K in Z", _image->comps[2].data, size * sizeof (int));
261 #endif  
262         
263         /* Setup the encoder parameters using the current image and user parameters */
264         opj_setup_encoder (_cinfo, _parameters, _image);
265
266         _cio = opj_cio_open ((opj_common_ptr) _cinfo, 0, 0);
267
268         int const r = opj_encode (_cinfo, _cio, _image, 0);
269         if (r == 0) {
270                 throw EncodeError ("jpeg2000 encoding failed");
271         }
272
273 #ifdef DEBUG_HASH
274         md5_data ("J2K out", _cio->buffer, cio_tell (_cio));
275 #endif  
276
277         {
278                 stringstream s;
279                 s << "Finished locally-encoded frame " << _frame << " length " << cio_tell (_cio);
280                 _log->log (s.str ());
281         }
282         
283         return shared_ptr<EncodedData> (new LocallyEncodedData (_cio->buffer, cio_tell (_cio)));
284 }
285
286 /** Send this frame to a remote server for J2K encoding, then read the result.
287  *  @param serv Server to send to.
288  *  @return Encoded data.
289  */
290 shared_ptr<EncodedData>
291 DCPVideoFrame::encode_remotely (Server const * serv)
292 {
293         int const fd = socket (AF_INET, SOCK_STREAM, 0);
294         if (fd < 0) {
295                 throw NetworkError ("could not create socket");
296         }
297
298         struct timeval tv;
299         tv.tv_sec = 20;
300         tv.tv_usec = 0;
301         
302         if (setsockopt (fd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv, sizeof (tv)) < 0) {
303                 close (fd);
304                 throw NetworkError ("setsockopt failed");
305         }
306
307         if (setsockopt (fd, SOL_SOCKET, SO_SNDTIMEO, (void *) &tv, sizeof (tv)) < 0) {
308                 close (fd);
309                 throw NetworkError ("setsockopt failed");
310         }
311         
312         struct hostent* server = gethostbyname (serv->host_name().c_str ());
313         if (server == 0) {
314                 close (fd);
315                 throw NetworkError ("gethostbyname failed");
316         }
317
318         struct sockaddr_in server_address;
319         memset (&server_address, 0, sizeof (server_address));
320         server_address.sin_family = AF_INET;
321         memcpy (&server_address.sin_addr.s_addr, server->h_addr, server->h_length);
322         server_address.sin_port = htons (Config::instance()->server_port ());
323         if (connect (fd, (struct sockaddr *) &server_address, sizeof (server_address)) < 0) {
324                 close (fd);
325                 stringstream s;
326                 s << "could not connect (" << strerror (errno) << ")";
327                 throw NetworkError (s.str());
328         }
329
330 #ifdef DEBUG_HASH
331         _input->hash ("Input for remote encoding (before sending)");
332 #endif
333
334         stringstream s;
335         s << "encode "
336           << _input->size().width << " " << _input->size().height << " "
337           << _input->pixel_format() << " "
338           << _out_size.width << " " << _out_size.height << " "
339           << _padding << " "
340           << _scaler->id () << " "
341           << _frame << " "
342           << _frames_per_second << " "
343           << (_post_process.empty() ? "none" : _post_process) << " "
344           << Config::instance()->colour_lut_index () << " "
345           << Config::instance()->j2k_bandwidth () << " ";
346
347         for (int i = 0; i < _input->components(); ++i) {
348                 s << _input->line_size()[i] << " ";
349         }
350
351         socket_write (fd, (uint8_t *) s.str().c_str(), s.str().length() + 1);
352
353         for (int i = 0; i < _input->components(); ++i) {
354                 socket_write (fd, _input->data()[i], _input->line_size()[i] * _input->lines(i));
355         }
356
357         SocketReader reader (fd);
358
359         char buffer[32];
360         reader.read_indefinite ((uint8_t *) buffer, sizeof (buffer));
361         reader.consume (strlen (buffer) + 1);
362         shared_ptr<EncodedData> e (new RemotelyEncodedData (atoi (buffer)));
363
364         /* now read the rest */
365         reader.read_definite_and_consume (e->data(), e->size());
366
367 #ifdef DEBUG_HASH
368         e->hash ("Encoded image (after receiving)");
369 #endif
370
371         {
372                 stringstream s;
373                 s << "Finished remotely-encoded frame " << _frame << " length " << e->size();
374                 _log->log (s.str ());
375         }
376         
377         close (fd);
378         return e;
379 }
380
381 /** Write this data to a J2K file.
382  *  @param opt Options.
383  *  @param frame Frame index.
384  */
385 void
386 EncodedData::write (shared_ptr<const Options> opt, int frame)
387 {
388         string const tmp_j2k = opt->frame_out_path (frame, true);
389
390         FILE* f = fopen (tmp_j2k.c_str (), "wb");
391         
392         if (!f) {
393                 throw WriteFileError (tmp_j2k, errno);
394         }
395
396         fwrite (_data, 1, _size, f);
397         fclose (f);
398
399         /* Rename the file from foo.j2c.tmp to foo.j2c now that it is complete */
400         filesystem::rename (tmp_j2k, opt->frame_out_path (frame, false));
401 }
402
403 /** Send this data to a file descriptor.
404  *  @param fd File descriptor.
405  */
406 void
407 EncodedData::send (int fd)
408 {
409         stringstream s;
410         s << _size;
411         socket_write (fd, (uint8_t *) s.str().c_str(), s.str().length() + 1);
412         socket_write (fd, _data, _size);
413 }
414
415 #ifdef DEBUG_HASH
416 void
417 EncodedData::hash (string n) const
418 {
419         md5_data (n, _data, _size);
420 }
421 #endif          
422
423 /** @param s Size of data in bytes */
424 RemotelyEncodedData::RemotelyEncodedData (int s)
425         : EncodedData (new uint8_t[s], s)
426 {
427
428 }
429
430 RemotelyEncodedData::~RemotelyEncodedData ()
431 {
432         delete[] _data;
433 }