summaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2026-01-25 01:02:02 +0100
committerCarl Hetherington <cth@carlh.net>2026-02-03 21:37:04 +0100
commit321ef9ea78b533486f251044676986b323029bcb (patch)
treed2ab4392b62d7c9bf3d32cfd4888993b0a82cfeb /src/tools
parentc9f0c73f4365fd6592e8c1d502d506bf0b057e01 (diff)
Move player frame (DOMFrame) class into wx/ as PlayerFrame.
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/dcpomatic_player.cc1252
1 files changed, 3 insertions, 1249 deletions
diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc
index d73f6dfe2..e120048fa 100644
--- a/src/tools/dcpomatic_player.cc
+++ b/src/tools/dcpomatic_player.cc
@@ -18,75 +18,36 @@
*/
-#include "wx/about_dialog.h"
-#include "wx/audio_dialog.h"
-#include "wx/file_dialog.h"
-#include "wx/film_viewer.h"
#include "wx/i18n_setup.h"
#include "wx/id.h"
-#include "wx/nag_dialog.h"
-#include "wx/player_config_dialog.h"
-#include "wx/player_information.h"
-#include "wx/player_stress_tester.h"
-#include "wx/playlist_controls.h"
-#include "wx/report_problem_dialog.h"
-#include "wx/standard_controls.h"
-#include "wx/system_information_dialog.h"
-#include "wx/timer_display.h"
-#include "wx/update_dialog.h"
-#include "wx/verify_dcp_dialog.h"
+#include "wx/player_frame.h"
#include "wx/wx_ptr.h"
#include "wx/wx_signal_manager.h"
#include "wx/wx_util.h"
#include "wx/wx_variant.h"
-#include "lib/audio_content.h"
-#include "lib/config.h"
#include "lib/constants.h"
-#include "lib/copy_dcp_details_to_film.h"
#include "lib/cross.h"
-#include "lib/dcp_content.h"
#include "lib/dcp_examiner.h"
-#include "lib/dcpomatic_log.h"
#include "lib/dcpomatic_socket.h"
-#include "lib/examine_content_job.h"
#include "lib/ffmpeg_content.h"
-#include "lib/file_log.h"
#include "lib/film.h"
-#include "lib/font_config.h"
-#include "lib/http_server.h"
-#include "lib/image.h"
-#include "lib/image_jpeg.h"
-#include "lib/image_png.h"
-#include "lib/internal_player_server.h"
#include "lib/internet.h"
#include "lib/job.h"
-#include "lib/job_manager.h"
-#include "lib/null_log.h"
#include "lib/player.h"
#include "lib/player_video.h"
#include "lib/ratio.h"
#include "lib/scoped_temporary.h"
#include "lib/server.h"
-#include "lib/text_content.h"
#include "lib/update_checker.h"
-#include "lib/variant.h"
#include "lib/verify_dcp_job.h"
-#include "lib/video_content.h"
-#include <dcp/cpl.h>
#include <dcp/dcp.h>
#include <dcp/exceptions.h>
#include <dcp/filesystem.h>
-#include <dcp/scope_guard.h>
-#include <dcp/search.h>
#include <dcp/warnings.h>
LIBDCP_DISABLE_WARNINGS
#include <wx/cmdline.h>
-#include <wx/display.h>
-#include <wx/dnd.h>
-#include <wx/preferences.h>
#include <wx/progdlg.h>
#include <wx/splash.h>
-#include <wx/stdpaths.h>
#include <wx/wx.h>
LIBDCP_ENABLE_WARNINGS
#ifdef __WXGTK__
@@ -101,1224 +62,17 @@ LIBDCP_ENABLE_WARNINGS
#endif
-#define MAX_CPLS 32
-
-
using std::cout;
-using std::dynamic_pointer_cast;
using std::exception;
using std::list;
-using std::make_shared;
-using std::shared_ptr;
using std::string;
-using std::vector;
-using std::weak_ptr;
-using boost::bind;
-using boost::optional;
using boost::scoped_array;
-using boost::thread;
#if BOOST_VERSION >= 106100
using namespace boost::placeholders;
#endif
using namespace dcpomatic;
-enum {
- ID_file_open = DCPOMATIC_MAIN_MENU,
- ID_file_add_ov,
- ID_file_add_kdm,
- ID_file_save_frame,
- ID_file_history,
- /* Allow spare IDs after _history for the recent files list */
- ID_file_close = DCPOMATIC_MAIN_MENU + 100,
- ID_view_cpl,
- /* Allow spare IDs for CPLs */
- ID_view_full_screen = DCPOMATIC_MAIN_MENU + 200,
- ID_view_dual_screen,
- ID_view_closed_captions,
- ID_view_eye,
- ID_view_eye_left,
- ID_view_eye_right,
- ID_view_scale_appropriate,
- ID_view_scale_full,
- ID_view_scale_half,
- ID_view_scale_quarter,
- ID_help_report_a_problem,
- ID_tools_verify,
- ID_tools_audio_graph,
- ID_tools_check_for_updates,
- ID_tools_timing,
- ID_tools_system_information,
- /* IDs for shortcuts (with no associated menu item) */
- ID_start_stop,
- ID_go_back_frame,
- ID_go_forward_frame,
- ID_go_back_small_amount,
- ID_go_forward_small_amount,
- ID_go_back_medium_amount,
- ID_go_forward_medium_amount,
- ID_go_back_large_amount,
- ID_go_forward_large_amount,
- ID_go_to_start,
- ID_go_to_end
-};
-
-
-class DOMFrame : public wxFrame
-{
-public:
-
- class DCPDropTarget : public wxFileDropTarget
- {
- public:
- DCPDropTarget(DOMFrame* owner)
- : _frame(owner)
- {}
-
- bool OnDropFiles(wxCoord, wxCoord, wxArrayString const& filenames) override
- {
- if (filenames.GetCount() == 1) {
- /* Try to load a directory */
- auto path = boost::filesystem::path(wx_to_std(filenames[0]));
- if (dcp::filesystem::is_directory(path)) {
- _frame->load_dcp(wx_to_std(filenames[0]));
- return true;
- }
- }
-
- if (filenames.GetCount() >= 1) {
- /* Try to load the parent if we drop some files, one if which is an asset map */
- for (size_t i = 0; i < filenames.GetCount(); ++i) {
- auto path = boost::filesystem::path(wx_to_std(filenames[i]));
- if (path.filename() == "ASSETMAP" || path.filename() == "ASSETMAP.xml") {
- _frame->load_dcp(path.parent_path());
- return true;
- }
- }
- }
-
- return false;
- }
-
- private:
- DOMFrame* _frame;
- };
-
-
- DOMFrame()
- : wxFrame(nullptr, -1, variant::wx::dcpomatic_player())
- , _mode(Config::instance()->player_mode())
- /* Use a panel as the only child of the Frame so that we avoid
- the dark-grey background on Windows.
- */
- , _overall_panel(new wxPanel(this, wxID_ANY))
- , _viewer(_overall_panel, true)
- , _main_sizer(new wxBoxSizer(wxVERTICAL))
- {
- dcpomatic_log = make_shared<NullLog>();
-
-#if defined(DCPOMATIC_WINDOWS)
- maybe_open_console();
- cout << variant::dcpomatic_player() << " is starting." << "\n";
-#endif
-
- auto bar = new wxMenuBar;
- setup_menu(bar);
- set_menu_sensitivity();
- SetMenuBar(bar);
-
-#ifdef DCPOMATIC_WINDOWS
- SetIcon(wxIcon(std_to_wx("id")));
-#endif
-
- _config_changed_connection = Config::instance()->Changed.connect(boost::bind(&DOMFrame::config_changed, this, _1));
- update_from_config(Config::PLAYER_DEBUG_LOG);
-
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_open, this), ID_file_open);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_add_ov, this), ID_file_add_ov);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_add_kdm, this), ID_file_add_kdm);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_save_frame, this), ID_file_save_frame);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_history, this, _1), ID_file_history, ID_file_history + HISTORY_SIZE);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_close, this), ID_file_close);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::file_exit, this), wxID_EXIT);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::edit_preferences, this), wxID_PREFERENCES);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::view_full_screen, this), ID_view_full_screen);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::view_dual_screen, this), ID_view_dual_screen);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::view_closed_captions, this), ID_view_closed_captions);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::view_cpl, this, _1), ID_view_cpl, ID_view_cpl + MAX_CPLS);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::view_eye_changed, this, _1), ID_view_eye_left);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::view_eye_changed, this, _1), ID_view_eye_right);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::set_decode_reduction, this, optional<int>(0)), ID_view_scale_full);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::set_decode_reduction, this, optional<int>(1)), ID_view_scale_half);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::set_decode_reduction, this, optional<int>(2)), ID_view_scale_quarter);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::help_about, this), wxID_ABOUT);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::help_report_a_problem, this), ID_help_report_a_problem);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::tools_verify, this), ID_tools_verify);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::tools_audio_graph, this), ID_tools_audio_graph);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::tools_check_for_updates, this), ID_tools_check_for_updates);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::tools_timing, this), ID_tools_timing);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::tools_system_information, this), ID_tools_system_information);
-
- Bind(wxEVT_CLOSE_WINDOW, boost::bind(&DOMFrame::close, this, _1));
-
- if (Config::instance()->enable_player_http_server()) {
- update_content_store();
- }
-
- if (Config::instance()->player_mode() == Config::PlayerMode::DUAL) {
- auto pc = new PlaylistControls(_overall_panel, _viewer);
- _controls = pc;
- pc->ResetFilm.connect(bind(&DOMFrame::reset_film_weak, this, _1, _2));
- } else {
- _controls = new StandardControls(_overall_panel, _viewer, false);
- }
- _controls->set_film(_viewer.film());
- _viewer.set_dcp_decode_reduction(Config::instance()->decode_reduction());
- _viewer.PlaybackPermitted.connect(bind(&DOMFrame::playback_permitted, this));
- _viewer.TooManyDropped.connect(bind(&DOMFrame::too_many_frames_dropped, this));
- _info = new PlayerInformation(_overall_panel, _viewer);
- setup_main_sizer(Config::instance()->player_mode());
-#ifdef __WXOSX__
- int accelerators = 12;
-#else
- int accelerators = 11;
-#endif
-
- _stress.setup(this, _controls);
-
- std::vector<wxAcceleratorEntry> accel(accelerators);
- accel[0].Set(wxACCEL_NORMAL, WXK_SPACE, ID_start_stop);
- accel[1].Set(wxACCEL_NORMAL, WXK_LEFT, ID_go_back_frame);
- accel[2].Set(wxACCEL_NORMAL, WXK_RIGHT, ID_go_forward_frame);
- accel[3].Set(wxACCEL_SHIFT, WXK_LEFT, ID_go_back_small_amount);
- accel[4].Set(wxACCEL_SHIFT, WXK_RIGHT, ID_go_forward_small_amount);
- accel[5].Set(wxACCEL_CTRL, WXK_LEFT, ID_go_back_medium_amount);
- accel[6].Set(wxACCEL_CTRL, WXK_RIGHT, ID_go_forward_medium_amount);
- accel[7].Set(wxACCEL_SHIFT | wxACCEL_CTRL, WXK_LEFT, ID_go_back_large_amount);
- accel[8].Set(wxACCEL_SHIFT | wxACCEL_CTRL, WXK_RIGHT, ID_go_forward_large_amount);
- accel[9].Set(wxACCEL_NORMAL, WXK_HOME, ID_go_to_start);
- accel[10].Set(wxACCEL_NORMAL, WXK_END, ID_go_to_end);
-#ifdef __WXOSX__
- accel[11].Set(wxACCEL_CTRL, static_cast<int>('W'), ID_file_close);
-#endif
- wxAcceleratorTable accel_table(accelerators, accel.data());
- SetAcceleratorTable(accel_table);
-
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::start_stop_pressed, this), ID_start_stop);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_back_frame, this), ID_go_back_frame);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_forward_frame, this), ID_go_forward_frame);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_seconds, this, -60), ID_go_back_small_amount);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_seconds, this, 60), ID_go_forward_small_amount);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_seconds, this, -600), ID_go_back_medium_amount);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_seconds, this, 600), ID_go_forward_medium_amount);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_seconds, this, -3600), ID_go_back_large_amount);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_seconds, this, 3600), ID_go_forward_large_amount);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_to_start, this), ID_go_to_start);
- Bind(wxEVT_MENU, boost::bind(&DOMFrame::go_to_end, this), ID_go_to_end);
-
- reset_film();
-
- UpdateChecker::instance()->StateChanged.connect(boost::bind(&DOMFrame::update_checker_state_changed, this));
- setup_screen();
-
- _stress.LoadDCP.connect(boost::bind(&DOMFrame::load_dcp, this, _1));
-
- setup_internal_player_server();
- setup_http_server();
-
- SetDropTarget(new DCPDropTarget(this));
- }
-
- ~DOMFrame()
- {
- try {
- stop_http_server();
- /* It's important that this is stopped before our frame starts destroying its children,
- * otherwise UI elements that it depends on will disappear from under it.
- */
- _viewer.stop();
- } catch (std::exception& e) {
- LOG_ERROR("Destructor threw {}", e.what());
- } catch (...) {
- LOG_ERROR("Destructor threw");
- }
- }
-
- void close(wxCloseEvent& ev)
- {
- FontConfig::drop();
- ev.Skip();
- }
-
- void setup_main_sizer(Config::PlayerMode mode)
- {
- _main_sizer->Detach(_viewer.panel());
- _main_sizer->Detach(_controls);
- _main_sizer->Detach(_info);
- if (mode != Config::PlayerMode::DUAL) {
- _main_sizer->Add(_viewer.panel(), 1, wxEXPAND);
- }
- _main_sizer->Add(_controls, mode == Config::PlayerMode::DUAL ? 1 : 0, wxEXPAND | wxALL, 6);
- _main_sizer->Add(_info, 0, wxEXPAND | wxALL, 6);
- _overall_panel->SetSizer(_main_sizer);
- _overall_panel->Layout();
- }
-
- bool playback_permitted()
- {
- if (!_film || !Config::instance()->respect_kdm_validity_periods()) {
- return true;
- }
-
- bool ok = true;
- for (auto i: _film->content()) {
- auto d = dynamic_pointer_cast<DCPContent>(i);
- if (d && !d->kdm_timing_window_valid()) {
- ok = false;
- }
- }
-
- if (!ok) {
- error_dialog(this, _("The KDM does not allow playback of this content at this time."));
- }
-
- return ok;
- }
-
-
- void too_many_frames_dropped()
- {
- if (!Config::instance()->nagged(Config::NAG_TOO_MANY_DROPPED_FRAMES)) {
- _viewer.stop();
- }
-
- NagDialog::maybe_nag(
- this,
- Config::NAG_TOO_MANY_DROPPED_FRAMES,
- wxGetTranslation(
- wxString::FromUTF8(
- "The player is dropping a lot of frames, so playback may not be accurate.\n\n"
- "<b>This does not necessarily mean that the DCP you are playing is defective!</b>\n\n"
- "You may be able to improve player performance by:\n"
- "• choosing 'decode at half resolution' or 'decode at quarter resolution' from the View menu\n"
- "• using a more powerful computer.\n"
- )
- )
- );
- }
-
- void set_decode_reduction(optional<int> reduction)
- {
- _viewer.set_dcp_decode_reduction(reduction);
- _info->triggered_update();
- Config::instance()->set_decode_reduction(reduction);
- }
-
- void load_dcp(boost::filesystem::path dir)
- {
- DCPOMATIC_ASSERT(_film);
-
- auto film = std::make_shared<Film>(optional<boost::filesystem::path>());
-
- try {
- _stress.set_suspended(true);
-
- /* Handler to set things up once the DCP has been examined */
- auto setup = [this](weak_ptr<Film> weak_film, weak_ptr<Job> weak_job, weak_ptr<Content> weak_content)
- {
- auto job = weak_job.lock();
- if (!job || !job->finished_ok()) {
- return;
- }
-
- auto content = weak_content.lock();
- if (!content) {
- return;
- }
-
- auto film = weak_film.lock();
- if (!film) {
- return;
- }
-
- film->add_content({content});
- _stress.set_suspended(false);
- reset_film(film);
- };
-
- auto dcp = make_shared<DCPContent>(dir);
- auto job = make_shared<ExamineContentJob>(vector<shared_ptr<Content>>{dcp}, true);
- _examine_job_connection = job->Finished.connect(boost::bind<void>(setup, weak_ptr<Film>(film), weak_ptr<Job>(job), weak_ptr<Content>(dcp)));
- JobManager::instance()->add(job);
- bool const ok = display_progress(variant::wx::dcpomatic_player(), _("Loading content"));
- if (ok && report_errors_from_last_job(this)) {
- Config::instance()->add_to_player_history(dir);
- }
- } catch (ProjectFolderError &) {
- error_dialog(
- this,
- wxString::Format(_("Could not load a DCP from %s"), std_to_wx(dir.string())),
- wxString::Format(
- _("This looks like a %s project folder, which cannot be loaded into the player. "
- "Choose the DCP folder inside the %s project folder if that's what you want to play."),
- variant::wx::dcpomatic(),
- variant::wx::dcpomatic()
- )
- );
- } catch (dcp::ReadError& e) {
- error_dialog(this, wxString::Format(_("Could not load a DCP from %s"), std_to_wx(dir.string())), std_to_wx(e.what()));
- } catch (DCPError& e) {
- error_dialog(this, wxString::Format(_("Could not load a DCP from %s"), std_to_wx(dir.string())), std_to_wx(e.what()));
- }
- }
-
- void reset_film_weak(weak_ptr<Film> weak_film, optional<float> crop_to_ratio)
- {
- if (auto film = weak_film.lock()) {
- reset_film(film, crop_to_ratio);
- }
- }
-
- void reset_film(shared_ptr<Film> film = std::make_shared<Film>(boost::none), optional<float> crop_to_ratio = {})
- {
- _film = film;
-
- if (!crop_to_ratio) {
- crop_to_ratio = Config::instance()->player_crop_output_ratio();
- }
-
- prepare_to_play_film(crop_to_ratio);
- }
-
- /* _film is now something new: set up to play it */
- void prepare_to_play_film(optional<float> crop_to_ratio)
- {
- if (_viewer.playing()) {
- _viewer.stop();
- }
-
- /* Start off as Flat */
- auto auto_ratio = Ratio::from_id("185");
-
- _film->set_audio_channels(MAX_DCP_AUDIO_CHANNELS);
-
- for (auto i: _film->content()) {
- auto dcp = dynamic_pointer_cast<DCPContent>(i);
-
- copy_dcp_markers_to_film(dcp, _film);
-
- for (auto j: i->text) {
- j->set_use(true);
- }
-
- if (i->video && i->video->size()) {
- auto const r = Ratio::nearest_from_ratio(i->video->size()->ratio());
- if (r.id() == "239") {
- /* Any scope content means we use scope */
- auto_ratio = r;
- }
- }
-
- /* Any 3D content means we use 3D mode */
- if (i->video && i->video->frame_type() != VideoFrameType::TWO_D) {
- _film->set_three_d(true);
- }
-
- if (dcp->video_frame_rate()) {
- _film->set_video_frame_rate(dcp->video_frame_rate().get());
- }
-
- switch (dcp->video_encoding().get_value_or(VideoEncoding::JPEG2000)) {
- case VideoEncoding::JPEG2000:
- _viewer.set_optimisation(Optimisation::JPEG2000);
- break;
- case VideoEncoding::MPEG2:
- _viewer.set_optimisation(Optimisation::MPEG2);
- break;
- case VideoEncoding::COUNT:
- DCPOMATIC_ASSERT(false);
- }
- }
-
- set_audio_delay_from_config();
-
- auto old = _cpl_menu->GetMenuItems();
- for (auto const& i: old) {
- _cpl_menu->Remove(i);
- }
-
- if (_film->content().size() == 1) {
- /* Offer a CPL menu */
- if (auto first = dynamic_pointer_cast<DCPContent>(_film->content().front())) {
- int id = ID_view_cpl;
- for (auto i: dcp::find_and_resolve_cpls(first->directories(), true)) {
- auto j = _cpl_menu->AppendRadioItem(
- id,
- wxString::Format(char_to_wx("%s (%s)"), std_to_wx(i->content_title_text()).data(), std_to_wx(i->id()).data())
- );
- j->Check(!first->cpl() || i->id() == *first->cpl());
- ++id;
- }
- }
-
- if (crop_to_ratio) {
- auto size = _film->content()[0]->video->size().get_value_or({1998, 1080});
- int pixels = 0;
- if (*crop_to_ratio > (2048.0 / 1080.0)) {
- pixels = (size.height - (size.width / *crop_to_ratio)) / 2;
- _film->content()[0]->video->set_crop(Crop{0, 0, std::max(0, pixels), std::max(0, pixels)});
- } else {
- pixels = (size.width - (size.height * *crop_to_ratio)) / 2;
- _film->content()[0]->video->set_crop(Crop{std::max(0, pixels), std::max(0, pixels), 0, 0});
- }
- }
- }
-
- if (crop_to_ratio) {
- _film->set_container(Ratio(*crop_to_ratio, "custom", "custom", {}, "custom"));
- } else {
- _film->set_container(auto_ratio);
- }
-
- _viewer.set_film(_film);
- _viewer.seek(DCPTime(), true);
- _viewer.set_eyes(_view_eye_left->IsChecked() ? Eyes::LEFT : Eyes::RIGHT);
- _info->triggered_update();
- set_menu_sensitivity();
-
- _controls->set_film(_film);
- }
-
- void set_audio_delay_from_config()
- {
- if (!_film) {
- return;
- }
-
- for (auto i: _film->content()) {
- if (i->audio) {
- i->audio->set_delay(Config::instance()->player_audio_delay());
- }
- }
- }
-
- void load_stress_script(boost::filesystem::path path)
- {
- _stress.load_script(path);
- }
-
- void idle()
- {
- if (_http_server) {
- struct timeval now;
- gettimeofday(&now, 0);
- auto time_since_last_update = (now.tv_sec + now.tv_usec / 1e6) - (_last_http_server_update.tv_sec + _last_http_server_update.tv_usec / 1e6);
- if (time_since_last_update > 0.25) {
- _http_server->set_playing(_viewer.playing());
- if (auto dcp = _viewer.dcp()) {
- _http_server->set_dcp_name(dcp->name());
- } else {
- _http_server->set_dcp_name("");
- }
- _http_server->set_position(_viewer.position());
- _last_http_server_update = now;
- }
- }
- }
-
-private:
-
- void examine_content()
- {
- DCPOMATIC_ASSERT(_film);
- auto dcp = dynamic_pointer_cast<DCPContent>(_film->content().front());
- DCPOMATIC_ASSERT(dcp);
- dcp->examine({}, true);
-
- /* Examining content re-creates the TextContent objects, so we must re-enable them */
- for (auto i: dcp->text) {
- i->set_use(true);
- }
- }
-
- bool report_errors_from_last_job(wxWindow* parent) const
- {
- auto jm = JobManager::instance();
-
- DCPOMATIC_ASSERT(!jm->get().empty());
-
- auto last = jm->get().back();
- if (last->finished_in_error()) {
- error_dialog(parent, wxString::Format(_("Could not load DCP.\n\n%s."), std_to_wx(last->error_summary()).data()), std_to_wx(last->error_details()));
- return false;
- }
-
- return true;
- }
-
- void setup_menu(wxMenuBar* m)
- {
- _file_menu = new wxMenu;
- _file_menu->Append(ID_file_open, _("&Open...\tCtrl-O"));
- _file_add_ov = _file_menu->Append(ID_file_add_ov, _("&Add OV..."));
- _file_add_kdm = _file_menu->Append(ID_file_add_kdm, _("Add &KDM..."));
- _file_menu->AppendSeparator();
- _file_save_frame = _file_menu->Append(ID_file_save_frame, _("&Save frame to file...\tCtrl-S"));
-
- _history_position = _file_menu->GetMenuItems().GetCount();
-
- _file_menu->AppendSeparator();
- _file_menu->Append(ID_file_close, _("&Close"));
- _file_menu->AppendSeparator();
-
-#ifdef __WXOSX__
- _file_menu->Append(wxID_EXIT, _("&Exit"));
-#else
- _file_menu->Append(wxID_EXIT, _("&Quit"));
-#endif
-
-#ifdef __WXOSX__
- auto prefs = _file_menu->Append(wxID_PREFERENCES, _("&Preferences...\tCtrl-,"));
-#else
- auto edit = new wxMenu;
- auto prefs = edit->Append(wxID_PREFERENCES, _("&Preferences...\tCtrl-P"));
-#endif
-
- prefs->Enable(Config::instance()->have_write_permission());
-
- _cpl_menu = new wxMenu;
-
- auto view = new wxMenu;
- auto c = Config::instance()->decode_reduction();
- _view_cpl = view->Append(ID_view_cpl, _("CPL"), _cpl_menu);
- view->AppendSeparator();
- _view_full_screen = view->AppendCheckItem(ID_view_full_screen, _("Full screen\tF11"));
- _view_dual_screen = view->AppendCheckItem(ID_view_dual_screen, _("Dual screen\tShift+F11"));
- setup_menu();
- view->AppendSeparator();
- view->Append(ID_view_closed_captions, _("Closed captions..."));
- _view_eye_menu = new wxMenu;
- _view_eye_left = _view_eye_menu->AppendRadioItem(ID_view_eye_left, _("Left"));
- _view_eye_menu->AppendRadioItem(ID_view_eye_right, _("Right"));
- _view_eye = view->Append(ID_view_eye, _("Eye"), _view_eye_menu);
- view->AppendSeparator();
- view->AppendRadioItem(ID_view_scale_appropriate, _("Set decode resolution to match display"))->Check(!static_cast<bool>(c));
- view->AppendRadioItem(ID_view_scale_full, _("Decode at full resolution"))->Check(c && c.get() == 0);
- view->AppendRadioItem(ID_view_scale_half, _("Decode at half resolution"))->Check(c && c.get() == 1);
- view->AppendRadioItem(ID_view_scale_quarter, _("Decode at quarter resolution"))->Check(c && c.get() == 2);
-
- auto tools = new wxMenu;
- _tools_verify = tools->Append(ID_tools_verify, _("Verify DCP..."));
- _tools_audio_graph = tools->Append(ID_tools_audio_graph, _("Audio graph..."));
- tools->AppendSeparator();
- tools->Append(ID_tools_check_for_updates, _("Check for updates"));
- tools->Append(ID_tools_timing, _("Timing..."));
- tools->Append(ID_tools_system_information, _("System information..."));
-
- auto help = new wxMenu;
-#ifdef __WXOSX__
- help->Append(wxID_ABOUT, variant::wx::insert_dcpomatic_player(_("About %s")));
-#else
- help->Append(wxID_ABOUT, _("About"));
-#endif
- if (variant::show_report_a_problem()) {
- help->Append(ID_help_report_a_problem, _("Report a problem..."));
- }
-
- m->Append (_file_menu, _("&File"));
- if (!Config::instance()->player_restricted_menus()) {
-#ifndef __WXOSX__
- m->Append(edit, _("&Edit"));
-#endif
- m->Append(view, _("&View"));
- m->Append(tools, _("&Tools"));
- m->Append(help, _("&Help"));
- }
- }
-
- void file_open()
- {
- auto d = wxStandardPaths::Get().GetDocumentsDir();
- if (Config::instance()->last_player_load_directory()) {
- d = std_to_wx(Config::instance()->last_player_load_directory()->string());
- }
-
- wxDirDialog dialog(this, _("Select DCP to open"), d, wxDEFAULT_DIALOG_STYLE | wxDD_DIR_MUST_EXIST);
-
- int r;
- while (true) {
- r = dialog.ShowModal();
- if (r == wxID_OK && dialog.GetPath() == wxStandardPaths::Get().GetDocumentsDir()) {
- error_dialog(this, _("You did not select a folder. Make sure that you select a folder before clicking Open."));
- } else {
- break;
- }
- }
-
- if (r == wxID_OK) {
- boost::filesystem::path const dcp(wx_to_std(dialog.GetPath()));
- load_dcp(dcp);
- Config::instance()->set_last_player_load_directory(dcp.parent_path());
- }
- }
-
- void file_add_ov()
- {
- auto initial_dir = wxStandardPaths::Get().GetDocumentsDir();
- if (Config::instance()->last_player_load_directory()) {
- initial_dir = std_to_wx(Config::instance()->last_player_load_directory()->string());
- }
-
- wxDirDialog dialog(
- this,
- _("Select DCP to open as OV"),
- initial_dir,
- wxDEFAULT_DIALOG_STYLE | wxDD_DIR_MUST_EXIST
- );
-
- int r;
- while (true) {
- r = dialog.ShowModal();
- if (r == wxID_OK && dialog.GetPath() == wxStandardPaths::Get().GetDocumentsDir()) {
- error_dialog(this, _("You did not select a folder. Make sure that you select a folder before clicking Open."));
- } else {
- break;
- }
- }
-
- if (r == wxID_OK) {
- DCPOMATIC_ASSERT(_film);
- DCPOMATIC_ASSERT(!_film->content().empty());
- auto dcp = std::dynamic_pointer_cast<DCPContent>(_film->content().front());
- DCPOMATIC_ASSERT(dcp);
-
- try {
- dcp->add_ov(wx_to_std(dialog.GetPath()));
- } catch (DCPError& e) {
- error_dialog(this, char_to_wx(e.what()));
- return;
- }
-
- auto job = make_shared<ExamineContentJob>(vector<shared_ptr<Content>>{dcp}, true);
- _examine_job_connection = job->Finished.connect(boost::bind(&DOMFrame::prepare_to_play_film, this, Config::instance()->player_crop_output_ratio()));
- JobManager::instance()->add(job);
-
- display_progress(variant::wx::dcpomatic_player(), _("Loading content"));
- report_errors_from_last_job(this);
- }
- }
-
- void file_add_kdm()
- {
- FileDialog dialog(this, _("Select KDM"), char_to_wx("XML files|*.xml|All files|*.*"), wxFD_MULTIPLE, "AddKDMPath");
-
- if (dialog.show()) {
- DCPOMATIC_ASSERT(_film);
- auto dcp = std::dynamic_pointer_cast<DCPContent>(_film->content().front());
- DCPOMATIC_ASSERT(dcp);
- try {
- if (dcp) {
- dcp::ScopeGuard sg([this]() {
- _viewer.set_coalesce_player_changes(false);
- });
- _viewer.set_coalesce_player_changes(true);
- for (auto path: dialog.paths()) {
- dcp->add_kdm(dcp::EncryptedKDM(dcp::file_to_string(path)));
- _kdms.push_back(path);
- }
- examine_content();
- }
- } catch (exception& e) {
- error_dialog(this, wxString::Format(_("Could not load KDM.")), std_to_wx(e.what()));
- return;
- }
- }
-
- _info->triggered_update();
- set_menu_sensitivity();
- }
-
- void file_save_frame()
- {
- wxFileDialog dialog(this, _("Save frame to file"), {}, {}, char_to_wx("PNG files (*.png)|*.png|JPEG files (*.jpg;*.jpeg)|*.jpg;*.jpeg"), wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
- if (dialog.ShowModal() == wxID_CANCEL) {
- return;
- }
-
- auto path = boost::filesystem::path(wx_to_std(dialog.GetPath()));
-
- auto player = make_shared<Player>(_film, Image::Alignment::PADDED, true);
- player->seek(_viewer.position(), true);
-
- bool done = false;
- player->Video.connect([path, &done, this](shared_ptr<PlayerVideo> video, DCPTime) {
- auto ext = boost::algorithm::to_lower_copy(path.extension().string());
- if (ext == ".png") {
- auto image = video->image(force(AV_PIX_FMT_RGBA), VideoRange::FULL, false);
- image_as_png(image).write(path);
- } else if (ext == ".jpg" || ext == ".jpeg") {
- auto image = video->image(force(AV_PIX_FMT_RGB24), VideoRange::FULL, false);
- image_as_jpeg(image, 80).write(path);
- } else {
- error_dialog(this, wxString::Format(_("Unrecognised file extension %s (use .jpg, .jpeg or .png)"), std_to_wx(ext)));
- }
- done = true;
- });
-
- int tries_left = 50;
- while (!done && tries_left >= 0) {
- player->pass();
- --tries_left;
- }
-
- DCPOMATIC_ASSERT(tries_left >= 0);
- }
-
- void file_history(wxCommandEvent& event)
- {
- auto history = Config::instance()->player_history();
- int n = event.GetId() - ID_file_history;
- if (n >= 0 && n < static_cast<int>(history.size())) {
- try {
- load_dcp(history[n]);
- } catch (exception& e) {
- error_dialog(nullptr, wxString::Format(_("Could not load DCP %s."), std_to_wx(history[n].string()))), std_to_wx(e.what());
- }
- }
- }
-
- void file_close()
- {
- reset_film();
- _info->triggered_update();
- set_menu_sensitivity();
- }
-
- void file_exit()
- {
- Close();
- }
-
- void edit_preferences()
- {
- if (!Config::instance()->have_write_permission()) {
- return;
- }
-
- if (!_config_dialog) {
- _config_dialog = create_player_config_dialog();
- }
- _config_dialog->Show(this);
- }
-
- void view_cpl(wxCommandEvent& ev)
- {
- auto dcp = std::dynamic_pointer_cast<DCPContent>(_film->content().front());
- DCPOMATIC_ASSERT(dcp);
- auto cpls = dcp->cpls();
- int id = ev.GetId() - ID_view_cpl;
- DCPOMATIC_ASSERT(id >= 0);
- DCPOMATIC_ASSERT(id < int(cpls.size()));
- auto i = cpls.begin();
- while (id > 0) {
- ++i;
- --id;
- }
-
- _viewer.set_coalesce_player_changes(true);
- dcp->set_cpl(*i);
- examine_content();
- _viewer.set_coalesce_player_changes(false);
-
- _info->triggered_update();
- }
-
- void view_eye_changed(wxCommandEvent& ev)
- {
- _viewer.set_eyes(ev.GetId() == ID_view_eye_left ? Eyes::LEFT : Eyes::RIGHT);
- }
-
- void view_full_screen()
- {
- if (_mode == Config::PlayerMode::FULL) {
- _mode = Config::PlayerMode::WINDOW;
- } else {
- _mode = Config::PlayerMode::FULL;
- }
- setup_screen();
- setup_menu();
- }
-
- void view_dual_screen()
- {
- if (_mode == Config::PlayerMode::DUAL) {
- _mode = Config::PlayerMode::WINDOW;
- } else {
- _mode = Config::PlayerMode::DUAL;
- }
- setup_screen();
- setup_menu();
- }
-
- void setup_menu()
- {
- if (_view_full_screen) {
- _view_full_screen->Check(_mode == Config::PlayerMode::FULL);
- }
- if (_view_dual_screen) {
- _view_dual_screen->Check(_mode == Config::PlayerMode::DUAL);
- }
- }
-
- void setup_screen()
- {
- _controls->Show(_mode != Config::PlayerMode::FULL);
- _info->Show(_mode != Config::PlayerMode::FULL);
- _overall_panel->SetBackgroundColour(_mode == Config::PlayerMode::FULL ? wxColour(0, 0, 0) : wxNullColour);
- ShowFullScreen(_mode == Config::PlayerMode::FULL);
- _viewer.set_pad_black(_mode != Config::PlayerMode::WINDOW);
-
- if (_mode == Config::PlayerMode::DUAL) {
- _dual_screen = new wxFrame(this, wxID_ANY, {});
- _dual_screen->SetBackgroundColour(wxColour(0, 0, 0));
- _dual_screen->ShowFullScreen(true);
- _viewer.panel()->Reparent(_dual_screen);
- _viewer.panel()->SetFocus();
- _dual_screen->Show();
- LOG_DEBUG_PLAYER("Setting up dual screen mode with {} displays", wxDisplay::GetCount());
- for (auto index = 0U; index < wxDisplay::GetCount(); ++index) {
- wxDisplay display(index);
- auto client = display.GetClientArea();
- auto mode = display.GetCurrentMode();
- auto geometry = display.GetGeometry();
- LOG_DEBUG_PLAYER("Display {}", index);
- LOG_DEBUG_PLAYER(" ClientArea position=({}, {}) size=({}, {})", client.GetX(), client.GetY(), client.GetWidth(), client.GetHeight());
- LOG_DEBUG_PLAYER(" Geometry position=({}, {}) size=({}, {})", geometry.GetX(), geometry.GetY(), geometry.GetWidth(), geometry.GetHeight());
- LOG_DEBUG_PLAYER(" Mode size=({}, {})", mode.GetWidth(), mode.GetHeight());
- LOG_DEBUG_PLAYER(" Primary? {}", static_cast<int>(display.IsPrimary()));
- }
- if (wxDisplay::GetCount() > 1) {
- wxRect geometry[2] = {
- wxDisplay(0U).GetGeometry(),
- wxDisplay(1U).GetGeometry()
- };
- auto const image_display = Config::instance()->image_display();
- _dual_screen->Move(geometry[image_display].GetX(), geometry[image_display].GetY());
- _viewer.panel()->SetSize(geometry[image_display].GetWidth(), geometry[image_display].GetHeight());
- Move(geometry[1 - image_display].GetX(), geometry[1 - image_display].GetY());
- }
- _dual_screen->Bind(wxEVT_CHAR_HOOK, boost::bind(&DOMFrame::dual_screen_key_press, this, _1));
- } else {
- if (_dual_screen) {
- _viewer.panel()->Reparent(_overall_panel);
- _dual_screen->Destroy();
- _dual_screen = 0;
- }
- }
-
- setup_main_sizer(_mode);
- }
-
- void dual_screen_key_press(wxKeyEvent& ev)
- {
- if (ev.GetKeyCode() == WXK_F11) {
- if (ev.ShiftDown()) {
- view_dual_screen();
- } else if (!ev.HasAnyModifiers()) {
- view_full_screen();
- }
- }
- }
-
- void view_closed_captions()
- {
- _viewer.show_closed_captions();
- }
-
- void tools_verify()
- {
- DCPOMATIC_ASSERT(!_film->content().empty());
- auto dcp = std::dynamic_pointer_cast<DCPContent>(_film->content().front());
- DCPOMATIC_ASSERT(dcp);
-
- VerifyDCPDialog dialog(this, _("Verify DCP"), dcp->directories(), _kdms);
- dialog.ShowModal();
- }
-
- void tools_audio_graph()
- {
- DCPOMATIC_ASSERT(!_film->content().empty());
- auto dcp = std::dynamic_pointer_cast<DCPContent>(_film->content().front());
- DCPOMATIC_ASSERT(dcp);
-
- _audio_dialog.reset(this, _film, dcp);
- _audio_dialog->Seek.connect(boost::bind(&FilmViewer::seek, &_viewer, _1, true));
- _audio_dialog->Show();
- }
-
- void tools_check_for_updates()
- {
- UpdateChecker::instance()->run();
- _update_news_requested = true;
- }
-
- void tools_timing()
- {
- TimerDisplay dialog(this, _viewer.state_timer(), _viewer.gets());
- dialog.ShowModal();
- }
-
- void tools_system_information()
- {
- if (!_system_information_dialog) {
- _system_information_dialog.reset(this, _viewer);
- }
-
- _system_information_dialog->Show();
- }
-
- void help_about()
- {
- AboutDialog dialog(this);
- dialog.ShowModal();
- }
-
- void help_report_a_problem()
- {
- ReportProblemDialog dialog(this);
- if (dialog.ShowModal() == wxID_OK) {
- dialog.report();
- }
- }
-
- void update_checker_state_changed()
- {
- auto uc = UpdateChecker::instance();
-
- bool const announce =
- _update_news_requested ||
- (uc->stable() && Config::instance()->check_for_updates()) ||
- (uc->test() && Config::instance()->check_for_updates() && Config::instance()->check_for_test_updates());
-
- _update_news_requested = false;
-
- if (!announce) {
- return;
- }
-
- if (uc->state() == UpdateChecker::State::YES) {
- UpdateDialog dialog(this, uc->stable(), uc->test());
- dialog.ShowModal();
- } else if (uc->state() == UpdateChecker::State::FAILED) {
- error_dialog(this, variant::wx::insert_dcpomatic(_("The %s download server could not be contacted.")));
- } else {
- error_dialog(this, variant::wx::insert_dcpomatic(_("There are no new versions of %s available.")));
- }
-
- _update_news_requested = false;
- }
-
- void config_changed(Config::Property prop)
- {
- /* Instantly save any config changes when using the player GUI */
- try {
- Config::instance()->write_config();
- } catch (FileError& e) {
- if (prop != Config::HISTORY) {
- error_dialog(
- this,
- wxString::Format(
- _("Could not write to config file at %s. Your changes have not been saved."),
- std_to_wx(e.file().string())
- )
- );
- }
- } catch (exception& e) {
- error_dialog(
- this,
- _("Could not write to config file. Your changes have not been saved.")
- );
- }
-
- update_from_config(prop);
-
- setup_http_server();
- }
-
- void stop_http_server()
- {
- if (_http_server) {
- _http_server->stop();
- _http_server_thread.join();
- _http_server.reset();
- }
- }
-
- void setup_http_server()
- {
- stop_http_server();
-
- auto config = Config::instance();
- try {
- if (config->enable_player_http_server()) {
- _http_server.reset(new HTTPServer(config->player_http_server_port()));
- _http_server->Play.connect(boost::bind(&FilmViewer::start, &_viewer));
- _http_server->Stop.connect(boost::bind(&FilmViewer::stop, &_viewer));
- _http_server_thread = boost::thread(boost::bind(&HTTPServer::run, _http_server.get()));
- }
- } catch (std::exception& e) {
- LOG_DEBUG_PLAYER("Failed to start player HTTP server ({})", e.what());
- }
- }
-
- void setup_internal_player_server()
- {
- try {
- auto server = new InternalPlayerServer();
- server->LoadDCP.connect(boost::bind(&DOMFrame::load_dcp, this, _1));
- new thread(boost::bind(&InternalPlayerServer::run, server));
- } catch (std::exception& e) {
- /* This is not the end of the world; probably a failure to bind the server socket
- * because there's already another player running.
- */
- LOG_DEBUG_PLAYER("Failed to start internal player server ({})", e.what());
- }
- }
-
- void update_from_config(Config::Property prop)
- {
- for (int i = 0; i < _history_items; ++i) {
- delete _file_menu->Remove(ID_file_history + i);
- }
-
- if (_history_separator) {
- _file_menu->Remove(_history_separator);
- }
- delete _history_separator;
- _history_separator = nullptr;
-
- int pos = _history_position;
-
- /* Clear out non-existent history items before we re-build the menu */
- Config::instance()->clean_player_history();
- auto history = Config::instance()->player_history();
-
- if (!history.empty()) {
- _history_separator = _file_menu->InsertSeparator(pos++);
- }
-
- for (size_t i = 0; i < history.size(); ++i) {
- string s;
- if (i < 9) {
- s = fmt::format("&{} {}", i + 1, history[i].string());
- } else {
- s = history[i].string();
- }
- _file_menu->Insert(pos++, ID_file_history + i, std_to_wx(s));
- }
-
- _history_items = history.size();
-
- if (prop == Config::PLAYER_DEBUG_LOG) {
- auto p = Config::instance()->player_debug_log_file();
- if (p) {
- dcpomatic_log = make_shared<FileLog>(*p);
- } else {
- dcpomatic_log = make_shared<NullLog>();
- }
- }
-
- dcpomatic_log->set_types(Config::instance()->log_types());
-
- set_audio_delay_from_config();
- }
-
- void set_menu_sensitivity()
- {
- auto const have_content = _film && !_film->content().empty();
- auto const dcp = _viewer.dcp();
- auto const playable = dcp && !dcp->needs_assets() && !dcp->needs_kdm();
- _tools_verify->Enable(have_content);
- _tools_audio_graph->Enable(playable);
- _file_add_ov->Enable(have_content);
- _file_add_kdm->Enable(have_content);
- _file_save_frame->Enable(playable);
- _view_cpl->Enable(have_content);
- _view_eye->Enable(have_content && _film->three_d());
- }
-
- void start_stop_pressed()
- {
- if (_viewer.playing()) {
- _viewer.stop();
- } else {
- _viewer.start();
- }
- }
-
- void go_back_frame()
- {
- _viewer.seek_by(-_viewer.one_video_frame(), true);
- }
-
- void go_forward_frame()
- {
- _viewer.seek_by(_viewer.one_video_frame(), true);
- }
-
- void go_seconds(int s)
- {
- _viewer.seek_by(DCPTime::from_seconds(s), true);
- }
-
- void go_to_start()
- {
- _viewer.seek(DCPTime(), true);
- }
-
- void go_to_end()
- {
- _viewer.seek(_film->length() - _viewer.one_video_frame(), true);
- }
-
- wxFrame* _dual_screen = nullptr;
- bool _update_news_requested = false;
- PlayerInformation* _info = nullptr;
- Config::PlayerMode _mode;
- wxPreferencesEditor* _config_dialog = nullptr;
- wxPanel* _overall_panel = nullptr;
- wxMenu* _file_menu = nullptr;
- wxMenuItem* _view_cpl = nullptr;
- wxMenu* _cpl_menu = nullptr;
- wxMenuItem* _view_eye = nullptr;
- wxMenuItem* _view_eye_left = nullptr;
- wxMenu* _view_eye_menu = nullptr;
- int _history_items = 0;
- int _history_position = 0;
- wxMenuItem* _history_separator = nullptr;
- FilmViewer _viewer;
- Controls* _controls;
- wx_ptr<SystemInformationDialog> _system_information_dialog;
- std::shared_ptr<Film> _film;
- boost::signals2::scoped_connection _config_changed_connection;
- boost::signals2::scoped_connection _examine_job_connection;
- wxMenuItem* _file_add_ov = nullptr;
- wxMenuItem* _file_add_kdm = nullptr;
- wxMenuItem* _file_save_frame = nullptr;
- wxMenuItem* _tools_verify = nullptr;
- wxMenuItem* _tools_audio_graph = nullptr;
- wxMenuItem* _view_full_screen = nullptr;
- wxMenuItem* _view_dual_screen = nullptr;
- wxSizer* _main_sizer = nullptr;
- PlayerStressTester _stress;
- /** KDMs that have been loaded, so that we can pass them to the verifier */
- std::vector<boost::filesystem::path> _kdms;
- boost::thread _http_server_thread;
- std::unique_ptr<HTTPServer> _http_server;
- struct timeval _last_http_server_update = { 0, 0 };
- wx_ptr<AudioDialog> _audio_dialog;
-};
-
static const wxCmdLineEntryDesc command_line_description[] = {
{ wxCMD_LINE_PARAM, 0, 0, "DCP to load or create", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_OPTION, "c", "config", "Directory containing config.xml", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
@@ -1390,7 +144,7 @@ private:
signal_manager = new wxSignalManager(this);
- _frame = new DOMFrame();
+ _frame = new dcpomatic::ui::PlayerFrame();
SetTopWindow(_frame);
_frame->Maximize();
if (splash) {
@@ -1525,7 +279,7 @@ private:
message_dialog(_frame, std_to_wx(m));
}
- DOMFrame* _frame = nullptr;
+ dcpomatic::ui::PlayerFrame* _frame = nullptr;
boost::optional<boost::filesystem::path> _dcp_to_load;
boost::optional<string> _stress;
};