diff options
| author | Carl Hetherington <cth@carlh.net> | 2014-07-20 21:22:52 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2014-07-20 21:22:52 +0100 |
| commit | d8d7ddd4c39e3ea347afd1fccc037d8b0a31bc87 (patch) | |
| tree | a9071c33d3a6e60f970e5e6c08c70a9efa142838 /src/lib | |
| parent | 72ae435a9b2a554d5de7280ad51793ed6a835f42 (diff) | |
Basic support for decryption of imported DCPs.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/dcp_content.cc | 32 | ||||
| -rw-r--r-- | src/lib/dcp_content.h | 36 | ||||
| -rw-r--r-- | src/lib/dcp_decoder.cc | 6 | ||||
| -rw-r--r-- | src/lib/dcp_examiner.cc | 44 | ||||
| -rw-r--r-- | src/lib/dcp_examiner.h | 10 | ||||
| -rw-r--r-- | src/lib/film.cc | 9 | ||||
| -rw-r--r-- | src/lib/film.h | 1 | ||||
| -rw-r--r-- | src/lib/player.cc | 4 | ||||
| -rw-r--r-- | src/lib/video_content.cc | 2 |
9 files changed, 136 insertions, 8 deletions
diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc index 0eef075d7..9d4ee6388 100644 --- a/src/lib/dcp_content.cc +++ b/src/lib/dcp_content.cc @@ -18,16 +18,22 @@ */ #include <dcp/dcp.h> +#include <dcp/exceptions.h> #include "dcp_content.h" #include "dcp_examiner.h" #include "job.h" #include "film.h" +#include "config.h" #include "compose.hpp" #include "i18n.h" using std::string; +using std::cout; using boost::shared_ptr; +using boost::optional; + +int const DCPContentProperty::CAN_BE_PLAYED = 600; DCPContent::DCPContent (shared_ptr<const Film> f, boost::filesystem::path p) : Content (f) @@ -35,7 +41,9 @@ DCPContent::DCPContent (shared_ptr<const Film> f, boost::filesystem::path p) , SingleStreamAudioContent (f) , SubtitleContent (f) , _has_subtitles (false) + , _encrypted (false) , _directory (p) + , _kdm_valid (false) { read_directory (p); } @@ -49,6 +57,8 @@ DCPContent::DCPContent (shared_ptr<const Film> f, cxml::ConstNodePtr node, int v _name = node->string_child ("Name"); _has_subtitles = node->bool_child ("HasSubtitles"); _directory = node->string_child ("Directory"); + _encrypted = node->bool_child ("Encrypted"); + _kdm_valid = node->bool_child ("KDMValid"); } void @@ -66,6 +76,8 @@ DCPContent::read_directory (boost::filesystem::path p) void DCPContent::examine (shared_ptr<Job> job) { + bool const could_be_played = can_be_played (); + job->set_progress_unknown (); Content::examine (job); @@ -76,6 +88,12 @@ DCPContent::examine (shared_ptr<Job> job) boost::mutex::scoped_lock lm (_mutex); _name = examiner->name (); _has_subtitles = examiner->has_subtitles (); + _encrypted = examiner->encrypted (); + _kdm_valid = examiner->kdm_valid (); + + if (could_be_played != can_be_played ()) { + signal_changed (DCPContentProperty::CAN_BE_PLAYED); + } } string @@ -106,7 +124,10 @@ DCPContent::as_xml (xmlpp::Node* node) const boost::mutex::scoped_lock lm (_mutex); node->add_child("Name")->add_child_text (_name); node->add_child("HasSubtitles")->add_child_text (_has_subtitles ? "1" : "0"); + node->add_child("Encrypted")->add_child_text (_encrypted ? "1" : "0"); node->add_child("Directory")->add_child_text (_directory.string ()); + /* XXX: KDM */ + node->add_child("KDMValid")->add_child_text (_kdm_valid ? "1" : "0"); } DCPTime @@ -123,9 +144,14 @@ DCPContent::identifier () const return SubtitleContent::identifier (); } +void +DCPContent::add_kdm (dcp::EncryptedKDM k) +{ + _kdm = k; +} + bool -DCPContent::has_subtitles () const +DCPContent::can_be_played () const { - boost::mutex::scoped_lock lm (_mutex); - return _has_subtitles; + return !_encrypted || _kdm_valid; } diff --git a/src/lib/dcp_content.h b/src/lib/dcp_content.h index 60b7142de..da78e6d72 100644 --- a/src/lib/dcp_content.h +++ b/src/lib/dcp_content.h @@ -17,15 +17,26 @@ */ +#ifndef DCPOMATIC_DCP_CONTENT_H +#define DCPOMATIC_DCP_CONTENT_H + /** @file src/lib/dcp_content.h * @brief DCPContent class. */ #include <libcxml/cxml.h> +#include <dcp/encrypted_kdm.h> +#include <dcp/decrypted_kdm.h> #include "video_content.h" #include "single_stream_audio_content.h" #include "subtitle_content.h" +class DCPContentProperty +{ +public: + static int const CAN_BE_PLAYED; +}; + /** @class DCPContent * @brief An existing DCP used as input. */ @@ -48,17 +59,40 @@ public: std::string identifier () const; /* SubtitleContent */ - bool has_subtitles () const; + bool has_subtitles () const { + boost::mutex::scoped_lock lm (_mutex); + return _has_subtitles; + } boost::filesystem::path directory () const { boost::mutex::scoped_lock lm (_mutex); return _directory; } + bool encrypted () const { + boost::mutex::scoped_lock lm (_mutex); + return _encrypted; + } + + void add_kdm (dcp::EncryptedKDM); + + boost::optional<dcp::EncryptedKDM> kdm () const { + return _kdm; + } + + bool can_be_played () const; + private: void read_directory (boost::filesystem::path); std::string _name; bool _has_subtitles; + /** true if our DCP is encrypted */ + bool _encrypted; boost::filesystem::path _directory; + boost::optional<dcp::EncryptedKDM> _kdm; + /** true if _kdm successfully decrypts the first frame of our DCP */ + bool _kdm_valid; }; + +#endif diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index d0642d8b6..bf016ef87 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -31,6 +31,7 @@ #include "dcp_content.h" #include "j2k_image_proxy.h" #include "image.h" +#include "config.h" using std::list; using std::cout; @@ -46,6 +47,9 @@ DCPDecoder::DCPDecoder (shared_ptr<const DCPContent> c, shared_ptr<Log> log) { dcp::DCP dcp (c->directory ()); dcp.read (); + if (c->kdm ()) { + dcp.add (dcp::DecryptedKDM (c->kdm().get (), Config::instance()->decryption_private_key ())); + } assert (dcp.cpls().size() == 1); _reels = dcp.cpls().front()->reels (); _reel = _reels.begin (); @@ -54,7 +58,7 @@ DCPDecoder::DCPDecoder (shared_ptr<const DCPContent> c, shared_ptr<Log> log) bool DCPDecoder::pass () { - if (_reel == _reels.end ()) { + if (_reel == _reels.end () || !_dcp_content->can_be_played ()) { return true; } diff --git a/src/lib/dcp_examiner.cc b/src/lib/dcp_examiner.cc index 625276e18..1e4cc899d 100644 --- a/src/lib/dcp_examiner.cc +++ b/src/lib/dcp_examiner.cc @@ -22,21 +22,38 @@ #include <dcp/reel.h> #include <dcp/reel_picture_asset.h> #include <dcp/reel_sound_asset.h> +#include <dcp/mono_picture_mxf.h> +#include <dcp/mono_picture_frame.h> +#include <dcp/stereo_picture_mxf.h> +#include <dcp/stereo_picture_frame.h> #include <dcp/sound_mxf.h> #include "dcp_examiner.h" #include "dcp_content.h" #include "exceptions.h" +#include "image.h" +#include "config.h" #include "i18n.h" using std::list; +using std::cout; using boost::shared_ptr; +using boost::dynamic_pointer_cast; DCPExaminer::DCPExaminer (shared_ptr<const DCPContent> content) + : _video_length (0) + , _audio_length (0) + , _has_subtitles (false) + , _encrypted (false) + , _kdm_valid (false) { dcp::DCP dcp (content->directory ()); dcp.read (); + if (content->kdm ()) { + dcp.add (dcp::DecryptedKDM (content->kdm().get(), Config::instance()->decryption_private_key ())); + } + if (dcp.cpls().size() == 0) { throw DCPError ("No CPLs found in DCP"); } else if (dcp.cpls().size() > 1) { @@ -89,4 +106,31 @@ DCPExaminer::DCPExaminer (shared_ptr<const DCPContent> content) _has_subtitles = true; } } + + _encrypted = dcp.encrypted (); + _kdm_valid = true; + + /* Check that we can read the first picture frame */ + try { + if (!dcp.cpls().empty () && !dcp.cpls().front()->reels().empty ()) { + shared_ptr<dcp::PictureMXF> mxf = dcp.cpls().front()->reels().front()->main_picture()->mxf (); + shared_ptr<dcp::MonoPictureMXF> mono = dynamic_pointer_cast<dcp::MonoPictureMXF> (mxf); + shared_ptr<dcp::StereoPictureMXF> stereo = dynamic_pointer_cast<dcp::StereoPictureMXF> (mxf); + + shared_ptr<Image> image (new Image (PIX_FMT_RGB24, _video_size.get(), false)); + + if (mono) { + mono->get_frame(0)->rgb_frame (image->data()[0]); + } else { + stereo->get_frame(0)->rgb_frame (dcp::EYE_LEFT, image->data()[0]); + } + + } + } catch (dcp::DCPReadError& e) { + _kdm_valid = false; + if (_encrypted && content->kdm ()) { + /* XXX: maybe don't use an exception for this */ + throw StringError (_("The KDM does not decrypt the DCP. Perhaps it is targeted at the wrong CPL")); + } + } } diff --git a/src/lib/dcp_examiner.h b/src/lib/dcp_examiner.h index 5b510743b..03d43d0f6 100644 --- a/src/lib/dcp_examiner.h +++ b/src/lib/dcp_examiner.h @@ -47,6 +47,10 @@ public: return _has_subtitles; } + bool encrypted () const { + return _encrypted; + } + int audio_channels () const { return _audio_channels.get_value_or (0); } @@ -59,6 +63,10 @@ public: return _audio_frame_rate.get_value_or (48000); } + bool kdm_valid () const { + return _kdm_valid; + } + private: boost::optional<float> _video_frame_rate; boost::optional<dcp::Size> _video_size; @@ -68,4 +76,6 @@ private: ContentTime _audio_length; std::string _name; bool _has_subtitles; + bool _encrypted; + bool _kdm_valid; }; diff --git a/src/lib/film.cc b/src/lib/film.cc index c3194eca8..99a668e37 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -940,6 +940,13 @@ Film::content () const } void +Film::examine_content (shared_ptr<Content> c) +{ + shared_ptr<Job> j (new ExamineContentJob (shared_from_this(), c)); + JobManager::instance()->add (j); +} + +void Film::examine_and_add_content (shared_ptr<Content> c) { if (dynamic_pointer_cast<FFmpegContent> (c)) { @@ -1083,7 +1090,7 @@ Film::make_kdm ( } return dcp::DecryptedKDM ( - cpl, from, until, "DCP-o-matic", cpl->content_title_text(), dcp::LocalTime().as_string() + cpl, key(), from, until, "DCP-o-matic", cpl->content_title_text(), dcp::LocalTime().as_string() ).encrypt (signer, target, formulation); } diff --git a/src/lib/film.h b/src/lib/film.h index 6c3f78895..dea669d98 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -250,6 +250,7 @@ public: void set_directory (boost::filesystem::path); void set_name (std::string); void set_use_isdcf_name (bool); + void examine_content (boost::shared_ptr<Content>); void examine_and_add_content (boost::shared_ptr<Content>); void add_content (boost::shared_ptr<Content>); void remove_content (boost::shared_ptr<Content>); diff --git a/src/lib/player.cc b/src/lib/player.cc index c8ac591a7..06f9e1365 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -31,6 +31,7 @@ #include "subtitle_content.h" #include "subrip_decoder.h" #include "subrip_content.h" +#include "dcp_content.h" #include "playlist.h" #include "job.h" #include "image.h" @@ -189,7 +190,8 @@ Player::content_changed (weak_ptr<Content> w, int property, bool frequent) property == ContentProperty::TRIM_START || property == ContentProperty::TRIM_END || property == ContentProperty::PATH || - property == VideoContentProperty::VIDEO_FRAME_TYPE + property == VideoContentProperty::VIDEO_FRAME_TYPE || + property == DCPContentProperty::CAN_BE_PLAYED ) { _have_valid_pieces = false; diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index a8590ce55..0d9a8fc45 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -192,7 +192,7 @@ VideoContent::take_from_video_examiner (shared_ptr<VideoExaminer> d) dcp::Size const vs = d->video_size (); float const vfr = d->video_frame_rate (); ContentTime vl = d->video_length (); - + { boost::mutex::scoped_lock lm (_mutex); _video_size = vs; |
