D3D11硬件加速解码NV12格式AVFrame画面损坏问题求助
D3D11硬件加速解码NV12帧画面损坏问题解决记录
我基于ffmpeg-autogen实现视频解码器,尝试采用D3D11作为硬件加速器时,解码得到的NV12格式AVFrame画面损坏;改用Vulkan加速器则一切正常,但Vulkan会占用更多显卡资源。渲染环节使用OpenTK,通过纹理和着色器将接收的帧转换为RGB格式。
解码器初始化代码
public VideoStreamDecoder(AVCodecParameters* parameters, AVCodec* codec) { AVCodec* _codec = codec; _pCodecContext = ffmpeg.avcodec_alloc_context3(_codec); ffmpeg.av_hwdevice_ctx_create(&_pCodecContext->hw_device_ctx, AVHWDeviceType.AV_HWDEVICE_TYPE_D3D11VA, null, null, 0).ThrowExceptionIfError(); ffmpeg.avcodec_parameters_to_context(_pCodecContext, parameters).ThrowExceptionIfError(); ffmpeg.avcodec_open2(_pCodecContext, _codec, null).ThrowExceptionIfError(); CodecName = ffmpeg.avcodec_get_name(_codec->id); FrameSize = new Size(_pCodecContext->width, _pCodecContext->height); PixelFormat = _pCodecContext->pix_fmt; _pFrame = ffmpeg.av_frame_alloc(); _receivedFrame = ffmpeg.av_frame_alloc(); }
帧读取函数
public bool TryReadNextFrame(out AVFrame frame, AVPacket packet) { int error; do { ffmpeg.avcodec_send_packet(_pCodecContext, &packet).ThrowExceptionIfError(); error = ffmpeg.avcodec_receive_frame(_pCodecContext, _pFrame); } while (error == ffmpeg.AVERROR(ffmpeg.EAGAIN)); error.ThrowExceptionIfError(); ffmpeg.av_hwframe_transfer_data(_receivedFrame, _pFrame, 0); // 获取NV12格式帧 var clonedFrame = ffmpeg.av_frame_clone(_receivedFrame); frame = *clonedFrame; return true; }
现象对比
- Vulkan:显示正常
- D3D11(同一摄像头,视频格式为yuv420p):画面损坏
- 特殊现象:仅视频格式为yuvj420的摄像头能在D3D11下正常工作
尝试过的解决方案
- 使用
sws_scale将NV12格式转NV12,可解决问题但CPU占用过高 - 在
av_hwframe_transfer_data前将帧转换为RGB格式,Vulkan下勉强可用,但D3D11下无效
更新记录
- 发现帧的linesize大于宽度,尝试修改:
_receivedFrame->linesize[0] = _receivedFrame->width;
画面有所改善,但仍不完美。
- 添加以下代码后,画面恢复正常:
_receivedFrame->linesize[1] = _receivedFrame->width;
耗时一整天仅写了两行代码 :)
内容的提问来源于stack exchange,提问作者faith0058
相关产品推荐
相关产品推荐

