diff options
Diffstat (limited to 'src/lib')
| -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 |
8 files changed, 347 insertions, 0 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> |
