void
Reel::add (DecryptedKDM const & kdm)
{
- auto keys = kdm.keys ();
+ give_kdm_to_assets (kdm);
+ /* We have to keep the KDMs that we are given, as they will not be passed to unresolved assets.
+ * After we resolve some assets we will re-call give_kdm_to_assets() with all the KDMs that
+ * we have been given so far.
+ */
+ _kdms.push_back (kdm);
+}
+
- for (auto const& i: keys) {
- if (_main_picture && i.id() == _main_picture->key_id()) {
+void
+Reel::give_kdm_to_assets (DecryptedKDM const & kdm)
+{
+ for (auto const& i: kdm.keys()) {
+ if (_main_picture && i.id() == _main_picture->key_id() && _main_picture->asset_ref().resolved()) {
_main_picture->asset()->set_key (i.key());
}
- if (_main_sound && i.id() == _main_sound->key_id()) {
+ if (_main_sound && i.id() == _main_sound->key_id() && _main_sound->asset_ref().resolved()) {
_main_sound->asset()->set_key (i.key());
}
if (_main_subtitle) {
auto smpte = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(_main_subtitle);
- if (smpte && i.id() == smpte->key_id()) {
+ if (smpte && i.id() == smpte->key_id() && smpte->asset_ref().resolved()) {
smpte->smpte_asset()->set_key(i.key());
}
}
for (auto j: _closed_captions) {
auto smpte = dynamic_pointer_cast<ReelSMPTESubtitleAsset>(j);
- if (smpte && i.id() == smpte->key_id()) {
+ if (smpte && i.id() == smpte->key_id() && smpte->asset_ref().resolved()) {
smpte->smpte_asset()->set_key(i.key());
}
}
- if (_atmos && i.id() == _atmos->key_id()) {
+ if (_atmos && i.id() == _atmos->key_id() && _atmos->asset_ref().resolved()) {
_atmos->asset()->set_key (i.key());
}
}
if (_atmos) {
_atmos->asset_ref().resolve (assets);
}
+
+ for (auto const& i: _kdms) {
+ give_kdm_to_assets (i);
+ }
}
#define LIBDCP_REEL_H
+#include "decrypted_kdm.h"
#include "key.h"
-#include "types.h"
#include "ref.h"
-#include <memory>
+#include "types.h"
#include <boost/function.hpp>
+#include <memory>
namespace cxml {
void resolve_refs (std::vector<std::shared_ptr<Asset>>);
private:
+ void give_kdm_to_assets (dcp::DecryptedKDM const& kdm);
+
std::shared_ptr<ReelPictureAsset> _main_picture;
std::shared_ptr<ReelSoundAsset> _main_sound;
std::shared_ptr<ReelSubtitleAsset> _main_subtitle;
std::shared_ptr<ReelMarkersAsset> _main_markers;
std::vector<std::shared_ptr<ReelClosedCaptionAsset>> _closed_captions;
std::shared_ptr<ReelAtmosAsset> _atmos;
+
+ std::vector<dcp::DecryptedKDM> _kdms;
};
}
extern std::shared_ptr<dcp::SoundAsset> simple_sound (
- boost::filesystem::path path, std::string suffix, dcp::MXFMetadata mxf_meta, std::string language, int frames, int sample_rate
+ boost::filesystem::path path, std::string suffix, dcp::MXFMetadata mxf_meta, std::string language, int frames, int sample_rate, boost::optional<dcp::Key>
);
private:
friend class SoundAssetWriter;
friend std::shared_ptr<dcp::SoundAsset> (::simple_sound) (
- boost::filesystem::path path, std::string suffix, dcp::MXFMetadata mxf_meta, std::string language, int frames, int sample_rate
+ boost::filesystem::path path, std::string suffix, dcp::MXFMetadata mxf_meta, std::string language, int frames, int sample_rate, boost::optional<dcp::Key>
);
std::string pkl_type (Standard standard) const override {
#include "picture_asset_writer.h"
#include "reel.h"
#include "reel_mono_picture_asset.h"
+#include "reel_sound_asset.h"
+#include "reel_smpte_subtitle_asset.h"
+#include "smpte_subtitle_asset.h"
#include "test.h"
#include "types.h"
#include "util.h"
#include <boost/test/unit_test.hpp>
-using std::list;
-using std::string;
-using std::vector;
+using std::dynamic_pointer_cast;
using std::make_shared;
using std::shared_ptr;
+using std::string;
+using std::vector;
using boost::optional;
dcp::BadKDMDateError
);
}
+
+
+/** Test the case where we have:
+ * - a OV + VF
+ * - a single KDM which has keys for both OV and VF assets
+ * and we load VF, then KDM, then the OV. The OV's assets should have their
+ * KDMs properly assigned.
+ */
+BOOST_AUTO_TEST_CASE (vf_kdm_test)
+{
+ /* Make OV */
+
+ boost::filesystem::path const ov_path = "build/test/vf_kdm_test_ov";
+ boost::filesystem::path const vf_path = "build/test/vf_kdm_test_vf";
+ dcp::Key key;
+
+ auto ov = make_simple(ov_path, 1, 48, dcp::Standard::SMPTE, key);
+ ov->write_xml ();
+
+ auto ov_reel = ov->cpls()[0]->reels()[0];
+ auto ov_reel_picture = make_shared<dcp::ReelMonoPictureAsset>(dynamic_pointer_cast<dcp::ReelMonoPictureAsset>(ov_reel->main_picture())->mono_asset(), 0);
+ auto ov_reel_sound = make_shared<dcp::ReelSoundAsset>(ov_reel->main_sound()->asset(), 0);
+
+ /* Make VF */
+
+ auto subs = make_shared<dcp::SMPTESubtitleAsset>();
+ subs->add(simple_subtitle());
+ subs->set_key(key);
+
+ boost::filesystem::remove_all (vf_path);
+ boost::filesystem::create_directory (vf_path);
+ dcp::ArrayData data(4096);
+ subs->add_font ("afont", data);
+ subs->write (vf_path / "subs.xml");
+
+ auto reel_subs = make_shared<dcp::ReelSMPTESubtitleAsset>(subs, dcp::Fraction(24, 1), 192, 0);
+
+ auto reel = make_shared<dcp::Reel>(ov_reel_picture, ov_reel_sound, reel_subs);
+
+ auto cpl = make_shared<dcp::CPL>("A Test DCP", dcp::ContentKind::TRAILER, dcp::Standard::SMPTE);
+ cpl->add (reel);
+
+ auto vf = make_shared<dcp::DCP>("build/test/vf_kdm_test_vf");
+ vf->add (cpl);
+ vf->write_xml ();
+
+ /* Make KDM for VF */
+
+ auto kdm = dcp::DecryptedKDM(
+ cpl,
+ key,
+ dcp::LocalTime ("2016-01-01T00:00:00+00:00"),
+ dcp::LocalTime ("2017-01-08T00:00:00+00:00"),
+ "libdcp",
+ "test",
+ "2012-07-17T04:45:18+00:00"
+ );
+
+ /* Decrypt VF with the KDM */
+
+ dcp::DCP reload_vf(vf_path);
+ reload_vf.read();
+ reload_vf.add (kdm);
+
+ /* Add the OV */
+
+ dcp::DCP reload_ov(ov_path);
+ reload_ov.read();
+ reload_vf.resolve_refs(reload_ov.assets());
+
+ /* Check that we can decrypt the VF */
+
+ BOOST_REQUIRE_EQUAL(reload_vf.cpls().size(), 1U);
+ BOOST_REQUIRE_EQUAL(reload_vf.cpls()[0]->reels().size(), 1U);
+ BOOST_REQUIRE(reload_vf.cpls()[0]->reels()[0]->main_picture());
+ BOOST_REQUIRE(reload_vf.cpls()[0]->reels()[0]->main_picture()->asset());
+ auto mono_asset = dynamic_pointer_cast<dcp::MonoPictureAsset>(reload_vf.cpls()[0]->reels()[0]->main_picture()->asset());
+ BOOST_REQUIRE(mono_asset);
+ auto reader = mono_asset->start_read();
+ reader->set_check_hmac(false);
+ reader->get_frame(0)->xyz_image();
+}
shared_ptr<dcp::MonoPictureAsset>
-simple_picture (boost::filesystem::path path, string suffix, int frames)
+simple_picture (boost::filesystem::path path, string suffix, int frames, optional<dcp::Key> key)
{
dcp::MXFMetadata mxf_meta;
mxf_meta.company_name = "OpenDCP";
mxf_meta.product_name = "OpenDCP";
mxf_meta.product_version = "0.0.25";
- shared_ptr<dcp::MonoPictureAsset> mp (new dcp::MonoPictureAsset (dcp::Fraction (24, 1), dcp::Standard::SMPTE));
+ auto mp = make_shared<dcp::MonoPictureAsset>(dcp::Fraction (24, 1), dcp::Standard::SMPTE);
mp->set_metadata (mxf_meta);
- shared_ptr<dcp::PictureAssetWriter> picture_writer = mp->start_write (path / dcp::String::compose("video%1.mxf", suffix), false);
+ if (key) {
+ mp->set_key (*key);
+ }
+ auto picture_writer = mp->start_write (path / dcp::String::compose("video%1.mxf", suffix), false);
dcp::Size const size (1998, 1080);
auto image = make_shared<dcp::OpenJPEGImage>(size);
shared_ptr<dcp::SoundAsset>
-simple_sound (boost::filesystem::path path, string suffix, dcp::MXFMetadata mxf_meta, string language, int frames, int sample_rate)
+simple_sound (boost::filesystem::path path, string suffix, dcp::MXFMetadata mxf_meta, string language, int frames, int sample_rate, optional<dcp::Key> key)
{
int const channels = 6;
/* Set a valid language, then overwrite it, so that the language parameter can be badly formed */
- shared_ptr<dcp::SoundAsset> ms (new dcp::SoundAsset(dcp::Fraction(24, 1), sample_rate, channels, dcp::LanguageTag("en-US"), dcp::Standard::SMPTE));
+ auto ms = make_shared<dcp::SoundAsset>(dcp::Fraction(24, 1), sample_rate, channels, dcp::LanguageTag("en-US"), dcp::Standard::SMPTE);
+ if (key) {
+ ms->set_key (*key);
+ }
ms->_language = language;
ms->set_metadata (mxf_meta);
shared_ptr<dcp::SoundAssetWriter> sound_writer = ms->start_write (path / dcp::String::compose("audio%1.mxf", suffix));
shared_ptr<dcp::DCP>
-make_simple (boost::filesystem::path path, int reels, int frames, dcp::Standard standard)
+make_simple (boost::filesystem::path path, int reels, int frames, dcp::Standard standard, optional<dcp::Key> key)
{
/* Some known metadata */
dcp::MXFMetadata mxf_meta;
mxf_meta.product_name = "OpenDCP";
mxf_meta.product_version = "0.0.25";
+ auto constexpr sample_rate = 48000;
+
boost::filesystem::remove_all (path);
boost::filesystem::create_directories (path);
auto d = make_shared<dcp::DCP>(path);
dcp::ContentVersion("urn:uuid:75ac29aa-42ac-1234-ecae-49251abefd11", "content-version-label-text")
);
cpl->set_main_sound_configuration("51/L,R,C,LFE,Ls,Rs");
- cpl->set_main_sound_sample_rate(48000);
+ cpl->set_main_sound_sample_rate(sample_rate);
cpl->set_main_picture_stored_area(dcp::Size(1998, 1080));
cpl->set_main_picture_active_area(dcp::Size(1998, 1080));
cpl->set_version_number(1);
for (int i = 0; i < reels; ++i) {
string suffix = reels == 1 ? "" : dcp::String::compose("%1", i);
- shared_ptr<dcp::MonoPictureAsset> mp = simple_picture (path, suffix, frames);
- shared_ptr<dcp::SoundAsset> ms = simple_sound (path, suffix, mxf_meta, "en-US", frames);
+ auto mp = simple_picture (path, suffix, frames, key);
+ auto ms = simple_sound (path, suffix, mxf_meta, "en-US", frames, sample_rate, key);
auto reel = make_shared<dcp::Reel>(
shared_ptr<dcp::ReelMonoPictureAsset>(new dcp::ReelMonoPictureAsset(mp, 0)),
extern void check_xml (xmlpp::Element* ref, xmlpp::Element* test, std::vector<std::string> ignore_tags, bool ignore_whitespace = false);
extern void check_xml (std::string ref, std::string test, std::vector<std::string> ignore, bool ignore_whitespace = false);
extern void check_file (boost::filesystem::path ref, boost::filesystem::path check);
-extern std::shared_ptr<dcp::MonoPictureAsset> simple_picture (boost::filesystem::path path, std::string suffix, int frames = 24);
-extern std::shared_ptr<dcp::SoundAsset> simple_sound (boost::filesystem::path path, std::string suffix, dcp::MXFMetadata mxf_meta, std::string language, int frames = 24, int sample_rate = 48000);
+extern std::shared_ptr<dcp::MonoPictureAsset> simple_picture (
+ boost::filesystem::path path,
+ std::string suffix,
+ int frames = 24,
+ boost::optional<dcp::Key> key = boost::optional<dcp::Key>()
+ );
+extern std::shared_ptr<dcp::SoundAsset> simple_sound (
+ boost::filesystem::path path,
+ std::string suffix,
+ dcp::MXFMetadata mxf_meta,
+ std::string language,
+ int frames = 24,
+ int sample_rate = 48000,
+ boost::optional<dcp::Key> key = boost::optional<dcp::Key>()
+ );
extern std::shared_ptr<dcp::Subtitle> simple_subtitle ();
extern std::shared_ptr<dcp::ReelMarkersAsset> simple_markers (int frames = 24);
-extern std::shared_ptr<dcp::DCP> make_simple (boost::filesystem::path path, int reels = 1, int frames = 24, dcp::Standard = dcp::Standard::SMPTE);
+extern std::shared_ptr<dcp::DCP> make_simple (
+ boost::filesystem::path path,
+ int reels = 1,
+ int frames = 24,
+ dcp::Standard = dcp::Standard::SMPTE,
+ boost::optional<dcp::Key> key = boost::optional<dcp::Key>()
+ );
extern std::shared_ptr<dcp::DCP> make_simple_with_interop_subs (boost::filesystem::path path);
extern std::shared_ptr<dcp::DCP> make_simple_with_smpte_subs (boost::filesystem::path path);
extern std::shared_ptr<dcp::DCP> make_simple_with_interop_ccaps (boost::filesystem::path path);
auto reel_picture = make_shared<dcp::ReelMonoPictureAsset>(picture, 0);
auto reel = make_shared<dcp::Reel>();
reel->add (reel_picture);
- auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "de-DE", 24, 96000);
+ auto sound = simple_sound (dir, "foo", dcp::MXFMetadata(), "de-DE", 24, 96000, boost::none);
auto reel_sound = make_shared<dcp::ReelSoundAsset>(sound, 0);
reel->add (reel_sound);
reel->add (simple_markers());