X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Ftools%2Fdcpomatic.cc;h=60f11752e89988687192314ec451490e0094d262;hp=73e215c045d8406e7b8e077f154df5e4a8f6705c;hb=c04fec82d25127fafa73c3daff87bece9aa8c8e8;hpb=be3402b1fa27c9c35b043fd88cef93a88b17c6de diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index 73e215c04..60f11752e 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -33,6 +33,7 @@ #include "wx/recreate_chain_dialog.h" #include "wx/about_dialog.h" #include "wx/kdm_dialog.h" +#include "wx/dkdm_dialog.h" #include "wx/self_dkdm_dialog.h" #include "wx/servers_list_dialog.h" #include "wx/hints_dialog.h" @@ -40,10 +41,12 @@ #include "wx/content_panel.h" #include "wx/report_problem_dialog.h" #include "wx/video_waveform_dialog.h" +#include "wx/system_information_dialog.h" #include "wx/save_template_dialog.h" #include "wx/templates_dialog.h" #include "wx/nag_dialog.h" -#include "wx/export_dialog.h" +#include "wx/export_subtitles_dialog.h" +#include "wx/export_video_file_dialog.h" #include "wx/paste_dialog.h" #include "wx/focus_manager.h" #include "wx/html_dialog.h" @@ -64,14 +67,13 @@ #include "lib/job_manager.h" #include "lib/exceptions.h" #include "lib/cinema.h" -#include "lib/screen_kdm.h" +#include "lib/kdm_with_metadata.h" #include "lib/send_kdm_email_job.h" #include "lib/encode_server_finder.h" #include "lib/update_checker.h" #include "lib/cross.h" #include "lib/content_factory.h" #include "lib/compose.hpp" -#include "lib/cinema_kdms.h" #include "lib/dcpomatic_socket.h" #include "lib/hints.h" #include "lib/dcp_content.h" @@ -82,20 +84,24 @@ #include "lib/check_content_change_job.h" #include "lib/text_content.h" #include "lib/dcpomatic_log.h" +#include "lib/subtitle_encoder.h" +#include "lib/warnings.h" #include #include +DCPOMATIC_DISABLE_WARNINGS #include #include #include #include #include #include +DCPOMATIC_ENABLE_WARNINGS +#ifdef __WXGTK__ +#include +#endif #ifdef __WXMSW__ #include #endif -#ifdef __WXOSX__ -#include -#endif #include #include #include @@ -125,6 +131,9 @@ using boost::optional; using boost::function; using boost::is_any_of; using boost::algorithm::find; +#if BOOST_VERSION >= 106100 +using namespace boost::placeholders; +#endif using dcp::raw_convert; class FilmChangedClosingDialog : public boost::noncopyable @@ -217,13 +226,13 @@ enum { ID_file_close = 100, ID_edit_copy, ID_edit_paste, - ID_content_scale_to_fit_width, - ID_content_scale_to_fit_height, ID_jobs_make_dcp, ID_jobs_make_dcp_batch, ID_jobs_make_kdms, + ID_jobs_make_dkdms, ID_jobs_make_self_dkdm, - ID_jobs_export, + ID_jobs_export_video_file, + ID_jobs_export_subtitles, ID_jobs_send_dcp_to_tms, ID_jobs_show_dcp, ID_jobs_open_dcp_in_player, @@ -234,6 +243,7 @@ enum { ID_tools_manage_templates, ID_tools_check_for_updates, ID_tools_send_translations, + ID_tools_system_information, ID_tools_restore_default_preferences, ID_help_report_a_problem, /* IDs for shortcuts (with no associated menu item) */ @@ -251,16 +261,19 @@ public: explicit DOMFrame (wxString const & title) : wxFrame (NULL, -1, title) , _video_waveform_dialog (0) + , _system_information_dialog (0) , _hints_dialog (0) , _servers_list_dialog (0) , _config_dialog (0) , _kdm_dialog (0) + , _dkdm_dialog (0) , _templates_dialog (0) , _file_menu (0) , _history_items (0) , _history_position (0) , _history_separator (0) , _update_news_requested (false) + , _first_shown_called (false) { #if defined(DCPOMATIC_WINDOWS) if (Config::instance()->win32_console ()) { @@ -307,13 +320,13 @@ public: Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_copy, this), ID_edit_copy); Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_paste, this), ID_edit_paste); Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_preferences, this), wxID_PREFERENCES); - Bind (wxEVT_MENU, boost::bind (&DOMFrame::content_scale_to_fit_width, this), ID_content_scale_to_fit_width); - Bind (wxEVT_MENU, boost::bind (&DOMFrame::content_scale_to_fit_height, this), ID_content_scale_to_fit_height); Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_dcp, this), ID_jobs_make_dcp); Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_kdms, this), ID_jobs_make_kdms); + Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_dkdms, this), ID_jobs_make_dkdms); Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_dcp_batch, this), ID_jobs_make_dcp_batch); Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_make_self_dkdm, this), ID_jobs_make_self_dkdm); - Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_export, this), ID_jobs_export); + Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_export_video_file, this), ID_jobs_export_video_file); + Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_export_subtitles, this), ID_jobs_export_subtitles); Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_send_dcp_to_tms, this), ID_jobs_send_dcp_to_tms); Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_show_dcp, this), ID_jobs_show_dcp); Bind (wxEVT_MENU, boost::bind (&DOMFrame::jobs_open_dcp_in_player, this), ID_jobs_open_dcp_in_player); @@ -324,11 +337,13 @@ public: Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_manage_templates, this), ID_tools_manage_templates); Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_check_for_updates, this), ID_tools_check_for_updates); Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_send_translations, this), ID_tools_send_translations); + Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_system_information, this),ID_tools_system_information); Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_restore_default_preferences, this), ID_tools_restore_default_preferences); 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_CLOSE_WINDOW, boost::bind (&DOMFrame::close, this, _1)); + Bind (wxEVT_SHOW, boost::bind (&DOMFrame::show, this, _1)); /* Use a panel as the only child of the Frame so that we avoid the dark-grey background on Windows. @@ -439,10 +454,21 @@ public: JobManager::instance()->add(shared_ptr(new CheckContentChangeJob(film))); } - catch (std::exception& e) { - wxString p = std_to_wx (file.string ()); - wxCharBuffer b = p.ToUTF8 (); - error_dialog (this, wxString::Format (_("Could not open film at %s"), p.data()), std_to_wx (e.what())); + catch (FileNotFoundError& e) { + boost::filesystem::path const dir = e.file().parent_path(); + if (boost::filesystem::exists(dir / "ASSETMAP") || boost::filesystem::exists(dir / "ASSETMAP.xml")) { + error_dialog ( + this, _("Could not open this folder as a DCP-o-matic project."), + _("It looks like you are trying to open a DCP. File -> Open is for loading DCP-o-matic projects, not DCPs. To import a DCP, create a new project with File -> New and then click the \"Add DCP...\" button.") + ); + } else { + wxString const p = std_to_wx(file.string ()); + error_dialog (this, wxString::Format(_("Could not open film at %s"), p.data()), std_to_wx(e.what())); + } + + } catch (std::exception& e) { + wxString const p = std_to_wx (file.string()); + error_dialog (this, wxString::Format(_("Could not open film at %s"), p.data()), std_to_wx(e.what())); } void set_film (shared_ptr film) @@ -472,6 +498,14 @@ public: private: + void show (wxShowEvent& ev) + { + if (ev.IsShown() && !_first_shown_called) { + _film_editor->first_shown (); + _first_shown_called = true; + } + } + void film_message (string m) { message_dialog (this, std_to_wx(m)); @@ -505,7 +539,7 @@ private: } catch (boost::filesystem::filesystem_error& e) { #ifdef DCPOMATIC_WINDOWS string bad_chars = "<>:\"/|?*"; - string const filename = d->path().string(); + string const filename = d->path().filename().string(); string found_bad_chars; for (size_t i = 0; i < bad_chars.length(); ++i) { if (filename.find(bad_chars[i]) != string::npos && found_bad_chars.find(bad_chars[i]) == string::npos) { @@ -513,9 +547,11 @@ private: } } wxString message = _("Could not create folder to store film."); + message += " "; if (!found_bad_chars.empty()) { - message += " "; message += wxString::Format (_("Try removing the %s characters from your folder name."), std_to_wx(found_bad_chars).data()); + } else { + message += _("Please check that you do not have Windows controlled folder access enabled for DCP-o-matic."); } error_dialog (this, message, std_to_wx(e.what())); #else @@ -753,7 +789,7 @@ private: a long time, and crashes/power failures are moderately likely. */ _film->write_metadata (); - _film->make_dcp (); + _film->make_dcp (true); } catch (BadSettingError& e) { error_dialog (this, wxString::Format (_("Bad setting for %s."), std_to_wx(e.setting()).data()), std_to_wx(e.what())); } catch (std::exception& e) { @@ -776,8 +812,23 @@ private: _kdm_dialog->Show (); } + void jobs_make_dkdms () + { + if (!_film) { + return; + } + + if (_dkdm_dialog) { + _dkdm_dialog->Destroy (); + _dkdm_dialog = 0; + } + + _dkdm_dialog = new DKDMDialog (this, _film); + _dkdm_dialog->Show (); + } + /** @return false if we succeeded, true if not */ - bool send_to_other_tool (int port, function start, string message) + bool send_to_other_tool (int port, function start, string message) { /* i = 0; try to connect via socket i = 1; try again, and then try to start the tool @@ -803,10 +854,10 @@ private: } if (i == 1) { - start (wx_to_std (wxStandardPaths::Get().GetExecutablePath())); + start (); } - dcpomatic_sleep (1); + dcpomatic_sleep_seconds (1); } return true; @@ -829,7 +880,7 @@ private: _film->write_metadata (); - if (send_to_other_tool (BATCH_JOB_PORT, bind (&start_batch_converter, _1), _film->directory()->string())) { + if (send_to_other_tool (BATCH_JOB_PORT, &start_batch_converter, _film->directory()->string())) { error_dialog (this, _("Could not find batch converter.")); } } @@ -840,7 +891,7 @@ private: return; } - if (send_to_other_tool (PLAYER_PLAY_PORT, bind (&start_player, _1), _film->dir(_film->dcp_name(false)).string())) { + if (send_to_other_tool (PLAYER_PLAY_PORT, &start_player, _film->dir(_film->dcp_name(false)).string())) { error_dialog (this, _("Could not find player.")); } } @@ -868,14 +919,19 @@ private: ) ); + + dcp::LocalTime from (Config::instance()->signer_chain()->leaf().not_before()); + from.add_days (1); + dcp::LocalTime to (Config::instance()->signer_chain()->leaf().not_after()); + to.add_days (-1); + optional kdm; try { kdm = _film->make_kdm ( Config::instance()->decryption_chain()->leaf(), vector(), d->cpl (), - dcp::LocalTime ("2012-01-01T01:00:00+00:00"), - dcp::LocalTime ("2112-01-01T01:00:00+00:00"), + from, to, dcp::MODIFIED_TRANSITIONAL_1, true, 0 @@ -902,14 +958,31 @@ private: d->Destroy (); } - void jobs_export () + + void jobs_export_video_file () { - ExportDialog* d = new ExportDialog (this); + ExportVideoFileDialog* d = new ExportVideoFileDialog (this, _film->isdcf_name(true)); if (d->ShowModal() == wxID_OK) { + if (boost::filesystem::exists(d->path())) { + bool ok = confirm_dialog( + this, + wxString::Format (_("File %s already exists. Do you want to overwrite it?"), std_to_wx(d->path().string()).data()) + ); + + if (!ok) { + d->Destroy (); + return; + } + } + shared_ptr job (new TranscodeJob (_film)); job->set_encoder ( shared_ptr ( - new FFmpegEncoder (_film, job, d->path(), d->format(), d->mixdown_to_stereo(), d->split_reels(), d->x264_crf()) + new FFmpegEncoder (_film, job, d->path(), d->format(), d->mixdown_to_stereo(), d->split_reels(), d->split_streams(), d->x264_crf() +#ifdef DCPOMATIC_VARIANT_SWAROOP + , optional(), optional() +#endif + ) ) ); JobManager::instance()->add (job); @@ -917,22 +990,21 @@ private: d->Destroy (); } - void content_scale_to_fit_width () - { - ContentList vc = _film_editor->content_panel()->selected_video (); - for (ContentList::iterator i = vc.begin(); i != vc.end(); ++i) { - (*i)->video->scale_and_crop_to_fit_width (_film); - } - } - void content_scale_to_fit_height () + void jobs_export_subtitles () { - ContentList vc = _film_editor->content_panel()->selected_video (); - for (ContentList::iterator i = vc.begin(); i != vc.end(); ++i) { - (*i)->video->scale_and_crop_to_fit_height (_film); + ExportSubtitlesDialog* d = new ExportSubtitlesDialog (this, _film->reels().size(), _film->interop()); + if (d->ShowModal() == wxID_OK) { + shared_ptr job (new TranscodeJob (_film)); + job->set_encoder ( + shared_ptr(new SubtitleEncoder(_film, job, d->path(), _film->isdcf_name(true), d->split_reels(), d->include_font())) + ); + JobManager::instance()->add (job); } + d->Destroy (); } + void jobs_send_dcp_to_tms () { _film->send_dcp_to_tms (); @@ -987,6 +1059,15 @@ private: _video_waveform_dialog->Show (); } + void tools_system_information () + { + if (!_system_information_dialog) { + _system_information_dialog = new SystemInformationDialog (this, _film_viewer); + } + + _system_information_dialog->Show (); + } + void tools_hints () { if (!_hints_dialog) { @@ -1248,21 +1329,27 @@ private: add_item (edit, _("&Preferences...\tCtrl-P"), wxID_PREFERENCES, ALWAYS); #endif - wxMenu* content = new wxMenu; - add_item (content, _("Scale to fit &width"), ID_content_scale_to_fit_width, NEEDS_FILM | NEEDS_SELECTED_VIDEO_CONTENT); - add_item (content, _("Scale to fit &height"), ID_content_scale_to_fit_height, NEEDS_FILM | NEEDS_SELECTED_VIDEO_CONTENT); - wxMenu* jobs_menu = new wxMenu; add_item (jobs_menu, _("&Make DCP\tCtrl-M"), ID_jobs_make_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION); add_item (jobs_menu, _("Make DCP in &batch converter\tCtrl-B"), ID_jobs_make_dcp_batch, NEEDS_FILM | NOT_DURING_DCP_CREATION); jobs_menu->AppendSeparator (); add_item (jobs_menu, _("Make &KDMs...\tCtrl-K"), ID_jobs_make_kdms, NEEDS_FILM); + add_item (jobs_menu, _("Make &DKDMs...\tCtrl-D"), ID_jobs_make_dkdms, NEEDS_FILM); add_item (jobs_menu, _("Make DKDM for DCP-o-matic..."), ID_jobs_make_self_dkdm, NEEDS_FILM | NEEDS_ENCRYPTION); jobs_menu->AppendSeparator (); - add_item (jobs_menu, _("Export...\tCtrl-E"), ID_jobs_export, NEEDS_FILM); + add_item (jobs_menu, _("Export video file...\tCtrl-E"), ID_jobs_export_video_file, NEEDS_FILM); + add_item (jobs_menu, _("Export subtitles..."), ID_jobs_export_subtitles, NEEDS_FILM); jobs_menu->AppendSeparator (); add_item (jobs_menu, _("&Send DCP to TMS"), ID_jobs_send_dcp_to_tms, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL); - add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL); + +#if defined(DCPOMATIC_OSX) + add_item (jobs_menu, _("S&how DCP in Finder"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL); +#elif defined(DCPOMATIC_WINDOWS) + add_item (jobs_menu, _("S&how DCP in Explorer"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL); +#else + add_item (jobs_menu, _("S&how DCP in Files"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL); +#endif + add_item (jobs_menu, _("Open DCP in &player"), ID_jobs_open_dcp_in_player, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL); wxMenu* view = new wxMenu; @@ -1275,6 +1362,7 @@ private: add_item (tools, _("Manage templates..."), ID_tools_manage_templates, 0); add_item (tools, _("Check for updates"), ID_tools_check_for_updates, 0); add_item (tools, _("Send translations..."), ID_tools_send_translations, 0); + add_item (tools, _("System information..."), ID_tools_system_information, 0); tools->AppendSeparator (); add_item (tools, _("Restore default preferences"), ID_tools_restore_default_preferences, ALWAYS); @@ -1288,7 +1376,6 @@ private: m->Append (_file_menu, _("&File")); m->Append (edit, _("&Edit")); - m->Append (content, _("&Content")); m->Append (jobs_menu, _("&Jobs")); m->Append (view, _("&View")); m->Append (tools, _("&Tools")); @@ -1422,10 +1509,12 @@ private: boost::shared_ptr _film_viewer; StandardControls* _controls; VideoWaveformDialog* _video_waveform_dialog; + SystemInformationDialog* _system_information_dialog; HintsDialog* _hints_dialog; ServersListDialog* _servers_list_dialog; wxPreferencesEditor* _config_dialog; KDMDialog* _kdm_dialog; + DKDMDialog* _dkdm_dialog; TemplatesDialog* _templates_dialog; wxMenu* _file_menu; shared_ptr _film; @@ -1436,12 +1525,15 @@ private: boost::signals2::scoped_connection _analytics_message_connection; bool _update_news_requested; shared_ptr _clipboard; + bool _first_shown_called; }; static const wxCmdLineEntryDesc command_line_description[] = { { wxCMD_LINE_SWITCH, "n", "new", "create new film", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_OPTION, "c", "content", "add content file / directory", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_OPTION, "d", "dcp", "add content DCP", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_SWITCH, "v", "version", "show DCP-o-matic version", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, + { wxCMD_LINE_OPTION, "", "config", "directory containing config.xml and cinemas.xml", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_PARAM, 0, 0, "film to load or create", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 } }; @@ -1456,7 +1548,11 @@ public: : wxApp () , _frame (0) , _splash (0) - {} + { +#ifdef DCPOMATIC_LINUX + XInitThreads (); +#endif + } private: @@ -1480,10 +1576,9 @@ private: unsetenv ("UBUNTU_MENUPROXY"); #endif -#ifdef __WXOSX__ - ProcessSerialNumber serial; - GetCurrentProcess (&serial); - TransformProcessType (&serial, kProcessTransformToForegroundApplication); +#ifdef DCPOMATIC_OSX + dcpomatic_sleep_seconds (1); + make_foreground_application (); #endif dcpomatic_setup_path_encoding (); @@ -1506,6 +1601,10 @@ private: */ Config::drop (); + /* We only look out for bad configuration from here on, as before + dcpomatic_setup() we haven't got OpenSSL ready so there will be + incorrect certificate chain validity errors. + */ Config::Bad.connect (boost::bind(&App::config_bad, this, _1)); _frame = new DOMFrame (_("DCP-o-matic")); @@ -1520,8 +1619,18 @@ private: Config::instance()->set_nagged(Config::NAG_INITIAL_SETUP, true); } + if (running_32_on_64 ()) { + NagDialog::maybe_nag ( + _frame, Config::NAG_32_ON_64, + _("You are running the 32-bit version of DCP-o-matic on a 64-bit version of Windows. This will limit the memory available to DCP-o-matic and may cause errors. You are strongly advised to install the 64-bit version of DCP-o-matic."), + false); + } + _frame->Show (); + signal_manager = new wxSignalManager (this); + Bind (wxEVT_IDLE, boost::bind (&App::idle, this, _1)); + if (!_film_to_load.empty() && boost::filesystem::is_directory (_film_to_load)) { try { _frame->load_film (_film_to_load); @@ -1542,9 +1651,6 @@ private: } } - signal_manager = new wxSignalManager (this); - Bind (wxEVT_IDLE, boost::bind (&App::idle, this)); - Bind (wxEVT_TIMER, boost::bind (&App::check, this)); _timer.reset (new wxTimer (this)); _timer->Start (1000); @@ -1573,6 +1679,11 @@ private: bool OnCmdLineParsed (wxCmdLineParser& parser) { + if (parser.Found (wxT("version"))) { + cout << "dcpomatic version " << dcpomatic_version << " " << dcpomatic_git_commit << "\n"; + exit (EXIT_SUCCESS); + } + if (parser.GetParamCount() > 0) { if (parser.Found (wxT ("new"))) { _film_to_create = wx_to_std (parser.GetParam (0)); @@ -1591,6 +1702,11 @@ private: _dcp_to_add = wx_to_std (dcp); } + wxString config; + if (parser.Found (wxT("config"), &config)) { + State::override_path = wx_to_std (config); + } + return true; } @@ -1633,9 +1749,10 @@ private: report_exception (); } - void idle () + void idle (wxIdleEvent& ev) { signal_manager->ui_idle (); + ev.Skip (); } void check ()