Commit 8f5e2e77 for libheif
commit 8f5e2e77e44edab05163fd6dc42b1ebc0b55bd63
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Mon May 11 19:31:03 2026 +0200
heif-dec: add option to control number of tile decoding threads (#1787)
diff --git a/examples/heif_dec.cc b/examples/heif_dec.cc
index 14cbaa3c..0fab4555 100644
--- a/examples/heif_dec.cc
+++ b/examples/heif_dec.cc
@@ -87,6 +87,8 @@ static void show_help(const char* argv0)
std::string title = sstr.str();
+ int default_tile_threads = heif_context_get_max_decoding_threads(nullptr);
+
std::cerr << title << "\n"
<< std::string(title.length() + 1, '-') << "\n"
<< "Usage: " << filename << " [options] <input-image> [output-image]\n"
@@ -116,7 +118,8 @@ static void show_help(const char* argv0)
" support transparency. MODE must be one of: white, black, checkerboard.\n"
" --disable-limits disable all security limits (do not use in production environment)\n"
" --codec-threads # number of threads to use in the codec plugin (0 = default)\n"
- " --extract-mime-item TYPE extract the MIME item with the given content type into a file (mime-item.data)\n";
+ << " --tile-threads # max number of tiles to decode in parallel (default = " << default_tile_threads << ")\n"
+ << " --extract-mime-item TYPE extract the MIME item with the given content type into a file (mime-item.data)\n";
}
@@ -149,6 +152,7 @@ int option_disable_limits = 0;
int option_sequence = 0;
int option_ignore_editlist = 0;
int option_num_codec_threads = 0;
+int option_num_tile_threads = -1; // -1 means "do not override library default"
std::string option_extract_mime_item_type;
std::string output_filename;
@@ -159,6 +163,7 @@ std::string transparency_composition_mode = "checkerboard";
#define OPTION_TRANSPARENCY_COMPOSITION_MODE 1001
#define OPTION_CODEC_THREADS 1002
#define OPTION_EXTRACT_MIME_ITEM 1003
+#define OPTION_TILE_THREADS 1004
static option long_options[] = {
{(char* const) "quality", required_argument, 0, 'q'},
@@ -182,6 +187,7 @@ static option long_options[] = {
{(char* const) "disable-limits", no_argument, &option_disable_limits, 1},
{(char* const) "ignore-editlist", no_argument, &option_ignore_editlist, 1},
{(char* const) "codec-threads", required_argument, 0, OPTION_CODEC_THREADS},
+ {(char* const) "tile-threads", required_argument, 0, OPTION_TILE_THREADS},
{(char* const) "extract-mime-item", required_argument, 0, OPTION_EXTRACT_MIME_ITEM},
{nullptr, no_argument, nullptr, 0}
};
@@ -677,6 +683,9 @@ int main(int argc, char** argv)
case OPTION_CODEC_THREADS:
option_num_codec_threads = atoi(optarg);
break;
+ case OPTION_TILE_THREADS:
+ option_num_tile_threads = atoi(optarg);
+ break;
case OPTION_EXTRACT_MIME_ITEM:
option_extract_mime_item_type = optarg;
break;
@@ -797,6 +806,10 @@ int main(int argc, char** argv)
heif_context_set_security_limits(ctx, heif_get_disabled_security_limits());
}
+ if (option_num_tile_threads >= 0) {
+ heif_context_set_max_decoding_threads(ctx, option_num_tile_threads);
+ }
+
ContextReleaser cr(ctx);
heif_error err;
err = heif_context_read_from_file(ctx, input_filename.c_str(), nullptr);
diff --git a/libheif/api/libheif/heif_decoding.cc b/libheif/api/libheif/heif_decoding.cc
index 23ffa9b4..575790b9 100644
--- a/libheif/api/libheif/heif_decoding.cc
+++ b/libheif/api/libheif/heif_decoding.cc
@@ -34,6 +34,15 @@ void heif_context_set_max_decoding_threads(heif_context* ctx, int max_threads)
}
+int heif_context_get_max_decoding_threads(const heif_context* ctx)
+{
+ if (!ctx) {
+ return HeifContext::default_max_decoding_threads;
+ }
+ return ctx->context->get_max_decoding_threads();
+}
+
+
int heif_have_decoder_for_format(heif_compression_format format)
{
auto plugin = get_decoder(format, nullptr);
diff --git a/libheif/api/libheif/heif_decoding.h b/libheif/api/libheif/heif_decoding.h
index e580b162..3078327d 100644
--- a/libheif/api/libheif/heif_decoding.h
+++ b/libheif/api/libheif/heif_decoding.h
@@ -39,6 +39,13 @@ extern "C" {
LIBHEIF_API
void heif_context_set_max_decoding_threads(heif_context* ctx, int max_threads);
+// Returns the current maximum number of background threads used for parallel tile decoding.
+// This reflects either the library default or the value last passed to
+// heif_context_set_max_decoding_threads().
+// If 'ctx' is NULL, the library default is returned.
+LIBHEIF_API
+int heif_context_get_max_decoding_threads(const heif_context* ctx);
+
// Quick check whether there is a decoder available for the given format.
// Note that the decoder still may not be able to decode all variants of that format.
// You will have to query that further (todo) or just try to decode and check the returned error.
diff --git a/libheif/context.h b/libheif/context.h
index 18c3aa4b..e773ce0b 100644
--- a/libheif/context.h
+++ b/libheif/context.h
@@ -69,6 +69,8 @@ public:
~HeifContext();
+ static constexpr int default_max_decoding_threads = 4;
+
void set_max_decoding_threads(int max_threads) { m_max_decoding_threads = max_threads; }
int get_max_decoding_threads() const { return m_max_decoding_threads; }
@@ -306,7 +308,7 @@ private:
std::shared_ptr<HeifFile> m_heif_file;
- int m_max_decoding_threads = 4;
+ int m_max_decoding_threads = default_max_decoding_threads;
heif_security_limits m_limits;
TotalMemoryTracker m_memory_tracker;