summary |
shortlog |
log |
commit | commitdiff |
tree
raw |
patch |
inline | side by side (from parent 1:
e82a4c8)
when moving content (or otherwise changing the playlist) while playing.
This commit refills the butler when things change in certain ways,
and improves locking to cope with Player methods being called from
the GUI and butler threads at the same time.
{
_player_video_connection = _player->Video.connect (bind (&Butler::video, this, _1, _2));
_player_audio_connection = _player->Audio.connect (bind (&Butler::audio, this, _1));
{
_player_video_connection = _player->Video.connect (bind (&Butler::video, this, _1, _2));
_player_audio_connection = _player->Audio.connect (bind (&Butler::audio, this, _1));
+ _player_changed_connection = _player->Changed.connect (bind (&Butler::player_changed, this, _1));
_thread = new boost::thread (bind (&Butler::thread, this));
#ifdef DCPOMATIC_LINUX
pthread_setname_np (_thread->native_handle(), "butler");
_thread = new boost::thread (bind (&Butler::thread, this));
#ifdef DCPOMATIC_LINUX
pthread_setname_np (_thread->native_handle(), "butler");
Butler::seek (DCPTime position, bool accurate)
{
boost::mutex::scoped_lock lm (_mutex);
Butler::seek (DCPTime position, bool accurate)
{
boost::mutex::scoped_lock lm (_mutex);
+ seek_unlocked (position, accurate);
+}
+
+void
+Butler::seek_unlocked (DCPTime position, bool accurate)
+{
- _video.clear ();
- _audio.clear ();
+ {
+ boost::mutex::scoped_lock lm (_video_audio_mutex);
+ _video.clear ();
+ _audio.clear ();
+ }
+
_finished = false;
_pending_seek_position = position;
_pending_seek_accurate = accurate;
_finished = false;
_pending_seek_position = position;
_pending_seek_accurate = accurate;
Butler::video (shared_ptr<PlayerVideo> video, DCPTime time)
{
boost::mutex::scoped_lock lm (_mutex);
Butler::video (shared_ptr<PlayerVideo> video, DCPTime time)
{
boost::mutex::scoped_lock lm (_mutex);
if (_pending_seek_position) {
/* Don't store any video while a seek is pending */
return;
}
_prepare_service.post (bind (&Butler::prepare, this, weak_ptr<PlayerVideo>(video)));
if (_pending_seek_position) {
/* Don't store any video while a seek is pending */
return;
}
_prepare_service.post (bind (&Butler::prepare, this, weak_ptr<PlayerVideo>(video)));
+
+ boost::mutex::scoped_lock lm2 (_video_audio_mutex);
_video.put (video, time);
}
_video.put (video, time);
}
+ boost::mutex::scoped_lock lm2 (_video_audio_mutex);
_audio.put (remap (audio, _audio_channels, _audio_mapping));
}
_audio.put (remap (audio, _audio_channels, _audio_mapping));
}
/* XXX: should also look at _audio.memory_used() */
return _video.memory_used();
}
/* XXX: should also look at _audio.memory_used() */
return _video.memory_used();
}
+
+void
+Butler::player_changed (int what)
+{
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_died || _pending_seek_position) {
+ return;
+ }
+
+ DCPTime seek_to;
+ DCPTime next = _video.get().second;
+ if (_awaiting && _awaiting > next) {
+ /* We have recently done a player_changed seek and our buffers haven't been refilled yet,
+ so assume that we're seeking to the same place as last time.
+ */
+ seek_to = *_awaiting;
+ } else {
+ seek_to = next;
+ }
+
+ {
+ boost::mutex::scoped_lock lm (_video_audio_mutex);
+ _video.clear ();
+ _audio.clear ();
+ }
+
+ _finished = false;
+ _summon.notify_all ();
+
+ seek_unlocked (seek_to, true);
+ _awaiting = seek_to;
+}
void audio (boost::shared_ptr<AudioBuffers> audio);
bool should_run () const;
void prepare (boost::weak_ptr<PlayerVideo> video) const;
void audio (boost::shared_ptr<AudioBuffers> audio);
bool should_run () const;
void prepare (boost::weak_ptr<PlayerVideo> video) const;
+ void player_changed (int);
+ void seek_unlocked (DCPTime position, bool accurate);
boost::shared_ptr<Player> _player;
boost::shared_ptr<Log> _log;
boost::thread* _thread;
boost::shared_ptr<Player> _player;
boost::shared_ptr<Log> _log;
boost::thread* _thread;
+ /** mutex to protect _video and _audio for when we are clearing them and they both need to be
+ cleared together without any data being inserted in the interim.
+ */
+ boost::mutex _video_audio_mutex;
VideoRingBuffers _video;
AudioRingBuffers _audio;
VideoRingBuffers _video;
AudioRingBuffers _audio;
+ /** If we are waiting to be refilled following a seek, this is the time we were
+ seeking to.
+ */
+ boost::optional<DCPTime> _awaiting;
+
boost::signals2::scoped_connection _player_video_connection;
boost::signals2::scoped_connection _player_audio_connection;
boost::signals2::scoped_connection _player_video_connection;
boost::signals2::scoped_connection _player_audio_connection;
+ boost::signals2::scoped_connection _player_changed_connection;
property == FFmpegContentProperty::FILTERS
) {
property == FFmpegContentProperty::FILTERS
) {
- _have_valid_pieces = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _have_valid_pieces = false;
+ }
+
Changed (property, frequent);
} else if (
Changed (property, frequent);
} else if (
void
Player::playlist_changed ()
{
void
Player::playlist_changed ()
{
- _have_valid_pieces = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _have_valid_pieces = false;
+ }
+
Changed (PlayerProperty::PLAYLIST, false);
}
Changed (PlayerProperty::PLAYLIST, false);
}
/* Pieces contain a FrameRateChange which contains the DCP frame rate,
so we need new pieces here.
*/
/* Pieces contain a FrameRateChange which contains the DCP frame rate,
so we need new pieces here.
*/
- _have_valid_pieces = false;
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _have_valid_pieces = false;
+ }
Changed (PlayerProperty::FILM_VIDEO_FRAME_RATE, false);
} else if (p == Film::AUDIO_PROCESSOR) {
if (_film->audio_processor ()) {
Changed (PlayerProperty::FILM_VIDEO_FRAME_RATE, false);
} else if (p == Film::AUDIO_PROCESSOR) {
if (_film->audio_processor ()) {
+ boost::mutex::scoped_lock lm (_mutex);
_audio_processor = _film->audio_processor()->clone (_film->audio_frame_rate ());
}
} else if (p == Film::AUDIO_CHANNELS) {
_audio_processor = _film->audio_processor()->clone (_film->audio_frame_rate ());
}
} else if (p == Film::AUDIO_CHANNELS) {
+ boost::mutex::scoped_lock lm (_mutex);
_audio_merger.clear ();
}
}
_audio_merger.clear ();
}
}
void
Player::set_ignore_audio ()
{
void
Player::set_ignore_audio ()
{
+ boost::mutex::scoped_lock lm (_mutex);
_ignore_audio = true;
_have_valid_pieces = false;
}
_ignore_audio = true;
_have_valid_pieces = false;
}
- cout << "start playback at " << to_string(_video_position) << "\n";
-
_playing = true;
_dropped = 0;
timer ();
_playing = true;
_dropped = 0;
timer ();