Commit e3eb59b9 for libheif
commit e3eb59b96dd2c607f8d235d3c9557f2d16b68962
Author: Dirk Farin <dirk.farin@gmail.com>
Date: Mon Oct 5 17:59:44 2026 +0200
Use a margin of 64 pixels for the tightened size limit of AVC and JPEG images
Since 9e2c938d, the FFmpeg decoder plugin passes the image size limit to
FFmpeg as max_pixels. For an image item, this is the limit that was
tightened to the 'ispe' size plus a margin of one coding unit in each
direction, which was 16 pixels for AVC and JPEG. FFmpeg compares
max_pixels with the picture width rounded up to its stride alignment (up
to 64 pixels) times the height. It therefore refused every AVC or JPEG
image for which this product is larger than (width+16)*(height+16), for
example 720x1280, 600x800 or 3024x4032, with "Error in
avcodec_send_packet". FFmpeg is the default AVC decoder when it is
compiled in. v1.23.5 decoded these images.
Use a margin of 64 pixels for AVC and JPEG, as for HEVC. This always
covers the alignment, since the width is rounded up by at most 63
pixels. The other codecs already have a margin of 64 or 128 pixels and
were not affected. Image sequences were not affected either, they are
decoded with the limit of the context.
diff --git a/libheif/security_limits.cc b/libheif/security_limits.cc
index 53c6703a..5ea231d3 100644
--- a/libheif/security_limits.cc
+++ b/libheif/security_limits.cc
@@ -79,8 +79,13 @@ uint32_t max_coding_unit_size_for_codec(heif_compression_format format)
case heif_compression_AV1: return 128; // AV1 max superblock
case heif_compression_VVC: return 128; // VVC max CTU
case heif_compression_HEVC: return 64; // HEVC max CTU
- case heif_compression_AVC: return 16; // H.264 macroblock
- case heif_compression_JPEG: return 16; // JPEG MCU (4:2:0)
+ // The coding units of AVC (macroblock) and JPEG (4:2:0 MCU) are 16 pixels. Their margin
+ // is larger because the tightened limit is also given to the decoder plugin as its
+ // maximum picture size, and FFmpeg compares that with the picture width rounded up to
+ // its stride alignment (up to 64 pixels). With a margin of 16, FFmpeg refused images
+ // like 720x1280, since 768*1280 is more than (720+16)*(1280+16).
+ case heif_compression_AVC: return 64;
+ case heif_compression_JPEG: return 64;
case heif_compression_JPEG2000: return 64;
case heif_compression_HTJ2K: return 64;
default: return 0;
diff --git a/libheif/security_limits.h b/libheif/security_limits.h
index ec13dad0..866c9195 100644
--- a/libheif/security_limits.h
+++ b/libheif/security_limits.h
@@ -105,6 +105,8 @@ Error check_for_valid_image_size(const heif_security_limits* limits, uint32_t wi
// Maximum coding-unit size (in pixels) that the given codec may pad a coded
// frame up to. Used as the margin for tighten_image_size_limit_for_ispe.
+// For AVC and JPEG, this is 64 instead of their coding-unit size of 16, so that
+// the margin also covers the stride alignment of the decoder (see the implementation).
// Returns 0 for codecs without coding-unit padding (e.g. uncompressed).
uint32_t max_coding_unit_size_for_codec(heif_compression_format format);
@@ -115,7 +117,7 @@ uint32_t max_coding_unit_size_for_codec(heif_compression_format format);
// to parse the codec bitstream ourselves.
//
// `coding_unit_size` is the maximum coding-unit size of the target codec
-// (e.g. 128 for AV1/VVC, 64 for HEVC, 16 for AVC). The allowed coded
+// (e.g. 128 for AV1/VVC, 64 for HEVC), see max_coding_unit_size_for_codec(). The allowed coded
// dimensions are (ispe + coding_unit_size) in each axis, since a codec may
// pad the coded frame up to a coding-unit boundary.
//