Skip to content

fix(previews): ffprobe hangs#60916

Open
adduxa wants to merge 2 commits into
nextcloud:masterfrom
adduxa:fix/previews/ffprobe-hangs
Open

fix(previews): ffprobe hangs#60916
adduxa wants to merge 2 commits into
nextcloud:masterfrom
adduxa:fix/previews/ffprobe-hangs

Conversation

@adduxa
Copy link
Copy Markdown
Contributor

@adduxa adduxa commented Jun 1, 2026

Summary

Fix pipe buffer deadlock in useHdr() in lib/private/Preview/Movie.php.

When ffprobe produces more than ~64KB on stderr, the sequential stream_get_contents calls
deadlock: PHP blocks reading stdout while ffprobe blocks flushing stderr. This caused
occ preview:generate-all to hang indefinitely on certain video files.

A tempting workaround is to swap the two stream_get_contents calls (reading stderr first),
but I'm not sure if ffprobe is guaranteed to produce <64KB on the stdout for this call.

Fix drains both pipes concurrently using stream_select with non-blocking I/O.

TODO

  • ...

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

Signed-off-by: Andrey Dyakov <adduxa@gmail.com>
@adduxa adduxa requested a review from a team as a code owner June 1, 2026 21:27
@adduxa adduxa requested review from ArtificialOwl, artonge, icewind1991 and leftybournes and removed request for a team June 1, 2026 21:27
@susnux susnux added bug 3. to review Waiting for reviews labels Jun 1, 2026
@susnux susnux added this to the Nextcloud 35 milestone Jun 1, 2026
Comment thread lib/private/Preview/Movie.php Outdated
}
foreach ($read as $pipe) {
$chunk = fread($pipe, 8192);
if ($chunk === false) continue;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fail CI lint.

Comment thread lib/private/Preview/Movie.php Outdated
!feof($test_hdr_pipes[2]) ? $test_hdr_pipes[2] : null,
]);
$write = $except = [];
if (stream_select($read, $write, $except, 5) === false) {
Copy link
Copy Markdown
Member

@solracsf solracsf Jun 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This 5 is a per-iteration timeout. Only the false (error) return is handled; the 0 (timeout) return falls through, $read becomes empty, the foreach does nothing, and the while loops again. So if ffprobe truly hangs (produces no output and never closes its pipes), this spins every 5s forever: the same "hangs indefinitely" symptom the PR title targets, just via a different path.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! I will search for the solution.

Do you know if stdout is always <64k here? Is it acceptable to just read stderr first in this case?

This approach is used at https://github.com/adduxa/server/blob/1bcc80b5f45a0d8619df64edbd2fec797fd70cd9/lib/private/Preview/Movie.php#L374 for ffmpeg

Copy link
Copy Markdown
Contributor

@invario invario Jun 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In useHDR, yes, stdout is always <64K here due to the command line switches passed '-of', 'default=noprint_wrappers=1:nokey=1'. The value will always be something like 'bt709' or (in the case of an HDR file) 'smpte2084' or 'arib-std-b67', so very small.

In the case of useHDR I think a better solution (which I am working on) is filtering the output using command line switches from ffprobe since it is all extraneous information that we do nothing with. useHDR only needs to know if libzimg is installed, and if the file is HDR (based on the colortransfer value from ffprobe).

Also, I replied separately in your issue thread with some important questions, and a request for a sample file for testing purposes.

Thanks!

Copy link
Copy Markdown
Contributor

@invario invario Jun 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, got your file, looked into it a bit. You are spot on! Just flipping the two lines and reading stderr first will resolve this. Preview generation itself already does it in this order. ffmpeg outputs nothing to stdout unless we tell it to like in useHDR (and very little in this case, will never fill the buffer)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for you time! I pushed a new fix

Signed-off-by: Andrey Dyakov <adduxa@gmail.com>
@invario
Copy link
Copy Markdown
Contributor

invario commented Jun 3, 2026

Maintainers are going to ask you to squash your commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3. to review Waiting for reviews bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: preview:generate-all hangs indefinitely on a specific .MTS video file waiting for ffprobe

4 participants