X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Ffilm_viewer.cc;h=3f6e7dacdd3dbae4e17a41ce1f743aaecdfaf3b9;hb=ee86fd488bff7b156c72565e1c799ad2a91da599;hp=588a27e011c9f64a0b4a15f93723e74bcefc5de8;hpb=4073923b2c5ccf127c61435cd575542351421f05;p=dcpomatic.git diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 588a27e01..3f6e7dacd 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -92,6 +92,7 @@ FilmViewer::FilmViewer (wxWindow* p) , _audio_channels (0) , _audio_block_size (1024) , _playing (false) + , _latency_history_count (0) { #ifndef __WXOSX__ _panel->SetDoubleBuffered (true); @@ -156,7 +157,7 @@ FilmViewer::FilmViewer (wxWindow* p) setup_sensitivity (); _config_changed_connection = Config::instance()->Changed.connect (bind (&FilmViewer::config_changed, this, _1)); - config_changed (Config::SOUND_OUTPUT); + config_changed (Config::PREVIEW_SOUND_OUTPUT); } FilmViewer::~FilmViewer () @@ -200,6 +201,9 @@ FilmViewer::set_film (shared_ptr film) _film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1)); _player->Changed.connect (boost::bind (&FilmViewer::player_changed, this, _1)); + /* Keep about 1 second's worth of history samples */ + _latency_history_count = _film->audio_frame_rate() / _audio_block_size; + recreate_butler (); calculate_sizes (); @@ -235,6 +239,9 @@ FilmViewer::recreate_butler () } _butler.reset (new Butler (_film, _player, map, _audio_channels)); + if (!Config::instance()->preview_sound()) { + _butler->disable_audio (); + } if (was_running) { start (); @@ -251,12 +258,21 @@ FilmViewer::refresh_panel () void FilmViewer::get () { + DCPOMATIC_ASSERT (_butler); + pair, DCPTime> video; do { video = _butler->get_video (); - } while (_film->three_d() && ((_left_eye->GetValue() && video.first->eyes() == EYES_RIGHT) || (_right_eye->GetValue() && video.first->eyes() == EYES_LEFT))); + } while ( + _film->three_d() && + ((_left_eye->GetValue() && video.first->eyes() == EYES_RIGHT) || (_right_eye->GetValue() && video.first->eyes() == EYES_LEFT)) + ); + + _butler->rethrow (); if (!video.first) { + _frame.reset (); + refresh_panel (); return; } @@ -296,17 +312,23 @@ FilmViewer::get () void FilmViewer::timer () { - if (!_film) { + if (!_film || !_playing) { return; } - if (_audio.isStreamRunning ()) { - DCPTime const now = time().ceil (_film->video_frame_rate ()); - get (); - update_position_label (); - update_position_slider (); - DCPTime const next = now + DCPTime::from_frames (1, _film->video_frame_rate ()); - _timer.Start (max ((next.seconds() - time().seconds()) * 1000, 0.0), wxTIMER_ONE_SHOT); + get (); + update_position_label (); + update_position_slider (); + DCPTime const next = _video_position + DCPTime::from_frames (1, _film->video_frame_rate ()); + + if (next >= _film->length()) { + stop (); + } + + _timer.Start (max ((next.seconds() - time().seconds()) * 1000, 1.0), wxTIMER_ONE_SHOT); + + if (_butler) { + _butler->rethrow (); } } @@ -434,7 +456,7 @@ FilmViewer::start () } _playing = true; - _timer.Start (0, wxTIMER_ONE_SHOT); + _timer.Start (1.0, wxTIMER_ONE_SHOT); } bool @@ -450,6 +472,7 @@ FilmViewer::stop () } _playing = false; + _play_button->SetValue (false); return true; } @@ -571,6 +594,7 @@ FilmViewer::setup_sensitivity () _outline_content->Enable (c); _frame_number->Enable (c); _timecode->Enable (c); + _jump_to_selected->Enable (c); _left_eye->Enable (c && _film->three_d ()); _right_eye->Enable (c && _film->three_d ()); @@ -647,15 +671,21 @@ FilmViewer::seek (DCPTime t, bool accurate) return; } + bool const was_running = stop (); + _butler->seek (t, accurate); _last_seek_accurate = accurate; get (); + + if (was_running) { + start (); + } } void FilmViewer::config_changed (Config::Property p) { - if (p != Config::SOUND_OUTPUT) { + if (p != Config::PREVIEW_SOUND && p != Config::PREVIEW_SOUND_OUTPUT) { return; } @@ -663,36 +693,46 @@ FilmViewer::config_changed (Config::Property p) _audio.closeStream (); } - unsigned int st = 0; - if (Config::instance()->sound_output()) { - while (st < _audio.getDeviceCount()) { - if (_audio.getDeviceInfo(st).name == Config::instance()->sound_output().get()) { - break; + if (Config::instance()->preview_sound()) { + unsigned int st = 0; + if (Config::instance()->preview_sound_output()) { + while (st < _audio.getDeviceCount()) { + if (_audio.getDeviceInfo(st).name == Config::instance()->preview_sound_output().get()) { + break; + } + ++st; } - ++st; - } - if (st == _audio.getDeviceCount()) { + if (st == _audio.getDeviceCount()) { + st = _audio.getDefaultOutputDevice(); + } + } else { st = _audio.getDefaultOutputDevice(); } - } else { - st = _audio.getDefaultOutputDevice(); - } - _audio_channels = _audio.getDeviceInfo(st).outputChannels; - recreate_butler (); + _audio_channels = _audio.getDeviceInfo(st).outputChannels; - RtAudio::StreamParameters sp; - sp.deviceId = st; - sp.nChannels = _audio_channels; - sp.firstChannel = 0; - try { - _audio.openStream (&sp, 0, RTAUDIO_FLOAT32, 48000, &_audio_block_size, &rtaudio_callback, this); + recreate_butler (); + + RtAudio::StreamParameters sp; + sp.deviceId = st; + sp.nChannels = _audio_channels; + sp.firstChannel = 0; + try { + _audio.openStream (&sp, 0, RTAUDIO_FLOAT32, 48000, &_audio_block_size, &rtaudio_callback, this); #ifdef DCPOMATIC_USE_RTERROR - } catch (RtError& e) { + } catch (RtError& e) { #else - } catch (RtAudioError& e) { + } catch (RtAudioError& e) { #endif - error_dialog (this, wxString::Format (_("Could not set up audio output (%s). There will be no audio during the preview."), e.what())); + error_dialog ( + this, + wxString::Format (_("Could not set up audio output (%s). There will be no audio during the preview."), e.what()) + ); + } + + } else { + _audio_channels = 0; + recreate_butler (); } } @@ -700,7 +740,8 @@ DCPTime FilmViewer::time () const { if (_audio.isStreamRunning ()) { - return DCPTime::from_seconds (const_cast(&_audio)->getStreamTime ()); + return DCPTime::from_seconds (const_cast(&_audio)->getStreamTime ()) - + DCPTime::from_frames (average_latency(), _film->audio_frame_rate()); } return _video_position; @@ -710,5 +751,30 @@ int FilmViewer::audio_callback (void* out_p, unsigned int frames) { _butler->get_audio (reinterpret_cast (out_p), frames); + + boost::mutex::scoped_lock lm (_latency_history_mutex, boost::try_to_lock); + if (lm) { + _latency_history.push_back (_audio.getStreamLatency ()); + if (_latency_history.size() > static_cast (_latency_history_count)) { + _latency_history.pop_front (); + } + } + return 0; } + +Frame +FilmViewer::average_latency () const +{ + boost::mutex::scoped_lock lm (_latency_history_mutex); + if (_latency_history.empty()) { + return 0; + } + + Frame total = 0; + BOOST_FOREACH (Frame i, _latency_history) { + total += i; + } + + return total / _latency_history.size(); +}