A few fixes; try to support sndfile audio in player.
authorCarl Hetherington <cth@carlh.net>
Sun, 7 Apr 2013 11:45:46 +0000 (12:45 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 7 Apr 2013 11:45:46 +0000 (12:45 +0100)
src/lib/encoder.cc
src/lib/encoder.h
src/lib/player.cc
src/lib/player.h
src/lib/util.cc
src/lib/util.h
src/wx/film_editor.cc
src/wx/film_viewer.cc

index 0542587a0af59505efcf4d4528bee80b04e4b4b0..46d11c55640e2fbf92a0789748f9f9a284c1d0b8 100644 (file)
@@ -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<AudioBuffers> 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<const AudioBuffers> 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<AudioBuffers> b (new AudioBuffers (m.dcp_channels(), data->frames ()));
-               for (int i = 0; i < m.dcp_channels(); ++i) {
-                       optional<int> s = m.dcp_to_source (static_cast<libdcp::Channel> (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);
-}
index b85132b7270fcc642f1baec01cd4dd4c50ffc094..70e6eea9a8ae30997d3f2132d31405e1e80e5850 100644 (file)
@@ -88,8 +88,6 @@ private:
        
        void frame_done ();
        
-       void write_audio (boost::shared_ptr<const AudioBuffers> data);
-
        void encoder_thread (ServerDescription *);
        void terminate_threads ();
 
index ac046fcc0e6eaf9e59c912da2f6ad6a3a812a5e7..756c3b85493bf940b8c15f136b7194907fb965d5 100644 (file)
@@ -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<shared_ptr<SndfileDecoder> >::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<Image> i, bool same, shared_ptr<Subtitle> s)
 }
 
 void
-Player::process_audio (shared_ptr<AudioBuffers> b)
+Player::process_audio (weak_ptr<const AudioContent> c, shared_ptr<AudioBuffers> 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<libdcp::Channel> dcp = mapping.content_to_dcp (AudioMapping::Channel (c, i));
+                       for (list<libdcp::Channel>::iterator j = dcp.begin(); j != dcp.end(); ++j) {
+                               _sndfile_buffers->accumulate (b, i, static_cast<int> (*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<shared_ptr<const SndfileContent> >::iterator i = sc.begin(); i != sc.end(); ++i) {
                        shared_ptr<SndfileDecoder> 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));
                }
        }
 }
index 79203692e963dc9c53df06dab626ad798378f6ce..afc856316cf48bee32cb4d560fe26dfba4432e4c 100644 (file)
@@ -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<Player>
+class Player : public VideoSource, public AudioSource, public VideoSink, public boost::enable_shared_from_this<Player>
 {
 public:
        Player (boost::shared_ptr<const Film>, boost::shared_ptr<const Playlist>);
@@ -54,7 +55,7 @@ public:
 
 private:
        void process_video (boost::shared_ptr<Image> i, bool same, boost::shared_ptr<Subtitle> s);
-       void process_audio (boost::shared_ptr<AudioBuffers>);
+       void process_audio (boost::weak_ptr<const AudioContent>, boost::shared_ptr<AudioBuffers>);
        void setup_decoders ();
        void playlist_changed ();
        void content_changed (boost::weak_ptr<Content>, int);
@@ -73,6 +74,8 @@ private:
        std::list<boost::shared_ptr<ImageMagickDecoder> >::iterator _imagemagick_decoder;
        std::list<boost::shared_ptr<SndfileDecoder> > _sndfile_decoders;
 
+       boost::shared_ptr<AudioBuffers> _sndfile_buffers;
+
        bool _video_sync;
 };
 
index 1e60b43fc1f2bef804373ffc4992083899436798..760b826c7649cc18cc20462bf07773c459412897 100644 (file)
@@ -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<asio::ip::tcp> const & endpoint)
+Socket::connect (boost::asio::ip::basic_resolver_entry<boost::asio::ip::tcp> 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<asio::ip::tcp> 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<AudioBuffers> 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.
index 1fe6212e43fb607082c1bcc03409e972e6441f47..f4af7c22bc8db2f17d84cf3b1881273bc014262d 100644 (file)
@@ -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<AudioBuffers>, int, int);
 
 private:
        /** Number of channels */
index 6f08b656768af6f3b95205158ff9f665517c97d9..07139313953f445102145663a6e47bcfa608b824 100644 (file)
@@ -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<Content> ();
+       }
+       
        return c[s];
 }
index 4d8685dd0cb232d3f95575c20f149500efd2119c..bd56efd579055347dc0b5522061a98803188d915 100644 (file)
@@ -84,18 +84,6 @@ FilmViewer::FilmViewer (shared_ptr<Film> 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<Film> 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);