A couple of unnecessary includes.
[dcpomatic.git] / src / lib / util.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3     Copyright (C) 2000-2007 Paul Davis
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/lib/util.cc
22  *  @brief Some utility functions and classes.
23  */
24
25 #include <sstream>
26 #include <iomanip>
27 #include <iostream>
28 #include <fstream>
29 #ifdef DVDOMATIC_POSIX
30 #include <execinfo.h>
31 #include <cxxabi.h>
32 #endif
33 #include <libssh/libssh.h>
34 #include <signal.h>
35 #include <boost/algorithm/string.hpp>
36 #include <openjpeg.h>
37 #include <openssl/md5.h>
38 #include <magick/MagickCore.h>
39 #include <magick/version.h>
40 #include <libdcp/version.h>
41 extern "C" {
42 #include <libavcodec/avcodec.h>
43 #include <libavformat/avformat.h>
44 #include <libswscale/swscale.h>
45 #include <libavfilter/avfiltergraph.h>
46 #include <libpostproc/postprocess.h>
47 #include <libavutil/pixfmt.h>
48 }
49 #include "util.h"
50 #include "exceptions.h"
51 #include "scaler.h"
52 #include "format.h"
53 #include "dcp_content_type.h"
54 #include "filter.h"
55 #include "screen.h"
56 #include "film_state.h"
57 #ifndef DVDOMATIC_DISABLE_PLAYER
58 #include "player_manager.h"
59 #endif
60
61 #ifdef DEBUG_HASH
62 #include <mhash.h>
63 #endif
64
65 using namespace std;
66 using namespace boost;
67
68 /** Convert some number of seconds to a string representation
69  *  in hours, minutes and seconds.
70  *
71  *  @param s Seconds.
72  *  @return String of the form H:M:S (where H is hours, M
73  *  is minutes and S is seconds).
74  */
75 string
76 seconds_to_hms (int s)
77 {
78         int m = s / 60;
79         s -= (m * 60);
80         int h = m / 60;
81         m -= (h * 60);
82
83         stringstream hms;
84         hms << h << ":";
85         hms.width (2);
86         hms << setfill ('0') << m << ":";
87         hms.width (2);
88         hms << setfill ('0') << s;
89
90         return hms.str ();
91 }
92
93 /** @param s Number of seconds.
94  *  @return String containing an approximate description of s (e.g. "about 2 hours")
95  */
96 string
97 seconds_to_approximate_hms (int s)
98 {
99         int m = s / 60;
100         s -= (m * 60);
101         int h = m / 60;
102         m -= (h * 60);
103
104         stringstream ap;
105         
106         if (h > 0) {
107                 if (m > 30) {
108                         ap << (h + 1) << " hours";
109                 } else {
110                         if (h == 1) {
111                                 ap << "1 hour";
112                         } else {
113                                 ap << h << " hours";
114                         }
115                 }
116         } else if (m > 0) {
117                 if (m == 1) {
118                         ap << "1 minute";
119                 } else {
120                         ap << m << " minutes";
121                 }
122         } else {
123                 ap << s << " seconds";
124         }
125
126         return ap.str ();
127 }
128
129 #ifdef DVDOMATIC_POSIX
130 /** @param l Mangled C++ identifier.
131  *  @return Demangled version.
132  */
133 static string
134 demangle (string l)
135 {
136         string::size_type const b = l.find_first_of ("(");
137         if (b == string::npos) {
138                 return l;
139         }
140
141         string::size_type const p = l.find_last_of ("+");
142         if (p == string::npos) {
143                 return l;
144         }
145
146         if ((p - b) <= 1) {
147                 return l;
148         }
149         
150         string const fn = l.substr (b + 1, p - b - 1);
151
152         int status;
153         try {
154                 
155                 char* realname = abi::__cxa_demangle (fn.c_str(), 0, 0, &status);
156                 string d (realname);
157                 free (realname);
158                 return d;
159                 
160         } catch (std::exception) {
161                 
162         }
163         
164         return l;
165 }
166
167 /** Write a stacktrace to an ostream.
168  *  @param out Stream to write to.
169  *  @param levels Number of levels to go up the call stack.
170  */
171 void
172 stacktrace (ostream& out, int levels)
173 {
174         void *array[200];
175         size_t size;
176         char **strings;
177         size_t i;
178      
179         size = backtrace (array, 200);
180         strings = backtrace_symbols (array, size);
181      
182         if (strings) {
183                 for (i = 0; i < size && (levels == 0 || i < size_t(levels)); i++) {
184                         out << "  " << demangle (strings[i]) << endl;
185                 }
186                 
187                 free (strings);
188         }
189 }
190 #endif
191
192 /** @param s Sample format.
193  *  @return String representation.
194  */
195 string
196 audio_sample_format_to_string (AVSampleFormat s)
197 {
198         /* Our sample format handling is not exactly complete */
199         
200         switch (s) {
201         case AV_SAMPLE_FMT_S16:
202                 return "S16";
203         default:
204                 break;
205         }
206
207         return "Unknown";
208 }
209
210 /** @param s String representation of a sample format, as returned from audio_sample_format_to_string().
211  *  @return Sample format.
212  */
213 AVSampleFormat
214 audio_sample_format_from_string (string s)
215 {
216         if (s == "S16") {
217                 return AV_SAMPLE_FMT_S16;
218         }
219
220         return AV_SAMPLE_FMT_NONE;
221 }
222
223 /** @return Version of vobcopy that is on the path (and hence that we will use) */
224 static string
225 vobcopy_version ()
226 {
227         FILE* f = popen ("vobcopy -V 2>&1", "r");
228         if (f == 0) {
229                 throw EncodeError ("could not run vobcopy to check version");
230         }
231
232         string version = "unknown";
233         
234         while (!feof (f)) {
235                 char buf[256];
236                 if (fgets (buf, sizeof (buf), f)) {
237                         string s (buf);
238                         vector<string> b;
239                         split (b, s, is_any_of (" "));
240                         if (b.size() >= 2 && b[0] == "Vobcopy") {
241                                 version = b[1];
242                         }
243                 }
244         }
245
246         pclose (f);
247
248         return version;
249 }
250
251 /** @param v Version as used by FFmpeg.
252  *  @return A string representation of v.
253  */
254 static string
255 ffmpeg_version_to_string (int v)
256 {
257         stringstream s;
258         s << ((v & 0xff0000) >> 16) << "." << ((v & 0xff00) >> 8) << "." << (v & 0xff);
259         return s.str ();
260 }
261
262 /** Return a user-readable string summarising the versions of our dependencies */
263 string
264 dependency_version_summary ()
265 {
266         stringstream s;
267         s << "libopenjpeg " << opj_version () << ", "
268           << "vobcopy " << vobcopy_version() << ", "
269           << "libavcodec " << ffmpeg_version_to_string (avcodec_version()) << ", "
270           << "libavfilter " << ffmpeg_version_to_string (avfilter_version()) << ", "
271           << "libavformat " << ffmpeg_version_to_string (avformat_version()) << ", "
272           << "libavutil " << ffmpeg_version_to_string (avutil_version()) << ", "
273           << "libpostproc " << ffmpeg_version_to_string (postproc_version()) << ", "
274           << "libswscale " << ffmpeg_version_to_string (swscale_version()) << ", "
275           << MagickVersion << ", "
276           << "libssh " << ssh_version (0) << ", "
277           << "libdcp " << libdcp::version << " git " << libdcp::git_commit;
278
279         return s.str ();
280 }
281
282 double
283 seconds (struct timeval t)
284 {
285         return t.tv_sec + (double (t.tv_usec) / 1e6);
286 }
287
288 /** @param socket Socket to read from */
289 SocketReader::SocketReader (shared_ptr<asio::ip::tcp::socket> socket)
290         : _socket (socket)
291         , _buffer_data (0)
292 {
293
294 }
295
296 /** Mark some data as being `consumed', so that it will not be returned
297  *  as data again.
298  *  @param size Amount of data to consume, in bytes.
299  */
300 void
301 SocketReader::consume (int size)
302 {
303         assert (_buffer_data >= size);
304         
305         _buffer_data -= size;
306         if (_buffer_data > 0) {
307                 /* Shift still-valid data to the start of the buffer */
308                 memmove (_buffer, _buffer + size, _buffer_data);
309         }
310 }
311
312 /** Read a definite amount of data from our socket, and mark
313  *  it as consumed.
314  *  @param data Where to put the data.
315  *  @param size Number of bytes to read.
316  */
317 void
318 SocketReader::read_definite_and_consume (uint8_t* data, int size)
319 {
320         int const from_buffer = min (_buffer_data, size);
321         if (from_buffer > 0) {
322                 /* Get data from our buffer */
323                 memcpy (data, _buffer, from_buffer);
324                 consume (from_buffer);
325                 /* Update our output state */
326                 data += from_buffer;
327                 size -= from_buffer;
328         }
329
330         /* read() the rest */
331         while (size > 0) {
332                 int const n = asio::read (*_socket, asio::buffer (data, size));
333                 if (n <= 0) {
334                         throw NetworkError ("could not read");
335                 }
336
337                 data += n;
338                 size -= n;
339         }
340 }
341
342 /** Read as much data as is available, up to some limit.
343  *  @param data Where to put the data.
344  *  @param size Maximum amount of data to read.
345  */
346 void
347 SocketReader::read_indefinite (uint8_t* data, int size)
348 {
349         assert (size < int (sizeof (_buffer)));
350
351         /* Amount of extra data we need to read () */
352         int to_read = size - _buffer_data;
353         while (to_read > 0) {
354                 /* read as much of it as we can (into our buffer) */
355                 int const n = asio::read (*_socket, asio::buffer (_buffer + _buffer_data, to_read));
356                 if (n <= 0) {
357                         throw NetworkError ("could not read");
358                 }
359
360                 to_read -= n;
361                 _buffer_data += n;
362         }
363
364         assert (_buffer_data >= size);
365
366         /* copy data into the output buffer */
367         assert (size >= _buffer_data);
368         memcpy (data, _buffer, size);
369 }
370
371 #ifdef DVDOMATIC_POSIX
372 void
373 sigchld_handler (int, siginfo_t* info, void *)
374 {
375 #ifndef DVDOMATIC_DISABLE_PLAYER        
376         PlayerManager::instance()->child_exited (info->si_pid);
377 #endif  
378 }
379 #endif
380
381 /** Call the required functions to set up DVD-o-matic's static arrays, etc. */
382 void
383 dvdomatic_setup ()
384 {
385         Format::setup_formats ();
386         DCPContentType::setup_dcp_content_types ();
387         Scaler::setup_scalers ();
388         Filter::setup_filters ();
389
390 #ifdef DVDOMATIC_POSIX  
391         struct sigaction sa;
392         sa.sa_flags = SA_SIGINFO;
393         sigemptyset (&sa.sa_mask);
394         sa.sa_sigaction = sigchld_handler;
395         sigaction (SIGCHLD, &sa, 0);
396 #endif  
397 }
398
399 string
400 crop_string (Position start, Size size)
401 {
402         stringstream s;
403         s << "crop=" << size.width << ":" << size.height << ":" << start.x << ":" << start.y;
404         return s.str ();
405 }
406
407 vector<string>
408 split_at_spaces_considering_quotes (string s)
409 {
410         vector<string> out;
411         bool in_quotes = false;
412         string c;
413         for (string::size_type i = 0; i < s.length(); ++i) {
414                 if (s[i] == ' ' && !in_quotes) {
415                         out.push_back (c);
416                         c = "";
417                 } else if (s[i] == '"') {
418                         in_quotes = !in_quotes;
419                 } else {
420                         c += s[i];
421                 }
422         }
423
424         out.push_back (c);
425         return out;
426 }
427
428 #ifdef DEBUG_HASH
429 void
430 md5_data (string title, void const * data, int size)
431 {
432         MHASH ht = mhash_init (MHASH_MD5);
433         if (ht == MHASH_FAILED) {
434                 throw EncodeError ("could not create hash thread");
435         }
436
437         mhash (ht, data, size);
438         
439         uint8_t hash[16];
440         mhash_deinit (ht, hash);
441         
442         printf ("%s [%d]: ", title.c_str (), size);
443         for (int i = 0; i < int (mhash_get_block_size (MHASH_MD5)); ++i) {
444                 printf ("%.2x", hash[i]);
445         }
446         printf ("\n");
447 }
448 #endif
449
450 string
451 md5_digest (string file)
452 {
453         ifstream f (file.c_str(), ios::binary);
454         if (!f.good ()) {
455                 throw OpenFileError (file);
456         }
457         
458         f.seekg (0, ios::end);
459         int bytes = f.tellg ();
460         f.seekg (0, ios::beg);
461
462         int const buffer_size = 64 * 1024;
463         char buffer[buffer_size];
464
465         MD5_CTX md5_context;
466         MD5_Init (&md5_context);
467         while (bytes > 0) {
468                 int const t = min (bytes, buffer_size);
469                 f.read (buffer, t);
470                 MD5_Update (&md5_context, buffer, t);
471                 bytes -= t;
472         }
473
474         unsigned char digest[MD5_DIGEST_LENGTH];
475         MD5_Final (digest, &md5_context);
476
477         stringstream s;
478         for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
479                 s << hex << setfill('0') << setw(2) << ((int) digest[i]);
480         }
481
482         return s.str ();
483 }
484
485 int
486 dcp_audio_sample_rate (int fs)
487 {
488         if (fs <= 48000) {
489                 return 48000;
490         }
491
492         return 96000;
493 }