When using VAAPI hardware decoding, certain malformed or corrupt frames at the
start of the stream may cause the ffmpeg h/w decoder to emit `AVERROR(EIO)` or
`AVERROR(EINVAL)` early in the picture decoding phase.
In these cases, libav will log errors such as:
[ ERROR]:libav: AVCodecContext: Failed to upload decode parameters: 18 (invalid parameter).
[ ERROR]:libav: AVCodecContext: Failed to end picture decode after error: 18 (invalid parameter).
[ ERROR]:libav: AVCodecContext: hardware accelerator failed to decode picture
Currently, Tvheadend treats these errors as fatal, resulting in the transcoder
stream being torn down via `tvh_stream_stop()` and interrupting client playback,
typically leaving only audio and a black screen.
While this behavior is somewhat tolerable during live TV viewing—where the user
can manually resolve the issue by changing channels—it is significantly more
disruptive in recording scenarios, as it results in recordings containing only
audio and no video.
However, when the same streams are run directly through FFmpeg’s CLI, FFmpeg
**does not abort** on these errors — it logs them and continues transcoding.
This makes FFmpeg's failure handling more robust than Tvheadend's.
To identify which errors should be considered recoverable, the transcoder was
instrumented to log the exact `AVERROR` codes encountered during decoding failures.
A stress test was then run using a channel-hopping script that switched channels
every 5 seconds over several hours. The failure rate was approximately 1%, and
in **all** cases, the decoding failures were either `AVERROR(EIO)` or
`AVERROR(EINVAL)`. Allowing the stream to continue after these specific errors
proved effective — playback resumed, and only a minor picture glitch was visible
at the affected frame, with no need to tear down the video stream.
This patch updates `tvh_context_decode()` to include `AVERROR(EIO)` and
`AVERROR(EINVAL)` in the list of tolerated decode errors, aligning Tvheadend's
behavior with FFmpeg’s more forgiving approach.
FFmpeg’s internal decoder logic in `vaapi_h264.c` and `decode.c` supports this
tolerance model. For example, in `decode_simple_internal()` and `submit_frame()`,
errors like `EIO` may occur during `av_hwframe_transfer_data()` or `vaEndPicture()`,
but are **not considered fatal**. Instead, FFmpeg logs the issue and decoding
continues on the next frame.
if (!ret && !(ret = _context_decode(self, avpkt))) {
ret = tvh_context_decode_packet(self, avpkt);
}
- return (ret == AVERROR(EAGAIN) || ret == AVERROR_INVALIDDATA) ? 0 : ret;
+ return (ret == AVERROR(EAGAIN) || ret == AVERROR_INVALIDDATA ||
+ ret == AVERROR(EIO) || ret == AVERROR(EINVAL) ) ? 0 : ret;
}