stride3d/stride · error · ApplicationException

Couldn't transfer frame data from GPU to CPU

Error message

Couldn't transfer frame data from GPU to CPU

What it means

When a decoded frame lives in GPU memory (hardware decoding, detected via the frame format matching the codec's HardwarePixelFormat), it must be copied to CPU memory with av_hwframe_transfer_data into pCpuCopyFrame. This ApplicationException is thrown when that transfer returns a negative FFmpeg error code.

Solutions

  1. Fall back to software decoding (disable hardware decoding) if hw transfer repeatedly fails
  2. Verify GPU drivers are current and the device is stable (no TDR)
  3. Check the FFmpeg build supports the used hwaccel (e.g. d3d11va) correctly
  4. Log the FFmpeg error code (ffmpeg.Av_strerror) to identify the exact hw failure

Example fix

// before
ret = ffmpeg.av_hwframe_transfer_data(pCpuCopyFrame, pDecodedFrame, 0);
if (ret < 0)
    throw new ApplicationException("Couldn't transfer frame data from GPU to CPU");
// after
ret = ffmpeg.av_hwframe_transfer_data(pCpuCopyFrame, pDecodedFrame, 0);
if (ret < 0)
{
    var err = FFmpegUtils.Avw_strerror(ret);
    throw new ApplicationException($"Couldn't transfer frame data from GPU to CPU: {err} (code {ret})");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// before extraction, verify hw device is alive
gpuDevice.DeviceRemovedReason == SharpDX.Result.Ok.Code // or equivalent graphics-device health check

Try / catch

try { status = media.ExtractNextImage(...); }
catch (ApplicationException ex) when (ex.Message.Contains("GPU to CPU"))
{
    // recreate media with software decoding fallback
    media.Dispose(); media = CreateMedia(useHardwareDecoding: false);
}

Prevention

When it happens

Trigger: ExtractNextImage encounters a hardware-decoded frame and av_hwframe_transfer_data fails — e.g. the hardware device context was lost, the GPU frame is invalid, or the hw device (GPU removed, driver reset, device lost) is unavailable.

Common situations: GPU driver resets/TDR during video playback; using hardware pixel formats on platforms where the hw device failed to initialize; mismatched hwaccel configuration in the FFmpeg build.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of stride3d/stride@96fad776d2 (2026-09-14). Data as JSON: /api/errors/690c9878943de87f. Report an issue: GitHub.

Appendix: source

Thrown at sources/engine/Stride.Video/FFmpeg/FFmpegMedia.cs:400

                        // and feed it the next packet.
                        continue;
                    }

                    if (ret < 0)
                    {
                        Logger.Error($"Error while receiving frame. Error code={ret.ToString("X8")}");
                        Logger.Error(GetErrorMessage(ret));
                        // Might be a bad frame, ignore it.
                        return FrameExtractionStatus.Failed;
                    }
                    var frameSideData = ffmpeg.av_frame_get_side_data(pDecodedFrame, AVFrameSideDataType.AV_FRAME_DATA_STEREO3D);

                    if (pDecodedFrame->format == (int)streamInfo.Codec.HardwarePixelFormat)
                    {
                        // the frame is coming from the GPU
                        ret = ffmpeg.av_hwframe_transfer_data(pCpuCopyFrame, pDecodedFrame, 0);
                        if (ret < 0)
                            throw new ApplicationException("Couldn't transfer frame data from GPU to CPU");

                        pFrame = pCpuCopyFrame;
                    }
                    else
                    {
                        pFrame = pDecodedFrame;
                    }

                    var width = pCodecContext->width;
                    var height = pCodecContext->height;
                    var sourcePixFmt = (AVPixelFormat)pFrame->format;
                    pConvertContext = ffmpeg.sws_getCachedContext(pConvertContext, width, height, sourcePixFmt, width, height, DestinationPixelFormat, ffmpeg.SWS_FAST_BILINEAR, null, null, null);
                    if (pConvertContext == null)
                        throw new ApplicationException("Could not initialize the conversion context.");

                    ffmpeg.sws_scale(pConvertContext, pFrame->data, pFrame->linesize, 0, outputImage.Height, dstData, dstLinesize);
                    outputImage.Timestamp = pDecodedFrame->pts;

View on GitHub (pinned to 96fad776d2)