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