summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/json_verify_report.cc146
-rw-r--r--src/json_verify_report.h41
-rw-r--r--src/wscript4
-rw-r--r--tools/dcpverify.cc16
-rw-r--r--wscript3
5 files changed, 207 insertions, 3 deletions
diff --git a/src/json_verify_report.cc b/src/json_verify_report.cc
new file mode 100644
index 00000000..01d30647
--- /dev/null
+++ b/src/json_verify_report.cc
@@ -0,0 +1,146 @@
+/*
+ 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 "cpl.h"
+#include "dcp.h"
+#include "reel.h"
+#include "reel_picture_asset.h"
+#include "reel_sound_asset.h"
+#include "reel_text_asset.h"
+#include "verify.h"
+#include "json_verify_report.h"
+#include <nlohmann/json.hpp>
+#include <fmt/format.h>
+#include <fstream>
+
+
+using std::shared_ptr;
+using std::string;
+using std::vector;
+using boost::optional;
+using namespace dcp;
+
+
+void
+dcp::make_json_verify_report(vector<dcp::VerificationResult> const& results, boost::filesystem::path file)
+{
+ auto reel_asset_details = [](shared_ptr<dcp::ReelAsset> asset) {
+ nlohmann::json details;
+ details["id"] = asset->id();
+ details["intrinsic_duration"] = asset->intrinsic_duration();
+ details["entry_point"] = asset->entry_point().get_value_or(0);
+ details["duration"] = asset->duration().get_value_or(0);
+ if (asset->annotation_text()) {
+ details["annotation_text"] = *asset->annotation_text();
+ }
+ return details;
+ };
+
+ auto get_notes = [](dcp::VerificationResult const& result, optional<string> cpl_id) {
+ nlohmann::json json = nlohmann::json::array();
+
+ for (auto note: result.notes) {
+ if (note.cpl_id() == cpl_id) {
+ switch (note.type()) {
+ case dcp::VerificationNote::Type::OK:
+ json.push_back({ {"type", "ok"}, {"message", dcp::note_to_string(note)} });
+ break;
+ case dcp::VerificationNote::Type::WARNING:
+ json.push_back({ {"type", "warning"}, {"message", dcp::note_to_string(note)} });
+ break;
+ case dcp::VerificationNote::Type::ERROR:
+ json.push_back({ {"type", "error"}, {"message", dcp::note_to_string(note)} });
+ break;
+ case dcp::VerificationNote::Type::BV21_ERROR:
+ json.push_back({ {"type", "bv21_error"}, {"message", dcp::note_to_string(note)} });
+ break;
+ }
+ }
+ }
+
+ return json;
+ };
+
+ nlohmann::json all_json = nlohmann::json::array();
+
+ for (auto const& result: results) {
+ for (auto dcp: result.dcps) {
+ nlohmann::json dcp_json;
+ dcp_json["cpls"] = nlohmann::json::array();
+ for (auto cpl: dcp->cpls()) {
+ nlohmann::json cpl_json;
+ cpl_json["reels"] = nlohmann::json::array();
+ if (cpl->annotation_text()) {
+ cpl_json["annotation_text"] = *cpl->annotation_text();
+ }
+ cpl_json["id"] = cpl->id();
+ int reel_index = 1;
+ for (auto reel: cpl->reels()) {
+ nlohmann::json reel_json;
+ reel_json["index"] = reel_index++;
+ if (auto pic = reel->main_picture()) {
+ auto pic_json = reel_asset_details(pic);
+ pic_json["frame_rate"] = pic->frame_rate().numerator;
+ pic_json["screen_aspect_ratio"] = {
+ { "width", pic->screen_aspect_ratio().numerator },
+ { "height", pic->screen_aspect_ratio().denominator }
+ };
+ reel_json["main_picture"] = pic_json;
+ }
+ if (auto sound = reel->main_sound()) {
+ reel_json["main_sound"] = reel_asset_details(sound);
+ }
+ if (auto sub = reel->main_subtitle()) {
+ auto sub_json = reel_asset_details(sub);
+ if (sub->language()) {
+ sub_json["language"] = *sub->language();
+ }
+ }
+ cpl_json["reels"].push_back(reel_json);
+ }
+ cpl_json["notes"] = get_notes(result, cpl->id());
+ dcp_json["cpls"].push_back(cpl_json);
+ }
+
+ if (std::count_if(result.notes.begin(), result.notes.end(), [](VerificationNote const& note) { return !note.cpl_id(); }) > 0) {
+ dcp_json["notes"] = get_notes(result, {});
+ }
+
+ all_json.push_back(dcp_json);
+ }
+ }
+
+ std::ofstream out(file.string().c_str());
+ out << all_json.dump(4) << "\n";
+}
diff --git a/src/json_verify_report.h b/src/json_verify_report.h
new file mode 100644
index 00000000..f36e170d
--- /dev/null
+++ b/src/json_verify_report.h
@@ -0,0 +1,41 @@
+/*
+ Copyright (C) 2025 Carl Hetherington <cth@carlh.net>
+
+ This file is part of DCP-o-matic.
+
+ DCP-o-matic 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.
+
+ DCP-o-matic 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 DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+
+#ifndef DCP_JSON_VERIFY_REPORT_H
+#define DCP_JSON_VERIFY_REPORT_H
+
+
+#include "verify.h"
+#include <boost/filesystem.hpp>
+#include <vector>
+
+
+namespace dcp {
+
+
+extern void make_json_verify_report(std::vector<dcp::VerificationResult> const& results, boost::filesystem::path file);
+
+
+}
+
+
+#endif
+
diff --git a/src/wscript b/src/wscript
index 6e83fe6a..064bd5a4 100644
--- a/src/wscript
+++ b/src/wscript
@@ -270,6 +270,10 @@ def build(bld):
headers += "pdf_formatter.h "
uselib += ' HARU'
+ if bld.env.LIBDCP_HAVE_JSON:
+ source += "json_verify_report.cc "
+ headers += "json_verify_report.h "
+
# Main library
if bld.env.STATIC:
obj = bld(features='cxx cxxstlib')
diff --git a/tools/dcpverify.cc b/tools/dcpverify.cc
index ed1b2a8c..6728bfcf 100644
--- a/tools/dcpverify.cc
+++ b/tools/dcpverify.cc
@@ -37,6 +37,9 @@
#include "filesystem.h"
#include "formatted_verify_report.h"
#include "html_formatter.h"
+#ifdef LIBDCP_HAVE_JSON
+#include "json_verify_report.h"
+#endif
#ifdef LIBDCP_HAVE_HARU
#include "pdf_formatter.h"
#endif
@@ -76,11 +79,14 @@ help (string n)
<< " --asset-hash-check-maximum-size <size-in-MB> only check hashes for assets smaller than this size (in MB)\n"
<< " --no-picture-details-check don't check details of picture assets (J2K bitstream etc.)\n"
<< " -o <filename> write report to filename "
+ " (.txt, .htm, .html"
#ifdef LIBDCP_HAVE_HARU
- " (.txt, .htm, .html or .pdf)\n"
-#else
- " (.txt, .htm or .html)\n"
+ ", .pdf"
+#endif
+#ifdef LIBDCP_HAVE_JSON
+ ", .json"
#endif
+ ")\n"
<< " -q, --quiet don't report progress\n";
}
@@ -244,6 +250,10 @@ main (int argc, char* argv[])
dcp::PDFFormatter formatter(*report_filename);
dcp::make_formatted_verify_report({ result }, formatter);
#endif
+#ifdef LIBDCP_HAVE_JSON
+ } else if (report_filename->extension() == ".json") {
+ dcp::make_json_verify_report({ result }, *report_filename);
+#endif
} else {
dcp::TextFormatter formatter(*report_filename);
dcp::make_formatted_verify_report({ result }, formatter);
diff --git a/wscript b/wscript
index 052bb014..f59dda7f 100644
--- a/wscript
+++ b/wscript
@@ -285,6 +285,9 @@ def configure(conf):
if haru:
conf.env.append_value('LIBDCP_HAVE_HARU', '1')
+ if conf.check_cxx(header_name="nlohmann/json.hpp", uselib_store='JSON', define_name='LIBDCP_HAVE_JSON', mandatory=False):
+ conf.env.append_value('LIBDCP_HAVE_JSON', '1')
+
if not conf.env.DISABLE_TESTS:
conf.recurse('test')
if conf.options.enable_gcov: