Skip to content

Declare _get_hw_format nogil - #2410

Closed
adrianrfreedman wants to merge 1 commit into
PyAV-Org:mainfrom
adrianrfreedman:fix/get-hw-format-nogil
Closed

adrianrfreedman wants to merge 1 commit into
PyAV-Org:mainfrom
adrianrfreedman:fix/get-hw-format-nogil

Conversation

@adrianrfreedman

@adrianrfreedman adrianrfreedman commented Sep 17, 2026

Copy link
Copy Markdown

_get_hw_format is installed as AVCodecContext.get_format, so libavcodec calls it from inside avcodec_send_packet, which PyAV runs under with nogil (av/codec/context.pyx). The callback therefore runs with no GIL held, and any Python object operation in it segfaults the interpreter.

It is already GIL-free in practice. AVCodecPrivateData holds only AVPixelFormat and bint, and since the pure-Python-mode migration the loop counter is typed (i: cython.int = 0), so nothing gets boxed. Nothing enforces that though. Declaring the callback nogil makes Cython reject a future change that reintroduces a Python object at compile time, rather than at runtime as a crash.

This is hardening, not a fix. The crash was real in 16.x, where the counter was untyped: i += 1 compiled to PyLong_FromLong/PyNumber_Add, so every hwaccel initialisation failure took the process down with SIGSEGV instead of falling back to software decoding. 17.0.0 fixed it as a side effect of the typing change rather than deliberately, which is why I think the constraint is worth pinning. Background in #2411.

Verified on an L40S. 16.x segfaults on a stream NVDEC cannot decode (10-bit H.264), and this branch decodes the same file through the software fallback cleanly. Built with python setup.py build_ext --inplace against the vendored ffmpeg from scripts/ffmpeg-latest.json (libavcodec 63.1.101).

No functional change.

_get_hw_format is installed as AVCodecContext.get_format, so libavcodec calls
it from inside avcodec_send_packet, which runs under `with nogil`. Any Python
object operation in the callback would execute without the GIL and crash the
interpreter.

It is already GIL-free in practice -- AVCodecPrivateData holds only plain C
fields and the loop counter is typed -- but nothing enforces that. Declaring it
nogil makes Cython reject a future change that reintroduces a Python object at
compile time rather than at runtime.

No functional change.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@WyattBlue

Copy link
Copy Markdown
Member

The commit message is so lousy, so I'd rather just add this myself.

@WyattBlue WyattBlue closed this Sep 17, 2026
@adrianrfreedman

Copy link
Copy Markdown
Author

The commit message is so lousy, so I'd rather just add this myself.

This seems a bit unfair. Why not give me the opportunity to amend the commit?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants