Fix creation of dcpdig files in projects that make VFs (#2109).
authorCarl Hetherington <cth@carlh.net>
Mon, 3 Jan 2022 00:11:16 +0000 (00:11 +0000)
committerCarl Hetherington <cth@carlh.net>
Tue, 4 Jan 2022 20:56:40 +0000 (20:56 +0000)
Previously we would always get keys from the project which was
wrong with assets that already have their own key.

src/lib/dcp_digest_file.cc
src/lib/dcp_transcode_job.cc
test/dcp_digest_file_test.cc

index 739cc2b7565d279a8b89ef0c6755b3d86cb04516..9e9ca71147232bf54b6b79347175747f31a54a9e 100644 (file)
@@ -39,7 +39,7 @@ using std::string;
 
 
 template <class R, class A>
-void add_asset(string key, shared_ptr<R> reel_asset, shared_ptr<A> asset, xmlpp::Element* reel, string name)
+void add_asset(string film_key, shared_ptr<R> reel_asset, shared_ptr<A> asset, xmlpp::Element* reel, string name)
 {
        if (asset) {
                auto out = reel->add_child(name);
@@ -47,7 +47,7 @@ void add_asset(string key, shared_ptr<R> reel_asset, shared_ptr<A> asset, xmlpp:
                out->add_child("AnnotationText")->add_child_text(reel_asset->annotation_text());
                if (asset->key_id()) {
                        out->add_child("KeyId")->add_child_text("urn:uuid:" + asset->key_id().get());
-                       out->add_child("Key")->add_child_text(key);
+                       out->add_child("Key")->add_child_text(asset->key() ? asset->key()->hex() : film_key);
                }
        }
 };
@@ -57,7 +57,7 @@ void
 write_dcp_digest_file (
        boost::filesystem::path path,
        shared_ptr<dcp::CPL> cpl,
-       string key
+       string film_key
        )
 {
        xmlpp::Document doc;
@@ -73,13 +73,13 @@ write_dcp_digest_file (
                out_reel->add_child("Id")->add_child_text("urn:uuid:" + in_reel->id());
                out_reel->add_child("AnnotationText");
                if (in_reel->main_picture()) {
-                       add_asset(key, in_reel->main_picture(), in_reel->main_picture()->asset(), out_reel, "MainPicture");
+                       add_asset(film_key, in_reel->main_picture(), in_reel->main_picture()->asset(), out_reel, "MainPicture");
                }
                if (in_reel->main_sound()) {
-                       add_asset(key, in_reel->main_sound(), in_reel->main_sound()->asset(), out_reel, "MainSound");
+                       add_asset(film_key, in_reel->main_sound(), in_reel->main_sound()->asset(), out_reel, "MainSound");
                }
                if (auto smpte_sub = dynamic_pointer_cast<dcp::ReelSMPTESubtitleAsset>(in_reel->main_subtitle())) {
-                       add_asset(key, smpte_sub, smpte_sub->smpte_asset(), out_reel, "MainSubtitle");
+                       add_asset(film_key, smpte_sub, smpte_sub->smpte_asset(), out_reel, "MainSubtitle");
                }
        }
        doc.write_to_file_formatted(path.string());
index 4eb2269b249f7b3eb7c7963471b69dbb4d1acf0f..2d3cc106b38992cb38f87a9010e6dee465ab722b 100644 (file)
@@ -22,6 +22,7 @@
 #include "config.h"
 #include "dcp_content.h"
 #include "dcp_digest_file.h"
+#include "dcp_transcode_job.h"
 #include "film.h"
 #include "job_manager.h"
 #include "upload_job.h"
 #include <dcp/search.h>
 
 
+using std::dynamic_pointer_cast;
 using std::make_shared;
 using std::shared_ptr;
+using std::vector;
 
 
 DCPTranscodeJob::DCPTranscodeJob (shared_ptr<const Film> film, ChangedBehaviour changed)
@@ -47,11 +50,30 @@ DCPTranscodeJob::post_transcode ()
                JobManager::instance()->add(make_shared<UploadJob>(_film));
        }
 
-       dcp::DCP dcp(_film->dir(_film->dcp_name()));
-       dcp.read();
+       /* The first directory is the project's DCP, so the first CPL will also be from the project
+        * (not from one of the DCPs imported into the project).
+        */
+       vector<boost::filesystem::path> all_directories = { _film->dir(_film->dcp_name()) };
+
+       vector<dcp::EncryptedKDM> all_kdms;
+       for (auto content: _film->content()) {
+               if (auto dcp_content = dynamic_pointer_cast<DCPContent>(content)) {
+                       auto directories = dcp_content->directories();
+                       std::copy (directories.begin(), directories.end(), std::back_inserter(all_directories));
+                       if (dcp_content->kdm()) {
+                               all_kdms.push_back (dcp_content->kdm().get());
+                       }
+               }
+       }
+
+       auto cpls = dcp::find_and_resolve_cpls (all_directories, true);
+       DCPOMATIC_ASSERT (!cpls.empty());
+       auto cpl = cpls.front ();
 
-       for (auto cpl: dcp.cpls()) {
-               write_dcp_digest_file (_film->file(cpl->annotation_text().get_value_or(cpl->id()) + ".dcpdig"), cpl, _film->key().hex());
+       for (auto const& kdm: all_kdms) {
+               cpl->add (decrypt_kdm_with_helpful_error(kdm));
        }
+
+       write_dcp_digest_file (_film->file(cpl->annotation_text().get_value_or(cpl->id()) + ".dcpdig"), cpl, _film->key().hex());
 }
 
index 85928b6bbac39421509571c9e4eba4821e09be54..becfd4317a0e9abed8a87f85da0d0c68efe0ba66 100644 (file)
 */
 
 
+#include "lib/config.h"
 #include "lib/content_factory.h"
+#include "lib/dcp_content.h"
 #include "lib/dcp_digest_file.h"
 #include "lib/film.h"
 #include "test.h"
+#include <dcp/cpl.h>
 #include <dcp/dcp.h>
+#include <boost/algorithm/string.hpp>
 #include <boost/test/unit_test.hpp>
 
 
+using std::ifstream;
+using std::make_shared;
+using std::string;
+using boost::optional;
+
+
 BOOST_AUTO_TEST_CASE (dcp_digest_file_test)
 {
        dcp::DCP dcp("test/data/dcp_digest_test_dcp");
@@ -38,3 +48,58 @@ BOOST_AUTO_TEST_CASE (dcp_digest_file_test)
        check_xml ("test/data/digest.xml", "build/test/digest.xml", {});
 }
 
+
+BOOST_AUTO_TEST_CASE (dcp_digest_file_test2)
+{
+       auto get_key_from_digest = [](boost::filesystem::path filename) -> optional<string> {
+               ifstream digest(filename.string().c_str());
+               while (digest.good()) {
+                       string line;
+                       getline (digest, line);
+                       boost::algorithm::trim (line);
+                       if (boost::starts_with(line, "<Key>") && line.length() > 37) {
+                               return line.substr(5, 32);
+                       }
+               }
+
+               return {};
+       };
+
+       auto red = content_factory("test/data/flat_red.png").front();
+       auto ov = new_test_film2 ("dcp_digest_file_test2_ov", { red });
+       ov->set_encrypted (true);
+       make_and_verify_dcp (ov);
+
+       auto ov_key_check = get_key_from_digest ("build/test/dcp_digest_file_test2_ov/" + ov->dcp_name() + ".dcpdig");
+       BOOST_REQUIRE (static_cast<bool>(ov_key_check));
+       BOOST_CHECK_EQUAL (*ov_key_check, ov->key().hex());
+
+       dcp::DCP find_cpl (ov->dir(ov->dcp_name()));
+       find_cpl.read ();
+       BOOST_REQUIRE (!find_cpl.cpls().empty());
+       auto ov_cpl = find_cpl.cpls()[0]->file();
+       BOOST_REQUIRE (static_cast<bool>(ov_cpl));
+
+       auto kdm = ov->make_kdm (
+               Config::instance()->decryption_chain()->leaf(),
+               {},
+               ov_cpl.get(),
+               dcp::LocalTime(), dcp::LocalTime(),
+               dcp::Formulation::MODIFIED_TRANSITIONAL_1,
+               true,
+               0
+               );
+
+       auto ov_dcp = make_shared<DCPContent>(ov->dir(ov->dcp_name()));
+       ov_dcp->add_kdm (kdm);
+       ov_dcp->set_reference_video (true);
+       ov_dcp->set_reference_audio (true);
+       auto vf = new_test_film2 ("dcp_digest_file_test2_vf", { ov_dcp });
+       vf->set_encrypted (true);
+       make_and_verify_dcp (vf, {dcp::VerificationNote::Code::EXTERNAL_ASSET});
+
+       auto vf_key_check = get_key_from_digest ("build/test/dcp_digest_file_test2_vf/" + vf->dcp_name() + ".dcpdig");
+       BOOST_REQUIRE (static_cast<bool>(vf_key_check));
+       BOOST_CHECK_EQUAL (*vf_key_check, ov->key().hex());
+}
+