X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fwx%2Ffilm_viewer.cc;h=fb02f0a0ff41074015ebc9c6b9b939aa5698f6b1;hb=e8748f158249d7be906f6c6cf2411df45dd07a24;hp=e678c6aa3045cc9057d29c77ecd6cafbe2f69cbe;hpb=c8fa584045ad65283a85015f18ee8789ddf881d1;p=dcpomatic.git diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index e678c6aa3..fb02f0a0f 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -32,36 +32,37 @@ #include "playhead_to_timecode_dialog.h" #include "simple_video_view.h" #include "wx_util.h" -#include "lib/film.h" -#include "lib/ratio.h" -#include "lib/util.h" -#include "lib/job_manager.h" -#include "lib/image.h" -#include "lib/exceptions.h" +#include "lib/butler.h" +#include "lib/compose.hpp" +#include "lib/config.h" +#include "lib/dcpomatic_log.h" #include "lib/examine_content_job.h" +#include "lib/exceptions.h" +#include "lib/film.h" #include "lib/filter.h" +#include "lib/image.h" +#include "lib/job_manager.h" +#include "lib/log.h" #include "lib/player.h" #include "lib/player_video.h" +#include "lib/ratio.h" +#include "lib/text_content.h" +#include "lib/timer.h" +#include "lib/util.h" #include "lib/video_content.h" #include "lib/video_decoder.h" -#include "lib/timer.h" -#include "lib/butler.h" -#include "lib/log.h" -#include "lib/config.h" -#include "lib/compose.hpp" -#include "lib/dcpomatic_log.h" -#include "lib/text_content.h" +#include +#include extern "C" { #include } -#include +LIBDCP_DISABLE_WARNINGS #include -#include +LIBDCP_ENABLE_WARNINGS #include using std::bad_alloc; -using std::cout; using std::dynamic_pointer_cast; using std::make_shared; using std::max; @@ -117,7 +118,7 @@ FilmViewer::~FilmViewer () } -/** Ask for ::get() to be called next time we are idle */ +/** Ask for ::idle_handler() to be called next time we are idle */ void FilmViewer::request_idle_display_next_frame () { @@ -159,15 +160,17 @@ FilmViewer::set_film (shared_ptr film) _video_view->clear (); _closed_captions_dialog->clear (); + destroy_butler(); + if (!_film) { - _player.reset (); - recreate_butler (); + _player = boost::none; + resume(); _video_view->update (); return; } try { - _player = make_shared(_film, _optimise_for_j2k ? Image::Alignment::COMPACT : Image::Alignment::PADDED); + _player.emplace(_film, _optimise_for_j2k ? Image::Alignment::COMPACT : Image::Alignment::PADDED); _player->set_fast (); if (_dcp_decode_reduction) { _player->set_dcp_decode_reduction (_dcp_decode_reduction); @@ -175,6 +178,7 @@ FilmViewer::set_film (shared_ptr film) } catch (bad_alloc &) { error_dialog (_video_view->get(), _("There is not enough free memory to do that.")); _film.reset (); + resume(); return; } @@ -194,7 +198,7 @@ FilmViewer::set_film (shared_ptr film) _closed_captions_dialog->update_tracks (_film); - recreate_butler (); + create_butler(); calculate_sizes (); slow_refresh (); @@ -202,38 +206,51 @@ FilmViewer::set_film (shared_ptr film) void -FilmViewer::recreate_butler () +FilmViewer::destroy_butler() { suspend (); _butler.reset (); +} + + +void +FilmViewer::destroy_and_maybe_create_butler() +{ + destroy_butler(); if (!_film) { resume (); return; } + create_butler(); +} + + +void +FilmViewer::create_butler() +{ #if wxCHECK_VERSION(3, 1, 0) auto const j2k_gl_optimised = dynamic_pointer_cast(_video_view) && _optimise_for_j2k; #else auto const j2k_gl_optimised = false; #endif + DCPOMATIC_ASSERT(_player); + _butler = std::make_shared( _film, - _player, + *_player, Config::instance()->audio_mapping(_audio_channels), _audio_channels, - bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), + boost::bind(&PlayerVideo::force, AV_PIX_FMT_RGB24), VideoRange::FULL, j2k_gl_optimised ? Image::Alignment::COMPACT : Image::Alignment::PADDED, true, - j2k_gl_optimised + j2k_gl_optimised, + (Config::instance()->sound() && _audio.isStreamOpen()) ? Butler::Audio::ENABLED : Butler::Audio::DISABLED ); - if (!Config::instance()->sound() && !_audio.isStreamOpen()) { - _butler->disable_audio (); - } - _closed_captions_dialog->set_butler (_butler); resume (); @@ -283,17 +300,21 @@ FilmViewer::calculate_sizes () auto const container = _film->container (); - auto const view_ratio = float(_video_view->get()->GetSize().x) / _video_view->get()->GetSize().y; + auto const scale = dpi_scale_factor (_video_view->get()); + int const video_view_width = std::round(_video_view->get()->GetSize().x * scale); + int const video_view_height = std::round(_video_view->get()->GetSize().y * scale); + + auto const view_ratio = float(video_view_width) / video_view_height; auto const film_ratio = container ? container->ratio () : 1.78; dcp::Size out_size; if (view_ratio < film_ratio) { /* panel is less widscreen than the film; clamp width */ - out_size.width = _video_view->get()->GetSize().x; + out_size.width = video_view_width; out_size.height = lrintf (out_size.width / film_ratio); } else { /* panel is more widescreen than the film; clamp height */ - out_size.height = _video_view->get()->GetSize().y; + out_size.height = video_view_height; out_size.width = lrintf (out_size.height * film_ratio); } @@ -301,6 +322,16 @@ FilmViewer::calculate_sizes () out_size.width = max (64, out_size.width); out_size.height = max (64, out_size.height); + /* Make sure the video container sizes are always a multiple of 2 so that + * we don't get gaps with subsampled sources (e.g. YUV420) + */ + if (out_size.width % 2) { + out_size.width++; + } + if (out_size.height % 2) { + out_size.height++; + } + _player->set_video_container_size (out_size); } @@ -315,16 +346,31 @@ FilmViewer::suspend () } +void +FilmViewer::start_audio_stream_if_open () +{ + if (_audio.isStreamOpen()) { + _audio.setStreamTime (_video_view->position().seconds()); + try { + _audio.startStream (); + } catch (RtAudioError& e) { + _audio_channels = 0; + error_dialog ( + _video_view->get(), + _("There was a problem starting audio playback. Please try another audio output device in Preferences."), std_to_wx(e.what()) + ); + } + } +} + + void FilmViewer::resume () { DCPOMATIC_ASSERT (_suspended > 0); --_suspended; if (_playing && !_suspended) { - if (_audio.isStreamOpen()) { - _audio.setStreamTime (_video_view->position().seconds()); - _audio.startStream (); - } + start_audio_stream_if_open (); _video_view->start (); } } @@ -354,24 +400,13 @@ FilmViewer::start () /* Take the video view's idea of position as our `playhead' and start the audio stream (which is the timing reference) there. */ - if (_audio.isStreamOpen()) { - _audio.setStreamTime (_video_view->position().seconds()); - try { - _audio.startStream (); - } catch (RtAudioError& e) { - _audio_channels = 0; - error_dialog ( - _video_view->get(), - _("There was a problem starting audio playback. Please try another audio output device in Preferences."), std_to_wx(e.what()) - ); - } - } + start_audio_stream_if_open (); _playing = true; /* Calling start() below may directly result in Stopped being emitted, and if that * happens we want it to come after the Started signal, so do that first. */ - Started (position()); + Started (); _video_view->start (); } @@ -390,7 +425,7 @@ FilmViewer::stop () _playing = false; _video_view->stop (); - Stopped (position()); + Stopped (); _video_view->rethrow (); return true; @@ -458,7 +493,7 @@ FilmViewer::film_change (ChangeType type, Film::Property p) } if (p == Film::Property::AUDIO_CHANNELS) { - recreate_butler (); + destroy_and_maybe_create_butler(); } else if (p == Film::Property::VIDEO_FRAME_RATE) { _video_view->set_video_frame_rate (_film->video_frame_rate()); } else if (p == Film::Property::THREE_D) { @@ -501,6 +536,7 @@ FilmViewer::quick_refresh () void FilmViewer::seek (shared_ptr content, ContentTime t, bool accurate) { + DCPOMATIC_ASSERT(_player); auto dt = _player->content_time_to_dcp (content, t); if (dt) { seek (*dt, accurate); @@ -560,7 +596,7 @@ void FilmViewer::config_changed (Config::Property p) { if (p == Config::AUDIO_MAPPING) { - recreate_butler (); + destroy_and_maybe_create_butler(); return; } @@ -606,11 +642,11 @@ FilmViewer::config_changed (Config::Property p) _("Could not set up audio output. There will be no audio during the preview."), std_to_wx(e.what()) ); } - recreate_butler (); + destroy_and_maybe_create_butler(); } else { _audio_channels = 0; - recreate_butler (); + destroy_and_maybe_create_butler(); } } @@ -703,6 +739,14 @@ FilmViewer::dcp_decode_reduction () const } +optional +FilmViewer::position_in_content (shared_ptr content) const +{ + DCPOMATIC_ASSERT(_player); + return _player->dcp_to_content_time (content, position()); +} + + DCPTime FilmViewer::one_video_frame () const { @@ -786,3 +830,21 @@ FilmViewer::set_optimise_for_j2k (bool o) _video_view->set_optimise_for_j2k (o); } + +void +FilmViewer::set_crop_guess (dcpomatic::Rect crop) +{ + if (crop != _crop_guess) { + _crop_guess = crop; + _video_view->update (); + } +} + + +void +FilmViewer::unset_crop_guess () +{ + _crop_guess = boost::none; + _video_view->update (); +} +