X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Flib%2Futil.cc;h=935566440276f563ba5adcb86c44075c06eb5fa7;hb=f29219ed06d27dcae5e18b8b9c52dcf24554f188;hp=799d0e54e088e41b89ed58b9858f2cbfbe623c2e;hpb=a7bc9d57f6a5c7c13400e700db50f21c283766f4;p=dcpomatic.git diff --git a/src/lib/util.cc b/src/lib/util.cc index 799d0e54e..935566440 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -29,12 +29,12 @@ #ifdef DVDOMATIC_POSIX #include #include -#include -#include #endif #include #include #include +#include +#include #include #include #include @@ -56,10 +56,9 @@ extern "C" { #include "filter.h" #include "screen.h" #include "film_state.h" +#include "sound_processor.h" +#ifndef DVDOMATIC_DISABLE_PLAYER #include "player_manager.h" - -#ifdef DEBUG_HASH -#include #endif using namespace std; @@ -279,126 +278,20 @@ dependency_version_summary () return s.str (); } -#ifdef DVDOMATIC_POSIX -/** Write some data to a socket. - * @param fd Socket file descriptor. - * @param data Data. - * @param size Amount to write, in bytes. - */ -void -socket_write (int fd, uint8_t const * data, int size) -{ - uint8_t const * p = data; - while (size) { - int const n = send (fd, p, size, MSG_NOSIGNAL); - if (n < 0) { - stringstream s; - s << "could not write (" << strerror (errno) << ")"; - throw NetworkError (s.str ()); - } - - size -= n; - p += n; - } -} -#endif - double seconds (struct timeval t) { return t.tv_sec + (double (t.tv_usec) / 1e6); } -#ifdef DVDOMATIC_POSIX -/** @param fd File descriptor to read from */ -SocketReader::SocketReader (int fd) - : _fd (fd) - , _buffer_data (0) -{ - -} - -/** Mark some data as being `consumed', so that it will not be returned - * as data again. - * @param size Amount of data to consume, in bytes. - */ -void -SocketReader::consume (int size) -{ - assert (_buffer_data >= size); - - _buffer_data -= size; - if (_buffer_data > 0) { - /* Shift still-valid data to the start of the buffer */ - memmove (_buffer, _buffer + size, _buffer_data); - } -} - -/** Read a definite amount of data from our socket, and mark - * it as consumed. - * @param data Where to put the data. - * @param size Number of bytes to read. - */ -void -SocketReader::read_definite_and_consume (uint8_t* data, int size) -{ - int const from_buffer = min (_buffer_data, size); - if (from_buffer > 0) { - /* Get data from our buffer */ - memcpy (data, _buffer, from_buffer); - consume (from_buffer); - /* Update our output state */ - data += from_buffer; - size -= from_buffer; - } - - /* read() the rest */ - while (size > 0) { - int const n = ::read (_fd, data, size); - if (n <= 0) { - throw NetworkError ("could not read"); - } - - data += n; - size -= n; - } -} - -/** Read as much data as is available, up to some limit. - * @param data Where to put the data. - * @param size Maximum amount of data to read. - */ -void -SocketReader::read_indefinite (uint8_t* data, int size) -{ - assert (size < int (sizeof (_buffer))); - - /* Amount of extra data we need to read () */ - int to_read = size - _buffer_data; - while (to_read > 0) { - /* read as much of it as we can (into our buffer) */ - int const n = ::read (_fd, _buffer + _buffer_data, to_read); - if (n <= 0) { - throw NetworkError ("could not read"); - } - - to_read -= n; - _buffer_data += n; - } - - assert (_buffer_data >= size); - - /* copy data into the output buffer */ - assert (size >= _buffer_data); - memcpy (data, _buffer, size); -} -#endif #ifdef DVDOMATIC_POSIX void sigchld_handler (int, siginfo_t* info, void *) { +#ifndef DVDOMATIC_DISABLE_PLAYER PlayerManager::instance()->child_exited (info->si_pid); +#endif } #endif @@ -410,6 +303,7 @@ dvdomatic_setup () DCPContentType::setup_dcp_content_types (); Scaler::setup_scalers (); Filter::setup_filters (); + SoundProcessor::setup_sound_processors (); #ifdef DVDOMATIC_POSIX struct sigaction sa; @@ -449,28 +343,26 @@ split_at_spaces_considering_quotes (string s) return out; } -#ifdef DEBUG_HASH -void -md5_data (string title, void const * data, int size) +string +md5_digest (void const * data, int size) { - MHASH ht = mhash_init (MHASH_MD5); - if (ht == MHASH_FAILED) { - throw EncodeError ("could not create hash thread"); - } - - mhash (ht, data, size); - - uint8_t hash[16]; - mhash_deinit (ht, hash); + MD5_CTX md5_context; + MD5_Init (&md5_context); + MD5_Update (&md5_context, data, size); + unsigned char digest[MD5_DIGEST_LENGTH]; + MD5_Final (digest, &md5_context); - printf ("%s [%d]: ", title.c_str (), size); - for (int i = 0; i < int (mhash_get_block_size (MHASH_MD5)); ++i) { - printf ("%.2x", hash[i]); + stringstream s; + for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { + s << hex << setfill('0') << setw(2) << ((int) digest[i]); } - printf ("\n"); + + return s.str (); } -#endif +/** @param file File name. + * @return MD5 digest of file's contents. + */ string md5_digest (string file) { @@ -505,3 +397,206 @@ md5_digest (string file) return s.str (); } + +/** @param An arbitrary sampling rate. + * @return The appropriate DCP-approved sampling rate (48kHz or 96kHz). + */ +int +dcp_audio_sample_rate (int fs) +{ + if (fs <= 48000) { + return 48000; + } + + return 96000; +} + +bool operator== (Crop const & a, Crop const & b) +{ + return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom); +} + +bool operator!= (Crop const & a, Crop const & b) +{ + return !(a == b); +} + +/** @param index Colour LUT index. + * @return Human-readable name. + */ +string +colour_lut_index_to_name (int index) +{ + switch (index) { + case 0: + return "sRGB"; + case 1: + return "Rec 709"; + } + + assert (false); + return ""; +} + +Socket::Socket () + : _deadline (_io_service) + , _socket (_io_service) + , _buffer_data (0) +{ + _deadline.expires_at (posix_time::pos_infin); + check (); +} + +void +Socket::check () +{ + if (_deadline.expires_at() <= asio::deadline_timer::traits_type::now ()) { + _socket.close (); + _deadline.expires_at (posix_time::pos_infin); + } + + _deadline.async_wait (boost::bind (&Socket::check, this)); +} + +/** Blocking connect with timeout. + * @param endpoint End-point to connect to. + * @param timeout Time-out in seconds. + */ +void +Socket::connect (asio::ip::basic_resolver_entry const & endpoint, int timeout) +{ + system::error_code ec = asio::error::would_block; + _socket.async_connect (endpoint, lambda::var(ec) = lambda::_1); + do { + _io_service.run_one(); + } while (ec == asio::error::would_block); + + if (ec || !_socket.is_open ()) { + throw NetworkError ("connect timed out"); + } +} + +/** Blocking write with timeout. + * @param data Buffer to write. + * @param size Number of bytes to write. + * @param timeout Time-out, in seconds. + */ +void +Socket::write (uint8_t const * data, int size, int timeout) +{ + _deadline.expires_from_now (posix_time::seconds (timeout)); + system::error_code ec = asio::error::would_block; + + asio::async_write (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + do { + _io_service.run_one (); + } while (ec == asio::error::would_block); + + if (ec) { + throw NetworkError ("write timed out"); + } +} + +/** Blocking read with timeout. + * @param data Buffer to read to. + * @param size Number of bytes to read. + * @param timeout Time-out, in seconds. + */ +int +Socket::read (uint8_t* data, int size, int timeout) +{ + _deadline.expires_from_now (posix_time::seconds (timeout)); + system::error_code ec = asio::error::would_block; + + int amount_read = 0; + + _socket.async_read_some ( + asio::buffer (data, size), + (lambda::var(ec) = lambda::_1, lambda::var(amount_read) = lambda::_2) + ); + + do { + _io_service.run_one (); + } while (ec == asio::error::would_block); + + if (ec) { + amount_read = 0; + } + + return amount_read; +} + +/** Mark some data as being `consumed', so that it will not be returned + * as data again. + * @param size Amount of data to consume, in bytes. + */ +void +Socket::consume (int size) +{ + assert (_buffer_data >= size); + + _buffer_data -= size; + if (_buffer_data > 0) { + /* Shift still-valid data to the start of the buffer */ + memmove (_buffer, _buffer + size, _buffer_data); + } +} + +/** Read a definite amount of data from our socket, and mark + * it as consumed. + * @param data Where to put the data. + * @param size Number of bytes to read. + */ +void +Socket::read_definite_and_consume (uint8_t* data, int size, int timeout) +{ + int const from_buffer = min (_buffer_data, size); + if (from_buffer > 0) { + /* Get data from our buffer */ + memcpy (data, _buffer, from_buffer); + consume (from_buffer); + /* Update our output state */ + data += from_buffer; + size -= from_buffer; + } + + /* read() the rest */ + while (size > 0) { + int const n = read (data, size, timeout); + if (n <= 0) { + throw NetworkError ("could not read"); + } + + data += n; + size -= n; + } +} + +/** Read as much data as is available, up to some limit. + * @param data Where to put the data. + * @param size Maximum amount of data to read. + */ +void +Socket::read_indefinite (uint8_t* data, int size, int timeout) +{ + assert (size < int (sizeof (_buffer))); + + /* Amount of extra data we need to read () */ + int to_read = size - _buffer_data; + while (to_read > 0) { + /* read as much of it as we can (into our buffer) */ + int const n = read (_buffer + _buffer_data, to_read, timeout); + if (n <= 0) { + throw NetworkError ("could not read"); + } + + to_read -= n; + _buffer_data += n; + } + + assert (_buffer_data >= size); + + /* copy data into the output buffer */ + assert (size >= _buffer_data); + memcpy (data, _buffer, size); +}