C#使用Gstreamer-d3d11-overlay渲染时Sink.Emit指针错误问题求助
解决GStreamer D3D11Overlay Sink Emit "draw"信号时的参数类型错误问题
你遇到的核心问题是gstreamer-sharp在传递非托管类型参数(比如IntPtr)给Emit方法时的类型绑定不匹配,导致反射调用时抛出参数类型异常。下面是针对性的解决方案和思路:
1. 问题根源分析
GStreamer的d3d11overlay sink的draw信号期望接收原生的共享句柄(HANDLE)类型,但gstreamer-sharp的Emit方法直接传递System.IntPtr时,无法正确映射到GStreamer内部期望的gpointer或HANDLE类型,从而触发Invalid parameter type异常。
2. 修复方案:手动包装GLib.Value参数
解决的关键是将每个参数都显式包装为GLib.Value类型,确保类型匹配GStreamer的信号签名。修改你的VideoSink_OnBeginDraw方法如下:
private void VideoSink_OnBeginDraw(Element sink, GLib.SignalArgs args) { var sharedHandle = _D3D11Scene.GetSharedHandle(); // 为每个参数创建对应的GLib.Value,确保类型匹配 using var sharedHandleValue = new GLib.Value(GLib.GType.Pointer); sharedHandleValue.SetPointer(sharedHandle); using var formatValue = new GLib.Value((uint)2); // 这里的2对应D3D11_TEXTURE2D_FORMAT_R8G8B8A8_UNORM,可根据场景调整 using var offsetXValue = new GLib.Value((ulong)0); using var offsetYValue = new GLib.Value((ulong)0); // 构建参数数组并调用Emit var parameters = new GLib.Value[] { sharedHandleValue, formatValue, offsetXValue, offsetYValue }; _ = sink.Emit("draw", parameters); }
为什么这样有效?
GLib.Value是GStreamer绑定中用于传递类型安全参数的容器,通过SetPointer可以正确将IntPtr(共享句柄)转换为GStreamer识别的原生指针类型。- 显式指定每个参数的类型,避免了gstreamer-sharp自动类型转换时的错误。
3. 额外验证步骤
- 确认
_D3D11Scene.GetSharedHandle()返回的是有效的D3D11共享纹理句柄:该句柄必须是通过IDXGIResource1::CreateSharedHandle创建的,且权限包含DXGI_SHARED_RESOURCE_READ,确保GStreamer可以访问该纹理。 - 检查
d3d11overlaysink的版本:确保你使用的gstreamer-d3d11-overlay组件是最新版本,避免已知的绑定或参数签名问题。
4. 备选方案:OpenTK集成思路
如果D3D11Overlay的问题持续,你提到的OpenTK方案也是可行的,核心步骤如下:
- 使用
glimagesink作为GStreamer的渲染输出,通过gst_gl_memory_get_texture原生API(需P/Invoke或扩展gstreamer-sharp绑定)获取其内部的OpenGL纹理ID。 - 共享OpenGL上下文:确保GStreamer的OpenGL上下文和OpenTK的上下文是共享的,这样OpenTK可以直接使用GStreamer创建的纹理。
- 渲染到WPF:使用
OpenTK.Wpf控件,在其渲染循环中绑定共享的纹理并绘制,再将控件嵌入WPF界面,规避空域问题。
内容的提问来源于stack exchange,提问作者Chinny
相关产品推荐
相关产品推荐

