From: Carl Hetherington Date: Sun, 7 Apr 2013 11:45:46 +0000 (+0100) Subject: A few fixes; try to support sndfile audio in player. X-Git-Tag: v2.0.48~1337^2~464 X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=263eee639546964aaa57f5d2d3b24008ecfe8adb A few fixes; try to support sndfile audio in player. --- diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 0542587a0..46d11c556 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -144,7 +144,7 @@ Encoder::process_end () } out->set_frames (frames); - write_audio (out); + _writer->write (out); } swr_free (&_swr_context); @@ -323,7 +323,7 @@ Encoder::process_audio (shared_ptr data) } #endif - write_audio (data); + _writer->write (data); } void @@ -423,30 +423,3 @@ Encoder::encoder_thread (ServerDescription* server) _condition.notify_all (); } } - -void -Encoder::write_audio (shared_ptr data) -{ -#if 0 - XXX - AutomaticAudioMapping m (_film->audio_channels ()); - if (m.dcp_channels() != _film->audio_channels()) { - - /* Remap (currently just for mono -> 5.1) */ - - shared_ptr b (new AudioBuffers (m.dcp_channels(), data->frames ())); - for (int i = 0; i < m.dcp_channels(); ++i) { - optional s = m.dcp_to_source (static_cast (i)); - if (!s) { - b->make_silent (i); - } else { - memcpy (b->data()[i], data->data()[s.get()], data->frames() * sizeof(float)); - } - } - - data = b; - } -#endif - - _writer->write (data); -} diff --git a/src/lib/encoder.h b/src/lib/encoder.h index b85132b72..70e6eea9a 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -88,8 +88,6 @@ private: void frame_done (); - void write_audio (boost::shared_ptr data); - void encoder_thread (ServerDescription *); void terminate_threads (); diff --git a/src/lib/player.cc b/src/lib/player.cc index ac046fcc0..756c3b854 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -22,6 +22,7 @@ #include "ffmpeg_decoder.h" #include "imagemagick_decoder.h" #include "sndfile_decoder.h" +#include "sndfile_content.h" #include "playlist.h" #include "job.h" @@ -95,7 +96,16 @@ Player::pass () } } - /* XXX: sndfile */ + if (_playlist->audio_from() == Playlist::AUDIO_SNDFILE) { + for (list >::iterator i = _sndfile_decoders.begin(); i != _sndfile_decoders.end(); ++i) { + if (!(*i)->pass ()) { + done = false; + } + } + + Audio (_sndfile_buffers); + _sndfile_buffers.reset (); + } return done; } @@ -133,9 +143,25 @@ Player::process_video (shared_ptr i, bool same, shared_ptr s) } void -Player::process_audio (shared_ptr b) +Player::process_audio (weak_ptr c, shared_ptr b) { - Audio (b); + if (_playlist->audio_from() == Playlist::AUDIO_SNDFILE) { + AudioMapping mapping = _film->audio_mapping (); + if (!_sndfile_buffers) { + _sndfile_buffers.reset (new AudioBuffers (mapping.dcp_channels(), b->frames ())); + _sndfile_buffers->make_silent (); + } + + for (int i = 0; i < b->channels(); ++i) { + list dcp = mapping.content_to_dcp (AudioMapping::Channel (c, i)); + for (list::iterator j = dcp.begin(); j != dcp.end(); ++j) { + _sndfile_buffers->accumulate (b, i, static_cast (*j)); + } + } + + } else { + Audio (b); + } } /** @return true on error */ @@ -238,7 +264,7 @@ Player::setup_decoders () } if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - _ffmpeg_decoder->connect_audio (shared_from_this ()); + _ffmpeg_decoder->Audio.connect (bind (&Player::process_audio, this, _playlist->ffmpeg (), _1)); } if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { @@ -257,7 +283,7 @@ Player::setup_decoders () for (list >::iterator i = sc.begin(); i != sc.end(); ++i) { shared_ptr d (new SndfileDecoder (_film, *i)); _sndfile_decoders.push_back (d); - d->connect_audio (shared_from_this ()); + d->Audio.connect (bind (&Player::process_audio, this, *i, _1)); } } } diff --git a/src/lib/player.h b/src/lib/player.h index 79203692e..afc856316 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -34,8 +34,9 @@ class SndfileDecoder; class Job; class Film; class Playlist; +class AudioContent; -class Player : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this +class Player : public VideoSource, public AudioSource, public VideoSink, public boost::enable_shared_from_this { public: Player (boost::shared_ptr, boost::shared_ptr); @@ -54,7 +55,7 @@ public: private: void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); - void process_audio (boost::shared_ptr); + void process_audio (boost::weak_ptr, boost::shared_ptr); void setup_decoders (); void playlist_changed (); void content_changed (boost::weak_ptr, int); @@ -73,6 +74,8 @@ private: std::list >::iterator _imagemagick_decoder; std::list > _sndfile_decoders; + boost::shared_ptr _sndfile_buffers; + bool _video_sync; }; diff --git a/src/lib/util.cc b/src/lib/util.cc index 1e60b43fc..760b826c7 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -63,8 +63,26 @@ extern "C" { #include "i18n.h" -using namespace std; -using namespace boost; +using std::string; +using std::stringstream; +using std::setfill; +using std::ostream; +using std::endl; +using std::vector; +using std::hex; +using std::setw; +using std::ifstream; +using std::ios; +using std::min; +using std::max; +using std::list; +using std::multimap; +using std::istream; +using std::numeric_limits; +using std::pair; +using boost::shared_ptr; +using boost::thread; +using boost::lexical_cast; using libdcp::Size; thread::id ui_thread; @@ -243,7 +261,7 @@ dvdomatic_setup () Filter::setup_filters (); SoundProcessor::setup_sound_processors (); - ui_thread = this_thread::get_id (); + ui_thread = boost::this_thread::get_id (); } #ifdef DVDOMATIC_WINDOWS @@ -498,16 +516,16 @@ Socket::Socket (int timeout) , _socket (_io_service) , _timeout (timeout) { - _deadline.expires_at (posix_time::pos_infin); + _deadline.expires_at (boost::posix_time::pos_infin); check (); } void Socket::check () { - if (_deadline.expires_at() <= asio::deadline_timer::traits_type::now ()) { + if (_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now ()) { _socket.close (); - _deadline.expires_at (posix_time::pos_infin); + _deadline.expires_at (boost::posix_time::pos_infin); } _deadline.async_wait (boost::bind (&Socket::check, this)); @@ -517,14 +535,14 @@ Socket::check () * @param endpoint End-point to connect to. */ void -Socket::connect (asio::ip::basic_resolver_entry const & endpoint) +Socket::connect (boost::asio::ip::basic_resolver_entry const & endpoint) { - _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); + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; + _socket.async_connect (endpoint, boost::lambda::var(ec) = boost::lambda::_1); do { _io_service.run_one(); - } while (ec == asio::error::would_block); + } while (ec == boost::asio::error::would_block); if (ec || !_socket.is_open ()) { throw NetworkError (_("connect timed out")); @@ -538,14 +556,14 @@ Socket::connect (asio::ip::basic_resolver_entry const & endpoint) void Socket::write (uint8_t const * data, int size) { - _deadline.expires_from_now (posix_time::seconds (_timeout)); - system::error_code ec = asio::error::would_block; + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; - asio::async_write (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + boost::asio::async_write (_socket, boost::asio::buffer (data, size), boost::lambda::var(ec) = boost::lambda::_1); do { _io_service.run_one (); - } while (ec == asio::error::would_block); + } while (ec == boost::asio::error::would_block); if (ec) { throw NetworkError (ec.message ()); @@ -566,14 +584,14 @@ Socket::write (uint32_t v) void Socket::read (uint8_t* data, int size) { - _deadline.expires_from_now (posix_time::seconds (_timeout)); - system::error_code ec = asio::error::would_block; + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; - asio::async_read (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + boost::asio::async_read (_socket, boost::asio::buffer (data, size), boost::lambda::var(ec) = boost::lambda::_1); do { _io_service.run_one (); - } while (ec == asio::error::would_block); + } while (ec == boost::asio::error::would_block); if (ec) { throw NetworkError (ec.message ()); @@ -850,11 +868,26 @@ AudioBuffers::move (int from, int to, int frames) } } +/** Add data from from `from', `from_channel' to our channel `to_channel' */ +void +AudioBuffers::accumulate (shared_ptr from, int from_channel, int to_channel) +{ + int const N = frames (); + assert (from->frames() == N); + + float* s = from->data (from_channel); + float* d = _data[to_channel]; + + for (int i = 0; i < N; ++i) { + *d++ += *s++; + } +} + /** Trip an assert if the caller is not in the UI thread */ void ensure_ui_thread () { - assert (this_thread::get_id() == ui_thread); + assert (boost::this_thread::get_id() == ui_thread); } /** @param v Content video frame. diff --git a/src/lib/util.h b/src/lib/util.h index 1fe6212e4..f4af7c22b 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -182,6 +182,7 @@ public: void copy_from (AudioBuffers* from, int frames_to_copy, int read_offset, int write_offset); void move (int from, int to, int frames); + void accumulate (boost::shared_ptr, int, int); private: /** Number of channels */ diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 6f08b6567..071393139 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -1344,6 +1344,9 @@ FilmEditor::selected_content () } ContentList c = _film->content (); - assert (s >= 0 && size_t (s) < c.size ()); + if (s < 0 || size_t (s) >= c.size ()) { + return shared_ptr (); + } + return c[s]; } diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 4d8685dd0..bd56efd57 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -84,18 +84,6 @@ FilmViewer::FilmViewer (shared_ptr f, wxWindow* p) _play_button->Connect (wxID_ANY, wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler (FilmViewer::play_clicked), 0, this); _timer.Connect (wxID_ANY, wxEVT_TIMER, wxTimerEventHandler (FilmViewer::timer), 0, this); - if (f) { - /* We need a player before we set_film() so that the first frame will be displayed */ - _player = f->player (); - _player->disable_audio (); - _player->disable_video_sync (); - /* Don't disable subtitles here as we may need them, and it's nice to be able to turn them - on and off without needing obtain a new Player. - */ - - _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); - } - set_film (f); JobManager::instance()->ActiveJobsChanged.connect ( @@ -142,13 +130,22 @@ FilmViewer::set_film (shared_ptr f) if (_film == f) { return; } - + _film = f; if (!_film) { return; } + _player = f->player (); + _player->disable_audio (); + _player->disable_video_sync (); + /* Don't disable subtitles here as we may need them, and it's nice to be able to turn them + on and off without needing obtain a new Player. + */ + + _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); + _film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1)); film_changed (Film::CONTENT);