X-Git-Url: https://git.carlh.net/gitweb/?p=dcpomatic.git;a=blobdiff_plain;f=src%2Ftools%2Fdcpomatic.cc;h=fe76c60436f2a50732872abc810a4a74444d5e66;hp=2fe5187b4732912c0eb3dfe56b3b015200f36d61;hb=451ab9374cc32483489cdde27a9382b546cdecf5;hpb=d1e19450e051d70531a6c1f0973bfd6cfd64319b diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index 2fe5187b4..fe76c6043 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" @@ -45,6 +46,7 @@ #include "wx/templates_dialog.h" #include "wx/nag_dialog.h" #include "wx/export_dialog.h" +#include "wx/export_subtitles_dialog.h" #include "wx/paste_dialog.h" #include "wx/focus_manager.h" #include "wx/html_dialog.h" @@ -65,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" @@ -83,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 @@ -218,24 +223,24 @@ 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_subtitles, ID_jobs_send_dcp_to_tms, ID_jobs_show_dcp, ID_jobs_open_dcp_in_player, ID_view_closed_captions, ID_view_video_waveform, - ID_view_system_information, ID_tools_hints, ID_tools_encoding_servers, 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) */ @@ -258,12 +263,14 @@ public: , _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 ()) { @@ -310,29 +317,30 @@ 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_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); Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_closed_captions, this), ID_view_closed_captions); Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_video_waveform, this), ID_view_video_waveform); - Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_system_information, this), ID_view_system_information); Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_hints, this), ID_tools_hints); Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_encoding_servers, this), ID_tools_encoding_servers); 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. @@ -443,10 +451,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) @@ -476,6 +495,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)); @@ -509,7 +536,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) { @@ -517,9 +544,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 @@ -757,7 +786,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) { @@ -780,8 +809,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 @@ -807,10 +851,10 @@ private: } if (i == 1) { - start (wx_to_std (wxStandardPaths::Get().GetExecutablePath())); + start (); } - dcpomatic_sleep (1); + dcpomatic_sleep_seconds (1); } return true; @@ -833,7 +877,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.")); } } @@ -844,7 +888,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.")); } } @@ -872,14 +916,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 @@ -908,35 +957,68 @@ private: void jobs_export () { - ExportDialog* d = new ExportDialog (this); + ExportDialog* d = new ExportDialog (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()) - ) - ); + if (d->format() == EXPORT_FORMAT_SUBTITLES_DCP) { + job->set_encoder ( + shared_ptr(new SubtitleEncoder(_film, job, d->path(), d->split_reels())) + ); + } else { + job->set_encoder ( + shared_ptr ( + 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); } 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->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 SubtitleEncoder(_film, job, d->path(), d->split_reels())) + ); + JobManager::instance()->add (job); } + d->Destroy (); } + void jobs_send_dcp_to_tms () { _film->send_dcp_to_tms (); @@ -991,7 +1073,7 @@ private: _video_waveform_dialog->Show (); } - void view_system_information () + void tools_system_information () { if (!_system_information_dialog) { _system_information_dialog = new SystemInformationDialog (this, _film_viewer); @@ -1261,27 +1343,32 @@ 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, 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; add_item (view, _("Closed captions..."), ID_view_closed_captions, NEEDS_FILM); add_item (view, _("Video waveform..."), ID_view_video_waveform, NEEDS_FILM); - add_item (view, _("System information..."), ID_view_system_information, 0); wxMenu* tools = new wxMenu; add_item (tools, _("Hints..."), ID_tools_hints, NEEDS_FILM); @@ -1289,6 +1376,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); @@ -1302,7 +1390,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")); @@ -1441,6 +1528,7 @@ private: ServersListDialog* _servers_list_dialog; wxPreferencesEditor* _config_dialog; KDMDialog* _kdm_dialog; + DKDMDialog* _dkdm_dialog; TemplatesDialog* _templates_dialog; wxMenu* _file_menu; shared_ptr _film; @@ -1451,12 +1539,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 } }; @@ -1471,7 +1562,11 @@ public: : wxApp () , _frame (0) , _splash (0) - {} + { +#ifdef DCPOMATIC_LINUX + XInitThreads (); +#endif + } private: @@ -1495,10 +1590,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 (); @@ -1539,8 +1633,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); @@ -1561,9 +1665,6 @@ private: } } - signal_manager = new wxSignalManager (this); - Bind (wxEVT_IDLE, boost::bind (&App::idle, this, _1)); - Bind (wxEVT_TIMER, boost::bind (&App::check, this)); _timer.reset (new wxTimer (this)); _timer->Start (1000); @@ -1592,6 +1693,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)); @@ -1610,6 +1716,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; }