summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/cinema.h26
-rw-r--r--src/lib/config.cc12
-rw-r--r--src/lib/config.h17
-rw-r--r--src/lib/exceptions.h8
-rw-r--r--src/lib/film.cc80
-rw-r--r--src/lib/film.h15
-rw-r--r--src/lib/make_dcp_job.cc188
-rw-r--r--src/lib/util.cc1
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>