22 Commits
Author SHA1 Message Date
Martin Mirchev cc30be196d avfilter/vf_curves: unmap the psfile with the mapped pointer and size
parse_psfile() advances buf and decrements size while reading the
file, and then passed these to av_file_unmap() instead of what
av_file_map() returned. With mmap, munmap() then fails with EINVAL
because the pointer is no longer page aligned, so the mapping leaks on
every init and every psfile command; on builds without mmap, av_free()
is called on a pointer into the middle of the buffer.

Keep the mapped pointer and size and unmap those.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-11-06 03:25:05 +00:00
Martin Mirchev c1a03c29ed doc/filters: concat next fails on the last segment
Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-11-06 01:58:48 +00:00
Martin Mirchev 58c989a73d avfilter/avf_concat: reject the next command on the last segment
process_command() called flush_segment() without checking that there is a
next segment. On the last segment this moved cur_idx past the inputs while
the outputs still wanted frames, so activate() accessed cat->in[] and
ctx->inputs[] out of bounds and crashed, e.g.

  ffmpeg -f lavfi -i "testsrc2=d=0.2[a];testsrc2=d=1[b];[a][b]concat=n=2,sendcmd=c='0.3 concat next'" -f null -

Fail the command instead.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-11-06 01:58:48 +00:00
Martin Mirchev c511a7fcf7 fate/image: add a test for 16-bit JPEG-LS with line interleaving
Encode a 16-bit gray image with the jpegls encoder, set the ILV byte of
the SOS header to 1 and check that it decodes to the source picture.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-11-03 12:58:10 +00:00
Martin Mirchev 60bc31fcf6 avcodec/jpeglsdec: decode line interleaved scans with more than 8 bits
The ILV=1 (line interleaved) path always called ls_decode_line() with
8 bits per sample, while the ILV=0 path selects 8 or 16 bits from the
frame. JPEG-LS with more than 8 bits is only accepted for a single
component, for which line interleaving is equivalent to ILV=0, but such
a scan was decoded as 8-bit samples into the 16-bit frame: only half of
each line was written and the output was wrong, e.g. a 16-bit gray image
from our encoder with the ILV byte set to 1 decodes to a different
picture than with ILV=0.

Use the 16-bit line decoder for more than 8 bits, as for ILV=0.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-11-03 12:58:10 +00:00
Martin Mirchev 332df18e67 avformat/mov: reject tfra boxes smaller than their header
mov_read_mfra() calls read_tfra() until it returns non-zero, and
read_tfra() ends by seeking to the box start plus its declared size.
A tfra box with size 0 therefore seeks back onto itself and is parsed
again forever. Since the whole box stays in the AVIOContext buffer, no
read reaches the protocol layer and the interrupt callback is never
checked, so the demuxer cannot be interrupted either.

The mfra is read on the first moof when use_mfra_for is enabled, which
an "Anevia" free box does by default, so a 76-byte file can make
avformat_open_input() spin indefinitely.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-30 17:20:33 +00:00
Martin Mirchev 60a2818f76 fate/vpx: add a test for Theora quantizer changes with frame threading
Patch the first quantizer of the first frame of a remuxed existing
sample that uses three quantizers per frame, and decode it with four
frame threads.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-30 04:22:49 +00:00
Martin Mirchev 7b3b537d55 avcodec/vp3: fix quantizer matrix update with frame threading
vp3_update_thread_context() compared every s->qps[i] with s1->qps[1]
instead of s1->qps[i]. When a thread's previous qps[i] happened to
equal the new qps[1], qmat[i] was not copied while qps[] still was, so
the next frame with the same quantizers was dequantized with a stale
matrix and the output depended on the number of threads.

This only affects Theora streams that use more than one quantizer per
frame.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-30 04:22:49 +00:00
Martin Mirchev 6b49c0e8d1 tests/fate/jxl: add a parser test for an empty box and a box of size 0
Two concatenated container images: the first ends with an empty
"free" box, the "jxlc" box of the second has size 0. The parser must
output them as two packets, and must not treat size 0 as an invalid
box size.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-28 02:25:25 +00:00
Martin Mirchev 47605bb2cd avcodec/jpegxl_parser: fix handling of special ISOBMFF box sizes
skip_boxes() treated a box of size 0 and an empty box (size equal to
the header size) as invalid. jpegxl_parse() then set ctx->next to -1,
which disables the search for the end of the image for the rest of the
stream, so all following images were merged into a single packet,
which is only output at EOF.

An empty box is valid and is now skipped. A box of size 0 extends to
the end of the file, so the rest of the stream belongs to the current
image; keep that behaviour, but explicitly. Boxes too large to track
are treated the same way, as before. A box smaller than its header is
invalid: log an error and end the current image at that box instead
of silently swallowing the rest of the stream.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-28 02:25:25 +00:00
Martin Mirchev 0718c6e195 fate/ogg-vorbis: add a test for a chained stream with a large comment
Remux two short streams from an existing sample, the second one with a
70000-byte comment header, and demux their concatenation.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-28 01:57:05 +00:00
Martin Mirchev 94110fbc39 avformat/oggparsevorbis: fix chained streams with headers over 64 KiB
When a chained Vorbis stream starts, its three header packets are
packed into new extradata with 16-bit size prefixes. A header larger
than 65535 bytes, typically a comment header with embedded cover art,
gets its size truncated, so the Vorbis parser cannot be reinitialized
and demuxing fails with "Failed to re-initialize Vorbis parser". The
audio of the new chained stream and everything after it is lost.

Use Xiph lacing instead, as vorbis_header() already does for the
initial extradata.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-28 01:57:05 +00:00
Martin Mirchev ab0eeb03cc tests/fate/filter-video: add tests for vignette backward mode
Use angle 0, so the gain is exactly 1 inside dmax, and move the center
to the top left corner so that part of the frame lies beyond dmax and
must saturate. Cover the planar (yuv444p) and packed (rgb24) paths.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-26 22:36:19 +00:00
Martin Mirchev a7241b6a77 avfilter/vf_vignette: keep the backward gain finite
In backward mode the gain is 1 / factor, but the factor is 0 for pixels
farther than dmax from the center (possible with x0/y0 or aspect), so
the gain is inf. inf * sample, or inf * 0 = NaN, is then converted to
int, which is undefined behaviour; on x86 these pixels come out black
instead of saturated.

For angles close to PI/2, the factor can also become small enough that
a finite backward gain produces sample values outside the range of int
before av_clip_uint8() is called. Bound the gain at 256 to keep these
conversions in range while preserving the saturated 8-bit output.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-26 22:36:19 +00:00
Martin Mirchev 4bef4614fe tests/fate/mov: add a test for IAMF stream group id collisions
Mux two IAMF audio elements with ids 1 and 2 and a mix presentation with
id 1 into mp4, then demux and probe the result. Without the previous
commit the mov demuxer aborts on an assertion when reading this file.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-21 16:32:08 +00:00
Martin Mirchev 6dba2558c0 avformat/mov: check the stream group type when updating IAMF streams
The lookup of the stream group for each IAMF audio element compared only
the group id and kept the last match. Mix presentation groups are created
after the audio element groups and use the mix_presentation_id as their
id, so if a mix_presentation_id equals an audio_element_id the mix
presentation group was picked instead. Its entries are the streams of
every audio element, so the same output stream got its index entries
filled twice and the av_assert0(!out_sti->index_entries) aborted.

Such files are written by FFmpeg's own mp4 muxer, e.g. with two audio
elements with ids 1 and 2 and a mix presentation with id 1.

Also check the group type. Keep using the last match: audio element ids
are only unique within one IAMF track, and the groups of the current
track were just appended, so the last match is the audio element of the
current track even if an earlier track uses the same id.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-21 16:32:08 +00:00
Martin Mirchev ca85613d10 tests/fate/libavutil: add a test for the IAMF AVClass hierarchy
Print the child class tree of the IAMF AVClasses as returned by
av_opt_child_class_iterate() and look up options of the child classes
with av_opt_find2() and AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-21 14:56:54 +00:00
Martin Mirchev 54502377c6 avutil/iamf: fix child_class_iterate callbacks
The child_class_iterate callbacks of AVIAMFAudioElement,
AVIAMFSubmixElement and AVIAMFMixPresentation returned their single
child class only for a non-zero iteration state. The state starts at
zero, so they never returned anything, and av_opt_child_class_iterate()
and av_opt_find2() with AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ
could not reach the AVIAMFLayer, AVIAMFParamDefinition and AVIAMFSubmix
options from these classes.

Return the child class on the first call instead.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-21 14:56:54 +00:00
Martin Mirchev 510dbddd52 avcodec/h264_parse: return SPS/PPS errors from avcC with explode
decode_extradata_ps_mp4() skips the retry with an escaped NAL when
AV_EF_EXPLODE is set, but then returns 0 regardless, so a parameter set
that fails to parse in avcC extradata is silently ignored exactly when
the caller asked for errors to be fatal. h264_decode_init() fails on
extradata errors only with explode, so avcodec_open2() succeeded with
-err_detect explode on avcC extradata with a broken SPS, and the
"Decoding sps %d from avcC failed" path was unreachable.

Return the error when explode is set.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-21 14:52:52 +00:00
Martin Mirchev 5993347a1b avformat/flvenc: reject text packets too long for an AMF0 string
AV_CODEC_ID_TEXT packets are written as an AMF0 string, whose length is a
16-bit field. For text over 65535 bytes the length wrapped (e.g. 4464 for
70000 bytes) while the whole text was written, so readers misparse the
onTextData tag.

Fail on such packets before writing the tag.
Found while reviewing the metadata length fix for FLV.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-19 19:33:13 +00:00
Martin Mirchev beb7168452 swscale/output: write the last partial byte in the mono error-diffusion paths
The SWS_DITHER_ED branches of yuv2mono_1_c_template() and
yuv2mono_2_c_template() only store a byte when (i & 7) == 6, so for widths
whose last pixel pair does not end a byte the final partial byte of each
row is never written and keeps whatever the destination held. Converting a
white 100x8 frame with -sws_flags +error_diffusion -pix_fmt monob leaves the
last 4 pixels of rows 1-7 black (0x00 instead of 0xf0).

Write the pending bits after the loop, shifted into the high bits as monob
expects, like the non-ED paths.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-19 00:51:53 +00:00
Martin Mirchev 6076399974 avfilter/vf_colormap: fix single-patch coefficient index
With one patch, the per-channel gains were written to transposed
coefficient indices. Subsequent channel initialization cleared the first
two misplaced gains, while the third was stored in an unused column,
leaving the identity transform in place: mapping 0xA06040 to 0x503020
turned 0xA06040 into (160,97,63) instead of (80,48,32).

Store each gain at icoeff[1+c][c], matching the pixel loop and the
two-patch case.

Signed-off-by: Martin Mirchev <mmirchev@comp.nus.edu.sg>
2026-10-18 19:07:29 +00:00