summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2025-10-31 00:03:49 +0100
committerCarl Hetherington <cth@carlh.net>2025-11-05 00:43:19 +0100
commite8ce097ce705446c27b51199a321a9918deaa0db (patch)
tree0a52cbc9c52791d453fa4bd478609aedde98c831 /src/lib
parentef65a179e8c907029d0d9254863d4884581f3d60 (diff)
Allow specification of which parts of the DCP to encrypt (#3099).
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/copy_dcp_details_to_film.cc4
-rw-r--r--src/lib/create_cli.cc8
-rw-r--r--src/lib/dcp_content.cc20
-rw-r--r--src/lib/dcp_content.h25
-rw-r--r--src/lib/dcp_examiner.cc18
-rw-r--r--src/lib/dcp_examiner.h16
-rw-r--r--src/lib/film.cc44
-rw-r--r--src/lib/film.h25
-rw-r--r--src/lib/film_property.h4
-rw-r--r--src/lib/reel_writer.cc8
-rw-r--r--src/lib/writer.cc2
11 files changed, 142 insertions, 32 deletions
diff --git a/src/lib/copy_dcp_details_to_film.cc b/src/lib/copy_dcp_details_to_film.cc
index 9e0ad79c1..67a207de1 100644
--- a/src/lib/copy_dcp_details_to_film.cc
+++ b/src/lib/copy_dcp_details_to_film.cc
@@ -45,7 +45,9 @@ copy_dcp_settings_to_film(shared_ptr<const DCPContent> dcp, shared_ptr<Film> fil
if (dcp->content_kind()) {
film->set_dcp_content_type(DCPContentType::from_libdcp_kind(dcp->content_kind().get()));
}
- film->set_encrypted(dcp->encrypted());
+ film->set_encrypt_picture(dcp->picture_encrypted());
+ film->set_encrypt_sound(dcp->sound_encrypted());
+ film->set_encrypt_text(dcp->text_encrypted());
film->set_reel_type(ReelType::BY_VIDEO_CONTENT);
film->set_interop(dcp->standard() == dcp::Standard::INTEROP);
film->set_three_d(dcp->three_d());
diff --git a/src/lib/create_cli.cc b/src/lib/create_cli.cc
index af2e90745..32834be23 100644
--- a/src/lib/create_cli.cc
+++ b/src/lib/create_cli.cc
@@ -473,9 +473,13 @@ CreateCLI::make_film(function<void (string)> error) const
}
film->set_use_isdcf_name(!_no_use_isdcf_name);
if (_no_encrypt) {
- film->set_encrypted(false);
+ film->set_encrypt_picture(false);
+ film->set_encrypt_sound(false);
+ film->set_encrypt_text(false);
} else if (_encrypt) {
- film->set_encrypted(true);
+ film->set_encrypt_picture(true);
+ film->set_encrypt_sound(true);
+ film->set_encrypt_text(true);
}
if (_twod) {
film->set_three_d(false);
diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc
index cff14deca..c75babfc6 100644
--- a/src/lib/dcp_content.cc
+++ b/src/lib/dcp_content.cc
@@ -66,7 +66,9 @@ using namespace dcpomatic;
DCPContent::DCPContent(boost::filesystem::path p)
- : _encrypted(false)
+ : _picture_encrypted(false)
+ , _sound_encrypted(false)
+ , _text_encrypted(false)
, _needs_assets(false)
, _kdm_valid(false)
, _reference_video(false)
@@ -103,7 +105,10 @@ DCPContent::DCPContent(cxml::ConstNodePtr node, boost::optional<boost::filesyste
}
_name = node->string_child("Name");
- _encrypted = node->bool_child("Encrypted");
+ auto encrypted = node->optional_bool_child("Encrypted").get_value_or(false);
+ _picture_encrypted = node->optional_bool_child("PictureEncrypted").get_value_or(encrypted);
+ _sound_encrypted = node->optional_bool_child("SoundEncrypted").get_value_or(encrypted);
+ _text_encrypted = node->optional_bool_child("TextEncrypted").get_value_or(encrypted);
_needs_assets = node->optional_bool_child("NeedsAssets").get_value_or(false);
if (node->optional_node_child("KDM")) {
_kdm = dcp::EncryptedKDM(node->string_child("KDM"));
@@ -314,7 +319,9 @@ DCPContent::examine(shared_ptr<const Film> film, shared_ptr<Job> job, bool toler
boost::mutex::scoped_lock lm(_mutex);
text = new_text;
_name = examiner->name();
- _encrypted = examiner->encrypted();
+ _picture_encrypted = examiner->picture_encrypted();
+ _sound_encrypted = examiner->sound_encrypted();
+ _text_encrypted = examiner->text_encrypted();
_needs_assets = examiner->needs_assets();
_kdm_valid = examiner->kdm_valid();
_standard = examiner->standard();
@@ -396,7 +403,10 @@ DCPContent::as_xml(xmlpp::Element* element, bool with_paths, PathBehaviour path_
boost::mutex::scoped_lock lm(_mutex);
cxml::add_text_child(element, "Name", _name);
- cxml::add_text_child(element, "Encrypted", _encrypted ? "1" : "0");
+ cxml::add_text_child(element, "Encrypted", (_picture_encrypted || _sound_encrypted || _text_encrypted) ? "1" : "0");
+ cxml::add_text_child(element, "PictureEncrypted", _picture_encrypted ? "1" : "0");
+ cxml::add_text_child(element, "SoundEncrypted", _sound_encrypted ? "1" : "0");
+ cxml::add_text_child(element, "TextEncrypted", _text_encrypted ? "1" : "0");
cxml::add_text_child(element, "NeedsAssets", _needs_assets ? "1" : "0");
if (_kdm) {
cxml::add_text_child(element, "KDM", _kdm->as_xml());
@@ -526,7 +536,7 @@ bool
DCPContent::needs_kdm() const
{
boost::mutex::scoped_lock lm(_mutex);
- return _encrypted && !_kdm_valid;
+ return (_picture_encrypted || _sound_encrypted || _text_encrypted) && !_kdm_valid;
}
bool
diff --git a/src/lib/dcp_content.h b/src/lib/dcp_content.h
index 1b58c8efc..97e4b3cc4 100644
--- a/src/lib/dcp_content.h
+++ b/src/lib/dcp_content.h
@@ -97,7 +97,25 @@ public:
bool encrypted() const {
boost::mutex::scoped_lock lm(_mutex);
- return _encrypted;
+ return _picture_encrypted || _sound_encrypted || _text_encrypted;
+ }
+
+ /** @return true if any picture asset in this DCP is encrypted */
+ bool picture_encrypted() const {
+ boost::mutex::scoped_lock lm(_mutex);
+ return _picture_encrypted;
+ }
+
+ /** @return true if any sound asset in this DCP is encrypted */
+ bool sound_encrypted() const {
+ boost::mutex::scoped_lock lm(_mutex);
+ return _sound_encrypted;
+ }
+
+ /** @return true if any text asset in this DCP is encrypted */
+ bool text_encrypted() const {
+ boost::mutex::scoped_lock lm(_mutex);
+ return _text_encrypted;
}
void add_kdm(dcp::EncryptedKDM);
@@ -217,8 +235,9 @@ private:
bool overlaps(std::shared_ptr<const Film> film, std::function<bool (std::shared_ptr<const Content>)> part) const;
std::string _name;
- /** true if our DCP is encrypted */
- bool _encrypted;
+ bool _picture_encrypted;
+ bool _sound_encrypted;
+ bool _text_encrypted;
/** true if this DCP needs more assets before it can be played */
bool _needs_assets;
boost::optional<dcp::EncryptedKDM> _kdm;
diff --git a/src/lib/dcp_examiner.cc b/src/lib/dcp_examiner.cc
index 59bd47702..b94d88486 100644
--- a/src/lib/dcp_examiner.cc
+++ b/src/lib/dcp_examiner.cc
@@ -313,7 +313,23 @@ DCPExaminer::DCPExaminer(shared_ptr<const DCPContent> content, bool tolerant)
++reel_index;
}
- _encrypted = selected_cpl->any_encrypted();
+ for (auto reel: selected_cpl->reels()) {
+ if (reel->main_picture() && reel->main_picture()->encrypted()) {
+ _picture_encrypted = true;
+ }
+ if (reel->main_sound() && reel->main_sound()->encrypted()) {
+ _sound_encrypted = true;
+ }
+ if (reel->main_subtitle() && reel->main_subtitle()->encrypted()) {
+ _text_encrypted = true;
+ }
+ for (auto cc: reel->closed_captions()) {
+ if (cc->encrypted()) {
+ _text_encrypted = true;
+ }
+ }
+ }
+
_kdm_valid = true;
LOG_GENERAL_NC("Check that everything encrypted has a key");
diff --git a/src/lib/dcp_examiner.h b/src/lib/dcp_examiner.h
index 0a6045ed0..6bc9793aa 100644
--- a/src/lib/dcp_examiner.h
+++ b/src/lib/dcp_examiner.h
@@ -76,8 +76,16 @@ public:
return _name;
}
- bool encrypted() const {
- return _encrypted;
+ bool picture_encrypted() const {
+ return _picture_encrypted;
+ }
+
+ bool sound_encrypted() const {
+ return _sound_encrypted;
+ }
+
+ bool text_encrypted() const {
+ return _text_encrypted;
}
bool needs_assets() const {
@@ -216,7 +224,9 @@ private:
std::vector<DCPTextTrack> _dcp_subtitle_tracks;
/** the DCPTextTracks for each of our closed captions */
std::vector<DCPTextTrack> _dcp_caption_tracks;
- bool _encrypted = false;
+ bool _picture_encrypted = false;
+ bool _sound_encrypted = false;
+ bool _text_encrypted = false;
bool _needs_assets = false;
bool _kdm_valid = false;
boost::optional<dcp::Standard> _standard;
diff --git a/src/lib/film.cc b/src/lib/film.cc
index 8dc55c590..b8f983add 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -168,7 +168,9 @@ Film::Film(optional<boost::filesystem::path> dir)
, _dcp_content_type(DCPContentType::from_isdcf_name("FTR"))
, _container(Ratio::from_id("185"))
, _resolution(Resolution::TWO_K)
- , _encrypted(false)
+ , _encrypt_picture(false)
+ , _encrypt_sound(false)
+ , _encrypt_text(false)
, _context_id(dcp::make_uuid())
, _video_frame_rate(24)
, _audio_channels(6)
@@ -418,7 +420,11 @@ Film::metadata(bool with_content_paths) const
cxml::add_text_child(root, "Interop", _interop ? "1" : "0");
cxml::add_text_child(root, "VideoEncoding", video_encoding_to_string(_video_encoding));
cxml::add_text_child(root, "LimitToSMPTEBv20", _limit_to_smpte_bv20 ? "1" : "0");
- cxml::add_text_child(root, "Encrypted", _encrypted ? "1" : "0");
+ /* We don't need this any more, but writing it makes the metadata backwards compatible */
+ cxml::add_text_child(root, "Encrypted", encrypted() ? "1" : "0");
+ cxml::add_text_child(root, "EncryptPicture", _encrypt_picture ? "1" : "0");
+ cxml::add_text_child(root, "EncryptSound", _encrypt_sound ? "1" : "0");
+ cxml::add_text_child(root, "EncryptText", _encrypt_text ? "1" : "0");
cxml::add_text_child(root, "Key", _key.hex());
cxml::add_text_child(root, "ContextID", _context_id);
if (_audio_processor) {
@@ -593,7 +599,10 @@ Film::read_metadata(optional<boost::filesystem::path> path)
_video_bit_rate[VideoEncoding::MPEG2] = f.optional_number_child<int64_t>("MPEG2VideoBitRate").get_value_or(Config::instance()->default_video_bit_rate(VideoEncoding::MPEG2));
_video_frame_rate = f.number_child<int>("VideoFrameRate");
_audio_frame_rate = f.optional_number_child<int>("AudioFrameRate").get_value_or(48000);
- _encrypted = f.bool_child("Encrypted");
+ auto encrypted = f.optional_bool_child("Encrypted").get_value_or(false);
+ _encrypt_picture = f.optional_bool_child("EncryptPicture").get_value_or(encrypted);
+ _encrypt_sound = f.optional_bool_child("EncryptSound").get_value_or(encrypted);
+ _encrypt_text = f.optional_bool_child("EncryptText").get_value_or(encrypted);
_audio_channels = f.number_child<int>("AudioChannels");
/* We used to allow odd numbers (and zero) channels, but it's just not worth
the pain.
@@ -1423,12 +1432,29 @@ Film::cpls() const
}
void
-Film::set_encrypted(bool e)
+Film::set_encrypt_picture(bool e)
{
- FilmChangeSignaller ch(this, FilmProperty::ENCRYPTED);
- _encrypted = e;
+ FilmChangeSignaller ch(this, FilmProperty::ENCRYPT_PICTURE);
+ _encrypt_picture = e;
}
+
+void
+Film::set_encrypt_sound(bool e)
+{
+ FilmChangeSignaller ch(this, FilmProperty::ENCRYPT_SOUND);
+ _encrypt_sound = e;
+}
+
+
+void
+Film::set_encrypt_text(bool e)
+{
+ FilmChangeSignaller ch(this, FilmProperty::ENCRYPT_TEXT);
+ _encrypt_text = e;
+}
+
+
ContentList
Film::content() const
{
@@ -1859,7 +1885,7 @@ Film::active_area() const
dcp::DecryptedKDM
Film::make_kdm(boost::filesystem::path cpl_file, dcp::LocalTime from, dcp::LocalTime until) const
{
- if (!_encrypted) {
+ if (!encrypted()) {
throw runtime_error(_("Cannot make a KDM as this project is not encrypted."));
}
@@ -2102,7 +2128,9 @@ Film::use_template(optional<string> name)
_video_bit_rate[encoding] = _template_film->_video_bit_rate[encoding];
}
_video_frame_rate = _template_film->_video_frame_rate;
- _encrypted = _template_film->_encrypted;
+ _encrypt_picture = _template_film->_encrypt_picture;
+ _encrypt_sound = _template_film->_encrypt_sound;
+ _encrypt_text = _template_film->_encrypt_text;
_audio_channels = _template_film->_audio_channels;
_sequence = _template_film->_sequence;
_three_d = _template_film->_three_d;
diff --git a/src/lib/film.h b/src/lib/film.h
index 6d04da9bf..adaff3c52 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -231,7 +231,19 @@ public:
}
bool encrypted() const {
- return _encrypted;
+ return _encrypt_picture || _encrypt_sound || _encrypt_text;
+ }
+
+ bool encrypt_picture() const {
+ return _encrypt_picture;
+ }
+
+ bool encrypt_sound() const {
+ return _encrypt_sound;
+ }
+
+ bool encrypt_text() const {
+ return _encrypt_text;
}
dcp::Key key() const {
@@ -392,7 +404,9 @@ public:
void set_dcp_content_type(DCPContentType const *);
void set_container(Ratio c, bool user_explicit = true);
void set_resolution(Resolution, bool user_explicit = true);
- void set_encrypted(bool);
+ void set_encrypt_picture(bool);
+ void set_encrypt_sound(bool);
+ void set_encrypt_text(bool);
void set_video_bit_rate(VideoEncoding encoding, int64_t);
void set_video_frame_rate(int rate, bool user_explicit = false);
void set_audio_channels(int);
@@ -512,7 +526,12 @@ private:
Ratio _container;
/** DCP resolution (2K or 4K) */
Resolution _resolution;
- bool _encrypted;
+ /** Encrypt picture assets */
+ bool _encrypt_picture;
+ /** Encrypt sound assets */
+ bool _encrypt_sound;
+ /** Encrypt text (subtitle/closed-caption) assets */
+ bool _encrypt_text;
dcp::Key _key;
/** context ID used when encrypting picture assets; we keep it so that we can
* re-start picture MXF encodes.
diff --git a/src/lib/film_property.h b/src/lib/film_property.h
index ebda0e807..5c38ae986 100644
--- a/src/lib/film_property.h
+++ b/src/lib/film_property.h
@@ -38,7 +38,9 @@ enum class FilmProperty {
DCP_CONTENT_TYPE,
CONTAINER,
RESOLUTION,
- ENCRYPTED,
+ ENCRYPT_PICTURE,
+ ENCRYPT_SOUND,
+ ENCRYPT_TEXT,
VIDEO_BIT_RATE,
VIDEO_FRAME_RATE,
AUDIO_FRAME_RATE,
diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc
index 01a798676..1d5a16075 100644
--- a/src/lib/reel_writer.cc
+++ b/src/lib/reel_writer.cc
@@ -146,7 +146,7 @@ ReelWriter::ReelWriter(
asset->set_size(film()->frame_size());
asset->set_metadata(mxf_metadata());
- if (film()->encrypted()) {
+ if (film()->encrypt_picture()) {
asset->set_key(film()->key());
asset->set_context_id(film()->context_id());
}
@@ -218,7 +218,7 @@ ReelWriter::ReelWriter(
_sound_asset->set_metadata(mxf_metadata());
- if (film()->encrypted()) {
+ if (film()->encrypt_sound()) {
_sound_asset->set_key(film()->key());
}
@@ -310,7 +310,7 @@ ReelWriter::write(shared_ptr<const dcp::AtmosFrame> atmos, AtmosMetadata metadat
{
if (!_atmos_asset) {
_atmos_asset = metadata.create(dcp::Fraction(film()->video_frame_rate(), 1));
- if (film()->encrypted()) {
+ if (film()->encrypt_sound()) {
_atmos_asset->set_key(film()->key());
}
_atmos_asset_writer = _atmos_asset->start_write(
@@ -820,7 +820,7 @@ ReelWriter::empty_text_asset(TextType type, optional<DCPTextTrack> track, bool w
s->set_reel_number(_reel_index + 1);
s->set_time_code_rate(film()->video_frame_rate());
s->set_start_time(dcp::Time());
- if (film()->encrypted()) {
+ if (film()->encrypt_text()) {
s->set_key(film()->key());
}
asset = s;
diff --git a/src/lib/writer.cc b/src/lib/writer.cc
index 7121c594b..41e831e94 100644
--- a/src/lib/writer.cc
+++ b/src/lib/writer.cc
@@ -723,7 +723,7 @@ Writer::finish()
bool
Writer::can_fake_write(Frame frame) const
{
- if (film()->encrypted()) {
+ if (film()->encrypt_picture()) {
/* We need to re-write the frame because the asset ID is embedded in the HMAC... I think... */
return false;
}