Protect the public API of Player with a mutex, since
authorCarl Hetherington <cth@carlh.net>
Thu, 26 Jul 2018 19:59:04 +0000 (20:59 +0100)
committerCarl Hetherington <cth@carlh.net>
Thu, 26 Jul 2018 19:59:04 +0000 (20:59 +0100)
seek() and pass() may be called from the Butler thread
ad the same time as other Player methods are called from
the GUI thread (by FilmViewer and ClosedCaptionViewDialog).

src/lib/butler.cc
src/lib/player.cc
src/lib/player.h
src/wx/film_viewer.cc

index 112778e25184794f7f72e20dd1f790192854c7be..138ee0fbdeb4630e91adf8717077e2532d177b3e 100644 (file)
@@ -198,6 +198,7 @@ Butler::get_video ()
        }
 
        pair<shared_ptr<PlayerVideo>, DCPTime> const r = _video.get ();
+       cout << "BGV " << to_string(r.second) << " " << _video.size() << "\n";
        _summon.notify_all ();
        return r;
 }
@@ -233,6 +234,7 @@ Butler::prepare (weak_ptr<PlayerVideo> weak_video) const
 void
 Butler::video (shared_ptr<PlayerVideo> video, DCPTime time)
 {
+       cout << "BV: " << to_string(time) << " " << _video.size() << " " << (float(_video.size()) / 24) << "\n";
        boost::mutex::scoped_lock lm (_mutex);
        if (_pending_seek_position) {
                /* Don't store any video while a seek is pending */
@@ -246,6 +248,7 @@ Butler::video (shared_ptr<PlayerVideo> video, DCPTime time)
 void
 Butler::audio (shared_ptr<AudioBuffers> audio)
 {
+       cout << "BA: " << audio->frames() << " " << _audio.size() << " " << (float(_audio.size()) / 48000) << "\n";
        {
                boost::mutex::scoped_lock lm (_mutex);
                if (_pending_seek_position || _disable_audio) {
@@ -265,6 +268,7 @@ bool
 Butler::get_audio (float* out, Frame frames)
 {
        bool const underrun = _audio.get (out, _audio_channels, frames);
+       cout << "BGA: " << frames << " " << _audio.size() << " " << (float(_audio.size()) / 48000) << "\n";
        _summon.notify_all ();
        return underrun;
 }
index 8b2ade1dc74b49510828695a80e274b1391b2282..f8471c752cb1838ad5841af2eb068d04acc8b96c 100644 (file)
@@ -258,14 +258,18 @@ Player::playlist_content_changed (weak_ptr<Content> w, int property, bool freque
 void
 Player::set_video_container_size (dcp::Size s)
 {
-       if (s == _video_container_size) {
-               return;
-       }
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+
+               if (s == _video_container_size) {
+                       return;
+               }
 
-       _video_container_size = s;
+               _video_container_size = s;
 
-       _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_container_size, true));
-       _black_image->make_black ();
+               _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_container_size, true));
+               _black_image->make_black ();
+       }
 
        Changed (PlayerProperty::VIDEO_CONTAINER_SIZE, false);
 }
@@ -414,6 +418,8 @@ Player::content_time_to_dcp (shared_ptr<const Piece> piece, ContentTime t) const
 list<shared_ptr<Font> >
 Player::get_subtitle_fonts ()
 {
+       /* Does not require a lock on _mutex as it's only called from DCPEncoder */
+
        if (!_have_valid_pieces) {
                setup_pieces ();
        }
@@ -436,12 +442,14 @@ Player::get_subtitle_fonts ()
 void
 Player::set_ignore_video ()
 {
+       boost::mutex::scoped_lock lm (_mutex);
        _ignore_video = true;
 }
 
 void
 Player::set_ignore_text ()
 {
+       boost::mutex::scoped_lock lm (_mutex);
        _ignore_text = true;
 }
 
@@ -449,6 +457,7 @@ Player::set_ignore_text ()
 void
 Player::set_always_burn_open_subtitles ()
 {
+       boost::mutex::scoped_lock lm (_mutex);
        _always_burn_open_subtitles = true;
 }
 
@@ -456,6 +465,7 @@ Player::set_always_burn_open_subtitles ()
 void
 Player::set_fast ()
 {
+       boost::mutex::scoped_lock lm (_mutex);
        _fast = true;
        _have_valid_pieces = false;
 }
@@ -463,6 +473,7 @@ Player::set_fast ()
 void
 Player::set_play_referenced ()
 {
+       boost::mutex::scoped_lock lm (_mutex);
        _play_referenced = true;
        _have_valid_pieces = false;
 }
@@ -470,6 +481,8 @@ Player::set_play_referenced ()
 list<ReferencedReelAsset>
 Player::get_reel_assets ()
 {
+       /* Does not require a lock on _mutex as it's only called from DCPEncoder */
+
        list<ReferencedReelAsset> a;
 
        BOOST_FOREACH (shared_ptr<Content> i, _playlist->content ()) {
@@ -546,6 +559,8 @@ Player::get_reel_assets ()
 bool
 Player::pass ()
 {
+       boost::mutex::scoped_lock lm (_mutex);
+
        if (!_have_valid_pieces) {
                setup_pieces ();
        }
@@ -680,6 +695,7 @@ Player::pass ()
 list<PlayerText>
 Player::closed_captions_for_frame (DCPTime time) const
 {
+       boost::mutex::scoped_lock _lm (_mutex);
        return _active_texts[TEXT_CLOSED_CAPTION].get (
                DCPTimePeriod(time, time + DCPTime::from_frames(1, _film->video_frame_rate()))
                );
@@ -972,6 +988,8 @@ Player::subtitle_stop (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, Conte
 void
 Player::seek (DCPTime time, bool accurate)
 {
+       boost::mutex::scoped_lock lm (_mutex);
+
        if (!_have_valid_pieces) {
                setup_pieces ();
        }
@@ -1120,18 +1138,25 @@ Player::discard_audio (shared_ptr<const AudioBuffers> audio, DCPTime time, DCPTi
 void
 Player::set_dcp_decode_reduction (optional<int> reduction)
 {
-       if (reduction == _dcp_decode_reduction) {
-               return;
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+
+               if (reduction == _dcp_decode_reduction) {
+                       return;
+               }
+
+               _dcp_decode_reduction = reduction;
+               _have_valid_pieces = false;
        }
 
-       _dcp_decode_reduction = reduction;
-       _have_valid_pieces = false;
        Changed (PlayerProperty::DCP_DECODE_REDUCTION, false);
 }
 
 DCPTime
 Player::content_time_to_dcp (shared_ptr<Content> content, ContentTime t)
 {
+       boost::mutex::scoped_lock lm (_mutex);
+
        if (_have_valid_pieces) {
                setup_pieces ();
        }
index 223db86b3d442e7cd7540d0c60442d1e426570bc..4a91c4c529011434800afc2ed899397db2c6b3bd 100644 (file)
@@ -73,6 +73,7 @@ public:
        std::list<boost::shared_ptr<Font> > get_subtitle_fonts ();
        std::list<ReferencedReelAsset> get_reel_assets ();
        dcp::Size video_container_size () const {
+               boost::mutex::scoped_lock lm (_mutex);
                return _video_container_size;
        }
 
@@ -141,6 +142,12 @@ private:
        void do_emit_video (boost::shared_ptr<PlayerVideo> pv, DCPTime time);
        void emit_audio (boost::shared_ptr<AudioBuffers> data, DCPTime time);
 
+       /** Mutex to protect the whole Player state.  When it's used for the preview we have
+           seek() and pass() called from the Butler thread and lots of other stuff called
+           from the GUI thread.
+       */
+       mutable boost::mutex _mutex;
+
        boost::shared_ptr<const Film> _film;
        boost::shared_ptr<const Playlist> _playlist;
 
index ef28018e96b0a960623ba665d4cc6344851f07b0..8c1a79113c732d33d2ca054307569eba039b1b90 100644 (file)
@@ -529,6 +529,8 @@ FilmViewer::start ()
                _audio.startStream ();
        }
 
+       cout << "start playback at " << to_string(_video_position) << "\n";
+
        _playing = true;
        _dropped = 0;
        timer ();