diff options
| author | Carl Hetherington <cth@carlh.net> | 2025-03-08 00:12:29 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2025-03-08 00:12:29 +0100 |
| commit | 182a0b48fb456355a139c21533a7d6ca0bbe42eb (patch) | |
| tree | 19722a22f8667a1fe029af2ec34efbbddea3c851 | |
| parent | d4bb9572785a19c394cff3242e2b9ebab7c5d31c (diff) | |
| parent | 42b92cbe4518a170b217ab54a26b51f56246a50f (diff) | |
Merge branch '2981-headless-grok'
This makes it possible to configure Grok for encoding from the command
line.
| -rw-r--r-- | src/lib/config.cc | 6 | ||||
| -rw-r--r-- | src/lib/config.h | 4 | ||||
| -rw-r--r-- | src/lib/encode_cli.cc | 105 | ||||
| -rw-r--r-- | src/lib/grok/context.h | 4 | ||||
| -rw-r--r-- | src/lib/grok/util.cc | 53 | ||||
| -rw-r--r-- | src/lib/grok/util.h | 27 | ||||
| -rw-r--r-- | src/lib/grok_j2k_encoder_thread.cc | 2 | ||||
| -rw-r--r-- | src/lib/j2k_encoder.cc | 10 | ||||
| -rw-r--r-- | src/lib/util.cc | 4 | ||||
| -rw-r--r-- | src/lib/wscript | 2 | ||||
| -rw-r--r-- | src/wx/grok/gpu_config_panel.h | 51 | ||||
| -rw-r--r-- | test/config_test.cc | 9 | ||||
| m--------- | test/data | 0 | ||||
| -rw-r--r-- | test/encode_cli_test.cc | 163 | ||||
| -rwxr-xr-x | test/gpu_lister | 6 | ||||
| -rw-r--r-- | test/grok_util_test.cc | 43 | ||||
| -rw-r--r-- | test/wscript | 2 |
17 files changed, 427 insertions, 64 deletions
diff --git a/src/lib/config.cc b/src/lib/config.cc index 3227ea433..49c64e5b6 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -238,7 +238,7 @@ Config::set_defaults() set_cover_sheet_to_default(); #ifdef DCPOMATIC_GROK - _grok = boost::none; + _grok = {}; #endif _main_divider_sash_position = {}; @@ -1151,9 +1151,7 @@ Config::write_config() const cxml::add_text_child(root, "LayoutForShortScreen", _layout_for_short_screen ? "1" : "0"); #ifdef DCPOMATIC_GROK - if (_grok) { - _grok->as_xml(cxml::add_child(root, "Grok")); - } + _grok.as_xml(cxml::add_child(root, "Grok")); #endif _export.write(cxml::add_child(root, "Export")); diff --git a/src/lib/config.h b/src/lib/config.h index d9a95ebfd..b2a979ffa 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -666,7 +666,7 @@ public: std::string licence; }; - boost::optional<Grok> grok() const { + Grok grok() const { return _grok; } #endif @@ -1495,7 +1495,7 @@ private: bool _layout_for_short_screen; #ifdef DCPOMATIC_GROK - boost::optional<Grok> _grok; + Grok _grok; #endif ExportConfig _export; diff --git a/src/lib/encode_cli.cc b/src/lib/encode_cli.cc index a682fa4e3..fa304b6e0 100644 --- a/src/lib/encode_cli.cc +++ b/src/lib/encode_cli.cc @@ -30,6 +30,7 @@ #include "filter.h" #ifdef DCPOMATIC_GROK #include "grok/context.h" +#include "grok/util.h" #endif #include "hints.h" #include "job_manager.h" @@ -43,6 +44,7 @@ #include "version.h" #include "video_content.h" #include <dcp/filesystem.h> +#include <dcp/raw_convert.h> #include <dcp/version.h> #include <fmt/format.h> #include <getopt.h> @@ -66,7 +68,19 @@ using boost::optional; static void help(function <void (string)> out) { - out(fmt::format("Syntax: {} [OPTION] [<FILM>]\n", program_name)); + out(fmt::format("Syntax: {} [OPTION] [COMMAND] [<PARAMETER>]\n", program_name)); + + out("\nCommands:\n\n"); + out(" make-dcp <FILM> make DCP from the given film; default if no other command is specified\n"); + out(variant::insert_dcpomatic(" list-servers display a list of encoding servers that %1 can use (until Ctrl-C)\n")); + out(" dump <FILM> show a summary of the film's settings\n"); +#ifdef DCPOMATIC_GROK + out(" config-params list the parameters that can be set with `config`\n"); + out(" config <PARAMETER> <VALUE> set a DCP-o-matic configuration value\n"); + out(" list-gpus list available GPUs\n"); +#endif + + out("\nOptions:\n\n"); out(variant::insert_dcpomatic(" -v, --version show %1 version\n")); out(" -h, --help show this help\n"); out(" -f, --flags show flags passed to C++ compiler on build\n"); @@ -77,15 +91,19 @@ help(function <void (string)> out) out(" -k, --keep-going keep running even when the job is complete\n"); out(" -s, --servers <file> specify servers to use in a text file\n"); out(variant::insert_dcpomatic(" -l, --list-servers just display a list of encoding servers that %1 is configured to use; don't encode\n")); + out(" (deprecated - use the list-servers command instead)\n"); out(" -d, --dcp-path echo DCP's path to stdout on successful completion (implies -n)\n"); out(" -c, --config <dir> directory containing config.xml and cinemas.xml\n"); out(" --dump just dump a summary of the film's settings; don't encode\n"); + out(" (deprecated - use the dump command instead)\n"); out(" --no-check don't check project's content files for changes before making the DCP\n"); out(" --export-format <format> export project to a file, rather than making a DCP: specify mov or mp4\n"); out(" --export-filename <filename> filename to export to with --export-format\n"); out(" --hints analyze film for hints before encoding and abort if any are found\n"); + out("\ne.g.\n"); + out(fmt::format("\n {} -t 4 make-dcp my_great_movie\n", program_name)); + out(fmt::format("\n {} config grok-licence 12345ABCD\n", program_name)); out("\n"); - out("<FILM> is the film directory.\n"); } @@ -270,6 +288,10 @@ encode_cli(int argc, char* argv[], function<void (string)> out, function<void () optional<string> export_format; optional<boost::filesystem::path> export_filename; bool hints = false; + string command = "make-dcp"; + + /* This makes it possible to call getopt several times in the same executable, for tests */ + optind = 0; int option_index = 0; while (true) { @@ -357,6 +379,77 @@ encode_cli(int argc, char* argv[], function<void (string)> out, function<void () } } + vector<string> commands = { + "make-dcp", + "list-servers", +#ifdef DCPOMATIC_GROK + "dump", + "config-params", + "config", + "list-gpus" +#else + "dump" +#endif + }; + + if (optind < argc - 1) { + /* Command with a film specified afterwards */ + command = argv[optind++]; + } else if (optind < argc) { + /* Look for a valid command, hoping that it's not the name of a film */ + if (std::find(commands.begin(), commands.end(), argv[optind]) != commands.end()) { + command = argv[optind++]; + } + } + + +#ifdef DCPOMATIC_GROK + if (command == "config-params") { + out("Configurable parameters:\n\n"); + out(" grok-licence licence string for using the Grok JPEG2000 encoder\n"); + out(" grok-enable 1 to enable the Grok encoder, 0 to disable it\n"); + out(" grok-binary-location directory containing Grok binaries\n"); + out(" grok-gpu-index index of GPU to use (from 0, see list-gpus)\n"); + return {}; + } + + if (command == "config") { + if (optind < argc - 1) { + string const parameter = argv[optind++]; + string const value = argv[optind++]; + auto grok = Config::instance()->grok(); + if (parameter == "grok-licence") { + grok.licence = value; + } else if (parameter == "grok-enable") { + if (value == "1") { + grok.enable = true; + } else if (value == "0") { + grok.enable = false; + } else { + return fmt::format("Invalid value {} for grok-enable (use 1 to enable, 0 to disable)", value); + } + } else if (parameter == "grok-binary-location") { + grok.binary_location = value; + } else if (parameter == "grok-gpu-index") { + grok.selected = dcp::raw_convert<int>(value); + } else { + return fmt::format("Unrecognised configuration parameter `{}'", parameter); + } + Config::instance()->set_grok(grok); + Config::instance()->write(); + } else { + return fmt::format("Missing configuration parameter: use {} config <parameter> <value>", program_name); + } + return {}; + } else if (command == "list-gpus") { + int N = 0; + for (auto gpu: get_gpu_names()) { + out(fmt::format("{}: {}\n", N++, gpu)); + } + return {}; + } +#endif + if (config) { State::override_path = *config; } @@ -376,7 +469,7 @@ encode_cli(int argc, char* argv[], function<void (string)> out, function<void () Config::instance()->set_servers(servers); } - if (list_servers_) { + if (command == "list-servers" || list_servers_) { list_servers(out); return {}; } @@ -420,7 +513,7 @@ encode_cli(int argc, char* argv[], function<void (string)> out, function<void () return fmt::format("{}: error reading film `{}' ({})\n", program_name, film_dir.string(), e.what()); } - if (dump) { + if (command == "dump" || dump) { print_dump(out, film); return {}; } @@ -489,9 +582,9 @@ encode_cli(int argc, char* argv[], function<void (string)> out, function<void () if (progress) { if (export_format) { - out(fmt::format("\nExporting {}\n", film->name())); + out(fmt::format("Exporting {}\n", film->name())); } else { - out(fmt::format("\nMaking DCP for {}\n", film->name())); + out(fmt::format("Making DCP for {}\n", film->name())); } } diff --git a/src/lib/grok/context.h b/src/lib/grok/context.h index 602c8b13f..b31867cf6 100644 --- a/src/lib/grok/context.h +++ b/src/lib/grok/context.h @@ -99,7 +99,7 @@ public: explicit GrokContext(DcpomaticContext* dcpomatic_context) : _dcpomatic_context(dcpomatic_context) { - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); if (!grok.enable) { return; } @@ -216,7 +216,7 @@ public: auto s = dcpv.get_size(); _dcpomatic_context->set_dimensions(s.width, s.height); - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); if (!_messenger->launch_grok( _dcpomatic_context->location, _dcpomatic_context->width, diff --git a/src/lib/grok/util.cc b/src/lib/grok/util.cc new file mode 100644 index 000000000..3cbc55678 --- /dev/null +++ b/src/lib/grok/util.cc @@ -0,0 +1,53 @@ +/* + Copyright (C) 2023 Grok Image Compression Inc. + + 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/>. + +*/ + + +#include "util.h" +#include "../config.h" +#include <boost/process.hpp> +#include <future> + + +using std::string; +using std::vector; + + +vector<string> +get_gpu_names() +{ + namespace bp = boost::process; + + auto binary = Config::instance()->grok().binary_location / "gpu_lister"; + + bp::ipstream stream; + bp::child child(binary, bp::std_out > stream); + + string line; + vector<string> gpu_names; + while (child.running() && std::getline(stream, line) && !line.empty()) { + gpu_names.push_back(line); + } + + child.wait(); + + return gpu_names; +} + + diff --git a/src/lib/grok/util.h b/src/lib/grok/util.h new file mode 100644 index 000000000..a78ecabca --- /dev/null +++ b/src/lib/grok/util.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2023 Grok Image Compression Inc. + + 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/>. + +*/ + + +#include <boost/filesystem.hpp> +#include <string> +#include <vector> + + +extern std::vector<std::string> get_gpu_names(); diff --git a/src/lib/grok_j2k_encoder_thread.cc b/src/lib/grok_j2k_encoder_thread.cc index e6c256f11..d6825113c 100644 --- a/src/lib/grok_j2k_encoder_thread.cc +++ b/src/lib/grok_j2k_encoder_thread.cc @@ -62,7 +62,7 @@ try LOG_TIMING("encoder-pop thread=%1 frame=%2 eyes=%3", thread_id(), frame.index(), static_cast<int>(frame.eyes())); - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); if (_context->launch(frame, grok.selected) && _context->scheduleCompress(frame)) { frame_guard.cancel(); diff --git a/src/lib/j2k_encoder.cc b/src/lib/j2k_encoder.cc index 309fce0b3..50452fbad 100644 --- a/src/lib/j2k_encoder.cc +++ b/src/lib/j2k_encoder.cc @@ -98,7 +98,7 @@ J2KEncoder::J2KEncoder(shared_ptr<const Film> film, Writer& writer) #endif { #ifdef DCPOMATIC_GROK - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); _dcpomatic_context = new grk_plugin::DcpomaticContext(film, writer, _history, grok.binary_location); if (grok.enable) { _context = new grk_plugin::GrokContext(_dcpomatic_context); @@ -135,7 +135,7 @@ J2KEncoder::servers_list_changed() { auto config = Config::instance(); #ifdef DCPOMATIC_GROK - auto const grok_enable = config->grok().get_value_or({}).enable; + auto const grok_enable = config->grok().enable; #else auto const grok_enable = false; #endif @@ -162,7 +162,7 @@ void J2KEncoder::pause() { #ifdef DCPOMATIC_GROK - if (!Config::instance()->grok().get_value_or({}).enable) { + if (!Config::instance()->grok().enable) { return; } return; @@ -183,7 +183,7 @@ J2KEncoder::pause() void J2KEncoder::resume() { #ifdef DCPOMATIC_GROK - if (!Config::instance()->grok().get_value_or({}).enable) { + if (!Config::instance()->grok().enable) { return; } @@ -226,7 +226,7 @@ J2KEncoder::end() */ for (auto & i: _queue) { #ifdef DCPOMATIC_GROK - if (Config::instance()->grok().get_value_or({}).enable) { + if (Config::instance()->grok().enable) { if (!_context->scheduleCompress(i)){ LOG_GENERAL (N_("[%1] J2KEncoder thread pushes frame %2 back onto queue after failure"), thread_id(), i.index()); // handle error diff --git a/src/lib/util.cc b/src/lib/util.cc index df15e1abb..1e2f7d61f 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -1146,7 +1146,7 @@ setup_grok_library_path() } } auto const grok = Config::instance()->grok(); - if (!grok || grok->binary_location.empty()) { + if (grok.binary_location.empty()) { setenv("LD_LIRARY_PATH", old_path.c_str(), 1); return; } @@ -1155,7 +1155,7 @@ setup_grok_library_path() if (!new_path.empty()) { new_path += ":"; } - new_path += grok->binary_location.string(); + new_path += grok.binary_location.string(); setenv("LD_LIBRARY_PATH", new_path.c_str(), 1); } diff --git a/src/lib/wscript b/src/lib/wscript index 79f0d563e..cae78fc4a 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -267,7 +267,7 @@ def build(bld): obj.uselib += ' POLKIT' if bld.env.ENABLE_GROK: - obj.source += ' grok_j2k_encoder_thread.cc' + obj.source += ' grok_j2k_encoder_thread.cc grok/util.cc' if bld.env.TARGET_WINDOWS_64 or bld.env.TARGET_WINDOWS_32: obj.uselib += ' WINSOCK2 DBGHELP SHLWAPI MSWSOCK BOOST_LOCALE SETUPAPI OLE32 UUID' diff --git a/src/wx/grok/gpu_config_panel.h b/src/wx/grok/gpu_config_panel.h index df38f9373..34bf38f12 100644 --- a/src/wx/grok/gpu_config_panel.h +++ b/src/wx/grok/gpu_config_panel.h @@ -22,30 +22,10 @@ #pragma once +#include "lib/grok/util.h" #include <wx/filepicker.h> -static std::vector<std::string> get_gpu_names(boost::filesystem::path binary, boost::filesystem::path filename) -{ - // Execute the GPU listing program and redirect its output to a file - if (std::system((binary.string() + " > " + filename.string()).c_str()) < 0) { - return {}; - } - - std::vector<std::string> gpu_names; - std::ifstream file(filename.c_str()); - if (file.is_open()) - { - std::string line; - while (std::getline(file, line)) - gpu_names.push_back(line); - file.close(); - } - - return gpu_names; -} - - class GpuList : public wxPanel { public: @@ -63,16 +43,9 @@ public: void update() { - auto grok = Config::instance()->grok().get_value_or({}); - auto lister_binary = grok.binary_location / "gpu_lister"; - auto lister_file = grok.binary_location / "gpus.txt"; - if (boost::filesystem::exists(lister_binary)) { - auto gpu_names = get_gpu_names(lister_binary, lister_file); - - _combo_box->Clear(); - for (auto const& name: gpu_names) { - _combo_box->Append(std_to_wx(name)); - } + _combo_box->Clear(); + for (auto const& name: get_gpu_names()) { + _combo_box->Append(std_to_wx(name)); } } @@ -88,7 +61,7 @@ private: { auto selection = _combo_box->GetSelection(); if (selection != wxNOT_FOUND) { - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); grok.selected = selection; Config::instance()->set_grok(grok); } @@ -155,7 +128,7 @@ private: void setup_sensitivity() { - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); _binary_location->Enable(grok.enable); _gpu_list_control->Enable(grok.enable); @@ -165,7 +138,7 @@ private: void config_changed() override { - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); checked_set(_enable_gpu, grok.enable); _binary_location->SetPath(std_to_wx(grok.binary_location.string())); @@ -177,7 +150,7 @@ private: void enable_gpu_changed() { - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); grok.enable = _enable_gpu->GetValue(); Config::instance()->set_grok(grok); @@ -186,7 +159,7 @@ private: void binary_location_changed() { - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); grok.binary_location = wx_to_std(_binary_location->GetPath()); Config::instance()->set_grok(grok); @@ -195,20 +168,20 @@ private: void server_changed() { - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); grok.licence_server = wx_to_std(_server->GetValue()); Config::instance()->set_grok(grok); } void port_changed() { - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); Config::instance()->set_grok(grok); } void licence_changed() { - auto grok = Config::instance()->grok().get_value_or({}); + auto grok = Config::instance()->grok(); grok.licence = _licence->get(); Config::instance()->set_grok(grok); } diff --git a/test/config_test.cc b/test/config_test.cc index a9b95bedf..8fd19b693 100644 --- a/test/config_test.cc +++ b/test/config_test.cc @@ -182,9 +182,11 @@ BOOST_AUTO_TEST_CASE (config_upgrade_test1) check_xml (dir / "config.xml", "test/data/2.14.config.xml", {}); check_xml (dir / "cinemas.xml", "test/data/2.14.cinemas.xml", {}); -#ifdef DCPOMATIC_WINDOWS +#if defined(DCPOMATIC_WINDOWS) /* This file has the windows path for dkdm_recipients.xml (with backslashes) */ check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.windows.sqlite.xml", {}); +#elif defined(DCPOMATIC_GROK) + check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.sqlite.grok.xml", {}); #else check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.sqlite.xml", {}); #endif @@ -215,10 +217,13 @@ BOOST_AUTO_TEST_CASE (config_upgrade_test2) Config::instance()->write(); check_xml(dir / "cinemas.xml", "test/data/2.14.cinemas.xml", {}); -#ifdef DCPOMATIC_WINDOWS +#if defined(DCPOMATIC_WINDOWS) /* This file has the windows path for dkdm_recipients.xml (with backslashes) */ check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.windows.xml", {}); check_xml(dir / "config.xml", "test/data/2.16.config.windows.xml", {}); +#elif defined(DCPOMATIC_GROK) + check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.grok.xml", {}); + check_xml(dir / "config.xml", "test/data/2.16.config.xml", {}); #else check_xml(dir / "2.18" / "config.xml", "test/data/2.18.config.xml", {}); check_xml(dir / "config.xml", "test/data/2.16.config.xml", {}); diff --git a/test/data b/test/data -Subproject df601f1580d852de043c2eca6acc4cfc9a2446b +Subproject 7d2ed165d8e65d92a02a20e22c1caedd15db82b diff --git a/test/encode_cli_test.cc b/test/encode_cli_test.cc new file mode 100644 index 000000000..0a0a17e3a --- /dev/null +++ b/test/encode_cli_test.cc @@ -0,0 +1,163 @@ +/* + 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/>. + +*/ + + +#include "lib/content_factory.h" +#include "lib/encode_cli.h" +#include "lib/film.h" +#include "test.h" +#include <boost/optional.hpp> +#include <boost/test/unit_test.hpp> +#include <iostream> +#include <string> +#include <vector> + + +using std::cout; +using std::string; +using std::vector; +using boost::optional; + + +static +optional<string> +run(vector<string> const& args, vector<string>& output) +{ + vector<char*> argv(args.size() + 1); + for (auto i = 0U; i < args.size(); ++i) { + argv[i] = const_cast<char*>(args[i].c_str()); + } + argv[args.size()] = nullptr; + + auto error = encode_cli(args.size(), argv.data(), [&output](string s) { output.push_back(s); }, []() { }); + for (auto i: output) { + std::cout << "O:" << i; + } + if (error) { + std::cout << "E:" << *error << "\n"; + } + + return error; +} + + +static +bool +find_in_order(vector<string> const& output, vector<string> const& check) +{ + BOOST_REQUIRE(!check.empty()); + + auto next = check.begin(); + for (auto line: output) { + if (line.find(*next) != string::npos) { + ++next; + if (next == check.end()) { + return true; + } + } + } + + return false; +} + + +BOOST_AUTO_TEST_CASE(basic_encode_cli_test) +{ + auto content = content_factory("test/data/flat_red.png"); + auto film = new_test_film("basic_encode_cli_test", content); + film->write_metadata(); + + vector<string> output; + run({ "cli", "build/test/basic_encode_cli_test" }, output); + + BOOST_CHECK(find_in_order(output, { "Making DCP for", "Examining content", "OK", "Transcoding DCP", "OK" })); +} + + +BOOST_AUTO_TEST_CASE(encode_cli_with_explicit_encode_command_test) +{ + auto content = content_factory("test/data/flat_red.png"); + auto film = new_test_film("basic_encode_cli_test", content); + film->write_metadata(); + + vector<string> output; + run({ "cli", "make-dcp", "build/test/basic_encode_cli_test" }, output); + + BOOST_CHECK(find_in_order(output, { "Making DCP for", "Examining content", "OK", "Transcoding DCP", "OK" })); +} + + +#ifdef DCPOMATIC_GROK +BOOST_AUTO_TEST_CASE(encode_cli_set_grok_licence) +{ + boost::filesystem::path config = "build/encode_cli_set_grok_licence"; + boost::filesystem::remove_all(config); + boost::filesystem::create_directories(config); + ConfigRestorer cr(config); + + vector<string> output; + auto error = run({ "cli", "config", "grok-licence", "12345678ABC" }, output); + BOOST_CHECK(output.empty()); + BOOST_CHECK(!error); + + cxml::Document check("Config"); + check.read_file(config / "2.18" / "config.xml"); + BOOST_CHECK_EQUAL(check.node_child("Grok")->string_child("Licence"), "12345678ABC"); +} + + +BOOST_AUTO_TEST_CASE(encode_cli_enable_grok) +{ + boost::filesystem::path config = "build/encode_cli_enable_grok"; + boost::filesystem::remove_all(config); + boost::filesystem::create_directories(config); + ConfigRestorer cr(config); + + for (auto value: vector<string>{ "1", "0"}) { + vector<string> output; + auto error = run({ "cli", "config", "grok-enable", value }, output); + BOOST_CHECK(output.empty()); + BOOST_CHECK(!error); + + cxml::Document check("Config"); + check.read_file(config / "2.18" / "config.xml"); + BOOST_CHECK_EQUAL(check.node_child("Grok")->string_child("Enable"), value); + } +} + + +BOOST_AUTO_TEST_CASE(encode_cli_set_grok_binary_location) +{ + boost::filesystem::path config = "build/encode_cli_set_grok_binary_location"; + boost::filesystem::remove_all(config); + boost::filesystem::create_directories(config); + ConfigRestorer cr(config); + + vector<string> output; + auto error = run({ "cli", "config", "grok-binary-location", "foo/bar/baz" }, output); + BOOST_CHECK(output.empty()); + BOOST_CHECK(!error); + + cxml::Document check("Config"); + check.read_file(config / "2.18" / "config.xml"); + BOOST_CHECK_EQUAL(check.node_child("Grok")->string_child("BinaryLocation"), "foo/bar/baz"); +} +#endif + diff --git a/test/gpu_lister b/test/gpu_lister new file mode 100755 index 000000000..6dcb750de --- /dev/null +++ b/test/gpu_lister @@ -0,0 +1,6 @@ +#!/bin/bash + +echo "Foo bar baz" +echo "Spondoolix Mega Kompute 2000" +echo "Energy Sink-o-matic" + diff --git a/test/grok_util_test.cc b/test/grok_util_test.cc new file mode 100644 index 000000000..2a84fe2a4 --- /dev/null +++ b/test/grok_util_test.cc @@ -0,0 +1,43 @@ +/* + 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/>. + +*/ + + +#include "lib/config.h" +#include "lib/grok/util.h" +#include "test.h" +#include <boost/test/unit_test.hpp> + + +#ifdef DCPOMATIC_GROK +BOOST_AUTO_TEST_CASE(get_gpu_names_test) +{ + ConfigRestorer cr; + + Config::Grok grok; + grok.binary_location = "test"; + Config::instance()->set_grok(grok); + + auto names = get_gpu_names(); + BOOST_REQUIRE_EQUAL(names.size(), 3U); + BOOST_CHECK_EQUAL(names[0], "Foo bar baz"); + BOOST_CHECK_EQUAL(names[1], "Spondoolix Mega Kompute 2000"); + BOOST_CHECK_EQUAL(names[2], "Energy Sink-o-matic"); +} +#endif diff --git a/test/wscript b/test/wscript index 85bfccf56..7e53dfb02 100644 --- a/test/wscript +++ b/test/wscript @@ -85,6 +85,7 @@ def build(bld): email_test.cc empty_caption_test.cc empty_test.cc + encode_cli_test.cc encryption_test.cc file_extension_test.cc ffmpeg_audio_only_test.cc @@ -109,6 +110,7 @@ def build(bld): font_id_allocator_test.cc frame_interval_checker_test.cc frame_rate_test.cc + grok_util_test.cc guess_crop_test.cc hints_test.cc image_content_fade_test.cc |
