X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Ffilm_viewer.cc;h=2b7f73e68328763c85e608617cb8df358269f4a4;hb=0253b4e45c71a1c2e2a8bffaf1c3cb84a0a3e41a;hp=2aef50c6ddf85b3f12f2316f1b3eb23ea2b1bb9b;hpb=1f2b267b0d2f7744f5f507ecd99aed2ab2db9260;p=dcpomatic.git diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 2aef50c6d..2b7f73e68 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -72,7 +72,7 @@ rtaudio_callback (void* out, void *, unsigned int frames, double, RtAudioStreamS return reinterpret_cast(data)->audio_callback (out, frames); } -FilmViewer::FilmViewer (wxWindow* p) +FilmViewer::FilmViewer (wxWindow* p, bool outline_content, bool jump_to_selected) : wxPanel (p) , _panel (new wxPanel (this)) , _outline_content (new wxCheckBox (this, wxID_ANY, _("Outline content"))) @@ -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); @@ -105,10 +106,14 @@ FilmViewer::FilmViewer (wxWindow* p) _v_sizer->Add (_panel, 1, wxEXPAND); wxBoxSizer* view_options = new wxBoxSizer (wxHORIZONTAL); - view_options->Add (_outline_content, 0, wxRIGHT, DCPOMATIC_SIZER_GAP); + if (outline_content) { + view_options->Add (_outline_content, 0, wxRIGHT, DCPOMATIC_SIZER_GAP); + } view_options->Add (_left_eye, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP); view_options->Add (_right_eye, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP); - view_options->Add (_jump_to_selected, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP); + if (jump_to_selected) { + view_options->Add (_jump_to_selected, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP); + } _v_sizer->Add (view_options, 0, wxALL, DCPOMATIC_SIZER_GAP); wxBoxSizer* h_sizer = new wxBoxSizer (wxHORIZONTAL); @@ -134,9 +139,10 @@ FilmViewer::FilmViewer (wxWindow* p) _outline_content->Bind (wxEVT_CHECKBOX, boost::bind (&FilmViewer::refresh_panel, this)); _left_eye->Bind (wxEVT_RADIOBUTTON, boost::bind (&FilmViewer::refresh, this)); _right_eye->Bind (wxEVT_RADIOBUTTON, boost::bind (&FilmViewer::refresh, this)); - _slider->Bind (wxEVT_SCROLL_THUMBTRACK, boost::bind (&FilmViewer::slider_moved, this)); - _slider->Bind (wxEVT_SCROLL_PAGEUP, boost::bind (&FilmViewer::slider_moved, this)); - _slider->Bind (wxEVT_SCROLL_PAGEDOWN, boost::bind (&FilmViewer::slider_moved, this)); + _slider->Bind (wxEVT_SCROLL_THUMBTRACK, boost::bind (&FilmViewer::slider_moved, this, false)); + _slider->Bind (wxEVT_SCROLL_PAGEUP, boost::bind (&FilmViewer::slider_moved, this, false)); + _slider->Bind (wxEVT_SCROLL_PAGEDOWN, boost::bind (&FilmViewer::slider_moved, this, false)); + _slider->Bind (wxEVT_SCROLL_CHANGED, boost::bind (&FilmViewer::slider_moved, this, true)); _play_button->Bind (wxEVT_TOGGLEBUTTON, boost::bind (&FilmViewer::play_clicked, this)); _timer.Bind (wxEVT_TIMER, boost::bind (&FilmViewer::timer, this)); _back_button->Bind (wxEVT_LEFT_DOWN, boost::bind (&FilmViewer::back_clicked, this, _1)); @@ -156,7 +162,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 +206,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 (); @@ -234,7 +243,10 @@ FilmViewer::recreate_butler () map.set (2, 1, 1 / sqrt(2)); // C -> R } - _butler.reset (new Butler (_film, _player, map, _audio_channels)); + _butler.reset (new Butler (_player, _film->log(), map, _audio_channels)); + if (!Config::instance()->preview_sound()) { + _butler->disable_audio (); + } if (was_running) { start (); @@ -251,6 +263,8 @@ FilmViewer::refresh_panel () void FilmViewer::get () { + DCPOMATIC_ASSERT (_butler); + pair, DCPTime> video; do { video = _butler->get_video (); @@ -259,6 +273,8 @@ FilmViewer::get () ((_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 (); @@ -301,19 +317,21 @@ 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 (); } @@ -358,7 +376,7 @@ FilmViewer::paint_panel () } void -FilmViewer::slider_moved () +FilmViewer::slider_moved (bool update_slider) { if (!_film) { return; @@ -371,6 +389,9 @@ FilmViewer::slider_moved () } seek (t, false); update_position_label (); + if (update_slider) { + update_position_slider (); + } } void @@ -443,7 +464,7 @@ FilmViewer::start () } _playing = true; - _timer.Start (0, wxTIMER_ONE_SHOT); + timer (); } bool @@ -459,6 +480,7 @@ FilmViewer::stop () } _playing = false; + _play_button->SetValue (false); return true; } @@ -657,15 +679,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; } @@ -673,36 +701,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 (); } } @@ -710,7 +748,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; @@ -720,5 +759,36 @@ 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(); +} + +void +FilmViewer::set_dcp_decode_reduction (optional reduction) +{ + _player->set_dcp_decode_reduction (reduction); +}