Skip to content

Misc. bug: mtmd video input hangs on Windows — probe() deadlocks on faststart MP4, decode emits 0 frames when MOOV at end #24429

Description

@warshanks

Name and Version

.\build\bin\Release\llama-cli.exe --version
version: 9590 (d2462f8)
built with MSVC 19.44.35227.0 for x64

Operating systems

Windows

Which llama.cpp modules do you know to be affected?

llama-cli, Other (Please specify in the next section), llama-server

Command line

.\build\bin\Release\llama-cli.exe -m gemma-4-12B-it-qat-UD-Q4_K_XL.gguf -mm mmproj-F32.gguf -v
# then in chat:
# /video C:\Users\Ben\Videos\test.mp4
# Tell me about this video

Problem description & steps to reproduce

Name and Version

version: b9590 (d2462f8)
built for Windows x86_64, CUDA backend (RTX 3090)

Operating systems

Windows

Which llama.cpp modules do you know to be affected?

llama-cli, mtmd

Problem description & steps to reproduce

Video input on Windows hangs in two different ways depending on where the MP4 MOOV atom is located. Both appear to be in the ffmpeg/ffprobe subprocess pipe handling in tools/mtmd/mtmd-helper.cpp (mtmd_helper_video). This extends #24394 (silent zero-frame failure on Linux) with Windows repro data — on Windows it hangs rather than failing silently.

Case 1: MOOV atom at end of file (default ffmpeg output)

probe() succeeds (ffprobe has to read the entire piped input to find the moov, so it fully drains stdin and exits cleanly). The ffmpeg decode step then produces zero frames:

0.24.617.771 D start_ffmpeg: launching: ffmpeg -nostdin -i cache:pipe:0 -vf fps=4.000000 -f rawvideo -pix_fmt rgb24 pipe:1 -loglevel error
0.24.622.579 D start_ffmpeg: subprocess_create ret=0 proc_alive=1
0.24.622.583 D start_ffmpeg: starting feeder thread for 1194147-byte buffer
0.24.622.649 D read_next_frame: reading frame 0, expecting 2764800 bytes (720x1280)
0.24.668.259 D read_next_frame: fread returned 0 after 0/2764800 bytes (ferror=0)
0.24.668.268 D add_text: <|turn>system ...
0.24.668.306 D add_text: Video:
0.24.668.319 D add_text: Tell me about this video<turn|>

The prompt is assembled with the bare Video: text and no frames, and then llama-cli hangs (no generation, no error).

Case 2: MOOV atom at front (-movflags +faststart)

After remuxing the same file with ffmpeg -i test.mp4 -c copy -movflags +faststart test_fast.mp4, the hang moves earlier, into probe() itself. The log stops here and never prints the probe result line:

0.28.766.262 D res  add_waiting_: add task 0 to waiting list. current waiting = 0 (before add)
0.28.766.269 D que    post: new task, id = 0, front = 0
0.28.767.532 D probe: launching: ffprobe -v quiet -show_entries stream=width,height,r_frame_rate,nb_frames,duration -select_streams v:0 -of default=noprint_wrappers=1 pipe:0
(hangs indefinitely)

Isolation: ffprobe itself behaves correctly on the same file

Running the exact probe command manually with a real pipe (cmd.exe, binary-safe):

C:\Users\Ben>cmd /c "type C:\Users\Ben\Videos\test_fast.mp4 | ffprobe -v quiet -show_entries stream=width,height,r_frame_rate,nb_frames,duration -select_streams v:0 -of default=noprint_wrappers=1 pipe:0"
width=720
height=1280
r_frame_rate=30/1
duration=7.050391
nb_frames=211
The process tried to write to a nonexistent pipe.

ffprobe prints the metadata and exits promptly. Because the moov is at the front, it stops reading stdin early; the writer (type) gets the expected broken-pipe error and terminates. So the deadlock is in how mtmd_helper_video handles this early-exit case on Windows: the feeder thread is blocked in fwrite() on the child's stdin while the main thread is blocked in fgets() on the child's stdout, and neither unblocks when ffprobe stops reading / exits.

Minor side issue while debugging: the probe() debug line prints fps_target and a not-yet-assigned info.n_frames, e.g. probe: 720x1280 fps=4.00 duration=7.02s n_frames=0 for a 30 fps / 211-frame video — info.n_frames is assigned on the line after the LOG_DBG, and fps here is the sampling target, not the source fps. Made the logs confusing to interpret.

Test video: 720x1280, H.264, 7.05 s, 30 fps, ~1.2 MB. Happy to provide the file or more verbose logs if useful.

First Bad Commit

Video input is new in #24269 (b9577); also reproduces after the #24316 refactor.

Relevant log output

Logs

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions