diff options
| author | Carl Hetherington <cth@carlh.net> | 2013-02-22 18:58:31 +0000 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2013-02-22 18:58:31 +0000 |
| commit | 62365221dd3cd80d6b771e9bf22b4f9365ee096a (patch) | |
| tree | 6d75b967b7e250a93eb3b600ce89706b2018f069 /src/lib | |
| parent | fa6c885de512cdde0590c2bbe9ea424030a12c6b (diff) | |
| parent | 5943bde6f1a29c84b3f79710535a41bb98f6ce7d (diff) | |
Merge branch 'master' into i18n
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/dcp_video_frame.cc | 22 | ||||
| -rw-r--r-- | src/lib/encoder.cc | 42 | ||||
| -rw-r--r-- | src/lib/encoder.h | 2 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 26 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.h | 2 | ||||
| -rw-r--r-- | src/lib/film.cc | 16 | ||||
| -rw-r--r-- | src/lib/film.h | 2 | ||||
| -rw-r--r-- | src/lib/image.cc | 19 | ||||
| -rw-r--r-- | src/lib/image.h | 1 | ||||
| -rw-r--r-- | src/lib/server.cc | 10 | ||||
| -rw-r--r-- | src/lib/subtitle.cc | 4 | ||||
| -rw-r--r-- | src/lib/util.cc | 128 | ||||
| -rw-r--r-- | src/lib/util.h | 22 | ||||
| -rw-r--r-- | src/lib/writer.cc | 4 |
14 files changed, 117 insertions, 183 deletions
diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 4f3fda44a..9b96724b0 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -316,7 +316,7 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) shared_ptr<Socket> socket (new Socket); - socket->connect (*endpoint_iterator, 30); + socket->connect (*endpoint_iterator); stringstream s; s << "encode please\n" @@ -352,21 +352,17 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) _input->lines(0), _input->lines(1), _input->lines(2), _input->line_size()[0], _input->line_size()[1], _input->line_size()[2] )); - - socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); + + socket->write (s.str().length() + 1); + socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1); _input->write_to_socket (socket); if (_subtitle) { _subtitle->image()->write_to_socket (socket); } - char buffer[32]; - socket->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); - socket->consume (strlen (buffer) + 1); - shared_ptr<EncodedData> e (new RemotelyEncodedData (atoi (buffer))); - - /* now read the rest */ - socket->read_definite_and_consume (e->data(), e->size(), 30); + shared_ptr<EncodedData> e (new RemotelyEncodedData (socket->read_uint32 ())); + socket->read (e->data(), e->size()); _log->log (String::compose ("Finished remotely-encoded frame %1", _frame)); @@ -438,10 +434,8 @@ EncodedData::write_info (shared_ptr<const Film> film, int frame, libdcp::FrameIn void EncodedData::send (shared_ptr<Socket> socket) { - stringstream s; - s << _size; - socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30); - socket->write (_data, _size, 30); + socket->write (_size); + socket->write (_data, _size); } LocallyEncodedData::LocallyEncodedData (uint8_t* d, int s) diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index d64622cba..f25256379 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -140,7 +140,7 @@ Encoder::process_end () } out->set_frames (frames); - _writer->write (out); + write_audio (out); } swr_free (&_swr_context); @@ -319,23 +319,7 @@ Encoder::process_audio (shared_ptr<AudioBuffers> data) } #endif - if (_film->audio_channels() == 1) { - /* We need to switch things around so that the mono channel is on - the centre channel of a 5.1 set (with other channels silent). - */ - - shared_ptr<AudioBuffers> b (new AudioBuffers (6, data->frames ())); - b->make_silent (libdcp::LEFT); - b->make_silent (libdcp::RIGHT); - memcpy (b->data()[libdcp::CENTRE], data->data()[0], data->frames() * sizeof(float)); - b->make_silent (libdcp::LFE); - b->make_silent (libdcp::LS); - b->make_silent (libdcp::RS); - - data = b; - } - - _writer->write (data); + write_audio (data); } void @@ -435,3 +419,25 @@ Encoder::encoder_thread (ServerDescription* server) _condition.notify_all (); } } + +void +Encoder::write_audio (shared_ptr<const AudioBuffers> data) +{ + if (_film->audio_channels() == 1) { + /* We need to switch things around so that the mono channel is on + the centre channel of a 5.1 set (with other channels silent). + */ + + shared_ptr<AudioBuffers> b (new AudioBuffers (6, data->frames ())); + b->make_silent (libdcp::LEFT); + b->make_silent (libdcp::RIGHT); + memcpy (b->data()[libdcp::CENTRE], data->data()[0], data->frames() * sizeof(float)); + b->make_silent (libdcp::LFE); + b->make_silent (libdcp::LS); + b->make_silent (libdcp::RS); + + data = b; + } + + _writer->write (data); +} diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 69a5c5a23..86880bc34 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -88,7 +88,7 @@ private: void frame_done (); - void write_audio (boost::shared_ptr<const AudioBuffers> audio); + void write_audio (boost::shared_ptr<const AudioBuffers> data); void encoder_thread (ServerDescription *); void terminate_threads (); diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 1f11f70a0..d4ed76e37 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -127,7 +127,7 @@ FFmpegDecoder::setup_general () /* This is a hack; sometimes it seems that _audio_codec_context->channel_layout isn't set up, so bodge it here. No idea why we should have to do this. */ - + if (s->codec->channel_layout == 0) { s->codec->channel_layout = av_get_default_channel_layout (s->codec->channels); } @@ -247,7 +247,7 @@ FFmpegDecoder::pass () ); assert (_audio_codec_context->channels == _film->audio_channels()); - Audio (deinterleave_audio (_frame->data[0], data_size)); + Audio (deinterleave_audio (_frame->data, data_size)); } } @@ -320,7 +320,7 @@ FFmpegDecoder::pass () ); assert (_audio_codec_context->channels == _film->audio_channels()); - Audio (deinterleave_audio (_frame->data[0], data_size)); + Audio (deinterleave_audio (_frame->data, data_size)); } } @@ -350,8 +350,11 @@ FFmpegDecoder::pass () return false; } +/** @param data pointer to array of pointers to buffers. + * Only the first buffer will be used for non-planar data, otherwise there will be one per channel. + */ shared_ptr<AudioBuffers> -FFmpegDecoder::deinterleave_audio (uint8_t* data, int size) +FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) { assert (_film->audio_channels()); assert (bytes_per_audio_sample()); @@ -370,7 +373,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t* data, int size) switch (audio_sample_format()) { case AV_SAMPLE_FMT_S16: { - int16_t* p = reinterpret_cast<int16_t *> (data); + int16_t* p = reinterpret_cast<int16_t *> (data[0]); int sample = 0; int channel = 0; for (int i = 0; i < total_samples; ++i) { @@ -387,10 +390,10 @@ FFmpegDecoder::deinterleave_audio (uint8_t* data, int size) case AV_SAMPLE_FMT_S16P: { - int16_t* p = reinterpret_cast<int16_t *> (data); + int16_t** p = reinterpret_cast<int16_t **> (data); for (int i = 0; i < _film->audio_channels(); ++i) { for (int j = 0; j < frames; ++j) { - audio->data(i)[j] = static_cast<float>(*p++) / (1 << 15); + audio->data(i)[j] = static_cast<float>(p[i][j]) / (1 << 15); } } } @@ -398,7 +401,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t* data, int size) case AV_SAMPLE_FMT_S32: { - int32_t* p = reinterpret_cast<int32_t *> (data); + int32_t* p = reinterpret_cast<int32_t *> (data[0]); int sample = 0; int channel = 0; for (int i = 0; i < total_samples; ++i) { @@ -415,7 +418,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t* data, int size) case AV_SAMPLE_FMT_FLT: { - float* p = reinterpret_cast<float*> (data); + float* p = reinterpret_cast<float*> (data[0]); int sample = 0; int channel = 0; for (int i = 0; i < total_samples; ++i) { @@ -432,10 +435,9 @@ FFmpegDecoder::deinterleave_audio (uint8_t* data, int size) case AV_SAMPLE_FMT_FLTP: { - float* p = reinterpret_cast<float*> (data); + float** p = reinterpret_cast<float**> (data); for (int i = 0; i < _film->audio_channels(); ++i) { - memcpy (audio->data(i), p, frames * sizeof(float)); - p += frames; + memcpy (audio->data(i), p[i], frames * sizeof(float)); } } break; diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 17308eb56..c383b8d13 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -121,7 +121,7 @@ private: void setup_subtitle (); void maybe_add_subtitle (); - boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t* data, int size); + boost::shared_ptr<AudioBuffers> deinterleave_audio (uint8_t** data, int size); void film_changed (Film::Property); diff --git a/src/lib/film.cc b/src/lib/film.cc index 77f61cbac..600cdfa02 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -237,11 +237,9 @@ Film::video_mxf_filename () const return video_state_identifier() + ".mxf"; } -/** Add suitable Jobs to the JobManager to create a DCP for this Film. - * @param true to transcode, false to use the WAV and J2K files that are already there. - */ +/** Add suitable Jobs to the JobManager to create a DCP for this Film */ void -Film::make_dcp (bool transcode) +Film::make_dcp () { set_dci_date_today (); @@ -298,12 +296,10 @@ Film::make_dcp (bool transcode) shared_ptr<Job> r; - if (transcode) { - if (dcp_ab()) { - r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), od))); - } else { - r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), od))); - } + if (dcp_ab()) { + r = JobManager::instance()->add (shared_ptr<Job> (new ABTranscodeJob (shared_from_this(), od))); + } else { + r = JobManager::instance()->add (shared_ptr<Job> (new TranscodeJob (shared_from_this(), od))); } } diff --git a/src/lib/film.h b/src/lib/film.h index cc77460db..04a483998 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -69,7 +69,7 @@ public: void examine_content (); void send_dcp_to_tms (); - void make_dcp (bool); + void make_dcp (); /** @return Logger. * It is safe to call this from any thread. diff --git a/src/lib/image.cc b/src/lib/image.cc index 0ec6bd26c..73d499fe8 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -323,7 +323,7 @@ Image::read_from_socket (shared_ptr<Socket> socket) for (int i = 0; i < components(); ++i) { uint8_t* p = data()[i]; for (int y = 0; y < lines(i); ++y) { - socket->read_definite_and_consume (p, line_size()[i], 30); + socket->read (p, line_size()[i]); p += stride()[i]; } } @@ -335,7 +335,7 @@ Image::write_to_socket (shared_ptr<Socket> socket) const for (int i = 0; i < components(); ++i) { uint8_t* p = data()[i]; for (int y = 0; y < lines(i); ++y) { - socket->write (p, line_size()[i], 30); + socket->write (p, line_size()[i]); p += stride()[i]; } } @@ -503,12 +503,18 @@ FilterBufferImage::FilterBufferImage (AVPixelFormat p, AVFilterBufferRef* b) : Image (p) , _buffer (b) { - + _line_size = (int *) av_malloc (4 * sizeof (int)); + _line_size[0] = _line_size[1] = _line_size[2] = _line_size[3] = 0; + + for (int i = 0; i < components(); ++i) { + _line_size[i] = size().width * bytes_per_pixel(i); + } } FilterBufferImage::~FilterBufferImage () { avfilter_unref_buffer (_buffer); + av_free (_line_size); } uint8_t ** @@ -520,13 +526,16 @@ FilterBufferImage::data () const int * FilterBufferImage::line_size () const { - return _buffer->linesize; + return _line_size; } int * FilterBufferImage::stride () const { - /* XXX? */ + /* I've seen images where the _buffer->linesize is larger than the width + (by a small amount), suggesting that _buffer->linesize is what we call + stride. But I'm not sure. + */ return _buffer->linesize; } diff --git a/src/lib/image.h b/src/lib/image.h index 23f13a648..f40ea9280 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -117,6 +117,7 @@ private: FilterBufferImage& operator= (FilterBufferImage const &); AVFilterBufferRef* _buffer; + int* _line_size; }; /** @class SimpleImage diff --git a/src/lib/server.cc b/src/lib/server.cc index d75ab0fb6..3614ed9e4 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -28,6 +28,7 @@ #include <iostream> #include <boost/algorithm/string.hpp> #include <boost/lexical_cast.hpp> +#include <boost/scoped_array.hpp> #include "server.h" #include "util.h" #include "scaler.h" @@ -45,6 +46,7 @@ using boost::algorithm::is_any_of; using boost::algorithm::split; using boost::thread; using boost::bind; +using boost::scoped_array; using libdcp::Size; /** Create a server description from a string of metadata returned from as_metadata(). @@ -82,11 +84,11 @@ Server::Server (Log* log) int Server::process (shared_ptr<Socket> socket) { - char buffer[512]; - socket->read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30); - socket->consume (strlen (buffer) + 1); + uint32_t length = socket->read_uint32 (); + scoped_array<char> buffer (new char[length]); + socket->read (reinterpret_cast<uint8_t*> (buffer.get()), length); - stringstream s (buffer); + stringstream s (buffer.get()); multimap<string, string> kv = read_key_value (s); if (get_required_string (kv, "encode") != "please") { diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc index bd5f0c879..5bb91af63 100644 --- a/src/lib/subtitle.cc +++ b/src/lib/subtitle.cc @@ -134,8 +134,8 @@ subtitle_transformed_area ( * Combining these two translations gives these expressions. */ - tx.x = target_x_scale * (sub_area.x + (sub_area.width * (1 - subtitle_scale) / 2)); - tx.y = target_y_scale * (sub_area.y + (sub_area.height * (1 - subtitle_scale) / 2)); + tx.x = rint (target_x_scale * (sub_area.x + (sub_area.width * (1 - subtitle_scale) / 2))); + tx.y = rint (target_y_scale * (sub_area.y + (sub_area.height * (1 - subtitle_scale) / 2))); return tx; } diff --git a/src/lib/util.cc b/src/lib/util.cc index c0c8be984..4ee304600 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -485,10 +485,10 @@ colour_lut_index_to_name (int index) return ""; } -Socket::Socket () +Socket::Socket (int timeout) : _deadline (_io_service) , _socket (_io_service) - , _buffer_data (0) + , _timeout (timeout) { _deadline.expires_at (posix_time::pos_infin); check (); @@ -505,14 +505,13 @@ Socket::check () _deadline.async_wait (boost::bind (&Socket::check, this)); } -/** Blocking connect with timeout. +/** Blocking connect. * @param endpoint End-point to connect to. - * @param timeout Time-out in seconds. */ void -Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint, int timeout) +Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint) { - _deadline.expires_from_now (posix_time::seconds (timeout)); + _deadline.expires_from_now (posix_time::seconds (_timeout)); system::error_code ec = asio::error::would_block; _socket.async_connect (endpoint, lambda::var(ec) = lambda::_1); do { @@ -524,132 +523,61 @@ Socket::connect (asio::ip::basic_resolver_entry<asio::ip::tcp> const & endpoint, } } -/** Blocking write with timeout. +/** Blocking write. * @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) +Socket::write (uint8_t const * data, int size) { - _deadline.expires_from_now (posix_time::seconds (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"); + throw NetworkError (ec.message ()); } } -/** Blocking read with timeout. +void +Socket::write (uint32_t v) +{ + v = htonl (v); + write (reinterpret_cast<uint8_t*> (&v), 4); +} + +/** Blocking read. * @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) +void +Socket::read (uint8_t* data, int size) { - _deadline.expires_from_now (posix_time::seconds (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) - ); + asio::async_read (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); 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); + throw NetworkError (ec.message ()); } } -/** 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. - * - * XXX This method assumes that there is always lots of data to read(); - * if there isn't, it will hang waiting for data that will never arrive. - */ -void -Socket::read_indefinite (uint8_t* data, int size, int timeout) +uint32_t +Socket::read_uint32 () { - 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); + uint32_t v; + read (reinterpret_cast<uint8_t *> (&v), 4); + return ntohl (v); } /** @param other A Rect. diff --git a/src/lib/util.h b/src/lib/util.h index c4940a5d7..87735ea8e 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -194,39 +194,35 @@ extern std::string get_optional_string (std::multimap<std::string, std::string> * that are useful for DVD-o-matic. * * This class wraps some things that I could not work out how to do with boost; - * most notably, sync read/write calls with timeouts, and the ability to peek into - * data being read. + * most notably, sync read/write calls with timeouts. */ class Socket { public: - Socket (); + Socket (int timeout = 30); /** @return Our underlying socket */ boost::asio::ip::tcp::socket& socket () { return _socket; } - void connect (boost::asio::ip::basic_resolver_entry<boost::asio::ip::tcp> const & endpoint, int timeout); - void write (uint8_t const * data, int size, int timeout); + void connect (boost::asio::ip::basic_resolver_entry<boost::asio::ip::tcp> const & endpoint); + + void write (uint32_t n); + void write (uint8_t const * data, int size); - void read_definite_and_consume (uint8_t* data, int size, int timeout); - void read_indefinite (uint8_t* data, int size, int timeout); - void consume (int amount); + void read (uint8_t* data, int size); + uint32_t read_uint32 (); private: void check (); - int read (uint8_t* data, int size, int timeout); Socket (Socket const &); boost::asio::io_service _io_service; boost::asio::deadline_timer _deadline; boost::asio::ip::tcp::socket _socket; - /** a buffer for small reads */ - uint8_t _buffer[1024]; - /** amount of valid data in the buffer */ - int _buffer_data; + int _timeout; }; /** @class AudioBuffers diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 8a09f254b..c2cc00328 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -72,13 +72,13 @@ Writer::Writer (shared_ptr<Film> f) _picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0); - if (_film->audio_channels() > 0) { + if (dcp_audio_channels (_film->audio_channels()) > 0) { _sound_asset.reset ( new libdcp::SoundAsset ( _film->dir (_film->dcp_name()), "audio.mxf", DCPFrameRate (_film->frames_per_second()).frames_per_second, - _film->audio_channels(), + dcp_audio_channels (_film->audio_channels()), dcp_audio_sample_rate (_film->audio_stream()->sample_rate()) ) ); |
