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 /src/lib | |
| parent | d4bb9572785a19c394cff3242e2b9ebab7c5d31c (diff) | |
| parent | 42b92cbe4518a170b217ab54a26b51f56246a50f (diff) | |
Merge branch '2981-headless-grok'
This makes it possible to configure Grok for encoding from the command
line.
Diffstat (limited to 'src/lib')
| -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 |
10 files changed, 194 insertions, 23 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' |
