diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lib/cinema.h | 26 | ||||
| -rw-r--r-- | src/lib/config.cc | 12 | ||||
| -rw-r--r-- | src/lib/config.h | 17 | ||||
| -rw-r--r-- | src/lib/exceptions.h | 8 | ||||
| -rw-r--r-- | src/lib/film.cc | 80 | ||||
| -rw-r--r-- | src/lib/film.h | 15 | ||||
| -rw-r--r-- | src/lib/make_dcp_job.cc | 188 | ||||
| -rw-r--r-- | src/lib/util.cc | 1 | ||||
| -rw-r--r-- | src/tools/dcpomatic.cc | 30 | ||||
| -rw-r--r-- | src/wx/cinema_dialog.cc | 62 | ||||
| -rw-r--r-- | src/wx/cinema_dialog.h | 33 | ||||
| -rw-r--r-- | src/wx/film_editor.cc | 20 | ||||
| -rw-r--r-- | src/wx/film_editor.h | 2 | ||||
| -rw-r--r-- | src/wx/kdm_dialog.cc | 373 | ||||
| -rw-r--r-- | src/wx/kdm_dialog.h | 81 | ||||
| -rw-r--r-- | src/wx/screen_dialog.cc | 97 | ||||
| -rw-r--r-- | src/wx/screen_dialog.h | 40 | ||||
| -rw-r--r-- | src/wx/wscript | 3 |
18 files changed, 1087 insertions, 1 deletions
diff --git a/src/lib/cinema.h b/src/lib/cinema.h new file mode 100644 index 000000000..6f426ae8d --- /dev/null +++ b/src/lib/cinema.h @@ -0,0 +1,26 @@ +#include <libdcp/certificates.h> + +class Screen +{ +public: + Screen (std::string const & n, boost::shared_ptr<libdcp::Certificate> cert) + : name (n) + , certificate (cert) + {} + + std::string name; + boost::shared_ptr<libdcp::Certificate> certificate; +}; + +class Cinema +{ +public: + Cinema (std::string const & n, std::string const & e) + : name (n) + , email (e) + {} + + std::string name; + std::string email; + std::list<boost::shared_ptr<Screen> > screens; +}; diff --git a/src/lib/config.cc b/src/lib/config.cc index 9f981c619..5b96d108c 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -135,6 +135,7 @@ Config::read_old_metadata () { ifstream f (file(true).c_str ()); string line; + while (getline (f, line)) { if (line.empty ()) { continue; @@ -207,6 +208,17 @@ Config::file (bool old) const return p.string (); } +string +Config::crypt_chain_directory () const +{ + boost::filesystem::path p; + p /= g_get_user_config_dir (); + p /= "dvdomatic"; + p /= "crypt"; + boost::filesystem::create_directories (p); + return p.string (); +} + /** @return Singleton instance */ Config * Config::instance () diff --git a/src/lib/config.h b/src/lib/config.h index bce6bfd7e..48eabd54c 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -38,6 +38,7 @@ class Filter; class SoundProcessor; class DCPContentType; class Ratio; +class Cinema; /** @class Config * @brief A singleton class holding configuration. @@ -92,6 +93,10 @@ public: return _sound_processor; } + std::list<boost::shared_ptr<Cinema> > cinemas () const { + return _cinemas; + } + std::list<int> allowed_dcp_frame_rates () const { return _allowed_dcp_frame_rates; } @@ -175,6 +180,14 @@ public: _tms_password = p; } + void add_cinema (boost::shared_ptr<Cinema> c) { + _cinemas.push_back (c); + } + + void remove_cinema (boost::shared_ptr<Cinema> c) { + _cinemas.remove (c); + } + void set_allowed_dcp_frame_rates (std::list<int> const & r) { _allowed_dcp_frame_rates = r; } @@ -217,6 +230,8 @@ public: void write () const; + std::string crypt_chain_directory () const; + static Config* instance (); static void drop (); @@ -260,6 +275,8 @@ private: int _default_j2k_bandwidth; std::vector<PresetColourConversion> _colour_conversions; + std::list<boost::shared_ptr<Cinema> > _cinemas; + /** Singleton instance, or 0 */ static Config* _instance; }; diff --git a/src/lib/exceptions.h b/src/lib/exceptions.h index f587f055f..b04d973dc 100644 --- a/src/lib/exceptions.h +++ b/src/lib/exceptions.h @@ -209,6 +209,14 @@ public: {} }; +class KDMError : public StringError +{ +public: + KDMError (std::string s) + : StringError (s) + {} +}; + class PixelFormatError : public StringError { public: diff --git a/src/lib/film.cc b/src/lib/film.cc index 940e94fa7..e885fe5fd 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -31,6 +31,8 @@ #include <boost/date_time.hpp> #include <libxml++/libxml++.h> #include <libcxml/cxml.h> +#include <libdcp/crypt_chain.h> +#include <libdcp/cpl.h> #include "film.h" #include "job.h" #include "util.h" @@ -49,6 +51,7 @@ #include "dcp_content_type.h" #include "ratio.h" #include "cross.h" +#include "cinema.h" #include "i18n.h" @@ -91,6 +94,7 @@ Film::Film (boost::filesystem::path dir) , _resolution (RESOLUTION_2K) , _scaler (Scaler::from_id ("bicubic")) , _with_subtitles (false) + , _encrypted (false) , _j2k_bandwidth (Config::instance()->default_j2k_bandwidth ()) , _dci_metadata (Config::instance()->default_dci_metadata ()) , _video_frame_rate (24) @@ -339,6 +343,7 @@ Film::write_metadata () const root->add_child("ThreeD")->add_child_text (_three_d ? "1" : "0"); root->add_child("SequenceVideo")->add_child_text (_sequence_video ? "1" : "0"); root->add_child("Interop")->add_child_text (_interop ? "1" : "0"); + root->add_child("Encrypted")->add_child_text (_encrypted ? "1" : "0"); _playlist->as_xml (root->add_child ("Playlist")); doc.write_to_file_formatted (file ("metadata.xml")); @@ -737,6 +742,13 @@ Film::make_player () const return shared_ptr<Player> (new Player (shared_from_this (), _playlist)); } +void +Film::set_encrypted (bool e) +{ + _encrypted = e; + signal_changed (ENCRYPTED); +} + shared_ptr<Playlist> Film::playlist () const { @@ -876,3 +888,71 @@ Film::full_frame () const assert (false); return libdcp::Size (); } + +void +Film::make_kdms ( + list<shared_ptr<Screen> > screens, + boost::posix_time::ptime from, + boost::posix_time::ptime until, + string directory + ) const +{ + string const cd = Config::instance()->crypt_chain_directory (); + if (boost::filesystem::is_empty (cd)) { + libdcp::make_crypt_chain (cd); + } + + libdcp::CertificateChain chain; + + { + boost::filesystem::path p (cd); + p /= "ca.self-signed.pem"; + chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p.string ()))); + } + + { + boost::filesystem::path p (cd); + p /= "intermediate.signed.pem"; + chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p.string ()))); + } + + { + boost::filesystem::path p (cd); + p /= "leaf.signed.pem"; + chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p.string ()))); + } + + boost::filesystem::path signer_key (cd); + signer_key /= "leaf.key"; + + /* Find the DCP to make the KDM for */ + string const dir = this->directory (); + list<string> dcps; + for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); ++i) { + if (boost::filesystem::is_directory (*i) && i->path().leaf() != "j2c" && i->path().leaf() != "wavs") { + dcps.push_back (i->path().string()); + } + } + + if (dcps.empty()) { + throw KDMError ("Could not find DCP to make KDM for"); + } else if (dcps.size() > 1) { + throw KDMError ("More than one possible DCP to make KDM for"); + } + + for (list<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) { + + libdcp::DCP dcp (dcps.front ()); + dcp.read (); + + /* XXX: single CPL only */ + shared_ptr<xmlpp::Document> kdm = dcp.cpls().front()->make_kdm ( + chain, signer_key.string(), (*i)->certificate, from, until, _interop, libdcp::MXFMetadata (), Config::instance()->dcp_metadata () + ); + + boost::filesystem::path out = directory; + out /= "kdm.xml"; + kdm->write_to_file_formatted (out.string()); + } +} + diff --git a/src/lib/film.h b/src/lib/film.h index f5b29466a..809eabdaa 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -42,6 +42,7 @@ class Player; class Playlist; class AudioContent; class Scaler; +class Screen; /** @class Film * @@ -113,6 +114,13 @@ public: bool has_subtitles () const; OutputVideoFrame best_video_frame_rate () const; + void make_kdms ( + std::list<boost::shared_ptr<Screen> >, + boost::posix_time::ptime from, + boost::posix_time::ptime until, + std::string directory + ) const; + /** Identifiers for the parts of our state; used for signalling changes. */ @@ -127,6 +135,7 @@ public: RESOLUTION, SCALER, WITH_SUBTITLES, + ENCRYPTED, J2K_BANDWIDTH, DCI_METADATA, VIDEO_FRAME_RATE, @@ -172,6 +181,10 @@ public: return _with_subtitles; } + bool encrypted () const { + return _encrypted; + } + int j2k_bandwidth () const { return _j2k_bandwidth; } @@ -215,6 +228,7 @@ public: void set_resolution (Resolution); void set_scaler (Scaler const *); void set_with_subtitles (bool); + void set_encrypted (bool); void set_j2k_bandwidth (int); void set_dci_metadata (DCIMetadata); void set_video_frame_rate (int); @@ -265,6 +279,7 @@ private: Scaler const * _scaler; /** True if subtitles should be shown for this film */ bool _with_subtitles; + bool _encrypted; /** bandwidth for J2K files in bits per second */ int _j2k_bandwidth; /** DCI naming stuff */ diff --git a/src/lib/make_dcp_job.cc b/src/lib/make_dcp_job.cc new file mode 100644 index 000000000..37c9ca620 --- /dev/null +++ b/src/lib/make_dcp_job.cc @@ -0,0 +1,188 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +/** @file src/make_dcp_job.cc + * @brief A job to create DCPs. + */ + +#include <iostream> +#include <boost/filesystem.hpp> +#include <libdcp/dcp.h> +#include <libdcp/picture_asset.h> +#include <libdcp/sound_asset.h> +#include <libdcp/reel.h> +extern "C" { +#include <libavutil/pixdesc.h> +} +#include "make_dcp_job.h" +#include "dcp_content_type.h" +#include "exceptions.h" +#include "options.h" +#include "imagemagick_decoder.h" +#include "film.h" + +using std::string; +using std::cout; +using boost::shared_ptr; + +/** @param f Film we are making the DCP for. + * @param o Options. + */ +MakeDCPJob::MakeDCPJob (shared_ptr<Film> f, shared_ptr<const EncodeOptions> o, shared_ptr<Job> req) + : Job (f, req) + , _opt (o) +{ + +} + +string +MakeDCPJob::name () const +{ + return String::compose ("Make DCP for %1", _film->name()); +} + +/** @param f DCP frame index */ +string +MakeDCPJob::j2c_path (int f, int offset) const +{ + SourceFrame const s = ((f + offset) * dcp_frame_rate(_film->frames_per_second()).skip) + _film->dcp_trim_start(); + return _opt->frame_out_path (s, false); +} + +string +MakeDCPJob::wav_path (libdcp::Channel c) const +{ + return _opt->multichannel_audio_out_path (int (c), false); +} + +void +MakeDCPJob::run () +{ + if (!_film->dcp_length()) { + throw EncodeError ("cannot make a DCP when the source length is not known"); + } + + descend (0.9); + + string const dcp_path = _film->dir (_film->dcp_name()); + + /* Remove any old DCP */ + boost::filesystem::remove_all (dcp_path); + + DCPFrameRate const dfr = dcp_frame_rate (_film->frames_per_second ()); + + int frames = 0; + switch (_film->content_type ()) { + case VIDEO: + /* Source frames -> DCP frames */ + frames = _film->dcp_length().get() / dfr.skip; + break; + case STILL: + frames = _film->still_duration() * 24; + break; + } + + libdcp::DCP dcp (_film->dir (_film->dcp_name())); + dcp.Progress.connect (boost::bind (&MakeDCPJob::dcp_progress, this, _1)); + + shared_ptr<libdcp::CPL> cpl ( + new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, dfr.frames_per_second) + ); + + dcp.add_cpl (cpl); + + int frames_per_reel = 0; + if (_film->reel_size()) { + frames_per_reel = (_film->reel_size().get() / (_film->j2k_bandwidth() / 8)) * dfr.frames_per_second; + } else { + frames_per_reel = frames; + } + + int frames_done = 0; + int reel = 0; + + while (frames_done < frames) { + + descend (float (frames_per_reel) / frames); + + int this_time = std::min (frames_per_reel, (frames - frames_done)); + + descend (0.8); + + shared_ptr<libdcp::MonoPictureAsset> pa ( + new libdcp::MonoPictureAsset ( + boost::bind (&MakeDCPJob::j2c_path, this, _1, frames_done), + _film->dir (_film->dcp_name()), + String::compose ("video_%1.mxf", reel), + &dcp.Progress, + dfr.frames_per_second, + this_time, + _opt->out_size.width, + _opt->out_size.height, + _film->encrypted() + ) + ); + + ascend (); + + shared_ptr<libdcp::SoundAsset> sa; + + if (_film->audio_channels() > 0) { + descend (0.1); + sa.reset ( + new libdcp::SoundAsset ( + boost::bind (&MakeDCPJob::wav_path, this, _1), + _film->dir (_film->dcp_name()), + String::compose ("audio_%1.mxf", reel), + &dcp.Progress, + dfr.frames_per_second, + this_time, + frames_done, + dcp_audio_channels (_film->audio_channels()), + _film->encrypted() + ) + ); + ascend (); + } + + descend (0.1); + cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (pa, sa, shared_ptr<libdcp::SubtitleAsset> ()))); + ascend (); + + frames_done += frames_per_reel; + ++reel; + + ascend (); + } + + ascend (); + + descend (0.1); + dcp.write_xml (); + ascend (); + + set_progress (1); + set_state (FINISHED_OK); +} + +void +MakeDCPJob::dcp_progress (float p) +{ + set_progress (p); +} diff --git a/src/lib/util.cc b/src/lib/util.cc index 4180bbfd7..b8bc1fc9e 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -45,6 +45,7 @@ #include <magick/MagickCore.h> #include <magick/version.h> #include <libdcp/version.h> +#include <libdcp/util.h> extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index 98501d3bb..f61ef19e2 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -39,6 +39,7 @@ #include "wx/properties_dialog.h" #include "wx/wx_ui_signaller.h" #include "wx/about_dialog.h" +#include "wx/kdm_dialog.h" #include "lib/film.h" #include "lib/config.h" #include "lib/util.h" @@ -47,6 +48,7 @@ #include "lib/log.h" #include "lib/job_manager.h" #include "lib/transcode_job.h" +#include "lib/exceptions.h" using std::cout; using std::string; @@ -167,6 +169,7 @@ enum { ID_file_save, ID_file_properties, ID_jobs_make_dcp, + ID_jobs_make_kdms, ID_jobs_send_dcp_to_tms, ID_jobs_show_dcp, }; @@ -201,6 +204,7 @@ setup_menu (wxMenuBar* m) jobs_menu = new wxMenu; add_item (jobs_menu, _("&Make DCP"), ID_jobs_make_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION); + add_item (jobs_menu, _("Make &KDMs..."), ID_jobs_make_kdms, NEEDS_FILM); add_item (jobs_menu, _("&Send DCP to TMS"), ID_jobs_send_dcp_to_tms, NEEDS_FILM | NOT_DURING_DCP_CREATION); add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION); @@ -236,6 +240,7 @@ public: Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_exit, this), wxID_EXIT); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::edit_preferences, this), wxID_PREFERENCES); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_make_dcp, this), ID_jobs_make_dcp); + Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_make_kdms, this), ID_jobs_make_kdms); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_send_dcp_to_tms, this), ID_jobs_send_dcp_to_tms); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_show_dcp, this), ID_jobs_show_dcp); Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::help_about, this), wxID_ABOUT); @@ -283,7 +288,7 @@ private: return; } - bool const have_dcp = film && film->have_dcp(); + bool const have_dcp = false;//film && film->have_dcp(); jobs_menu->Enable (ID_jobs_send_dcp_to_tms, have_dcp); jobs_menu->Enable (ID_jobs_show_dcp, have_dcp); } @@ -407,6 +412,29 @@ private: { JobWrapper::make_dcp (this, film); } + + void jobs_make_kdms () + { + if (!film) { + return; + } + + KDMDialog* d = new KDMDialog (this); + if (d->ShowModal () == wxID_OK) { + try { + film->make_kdms ( + d->screens (), + d->from (), + d->until (), + d->directory () + ); + } catch (KDMError& e) { + error_dialog (this, e.what ()); + } + } + + d->Destroy (); + } void jobs_send_dcp_to_tms () { diff --git a/src/wx/cinema_dialog.cc b/src/wx/cinema_dialog.cc new file mode 100644 index 000000000..2c0b0b4a4 --- /dev/null +++ b/src/wx/cinema_dialog.cc @@ -0,0 +1,62 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "cinema_dialog.h" +#include "wx_util.h" + +using std::string; + +CinemaDialog::CinemaDialog (wxWindow* parent, string title, string name, string email) + : wxDialog (parent, wxID_ANY, std_to_wx (title)) +{ + wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); + table->AddGrowableCol (1, 1); + + add_label_to_sizer (table, this, "Name", true); + _name = new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (256, -1)); + table->Add (_name, 1, wxEXPAND); + + add_label_to_sizer (table, this, "Email address for KDM delivery", true); + _email = new wxTextCtrl (this, wxID_ANY, std_to_wx (email), wxDefaultPosition, wxSize (256, -1)); + table->Add (_email, 1, wxEXPAND); + + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer (overall_sizer); + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); +} + +string +CinemaDialog::name () const +{ + return wx_to_std (_name->GetValue()); +} + +string +CinemaDialog::email () const +{ + return wx_to_std (_email->GetValue()); +} diff --git a/src/wx/cinema_dialog.h b/src/wx/cinema_dialog.h new file mode 100644 index 000000000..02520eea9 --- /dev/null +++ b/src/wx/cinema_dialog.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <wx/wx.h> + +class CinemaDialog : public wxDialog +{ +public: + CinemaDialog (wxWindow *, std::string, std::string name = "", std::string email = ""); + + std::string name () const; + std::string email () const; + +private: + wxTextCtrl* _name; + wxTextCtrl* _email; +}; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index bcc63c735..56b697375 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -148,6 +148,10 @@ FilmEditor::make_dcp_panel () } ++r; + _encrypted = new wxCheckBox (_dcp_panel, wxID_ANY, wxT ("Encrypted")); + grid->Add (_encrypted, wxGBPosition (r, 0), wxGBSpan (1, 2)); + ++r; + add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Audio channels"), true, wxGBPosition (r, 0)); _audio_channels = new wxSpinCtrl (_dcp_panel, wxID_ANY); grid->Add (_audio_channels, wxGBPosition (r, 1)); @@ -307,6 +311,17 @@ FilmEditor::j2k_bandwidth_changed () } void +FilmEditor::encrypted_toggled () +{ + if (!_film) { + return; + } + + _film->set_encrypted (_encrypted->GetValue ()); +} + +/** Called when the name widget has been changed */ +void FilmEditor::frame_rate_changed () { if (!_film) { @@ -392,6 +407,9 @@ FilmEditor::film_changed (Film::Property p) case Film::SCALER: checked_set (_scaler, Scaler::as_index (_film->scaler ())); break; + case Film::ENCRYPTED: + checked_set (_encrypted, _film->encrypted ()); + break; case Film::RESOLUTION: checked_set (_resolution, _film->resolution() == RESOLUTION_2K ? 0 : 1); setup_dcp_name (); @@ -548,6 +566,7 @@ FilmEditor::set_film (shared_ptr<Film> f) film_changed (Film::RESOLUTION); film_changed (Film::SCALER); film_changed (Film::WITH_SUBTITLES); + film_changed (Film::ENCRYPTED); film_changed (Film::J2K_BANDWIDTH); film_changed (Film::DCI_METADATA); film_changed (Film::VIDEO_FRAME_RATE); @@ -578,6 +597,7 @@ FilmEditor::set_general_sensitivity (bool s) _content_remove->Enable (s); _content_timeline->Enable (s); _dcp_content_type->Enable (s); + _encrypted->Enable (s); _frame_rate->Enable (s); _audio_channels->Enable (s); _j2k_bandwidth->Enable (s); diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 8ecec3ec7..bb217211c 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -93,6 +93,7 @@ private: void content_right_click (wxListEvent &); void three_d_changed (); void standard_changed (); + void encrypted_toggled (); /* Handle changes to the model */ void film_changed (Film::Property); @@ -143,6 +144,7 @@ private: wxCheckBox* _three_d; wxChoice* _resolution; wxChoice* _standard; + wxCheckBox* _encrypted; ContentMenu _menu; diff --git a/src/wx/kdm_dialog.cc b/src/wx/kdm_dialog.cc new file mode 100644 index 000000000..a9f63cffc --- /dev/null +++ b/src/wx/kdm_dialog.cc @@ -0,0 +1,373 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <wx/treectrl.h> +#include <wx/datectrl.h> +#include <wx/timectrl.h> +#include "lib/cinema.h" +#include "lib/config.h" +#include "kdm_dialog.h" +#include "cinema_dialog.h" +#include "screen_dialog.h" +#include "wx_util.h" +#ifdef __WXMSW__ +#include "dir_picker_ctrl.h" +#else +#include <wx/filepicker.h> +#endif + +using std::string; +using std::map; +using std::list; +using std::pair; +using std::make_pair; +using boost::shared_ptr; + +KDMDialog::KDMDialog (wxWindow* parent) + : wxDialog (parent, wxID_ANY, _("Make KDMs")) +{ + wxBoxSizer* vertical = new wxBoxSizer (wxVERTICAL); + wxBoxSizer* targets = new wxBoxSizer (wxHORIZONTAL); + + _targets = new wxTreeCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_HIDE_ROOT | wxTR_MULTIPLE | wxTR_HAS_BUTTONS); + targets->Add (_targets, 1, wxEXPAND | wxALL, 6); + + _root = _targets->AddRoot ("Foo"); + + list<shared_ptr<Cinema> > c = Config::instance()->cinemas (); + for (list<shared_ptr<Cinema> >::iterator i = c.begin(); i != c.end(); ++i) { + add_cinema (*i); + } + + _targets->ExpandAll (); + + wxBoxSizer* target_buttons = new wxBoxSizer (wxVERTICAL); + + _add_cinema = new wxButton (this, wxID_ANY, _("Add Cinema...")); + target_buttons->Add (_add_cinema, 1, wxEXPAND, 6); + _edit_cinema = new wxButton (this, wxID_ANY, _("Edit Cinema...")); + target_buttons->Add (_edit_cinema, 1, wxEXPAND, 6); + _remove_cinema = new wxButton (this, wxID_ANY, _("Remove Cinema")); + target_buttons->Add (_remove_cinema, 1, wxEXPAND, 6); + + _add_screen = new wxButton (this, wxID_ANY, _("Add Screen...")); + target_buttons->Add (_add_screen, 1, wxEXPAND, 6); + _edit_screen = new wxButton (this, wxID_ANY, _("Edit Screen...")); + target_buttons->Add (_edit_screen, 1, wxEXPAND, 6); + _remove_screen = new wxButton (this, wxID_ANY, _("Remove Screen")); + target_buttons->Add (_remove_screen, 1, wxEXPAND, 6); + + targets->Add (target_buttons, 0, 0, 6); + + vertical->Add (targets, 1, wxEXPAND | wxALL, 6); + + wxFlexGridSizer* table = new wxFlexGridSizer (3, 2, 6); + add_label_to_sizer (table, this, "From", true); + _from_date = new wxDatePickerCtrl (this, wxID_ANY); + table->Add (_from_date, 1, wxEXPAND); + _from_time = new wxTimePickerCtrl (this, wxID_ANY); + table->Add (_from_time, 1, wxEXPAND); + + add_label_to_sizer (table, this, "Until", true); + _until_date = new wxDatePickerCtrl (this, wxID_ANY); + table->Add (_until_date, 1, wxEXPAND); + _until_time = new wxTimePickerCtrl (this, wxID_ANY); + table->Add (_until_time, 1, wxEXPAND); + + add_label_to_sizer (table, this, "Write to", true); + +#ifdef __WXMSW__ + _folder = new DirPickerCtrl (this); +#else + _folder = new wxDirPickerCtrl (this, wxDD_DIR_MUST_EXIST); +#endif + + table->Add (_folder, 1, wxEXPAND); + + vertical->Add (table, 0, wxEXPAND | wxALL, 6); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); + if (buttons) { + vertical->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + _targets->Connect (wxID_ANY, wxEVT_COMMAND_TREE_SEL_CHANGED, wxCommandEventHandler (KDMDialog::targets_selection_changed), 0, this); + + _add_cinema->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::add_cinema_clicked), 0, this); + _edit_cinema->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::edit_cinema_clicked), 0, this); + _remove_cinema->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::remove_cinema_clicked), 0, this); + + _add_screen->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::add_screen_clicked), 0, this); + _edit_screen->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::edit_screen_clicked), 0, this); + _remove_screen->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::remove_screen_clicked), 0, this); + + setup_sensitivity (); + + SetSizer (vertical); + vertical->Layout (); + vertical->SetSizeHints (this); +} + +list<pair<wxTreeItemId, shared_ptr<Cinema> > > +KDMDialog::selected_cinemas () const +{ + wxArrayTreeItemIds s; + _targets->GetSelections (s); + + list<pair<wxTreeItemId, shared_ptr<Cinema> > > c; + for (size_t i = 0; i < s.GetCount(); ++i) { + map<wxTreeItemId, shared_ptr<Cinema> >::const_iterator j = _cinemas.find (s[i]); + if (j != _cinemas.end ()) { + c.push_back (make_pair (j->first, j->second)); + } + } + + return c; +} + +list<pair<wxTreeItemId, shared_ptr<Screen> > > +KDMDialog::selected_screens () const +{ + wxArrayTreeItemIds s; + _targets->GetSelections (s); + + list<pair<wxTreeItemId, shared_ptr<Screen> > > c; + for (size_t i = 0; i < s.GetCount(); ++i) { + map<wxTreeItemId, shared_ptr<Screen> >::const_iterator j = _screens.find (s[i]); + if (j != _screens.end ()) { + c.push_back (make_pair (j->first, j->second)); + } + } + + return c; +} + +void +KDMDialog::targets_selection_changed (wxCommandEvent &) +{ + setup_sensitivity (); +} + +void +KDMDialog::setup_sensitivity () +{ + bool const sc = selected_cinemas().size() == 1; + bool const ss = selected_screens().size() == 1; + + _edit_cinema->Enable (sc); + _remove_cinema->Enable (sc); + + _add_screen->Enable (sc); + _edit_screen->Enable (ss); + _remove_screen->Enable (ss); +} + +void +KDMDialog::add_cinema (shared_ptr<Cinema> c) +{ + _cinemas[_targets->AppendItem (_root, std_to_wx (c->name))] = c; + + for (list<shared_ptr<Screen> >::iterator i = c->screens.begin(); i != c->screens.end(); ++i) { + add_screen (c, *i); + } +} + +void +KDMDialog::add_screen (shared_ptr<Cinema> c, shared_ptr<Screen> s) +{ + map<wxTreeItemId, shared_ptr<Cinema> >::const_iterator i = _cinemas.begin(); + while (i != _cinemas.end() && i->second != c) { + ++i; + } + + if (i == _cinemas.end()) { + return; + } + + _screens[_targets->AppendItem (i->first, std_to_wx (s->name))] = s; +} + +void +KDMDialog::add_cinema_clicked (wxCommandEvent &) +{ + CinemaDialog* d = new CinemaDialog (this, "Add Cinema"); + d->ShowModal (); + + shared_ptr<Cinema> c (new Cinema (d->name(), d->email())); + Config::instance()->add_cinema (c); + add_cinema (c); + + Config::instance()->write (); + + d->Destroy (); +} + +void +KDMDialog::edit_cinema_clicked (wxCommandEvent &) +{ + if (selected_cinemas().size() != 1) { + return; + } + + pair<wxTreeItemId, shared_ptr<Cinema> > c = selected_cinemas().front(); + + CinemaDialog* d = new CinemaDialog (this, "Edit cinema", c.second->name, c.second->email); + d->ShowModal (); + + c.second->name = d->name (); + c.second->email = d->email (); + _targets->SetItemText (c.first, std_to_wx (d->name())); + + Config::instance()->write (); + + d->Destroy (); +} + +void +KDMDialog::remove_cinema_clicked (wxCommandEvent &) +{ + if (selected_cinemas().size() != 1) { + return; + } + + pair<wxTreeItemId, shared_ptr<Cinema> > c = selected_cinemas().front(); + + Config::instance()->remove_cinema (c.second); + _targets->Delete (c.first); + + Config::instance()->write (); +} + +void +KDMDialog::add_screen_clicked (wxCommandEvent &) +{ + if (selected_cinemas().size() != 1) { + return; + } + + shared_ptr<Cinema> c = selected_cinemas().front().second; + + ScreenDialog* d = new ScreenDialog (this, "Add Screen"); + d->ShowModal (); + + shared_ptr<Screen> s (new Screen (d->name(), d->certificate())); + c->screens.push_back (s); + add_screen (c, s); + + Config::instance()->write (); + + d->Destroy (); +} + +void +KDMDialog::edit_screen_clicked (wxCommandEvent &) +{ + if (selected_screens().size() != 1) { + return; + } + + pair<wxTreeItemId, shared_ptr<Screen> > s = selected_screens().front(); + + ScreenDialog* d = new ScreenDialog (this, "Edit screen", s.second->name, s.second->certificate); + d->ShowModal (); + + s.second->name = d->name (); + s.second->certificate = d->certificate (); + _targets->SetItemText (s.first, std_to_wx (d->name())); + + Config::instance()->write (); + + d->Destroy (); +} + +void +KDMDialog::remove_screen_clicked (wxCommandEvent &) +{ + if (selected_screens().size() != 1) { + return; + } + + pair<wxTreeItemId, shared_ptr<Screen> > s = selected_screens().front(); + + map<wxTreeItemId, shared_ptr<Cinema> >::iterator i = _cinemas.begin (); + while (i != _cinemas.end() && find (i->second->screens.begin(), i->second->screens.end(), s.second) == i->second->screens.end()) { + ++i; + } + + if (i == _cinemas.end()) { + return; + } + + i->second->screens.remove (s.second); + _targets->Delete (s.first); + + Config::instance()->write (); +} + +list<shared_ptr<Screen> > +KDMDialog::screens () const +{ + list<shared_ptr<Screen> > s; + + list<pair<wxTreeItemId, shared_ptr<Cinema> > > cinemas = selected_cinemas (); + for (list<pair<wxTreeItemId, shared_ptr<Cinema> > >::iterator i = cinemas.begin(); i != cinemas.end(); ++i) { + for (list<shared_ptr<Screen> >::iterator j = i->second->screens.begin(); j != i->second->screens.end(); ++j) { + s.push_back (*j); + } + } + + list<pair<wxTreeItemId, shared_ptr<Screen> > > screens = selected_screens (); + for (list<pair<wxTreeItemId, shared_ptr<Screen> > >::iterator i = screens.begin(); i != screens.end(); ++i) { + s.push_back (i->second); + } + + s.sort (); + s.unique (); + + return s; +} + +boost::posix_time::ptime +KDMDialog::from () const +{ + return posix_time (_from_date, _from_time); +} + +boost::posix_time::ptime +KDMDialog::posix_time (wxDatePickerCtrl* date_picker, wxTimePickerCtrl* time_picker) +{ + wxDateTime const date = date_picker->GetValue (); + wxDateTime const time = time_picker->GetValue (); + return boost::posix_time::ptime ( + boost::gregorian::date (date.GetYear(), date.GetMonth() + 1, date.GetDay()), + boost::posix_time::time_duration (time.GetHour(), time.GetMinute(), time.GetSecond()) + ); +} + +boost::posix_time::ptime +KDMDialog::until () const +{ + return posix_time (_until_date, _until_time); +} + +string +KDMDialog::directory () const +{ + return wx_to_std (_folder->GetPath ()); +} diff --git a/src/wx/kdm_dialog.h b/src/wx/kdm_dialog.h new file mode 100644 index 000000000..ac2db9b95 --- /dev/null +++ b/src/wx/kdm_dialog.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <map> +#include <boost/shared_ptr.hpp> +#include <boost/date_time/posix_time/posix_time.hpp> +#include <wx/wx.h> +#include <wx/treectrl.h> + +class wxTreeCtrl; +class wxDatePickerCtrl; +class wxTimePickerCtrl; +class wxDirPickerCtrl; +class DirPickerCtrl; + +class Cinema; +class Screen; + +class KDMDialog : public wxDialog +{ +public: + KDMDialog (wxWindow *); + + std::list<boost::shared_ptr<Screen> > screens () const; + boost::posix_time::ptime from () const; + boost::posix_time::ptime until () const; + std::string directory () const; + +private: + void add_cinema (boost::shared_ptr<Cinema>); + void add_screen (boost::shared_ptr<Cinema>, boost::shared_ptr<Screen>); + void targets_selection_changed (wxCommandEvent &); + void add_cinema_clicked (wxCommandEvent &); + void edit_cinema_clicked (wxCommandEvent &); + void remove_cinema_clicked (wxCommandEvent &); + void add_screen_clicked (wxCommandEvent &); + void edit_screen_clicked (wxCommandEvent &); + void remove_screen_clicked (wxCommandEvent &); + std::list<std::pair<wxTreeItemId, boost::shared_ptr<Cinema> > > selected_cinemas () const; + std::list<std::pair<wxTreeItemId, boost::shared_ptr<Screen> > > selected_screens () const; + void setup_sensitivity (); + + static boost::posix_time::ptime posix_time (wxDatePickerCtrl *, wxTimePickerCtrl *); + + wxTreeCtrl* _targets; + wxButton* _add_cinema; + wxButton* _edit_cinema; + wxButton* _remove_cinema; + wxButton* _add_screen; + wxButton* _edit_screen; + wxButton* _remove_screen; + wxDatePickerCtrl* _from_date; + wxDatePickerCtrl* _until_date; + wxTimePickerCtrl* _from_time; + wxTimePickerCtrl* _until_time; +#ifdef __WXMSW__ + DirPickerCtrl* _folder; +#else + wxDirPickerCtrl* _folder; +#endif + + wxTreeItemId _root; + std::map<wxTreeItemId, boost::shared_ptr<Cinema> > _cinemas; + std::map<wxTreeItemId, boost::shared_ptr<Screen> > _screens; +}; diff --git a/src/wx/screen_dialog.cc b/src/wx/screen_dialog.cc new file mode 100644 index 000000000..7ff519713 --- /dev/null +++ b/src/wx/screen_dialog.cc @@ -0,0 +1,97 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <wx/filepicker.h> +#include <wx/validate.h> +#include <libdcp/exceptions.h> +#include "lib/compose.hpp" +#include "screen_dialog.h" +#include "wx_util.h" + +using std::string; +using std::cout; +using boost::shared_ptr; + +ScreenDialog::ScreenDialog (wxWindow* parent, string title, string name, shared_ptr<libdcp::Certificate> certificate) + : wxDialog (parent, wxID_ANY, std_to_wx (title)) + , _certificate (certificate) +{ + wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6); + table->AddGrowableCol (1, 1); + + add_label_to_sizer (table, this, "Name", true); + _name = new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (320, -1)); + table->Add (_name, 1, wxEXPAND); + + add_label_to_sizer (table, this, "Certificate", true); + _certificate_load = new wxButton (this, wxID_ANY, wxT ("Load from file...")); + table->Add (_certificate_load, 1, wxEXPAND); + + table->AddSpacer (0); + _certificate_text = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, wxSize (320, 256), wxTE_MULTILINE | wxTE_READONLY); + if (certificate) { + _certificate_text->SetValue (certificate->certificate ()); + } + wxFont font = wxSystemSettings::GetFont (wxSYS_ANSI_FIXED_FONT); + font.SetPointSize (font.GetPointSize() / 2); + _certificate_text->SetFont (font); + table->Add (_certificate_text, 1, wxEXPAND); + + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer (overall_sizer); + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); + + _certificate_load->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ScreenDialog::load_certificate), 0, this); +} + +string +ScreenDialog::name () const +{ + return wx_to_std (_name->GetValue()); +} + +shared_ptr<libdcp::Certificate> +ScreenDialog::certificate () const +{ + return _certificate; +} + +void +ScreenDialog::load_certificate (wxCommandEvent &) +{ + wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File")); + d->ShowModal (); + + try { + _certificate.reset (new libdcp::Certificate (wx_to_std (d->GetPath ()))); + _certificate_text->SetValue (_certificate->certificate ()); + } catch (libdcp::MiscError& e) { + error_dialog (this, String::compose ("Could not read certificate file (%1)", e.what())); + } + + d->Destroy (); +} diff --git a/src/wx/screen_dialog.h b/src/wx/screen_dialog.h new file mode 100644 index 000000000..1bd4a89a9 --- /dev/null +++ b/src/wx/screen_dialog.h @@ -0,0 +1,40 @@ +/* + Copyright (C) 2012 Carl Hetherington <cth@carlh.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <wx/wx.h> +#include <boost/shared_ptr.hpp> +#include <libdcp/certificates.h> + +class ScreenDialog : public wxDialog +{ +public: + ScreenDialog (wxWindow *, std::string, std::string name = "", boost::shared_ptr<libdcp::Certificate> c = boost::shared_ptr<libdcp::Certificate> ()); + + std::string name () const; + boost::shared_ptr<libdcp::Certificate> certificate () const; + +private: + void load_certificate (wxCommandEvent &); + + wxTextCtrl* _name; + wxButton* _certificate_load; + wxTextCtrl* _certificate_text; + + boost::shared_ptr<libdcp::Certificate> _certificate; +}; diff --git a/src/wx/wscript b/src/wx/wscript index 9c3ecdd71..8f35e2fac 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -9,6 +9,7 @@ sources = """ audio_mapping_view.cc audio_panel.cc audio_plot.cc + cinema_dialog.cc colour_conversion_editor.cc config_dialog.cc content_colour_conversion_dialog.cc @@ -23,10 +24,12 @@ sources = """ gain_calculator_dialog.cc job_manager_view.cc job_wrapper.cc + kdm_dialog.cc new_film_dialog.cc preset_colour_conversion_dialog.cc properties_dialog.cc repeat_dialog.cc + screen_dialog.cc server_dialog.cc subtitle_panel.cc timecode.cc |
