Skip to content

Preserve selected codec across a failed CodecContext.open() - #2506

Merged
WyattBlue merged 1 commit into
masterfrom
preserve-codec-on-failed-open
Nov 4, 2026
Merged

WyattBlue merged 1 commit into
masterfrom
preserve-codec-on-failed-open

Conversation

@WyattBlue

@WyattBlue WyattBlue commented Nov 4, 2026 •

Copy link
Copy Markdown
Member

A failed avcodec_open2() runs FFmpeg's cleanup path (free_and_end: → ff_codec_close()), which sets avctx->codec = NULL. After a failed CodecContext.open(), the context is left broken:

ctx = av.AudioCodecContext.create("aac", "w")
ctx.format = av.AudioFormat("s16")  # AAC wants fltp
ctx.layout = "stereo"; ctx.sample_rate = 44100
try:
    ctx.open()
except av.error.FFmpegError:
    pass
ctx.codec        # -> UnknownCodecError; ptr.codec is NULL
ctx.is_encoder   # likewise broken

Capture the codec pointer before avcodec_open2() and restore it on failure, in open() alone. Every reader of ptr.codec then stays correct, and the context can be reopened after fixing the offending parameters. This fixes the root cause in one place rather than guarding each reader. AVCodec structs are static globals in FFmpeg, so holding and restoring the pointer has no lifetime risk.

Why the pointer, not codec_id?

codec_id survives the failed open, but it identifies a format, not an implementation: aac and aac_at share the same id, as do h264/libx264/h264_videotoolbox. Re-deriving via avcodec_find_encoder(codec_id) could silently swap in a different codec than the caller selected. Restoring the pointer preserves the exact codec.

@WyattBlue
WyattBlue force-pushed the preserve-codec-on-failed-open branch 3 times, most recently from 962ef1a to ae84d1e Compare November 4, 2026 23:26
A failed avcodec_open2() runs FFmpeg's cleanup (ff_codec_close), which
sets avctx->codec to NULL. That left the context in a broken state:
codec, name, is_encoder, and is_decoder would raise or crash, and the
context could not be reused.

Capture the codec pointer before avcodec_open2() and restore it on
failure, in open() alone, so every reader of ptr.codec stays correct and
the context can be reopened after fixing the offending parameters.

The failed open still resets other fields (notably layout drops to 0
channels), so a retry must re-apply the parameters set before; this is
documented in the open() docstring.
@WyattBlue
WyattBlue force-pushed the preserve-codec-on-failed-open branch from ae84d1e to 203da84 Compare November 4, 2026 23:28
@WyattBlue
WyattBlue merged commit 0edf2b7 into master Nov 4, 2026
10 checks passed
@WyattBlue
WyattBlue deleted the preserve-codec-on-failed-open branch November 4, 2026 23:36
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.

1 participant