+
+pair<size_t, string>
+Butler::memory_used () const
+{
+ /* XXX: should also look at _audio.memory_used() */
+ return _video.memory_used();
+}
+
+void
+Butler::player_change (ChangeType type)
+{
+ boost::mutex::scoped_lock lm (_mutex);
+
+ if (type == CHANGE_TYPE_PENDING) {
+ ++_suspended;
+ } else if (type == CHANGE_TYPE_DONE) {
+ --_suspended;
+ if (_died || _pending_seek_position) {
+ lm.unlock ();
+ _summon.notify_all ();
+ 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;
+ }
+
+ seek_unlocked (seek_to, true);
+ _awaiting = seek_to;
+ } else if (type == CHANGE_TYPE_CANCELLED) {
+ --_suspended;
+ }
+
+ lm.unlock ();
+ _summon.notify_all ();
+}
+
+void
+Butler::text (PlayerText pt, TextType type, optional<DCPTextTrack> track, DCPTimePeriod period)
+{
+ if (type != TEXT_CLOSED_CAPTION) {
+ return;
+ }
+
+ DCPOMATIC_ASSERT (track);
+
+ boost::mutex::scoped_lock lm2 (_buffers_mutex);
+ _closed_caption.put (pt, *track, period);
+}