X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Ftools%2Fdcpomatic_player.cc;h=e0112764fed6c814666a80e4faf720002aa5537d;hb=d0d89009ad0acca0ddfa43dc45d8ac4186c5fc21;hp=0af44fd05d2dd27a89800c13c057a43f6d48d1cd;hpb=27b83475435dda4e84a90cf59a52f150905c4ab1;p=dcpomatic.git diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc index 0af44fd05..e0112764f 100644 --- a/src/tools/dcpomatic_player.cc +++ b/src/tools/dcpomatic_player.cc @@ -18,6 +18,16 @@ */ +#include "wx/wx_signal_manager.h" +#include "wx/wx_util.h" +#include "wx/about_dialog.h" +#include "wx/report_problem_dialog.h" +#include "wx/film_viewer.h" +#include "wx/player_information.h" +#include "wx/update_dialog.h" +#include "wx/player_config_dialog.h" +#include "wx/verify_dcp_dialog.h" +#include "wx/controls.h" #include "lib/cross.h" #include "lib/config.h" #include "lib/util.h" @@ -26,29 +36,22 @@ #include "lib/dcp_content.h" #include "lib/job_manager.h" #include "lib/job.h" +#include "lib/film.h" #include "lib/video_content.h" -#include "lib/caption_content.h" +#include "lib/text_content.h" #include "lib/ratio.h" #include "lib/verify_dcp_job.h" #include "lib/dcp_examiner.h" #include "lib/examine_content_job.h" #include "lib/server.h" #include "lib/dcpomatic_socket.h" -#include "wx/wx_signal_manager.h" -#include "wx/wx_util.h" -#include "wx/about_dialog.h" -#include "wx/report_problem_dialog.h" -#include "wx/film_viewer.h" -#include "wx/player_information.h" -#include "wx/update_dialog.h" -#include "wx/player_config_dialog.h" -#include "wx/verify_dcp_dialog.h" #include #include #include #include #include #include +#include #ifdef __WXOSX__ #include #endif @@ -82,7 +85,10 @@ enum { ID_file_close = 100, ID_view_cpl, /* Allow spare IDs for CPLs */ - ID_view_scale_appropriate = 200, + ID_view_full_screen = 200, + ID_view_dual_screen, + ID_view_closed_captions, + ID_view_scale_appropriate, ID_view_scale_full, ID_view_scale_half, ID_view_scale_quarter, @@ -100,14 +106,17 @@ class DOMFrame : public wxFrame public: DOMFrame () : wxFrame (0, -1, _("DCP-o-matic Player")) + , _dual_screen (0) , _update_news_requested (false) , _info (0) + , _mode (Config::instance()->player_mode()) , _config_dialog (0) , _file_menu (0) , _history_items (0) , _history_position (0) , _history_separator (0) - , _viewer (0) + , _view_full_screen (0) + , _view_dual_screen (0) { #if defined(DCPOMATIC_WINDOWS) @@ -134,6 +143,9 @@ public: 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::set_decode_reduction, this, optional(0)), ID_view_scale_full); Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional(1)), ID_view_scale_half); @@ -146,16 +158,17 @@ public: /* Use a panel as the only child of the Frame so that we avoid the dark-grey background on Windows. */ - wxPanel* overall_panel = new wxPanel (this, wxID_ANY); + _overall_panel = new wxPanel (this, wxID_ANY); - _viewer = new FilmViewer (overall_panel, false, false); + _viewer.reset (new FilmViewer (_overall_panel)); + _controls = new Controls (_overall_panel, _viewer, false); _viewer->set_dcp_decode_reduction (Config::instance()->decode_reduction ()); - _info = new PlayerInformation (overall_panel, _viewer); - wxSizer* main_sizer = new wxBoxSizer (wxVERTICAL); - main_sizer->Add (_viewer, 1, wxEXPAND | wxALL, 6); - main_sizer->Add (_info, 0, wxEXPAND | wxALL, 6); - overall_panel->SetSizer (main_sizer); - + _viewer->PlaybackPermitted.connect (bind(&DOMFrame::playback_permitted, this)); + _viewer->Started.connect (bind(&DOMFrame::playback_started, this, _1)); + _viewer->Seeked.connect (bind(&DOMFrame::playback_seeked, this, _1)); + _viewer->Stopped.connect (bind(&DOMFrame::playback_stopped, this, _1)); + _info = new PlayerInformation (_overall_panel, _viewer); + setup_main_sizer (true); #ifdef __WXOSX__ int accelerators = 4; #else @@ -178,6 +191,97 @@ public: Bind (wxEVT_MENU, boost::bind (&DOMFrame::forward_frame, this), ID_forward_frame); UpdateChecker::instance()->StateChanged.connect (boost::bind (&DOMFrame::update_checker_state_changed, this)); + _controls->DCPDirectorySelected.connect (boost::bind(&DOMFrame::load_dcp, this, _1)); + _controls->DCPEjected.connect (boost::bind(&DOMFrame::eject_dcp, this)); + + setup_screen (); + } + + void setup_main_sizer (bool with_viewer) + { + wxSizer* main_sizer = new wxBoxSizer (wxVERTICAL); + if (with_viewer) { + main_sizer->Add (_viewer->panel(), 1, wxEXPAND | wxALIGN_CENTER_VERTICAL); + } + main_sizer->Add (_controls, 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; + BOOST_FOREACH (shared_ptr i, _film->content()) { + shared_ptr d = dynamic_pointer_cast(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 playback_started (DCPTime time) + { + optional log = Config::instance()->player_log_file(); + if (!log) { + return; + } + + shared_ptr dcp = boost::dynamic_pointer_cast(_film->content().front()); + DCPOMATIC_ASSERT (dcp); + DCPExaminer ex (dcp); + shared_ptr playing_cpl; + BOOST_FOREACH (shared_ptr i, ex.cpls()) { + if (!dcp->cpl() || i->id() == *dcp->cpl()) { + playing_cpl = i; + } + } + DCPOMATIC_ASSERT (playing_cpl) + + FILE* f = fopen_boost(*log, "a"); + fprintf ( + f, + "%s playback-started %s %s %s\n", + dcp::LocalTime().as_string().c_str(), + time.timecode(_film->video_frame_rate()).c_str(), + dcp->directories().front().string().c_str(), + playing_cpl->annotation_text().c_str() + ); + fclose (f); + } + + void playback_seeked (DCPTime time) + { + optional log = Config::instance()->player_log_file(); + if (!log) { + return; + } + + FILE* f = fopen_boost(*log, "a"); + fprintf (f, "%s playback-seeked %s\n", dcp::LocalTime().as_string().c_str(), time.timecode(_film->video_frame_rate()).c_str()); + fclose (f); + } + + void playback_stopped (DCPTime time) + { + optional log = Config::instance()->player_log_file(); + if (!log) { + return; + } + + FILE* f = fopen_boost(*log, "a"); + fprintf (f, "%s playback-stopped %s\n", dcp::LocalTime().as_string().c_str(), time.timecode(_film->video_frame_rate()).c_str()); + fclose (f); } void set_decode_reduction (optional reduction) @@ -187,6 +291,13 @@ public: Config::instance()->set_decode_reduction (reduction); } + void eject_dcp () + { + _film.reset (new Film (optional())); + _viewer->set_film (_film); + _info->triggered_update (); + } + void load_dcp (boost::filesystem::path dir) { _film.reset (new Film (optional())); @@ -211,7 +322,7 @@ public: } _viewer->set_film (_film); - _viewer->set_position (DCPTime ()); + _viewer->seek (DCPTime(), true); _info->triggered_update (); Config::instance()->add_to_player_history (dir); @@ -226,10 +337,11 @@ public: DCPExaminer ex (dcp); int id = ID_view_cpl; BOOST_FOREACH (shared_ptr i, ex.cpls()) { - wxMenuItem* j = _cpl_menu->AppendRadioItem(id, i->id()); - if (!dcp->cpl() || i->id() == *dcp->cpl()) { - j->Check(true); - } + wxMenuItem* j = _cpl_menu->AppendRadioItem( + id, + wxString::Format("%s (%s)", std_to_wx(i->annotation_text()).data(), std_to_wx(i->id()).data()) + ); + j->Check(!dcp->cpl() || i->id() == *dcp->cpl()); ++id; } } @@ -268,6 +380,14 @@ private: optional c = Config::instance()->decode_reduction(); _view_cpl = view->Append(ID_view_cpl, _("CPL"), _cpl_menu); view->AppendSeparator(); +#ifndef DCPOMATIC_VARIANT_SWAROOP + _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")); +#endif + setup_menu (); + view->AppendSeparator(); + view->Append(ID_view_closed_captions, _("Closed captions...")); + view->AppendSeparator(); view->AppendRadioItem(ID_view_scale_appropriate, _("Set decode resolution to match display"))->Check(!static_cast(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); @@ -430,6 +550,81 @@ private: dcp->examine (shared_ptr()); } + void view_full_screen () + { + if (_mode == Config::PLAYER_MODE_FULL) { + _mode = Config::PLAYER_MODE_WINDOW; + } else { + _mode = Config::PLAYER_MODE_FULL; + } + setup_screen (); + setup_menu (); + } + + void view_dual_screen () + { + if (_mode == Config::PLAYER_MODE_DUAL) { + _mode = Config::PLAYER_MODE_WINDOW; + } else { + _mode = Config::PLAYER_MODE_DUAL; + } + setup_screen (); + setup_menu (); + } + + void setup_menu () + { + if (_view_full_screen) { + _view_full_screen->Check (_mode == Config::PLAYER_MODE_FULL); + } + if (_view_dual_screen) { + _view_dual_screen->Check (_mode == Config::PLAYER_MODE_DUAL); + } + } + + void setup_screen () + { + _controls->Show (_mode != Config::PLAYER_MODE_FULL); + _controls->show_extended_player_controls (_mode == Config::PLAYER_MODE_DUAL); + _info->Show (_mode != Config::PLAYER_MODE_FULL); + _overall_panel->SetBackgroundColour (_mode == Config::PLAYER_MODE_FULL ? wxColour(0, 0, 0) : wxNullColour); + ShowFullScreen (_mode == Config::PLAYER_MODE_FULL); + + if (_mode == Config::PLAYER_MODE_DUAL) { + _dual_screen = new wxFrame (this, wxID_ANY, wxT("")); + _dual_screen->SetBackgroundColour (wxColour(0, 0, 0)); + _dual_screen->ShowFullScreen (true); + _viewer->panel()->Reparent (_dual_screen); + _dual_screen->Show (); + if (wxDisplay::GetCount() > 1) { + switch (Config::instance()->image_display()) { + case 0: + _dual_screen->Move (0, 0); + Move (wxDisplay(0).GetClientArea().GetWidth(), 0); + break; + case 1: + _dual_screen->Move (wxDisplay(0).GetClientArea().GetWidth(), 0); + // (0, 0) doesn't seem to work for some strange reason + Move (8, 8); + break; + } + } + } else { + if (_dual_screen) { + _viewer->panel()->Reparent (_overall_panel); + _dual_screen->Destroy (); + _dual_screen = 0; + } + } + + setup_main_sizer (_mode != Config::PLAYER_MODE_DUAL); + } + + void view_closed_captions () + { + _viewer->show_closed_captions (); + } + void tools_verify () { shared_ptr dcp = boost::dynamic_pointer_cast(_film->content().front()); @@ -566,12 +761,12 @@ private: void back_frame () { - _viewer->back_frame (); + _viewer->seek_by (-_viewer->one_video_frame(), true); } void forward_frame () { - _viewer->forward_frame (); + _viewer->seek_by (_viewer->one_video_frame(), true); } private: @@ -618,8 +813,8 @@ private: void setup_from_dcp (shared_ptr dcp) { - if (dcp->caption) { - dcp->caption->set_use (true); + BOOST_FOREACH (shared_ptr i, dcp->text) { + i->set_use (true); } if (dcp->video) { @@ -630,21 +825,27 @@ private: } } + wxFrame* _dual_screen; bool _update_news_requested; PlayerInformation* _info; + Config::PlayerMode _mode; wxPreferencesEditor* _config_dialog; + wxPanel* _overall_panel; wxMenu* _file_menu; wxMenuItem* _view_cpl; wxMenu* _cpl_menu; int _history_items; int _history_position; wxMenuItem* _history_separator; - FilmViewer* _viewer; + shared_ptr _viewer; + Controls* _controls; boost::shared_ptr _film; boost::signals2::scoped_connection _config_changed_connection; wxMenuItem* _file_add_ov; wxMenuItem* _file_add_kdm; wxMenuItem* _tools_verify; + wxMenuItem* _view_full_screen; + wxMenuItem* _view_dual_screen; }; static const wxCmdLineEntryDesc command_line_description[] = {