X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Flib%2Ffilm.cc;h=48677ba613848f419864efe0e4307a6842c5bea9;hb=fad726e94700bccdae0d301d54cdb1eab51cc71f;hp=e7f47c462c550c4bb8bc9fedb97cad1871bdd1ed;hpb=1f2bc4d8f3601ad1e12b94f37b3889fcd003509b;p=dcpomatic.git diff --git a/src/lib/film.cc b/src/lib/film.cc index e7f47c462..48677ba61 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -29,6 +29,10 @@ #include #include #include +#include +#include +#include +#include "cinema.h" #include "film.h" #include "format.h" #include "job.h" @@ -65,6 +69,7 @@ using std::ofstream; using std::setfill; using std::min; using std::make_pair; +using std::list; using std::cout; using boost::shared_ptr; using boost::lexical_cast; @@ -85,6 +90,7 @@ int const Film::state_version = 1; Film::Film (string d, bool must_exist) : _use_dci_name (true) + , _trust_content_header (true) , _dcp_content_type (0) , _format (0) , _scaler (Scaler::from_id ("bicubic")) @@ -98,6 +104,7 @@ Film::Film (string d, bool must_exist) , _with_subtitles (false) , _subtitle_offset (0) , _subtitle_scale (1) + , _encrypted (false) , _frames_per_second (0) , _dirty (false) { @@ -130,19 +137,23 @@ Film::Film (string d, bool must_exist) } _external_audio_stream = ExternalAudioStream::create (); - - read_metadata (); + + if (must_exist) { + read_metadata (); + } _log = new FileLog (file ("log")); set_dci_date_today (); } Film::Film (Film const & o) - : _log (0) + : boost::enable_shared_from_this (o) + , _log (0) , _directory (o._directory) , _name (o._name) , _use_dci_name (o._use_dci_name) , _content (o._content) + , _trust_content_header (o._trust_content_header) , _dcp_content_type (o._dcp_content_type) , _format (o._format) , _crop (o._crop) @@ -161,6 +172,7 @@ Film::Film (Film const & o) , _with_subtitles (o._with_subtitles) , _subtitle_offset (o._subtitle_offset) , _subtitle_scale (o._subtitle_scale) + , _encrypted (o._encrypted) , _audio_language (o._audio_language) , _subtitle_language (o._subtitle_language) , _territory (o._territory) @@ -240,6 +252,8 @@ Film::make_dcp (bool transcode) char buffer[128]; gethostname (buffer, sizeof (buffer)); log()->log (String::compose ("Starting to make DCP on %1", buffer)); + log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? "still" : "video"))); + log()->log (String::compose ("Content length %1", length())); } if (format() == 0) { @@ -265,8 +279,18 @@ Film::make_dcp (bool transcode) oe->video_range = make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get()); if (audio_stream()) { oe->audio_range = make_pair ( - video_frames_to_audio_frames (oe->video_range.get().first, audio_stream()->sample_rate(), frames_per_second()), - video_frames_to_audio_frames (oe->video_range.get().second, audio_stream()->sample_rate(), frames_per_second()) + + video_frames_to_audio_frames ( + oe->video_range.get().first, + dcp_audio_sample_rate (audio_stream()->sample_rate()), + dcp_frame_rate (frames_per_second()).frames_per_second + ), + + video_frames_to_audio_frames ( + oe->video_range.get().second, + dcp_audio_sample_rate (audio_stream()->sample_rate()), + dcp_frame_rate (frames_per_second()).frames_per_second + ) ); } @@ -369,6 +393,7 @@ Film::write_metadata () const f << "name " << _name << "\n"; f << "use_dci_name " << _use_dci_name << "\n"; f << "content " << _content << "\n"; + f << "trust_content_header " << (_trust_content_header ? "1" : "0") << "\n"; if (_dcp_content_type) { f << "dcp_content_type " << _dcp_content_type->pretty_name () << "\n"; } @@ -402,6 +427,7 @@ Film::write_metadata () const f << "with_subtitles " << _with_subtitles << "\n"; f << "subtitle_offset " << _subtitle_offset << "\n"; f << "subtitle_scale " << _subtitle_scale << "\n"; + f << "encrypted " << _encrypted << "\n"; f << "audio_language " << _audio_language << "\n"; f << "subtitle_language " << _subtitle_language << "\n"; f << "territory " << _territory << "\n"; @@ -446,8 +472,12 @@ Film::read_metadata () boost::optional audio_sample_rate; boost::optional audio_stream_index; boost::optional subtitle_stream_index; - + ifstream f (file ("metadata").c_str()); + if (!f.good()) { + throw OpenFileError (file("metadata")); + } + multimap kv = read_key_value (f); /* We need version before anything else */ @@ -471,6 +501,8 @@ Film::read_metadata () _use_dci_name = (v == "1"); } else if (k == "content") { _content = v; + } else if (k == "trust_content_header") { + _trust_content_header = (v == "1"); } else if (k == "dcp_content_type") { _dcp_content_type = DCPContentType::from_pretty_name (v); } else if (k == "format") { @@ -521,6 +553,8 @@ Film::read_metadata () _subtitle_offset = atoi (v.c_str ()); } else if (k == "subtitle_scale") { _subtitle_scale = atof (v.c_str ()); + } else if (k == "encrypted") { + _encrypted = (v == "1"); } else if (k == "audio_language") { _audio_language = v; } else if (k == "subtitle_language") { @@ -670,11 +704,15 @@ Film::target_audio_sample_rate () const return rint (t); } -boost::optional +boost::optional Film::dcp_length () const { + if (content_type() == STILL) { + return _still_duration * frames_per_second(); + } + if (!length()) { - return boost::optional (); + return boost::optional (); } return length().get() - dcp_trim_start() - dcp_trim_end(); @@ -841,6 +879,9 @@ Film::set_content (string c) _content_audio_stream = shared_ptr (); _subtitle_stream = shared_ptr (); + /* Start off using content audio */ + set_use_content_audio (true); + /* Create a temporary decoder so that we can get information about the content. */ @@ -852,10 +893,12 @@ Film::set_content (string c) set_size (d.video->native_size ()); set_frames_per_second (d.video->frames_per_second ()); set_subtitle_streams (d.video->subtitle_streams ()); - set_content_audio_streams (d.audio->audio_streams ()); + if (d.audio) { + set_content_audio_streams (d.audio->audio_streams ()); + } /* Start off with the first audio and subtitle streams */ - if (!d.audio->audio_streams().empty()) { + if (d.audio && !d.audio->audio_streams().empty()) { set_content_audio_stream (d.audio->audio_streams().front()); } @@ -870,8 +913,6 @@ Film::set_content (string c) signal_changed (CONTENT); - set_content_digest (md5_digest (content_path ())); - examine_content (); } catch (...) { @@ -881,6 +922,37 @@ Film::set_content (string c) throw; } + + /* Default format */ + switch (content_type()) { + case STILL: + set_format (Format::from_id ("var-185")); + break; + case VIDEO: + set_format (Format::from_id ("185")); + break; + } + + /* Still image DCPs must use external audio */ + if (content_type() == STILL) { + set_use_content_audio (false); + } +} + +void +Film::set_trust_content_header (bool t) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _trust_content_header = t; + } + + signal_changed (TRUST_CONTENT_HEADER); + + if (!_trust_content_header && !content().empty()) { + /* We just said that we don't trust the content's header */ + examine_content (); + } } void @@ -1128,6 +1200,16 @@ Film::set_subtitle_scale (float s) signal_changed (SUBTITLE_SCALE); } +void +Film::set_encrypted (bool e) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _encrypted = e; + } + signal_changed (ENCRYPTED); +} + void Film::set_audio_language (string l) { @@ -1307,3 +1389,69 @@ Film::audio_stream () const return _external_audio_stream; } + +void +Film::make_kdms ( + list > 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 (new libdcp::Certificate (p.string ()))); + } + + { + boost::filesystem::path p (cd); + p /= "intermediate.signed.pem"; + chain.add (shared_ptr (new libdcp::Certificate (p.string ()))); + } + + { + boost::filesystem::path p (cd); + p /= "leaf.signed.pem"; + chain.add (shared_ptr (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 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 >::iterator i = screens.begin(); i != screens.end(); ++i) { + + libdcp::DCP dcp (dcps.front ()); + dcp.read (); + + /* XXX: single CPL only */ + shared_ptr kdm = dcp.cpls().front()->make_kdm (chain, signer_key.string(), (*i)->certificate, from, until); + + boost::filesystem::path out = directory; + out /= "kdm.xml"; + kdm->write_to_file_formatted (out.string()); + } +} +