X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Ftools%2Fdcpomatic_player.cc;h=4b63441f753451728b520253598cf7dc1f96cd49;hb=54af50c3b8e9082f9751e809d63540c51197a4a1;hp=a1a5a59eb99db36a5190ff83076268692582bd8f;hpb=86bbc0981a60ad9ba7b7bdbf28a34f197f83f6cb;p=dcpomatic.git diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc index a1a5a59eb..4b63441f7 100644 --- a/src/tools/dcpomatic_player.cc +++ b/src/tools/dcpomatic_player.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2017-2018 Carl Hetherington + Copyright (C) 2017-2019 Carl Hetherington This file is part of DCP-o-matic. @@ -28,7 +28,11 @@ #include "wx/player_config_dialog.h" #include "wx/verify_dcp_dialog.h" #include "wx/standard_controls.h" +#ifdef DCPOMATIC_VARIANT_SWAROOP #include "wx/swaroop_controls.h" +#endif +#include "wx/timer_display.h" +#include "wx/system_information_dialog.h" #include "lib/cross.h" #include "lib/config.h" #include "lib/util.h" @@ -64,10 +68,14 @@ #include #include #include +#ifdef __WXGTK__ +#include +#endif #ifdef __WXOSX__ #include #endif #include +#include #include #ifdef check @@ -88,6 +96,60 @@ using boost::optional; using boost::dynamic_pointer_cast; using boost::thread; using boost::bind; +using dcp::raw_convert; +using namespace dcpomatic; + +#ifdef DCPOMATIC_PLAYER_STRESS_TEST +#define STRESS_TEST_CHECK_INTERVAL 20 + +class Command +{ +public: + enum Type { + NONE, + OPEN, + PLAY, + WAIT, + STOP, + SEEK, + }; + + Command(string line) + : type (NONE) + , int_param (0) + { + vector bits; + boost::split (bits, line, boost::is_any_of(" ")); + if (bits[0] == "O") { + if (bits.size() != 2) { + return; + } + type = OPEN; + string_param = bits[1]; + } else if (bits[0] == "P") { + type = PLAY; + } else if (bits[0] == "W") { + if (bits.size() != 2) { + return; + } + type = WAIT; + int_param = raw_convert(bits[1]); + } else if (bits[0] == "S") { + type = STOP; + } else if (bits[0] == "K") { + if (bits.size() != 2) { + return; + } + type = SEEK; + int_param = raw_convert(bits[1]); + } + } + + Type type; + string string_param; + int int_param; +}; +#endif enum { ID_file_open = 1, @@ -108,6 +170,8 @@ enum { ID_help_report_a_problem, ID_tools_verify, ID_tools_check_for_updates, + ID_tools_timing, + ID_tools_system_information, /* IDs for shortcuts (with no associated menu item) */ ID_start_stop, ID_back_frame, @@ -128,9 +192,13 @@ public: , _history_items (0) , _history_position (0) , _history_separator (0) + , _system_information_dialog (0) , _view_full_screen (0) , _view_dual_screen (0) - { +#ifdef DCPOMATIC_PLAYER_STRESS_TEST + , _timer (this) +#endif +{ dcpomatic_log.reset (new NullLog()); #if defined(DCPOMATIC_WINDOWS) @@ -168,6 +236,8 @@ public: 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_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); /* Use a panel as the only child of the Frame so that we avoid the dark-grey background on Windows. @@ -225,6 +295,70 @@ public: #endif } +#ifdef DCPOMATIC_PLAYER_STRESS_TEST + void stress (boost::filesystem::path script_file) + { + Bind (wxEVT_TIMER, boost::bind(&DOMFrame::check_commands, this)); + _timer.Start(STRESS_TEST_CHECK_INTERVAL); + vector lines; + string const script = dcp::file_to_string(script_file); + boost::split (lines, script, boost::is_any_of("\n")); + BOOST_FOREACH (string i, lines) { + _commands.push_back (Command(i)); + } + _current_command = _commands.begin(); + } + + void check_commands () + { + if (_current_command == _commands.end()) { + _timer.Stop (); + cout << "ST: finished.\n"; + return; + } + + switch (_current_command->type) { + case Command::OPEN: + cout << "ST: load " << _current_command->string_param << "\n"; + load_dcp (_current_command->string_param); + ++_current_command; + break; + case Command::PLAY: + cout << "ST: play\n"; + _controls->play (); + ++_current_command; + break; + case Command::WAIT: + if (_wait_remaining) { + _wait_remaining = *_wait_remaining - STRESS_TEST_CHECK_INTERVAL; + if (_wait_remaining < 0) { + cout << "ST: wait done.\n"; + _wait_remaining = optional(); + ++_current_command; + } + } else { + _wait_remaining = _current_command->int_param; + cout << "ST: waiting for " << *_wait_remaining << ".\n"; + } + break; + case Command::STOP: + cout << "ST: stop\n"; + _controls->stop (); + ++_current_command; + break; + case Command::NONE: + ++_current_command; + break; + case Command::SEEK: + /* int_param here is a number between 0 and 4095, corresponding to the possible slider positions */ + cout << "ST: seek to " << _current_command->int_param << "\n"; + _controls->seek (_current_command->int_param); + ++_current_command; + break; + } + } +#endif + #ifdef DCPOMATIC_VARIANT_SWAROOP void monitor_checker_state_changed () { @@ -279,6 +413,15 @@ public: } } +#ifdef DCPOMATIC_VARIANT_SWAROOP + BOOST_FOREACH (shared_ptr i, _film->content()) { + shared_ptr c = dynamic_pointer_cast(i); + if (c && !c->kdm_timing_window_valid()) { + ok = false; + } + } +#endif + if (!ok) { error_dialog (this, _("The KDM does not allow playback of this content at this time.")); } @@ -289,10 +432,13 @@ public: void playback_started (DCPTime time) { /* XXX: this only logs the first piece of content; probably should be each piece? */ + if (_film->content().empty()) { + return; + } shared_ptr dcp = dynamic_pointer_cast(_film->content().front()); if (dcp) { - DCPExaminer ex (dcp); + DCPExaminer ex (dcp, true); shared_ptr playing_cpl; BOOST_FOREACH (shared_ptr i, ex.cpls()) { if (!dcp->cpl() || i->id() == *dcp->cpl()) { @@ -374,6 +520,8 @@ public: void reset_film (shared_ptr film = shared_ptr(new Film(optional()))) { _film = film; + _film->set_tolerant (true); + _film->set_audio_channels (MAX_DCP_AUDIO_CHANNELS); _viewer->set_film (_film); _controls->set_film (_film); _film->Change.connect (bind(&DOMFrame::film_changed, this, _1, _2)); @@ -428,7 +576,7 @@ public: /* Offer a CPL menu */ shared_ptr first = dynamic_pointer_cast(_film->content().front()); if (first) { - DCPExaminer ex (first); + DCPExaminer ex (first, true); int id = ID_view_cpl; BOOST_FOREACH (shared_ptr i, ex.cpls()) { wxMenuItem* j = _cpl_menu->AppendRadioItem( @@ -444,12 +592,27 @@ public: private: + bool report_errors_from_last_job (wxWindow* parent) const + { + JobManager* jm = JobManager::instance (); + + DCPOMATIC_ASSERT (!jm->get().empty()); + + shared_ptr 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_add_kdm = _file_menu->Append (ID_file_add_kdm, _("Add &KDM...")); _history_position = _file_menu->GetMenuItems().GetCount(); @@ -495,6 +658,8 @@ private: _tools_verify = tools->Append (ID_tools_verify, _("Verify DCP")); 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...")); wxMenu* help = new wxMenu; #ifdef __WXOSX__ @@ -591,11 +756,27 @@ private: if (d->ShowModal() == wxID_OK) { DCPOMATIC_ASSERT (_film); +#ifdef DCPOMATIC_VARIANT_SWAROOP + shared_ptr ffmpeg = boost::dynamic_pointer_cast(_film->content().front()); + if (ffmpeg) { + try { + ffmpeg->add_kdm (EncryptedECinemaKDM(dcp::file_to_string(wx_to_std(d->GetPath()), MAX_KDM_SIZE))); + } catch (exception& e) { + error_dialog (this, wxString::Format(_("Could not load KDM.")), std_to_wx(e.what())); + d->Destroy(); + return; + } + } +#endif shared_ptr dcp = boost::dynamic_pointer_cast(_film->content().front()); +#ifndef DCPOMATIC_VARIANT_SWAROOP DCPOMATIC_ASSERT (dcp); +#endif try { - dcp->add_kdm (dcp::EncryptedKDM (dcp::file_to_string (wx_to_std (d->GetPath ()), MAX_KDM_SIZE))); - dcp->examine (_film, shared_ptr()); + if (dcp) { + dcp->add_kdm (dcp::EncryptedKDM(dcp::file_to_string(wx_to_std(d->GetPath()), MAX_KDM_SIZE))); + dcp->examine (_film, shared_ptr()); + } } catch (exception& e) { error_dialog (this, wxString::Format (_("Could not load KDM.")), std_to_wx(e.what())); d->Destroy (); @@ -648,7 +829,7 @@ private: { shared_ptr dcp = boost::dynamic_pointer_cast(_film->content().front()); DCPOMATIC_ASSERT (dcp); - DCPExaminer ex (dcp); + DCPExaminer ex (dcp, true); int id = ev.GetId() - ID_view_cpl; DCPOMATIC_ASSERT (id >= 0); DCPOMATIC_ASSERT (id < int(ex.cpls().size())); @@ -765,6 +946,22 @@ private: _update_news_requested = true; } + void tools_timing () + { + TimerDisplay* d = new TimerDisplay (this, _viewer->state_timer(), _viewer->gets()); + d->ShowModal (); + d->Destroy (); + } + + void tools_system_information () + { + if (!_system_information_dialog) { + _system_information_dialog = new SystemInformationDialog (this, _viewer); + } + + _system_information_dialog->Show (); + } + void help_about () { AboutDialog* d = new AboutDialog (this); @@ -922,6 +1119,7 @@ private: wxMenuItem* _history_separator; shared_ptr _viewer; Controls* _controls; + SystemInformationDialog* _system_information_dialog; boost::shared_ptr _film; boost::signals2::scoped_connection _config_changed_connection; wxMenuItem* _file_add_ov; @@ -929,11 +1127,20 @@ private: wxMenuItem* _tools_verify; wxMenuItem* _view_full_screen; wxMenuItem* _view_dual_screen; +#ifdef DCPOMATIC_PLAYER_STRESS_TEST + wxTimer _timer; + list _commands; + list::const_iterator _current_command; + optional _wait_remaining; +#endif }; 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 }, +#ifdef DCPOMATIC_PLAYER_STRESS_TEST + { wxCMD_LINE_OPTION, "s", "stress", "File containing description of stress test", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, +#endif { wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 } }; @@ -972,7 +1179,11 @@ public: App () : wxApp () , _frame (0) - {} + { +#ifdef DCPOMATIC_LINUX + XInitThreads (); +#endif + } private: @@ -1045,6 +1256,16 @@ private: } } +#ifdef DCPOMATIC_PLAYER_STRESS_TEST + if (_stress) { + try { + _frame->stress (_stress.get()); + } catch (exception& e) { + error_dialog (0, wxString::Format("Could not load stress test file %s", std_to_wx(*_stress))); + } + } +#endif + Bind (wxEVT_IDLE, boost::bind (&App::idle, this)); if (Config::instance()->check_for_updates ()) { @@ -1078,6 +1299,12 @@ private: if (parser.Found("c", &config)) { Config::override_path = wx_to_std (config); } +#ifdef DCPOMATIC_PLAYER_STRESS_TEST + wxString stress; + if (parser.Found("s", &stress)) { + _stress = wx_to_std (stress); + } +#endif return true; } @@ -1138,6 +1365,9 @@ private: DOMFrame* _frame; string _dcp_to_load; +#ifdef DCPOMATIC_PLAYER_STRESS_TEST + boost::optional _stress; +#endif }; IMPLEMENT_APP (App)