From: James Hutchinson Date: Sat, 3 May 2025 11:02:58 +0000 (+0100) Subject: transcode: gracefully handle common hardware decoder errors X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=85360924d0e215c2ba0b1b224e3111be712eae0f;p=thirdparty%2Ftvheadend.git transcode: gracefully handle common hardware decoder errors 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. --- diff --git a/src/transcoding/transcode/context.c b/src/transcoding/transcode/context.c index 7480b6b69..09f935ed7 100644 --- a/src/transcoding/transcode/context.c +++ b/src/transcoding/transcode/context.c @@ -474,7 +474,8 @@ tvh_context_decode(TVHContext *self, AVPacket *avpkt) 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; }