summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2025-12-08 23:54:25 +0100
committerCarl Hetherington <cth@carlh.net>2025-12-09 02:38:50 +0100
commit1df6f4a08a2f3b67c1637068ae4714c1cba2e1e7 (patch)
tree92be307e0ba7a6659b8943245d44703d48354bb2
parentf043af026316728c4ac2b84357a77d84082c06a1 (diff)
Add DCP::cpl_summaries().v1.10.42
DCP-o-matic needs to know some basic CPL details as quickly as possible, and this is faster than doing read() and then cpls().
-rw-r--r--src/cpl_summary.h80
-rw-r--r--src/dcp.cc53
-rw-r--r--src/dcp.h7
-rw-r--r--src/wscript1
-rw-r--r--test/cpl_summary_test.cc115
-rw-r--r--test/wscript1
6 files changed, 257 insertions, 0 deletions
diff --git a/src/cpl_summary.h b/src/cpl_summary.h
new file mode 100644
index 00000000..1475fad5
--- /dev/null
+++ b/src/cpl_summary.h
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2025 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#ifndef LIBDCP_CPL_SUMMARY_H
+#define LIBDCP_CPL_SUMMARY_H
+
+
+#include <boost/filesystem.hpp>
+#include <boost/optional.hpp>
+#include <string>
+
+
+namespace dcp {
+
+
+class CPLSummary
+{
+public:
+ CPLSummary(
+ boost::filesystem::path dcp_directory_,
+ std::string cpl_id_,
+ boost::optional<std::string> annotation_text_,
+ boost::filesystem::path cpl_file_,
+ bool encrypted_,
+ time_t last_write_time_
+ )
+ : dcp_directory(dcp_directory_)
+ , cpl_id(cpl_id_)
+ , cpl_annotation_text(annotation_text_)
+ , cpl_file(cpl_file_)
+ , encrypted(encrypted_)
+ , last_write_time(last_write_time_)
+ {}
+
+ boost::filesystem::path dcp_directory;
+ std::string cpl_id;
+ boost::optional<std::string> cpl_annotation_text;
+ boost::filesystem::path cpl_file;
+ /** true if this CPL has any encrypted assets */
+ bool encrypted;
+ time_t last_write_time;
+};
+
+
+}
+
+
+#endif
+
diff --git a/src/dcp.cc b/src/dcp.cc
index 3ba62d35..a4ac3eb3 100644
--- a/src/dcp.cc
+++ b/src/dcp.cc
@@ -58,6 +58,7 @@
#include "raw_convert.h"
#include "reel_asset.h"
#include "reel_text_asset.h"
+#include "scope_guard.h"
#include "smpte_text_asset.h"
#include "sound_asset.h"
#include "stereo_j2k_picture_asset.h"
@@ -638,3 +639,55 @@ DCP::set_annotation_text(string annotation_text)
_new_annotation_text = annotation_text;
}
+
+vector<CPLSummary>
+DCP::cpl_summaries() const
+{
+ auto asset_map = read_assetmap();
+ vector<PKL> pkls;
+ for (auto const& i: asset_map.pkl_paths()) {
+ pkls.push_back(PKL(i));
+ }
+
+ vector<CPLSummary> cpls;
+
+ for (auto const& id_and_path: asset_map.asset_ids_and_paths()) {
+ optional<string> pkl_type;
+ for (auto const& pkl: pkls) {
+ pkl_type = pkl.type(id_and_path.first);
+ if (pkl_type) {
+ break;
+ }
+ }
+
+ if (!pkl_type) {
+ continue;
+ }
+
+ if (
+ pkl_type == remove_parameters(CPL::static_pkl_type(Standard::INTEROP)) ||
+ pkl_type == remove_parameters(CPL::static_pkl_type(Standard::SMPTE))) {
+
+ auto parser = new xmlpp::DomParser;
+ dcp::ScopeGuard sg = [parser]() { delete parser; };
+
+ try {
+ parser->parse_file(dcp::filesystem::fix_long_path(id_and_path.second).string());
+ } catch (std::exception& e) {
+ throw ReadError(String::compose("XML error in %1", id_and_path.second.string()), e.what());
+ }
+
+ if (parser->get_document()->get_root_node()->get_name() == "CompositionPlaylist") {
+ auto cpl = CPL(id_and_path.second);
+ cpls.push_back(
+ CPLSummary(
+ _directory, cpl.id(), cpl.annotation_text(), *cpl.file(), cpl.any_encrypted(), filesystem::last_write_time(_directory)
+ )
+ );
+ }
+ }
+ }
+
+ return cpls;
+}
+
diff --git a/src/dcp.h b/src/dcp.h
index f11ec711..4e706349 100644
--- a/src/dcp.h
+++ b/src/dcp.h
@@ -44,6 +44,7 @@
#include "asset_map.h"
#include "certificate.h"
#include "compose.hpp"
+#include "cpl_summary.h"
#include "metadata.h"
#include "name_format.h"
#include "util.h"
@@ -117,6 +118,12 @@ public:
*/
void read (std::vector<VerificationNote>* notes = nullptr, bool ignore_incorrect_picture_mxf_type = false);
+ /** Return summaries of the CPLs in this DCP. This should only be used if the information
+ * in CPLSummary is all you need. It's faster than read(), but if you need more than
+ * the CPLSummary you will need to just call read().
+ */
+ std::vector<CPLSummary> cpl_summaries() const;
+
/** Compare this DCP with another, according to various options.
* @param other DCP to compare this one to.
* @param options Options to define what "equality" means.
diff --git a/src/wscript b/src/wscript
index 3dc2ec12..04356b4f 100644
--- a/src/wscript
+++ b/src/wscript
@@ -158,6 +158,7 @@ def build(bld):
compose.hpp
content_kind.h
cpl.h
+ cpl_summary.h
crypto_context.h
data.h
dcp.h
diff --git a/test/cpl_summary_test.cc b/test/cpl_summary_test.cc
new file mode 100644
index 00000000..2f6ee839
--- /dev/null
+++ b/test/cpl_summary_test.cc
@@ -0,0 +1,115 @@
+/*
+ Copyright (C) 2025 Carl Hetherington <cth@carlh.net>
+
+ This file is part of libdcp.
+
+ libdcp is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ libdcp is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with libdcp. If not, see <http://www.gnu.org/licenses/>.
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of portions of this program with the
+ OpenSSL library under certain conditions as described in each
+ individual source file, and distribute linked combinations
+ including the two.
+
+ You must obey the GNU General Public License in all respects
+ for all of the code used other than OpenSSL. If you modify
+ file(s) with this exception, you may extend this exception to your
+ version of the file(s), but you are not obligated to do so. If you
+ do not wish to do so, delete this exception statement from your
+ version. If you delete this exception statement from all source
+ files in the program, then also delete it here.
+*/
+
+
+#include "dcp.h"
+#include "filesystem.h"
+#include "test.h"
+#include <boost/test/unit_test.hpp>
+
+
+BOOST_AUTO_TEST_CASE(cpl_summary_test1)
+{
+ auto const name = "TONEPLATES-SMPTE-PLAINTEXT_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV";
+ auto const dir = private_test / name;
+ dcp::DCP dcp(dir);
+ auto cpls = dcp.cpl_summaries();
+
+ BOOST_REQUIRE_EQUAL(cpls.size(), 1U);
+
+ BOOST_CHECK_EQUAL(cpls[0].dcp_directory, dcp::filesystem::canonical(dir));
+ BOOST_CHECK_EQUAL(cpls[0].cpl_id, "0435b2ae-741b-4853-ad7c-6014060344aa");
+ BOOST_REQUIRE(static_cast<bool>(cpls[0].cpl_annotation_text));
+ BOOST_CHECK_EQUAL(*cpls[0].cpl_annotation_text, name);
+ BOOST_CHECK_EQUAL(
+ cpls[0].cpl_file,
+ dcp::filesystem::canonical(dir / "cpl_0435b2ae-741b-4853-ad7c-6014060344aa_.xml")
+ );
+ BOOST_CHECK(!cpls[0].encrypted);
+ BOOST_CHECK(cpls[0].last_write_time > 0);
+}
+
+
+BOOST_AUTO_TEST_CASE(cpl_summary_test2)
+{
+ auto const name = "TONEPLATES-SMPTE-ENCRYPTED_TST_F_XX-XX_ITL-TD_51-XX_2K_WOE_20111001_WOE_OV";
+ auto const dir = private_test / name;
+ dcp::DCP dcp(dir);
+ auto cpls = dcp.cpl_summaries();
+
+ BOOST_REQUIRE_EQUAL(cpls.size(), 1U);
+
+ BOOST_CHECK_EQUAL(cpls[0].dcp_directory, dcp::filesystem::canonical(dir));
+ BOOST_CHECK_EQUAL(cpls[0].cpl_id, "eece17de-77e8-4a55-9347-b6bab5724b9f");
+ BOOST_REQUIRE(static_cast<bool>(cpls[0].cpl_annotation_text));
+ BOOST_CHECK_EQUAL(*cpls[0].cpl_annotation_text, name);
+ BOOST_CHECK_EQUAL(
+ cpls[0].cpl_file,
+ dcp::filesystem::canonical(dir / "cpl_eece17de-77e8-4a55-9347-b6bab5724b9f_.xml")
+ );
+ BOOST_CHECK(cpls[0].encrypted);
+ BOOST_CHECK(cpls[0].last_write_time > 0);
+}
+
+
+BOOST_AUTO_TEST_CASE(cpl_summary_test3)
+{
+ auto const name = "data/SMPTE_TST-B1PB2P_S_EN-EN-CCAP_5171-HI-VI_2K_ISDCF_20151123_DPPT_SMPTE_combo/";
+ auto const dir = private_test / name;
+ dcp::DCP dcp(dir);
+ auto cpls = dcp.cpl_summaries();
+
+ BOOST_REQUIRE_EQUAL(cpls.size(), 2U);
+
+ BOOST_CHECK_EQUAL(cpls[0].dcp_directory, dcp::filesystem::canonical(dir));
+ BOOST_CHECK_EQUAL(cpls[0].cpl_id, "0f404021-652a-4cca-8a7e-c181c5bb83f9");
+ BOOST_REQUIRE(!static_cast<bool>(cpls[0].cpl_annotation_text));
+ BOOST_CHECK_EQUAL(
+ cpls[0].cpl_file,
+ dcp::filesystem::canonical(dir / "CPL_SMPTE_TST-B1P_S_EN-EN-CCAP_51-HI-VI_2K_ISDCF_20151123_DPPT_SMPTE-mod.xml")
+ );
+ BOOST_CHECK(!cpls[0].encrypted);
+ BOOST_CHECK(cpls[0].last_write_time > 0);
+
+ BOOST_CHECK_EQUAL(cpls[1].dcp_directory, dcp::filesystem::canonical(dir));
+ BOOST_CHECK_EQUAL(cpls[1].cpl_id, "29e1a00b-0e19-4d5b-a1d6-24e97b331de6");
+ BOOST_REQUIRE(!static_cast<bool>(cpls[1].cpl_annotation_text));
+ BOOST_CHECK_EQUAL(
+ cpls[1].cpl_file,
+ dcp::filesystem::canonical(dir / "CPL_SMPTE_TST-B2P_S_EN-EN-CCAP_71-HI-VI_2K_ISDCF_20151123_DPPT_SMPTE-mod.xml")
+ );
+ BOOST_CHECK(!cpls[1].encrypted);
+ BOOST_CHECK(cpls[1].last_write_time > 0);
+}
+
+
diff --git a/test/wscript b/test/wscript
index 5e94b1f7..b4f526bf 100644
--- a/test/wscript
+++ b/test/wscript
@@ -76,6 +76,7 @@ def build(bld):
cpl_test.cc
cpl_metadata_test.cc
cpl_sar_test.cc
+ cpl_summary_test.cc
cpl_ratings_test.cc
dcp_font_test.cc
dcp_test.cc