/** Video readahead in frames */
#define VIDEO_READAHEAD 10
+/** Audio readahead in frames */
+#define AUDIO_READAHEAD 48000
Butler::Butler (weak_ptr<const Film> film, shared_ptr<Player> player, AudioMapping audio_mapping, int audio_channels)
: _film (film)
boost::mutex::scoped_lock lm (_mutex);
/* Wait until we have something to do */
- while ((_video.size() >= VIDEO_READAHEAD && !_pending_seek_position) || _stop_thread) {
+ while ((_video.size() >= VIDEO_READAHEAD && _audio.size() >= AUDIO_READAHEAD && !_pending_seek_position) || _stop_thread) {
_summon.wait (lm);
}
_pending_seek_position = optional<DCPTime> ();
}
- /* Fill _video. Don't try to carry on if a pending seek appears
+ /* Fill _video and _audio. Don't try to carry on if a pending seek appears
while lm is unlocked, as in that state nothing will be added to
- _video.
+ _video/_audio.
*/
- while (_video.size() < VIDEO_READAHEAD && !_pending_seek_position && !_stop_thread) {
+ while ((_video.size() < VIDEO_READAHEAD || _audio.size() < AUDIO_READAHEAD) && !_pending_seek_position && !_stop_thread) {
lm.unlock ();
if (_player->pass ()) {
_finished = true;
void
Butler::audio (shared_ptr<AudioBuffers> audio, DCPTime time)
{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_pending_seek_position) {
+ /* Don't store any audio while a seek is pending */
+ return;
+ }
+ }
+ _audio.put (audio, time);
}
void
if (!earliest) {
/* No more content; fill up with silent black */
DCPTimePeriod remaining_video (DCPTime(), _playlist->length());
- if (_last_time) {
- remaining_video.from = _last_time.get() + one_video_frame();
+ if (_last_video_time) {
+ remaining_video.from = _last_video_time.get() + one_video_frame();
}
fill_video (remaining_video);
- fill_audio (DCPTimePeriod (_last_audio_time, _playlist->length()));
+ DCPTimePeriod remaining_audio (DCPTime(), _playlist->length());
+ if (_last_audio_time) {
+ remaining_audio.from = _last_audio_time.get();
+ }
+ fill_audio (remaining_audio);
return true;
}
list<pair<shared_ptr<AudioBuffers>, DCPTime> > audio = _audio_merger.pull (pull_from);
for (list<pair<shared_ptr<AudioBuffers>, DCPTime> >::iterator i = audio.begin(); i != audio.end(); ++i) {
- DCPOMATIC_ASSERT (i->second >= _last_audio_time);
- fill_audio (DCPTimePeriod (_last_audio_time, i->second));
+ DCPOMATIC_ASSERT (!_last_audio_time || i->second >= _last_audio_time.get());
+ if (_last_audio_time) {
+ fill_audio (DCPTimePeriod (_last_audio_time.get(), i->second));
+ }
Audio (i->first, i->second);
_last_audio_time = i->second + DCPTime::from_frames(i->first->frames(), _film->audio_frame_rate());
}
/* Fill gaps */
- if (_last_time) {
- fill_video (DCPTimePeriod (_last_time.get() + one_video_frame(), time));
+ if (_last_video_time) {
+ fill_video (DCPTimePeriod (_last_video_time.get() + one_video_frame(), time));
}
_last_video.reset (
_last_video->set_subtitle (subtitles.get ());
}
- _last_time = time;
+ _last_video_time = time;
- Video (_last_video, *_last_time);
+ Video (_last_video, *_last_video_time);
/* Discard any subtitles we no longer need */
}
if (accurate) {
- _last_time = time - one_video_frame ();
+ _last_video_time = time - one_video_frame ();
+ _last_audio_time = time;
} else {
- _last_time = optional<DCPTime> ();
+ _last_video_time = optional<DCPTime> ();
+ _last_audio_time = optional<DCPTime> ();
}
}
/** Last PlayerVideo that was emitted */
boost::shared_ptr<PlayerVideo> _last_video;
- /** Time of the last thing we emitted, or the last seek time */
- boost::optional<DCPTime> _last_time;
+ /** Time of the last video we emitted, or the last seek time */
+ boost::optional<DCPTime> _last_video_time;
AudioMerger _audio_merger;
- DCPTime _last_audio_time;
+ boost::optional<DCPTime> _last_audio_time;
class StreamState {
public:
void
VideoRingBuffers::put (shared_ptr<PlayerVideo> frame, DCPTime time)
{
- cout << "put " << to_string(time) << "\n";
boost::mutex::scoped_lock lm (_mutex);
_data.push_back (make_pair (frame, time));
}
{
boost::mutex::scoped_lock lm (_mutex);
if (_data.empty ()) {
- cout << "get: no data.\n";
return make_pair(shared_ptr<PlayerVideo>(), DCPTime());
}
pair<shared_ptr<PlayerVideo>, DCPTime> const r = _data.front ();
- cout << "get: here we go! " << to_string(r.second) << "\n";
_data.pop_front ();
return r;
}
in the preview.
*/
_player->set_always_burn_subtitles (true);
- _player->set_ignore_audio ();
_player->set_play_referenced ();
_film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1));
void
FilmViewer::get ()
{
- cout << "get!\n";
-
pair<shared_ptr<PlayerVideo>, DCPTime> video;
do {
video = _butler->get_video ();
}
if (_play_button->GetValue()) {
- _timer.Start (1000 / _film->video_frame_rate());
+ start ();
} else {
- _timer.Stop ();
+ stop ();
}
}