You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity调用OpenCV DLL播放RTSP遇MarshalDirectiveException错误求助

问题解决方案

一、解决MarshalDirectiveException异常

你遇到的核心问题是托管的OpenCvSharp.Mat无法直接通过P/Invoke传递给非托管C++的cv::Mat,CLR无法自动封送没有StructLayout属性的托管对象。解决思路是避开直接传递Mat对象,改用底层数据交互:

方案1:传递Mat的原始数据参数

修改C#和C的函数签名,传递Mat的内存指针、宽、高、通道数等核心参数,让C端重新构造cv::Mat:

C# 代码

[DllImport("OpenCVDll")]
private static extern void PlayRTSP(IntPtr dataPtr, int width, int height, int channels, IntPtr rtspLink);

// 调用示例(假设已通过OpenCvSharp获取Mat)
Mat frame = ...; // 初始化或从其他地方获取的Mat
IntPtr rtspLink = Marshal.StringToHGlobalAnsi("rtsp://your-stream-url");
PlayRTSP(frame.DataPointer, frame.Width, frame.Height, frame.Channels(), rtspLink);
Marshal.FreeHGlobal(rtspLink);

C++ 代码

extern "C" __declspec(dllexport) void PlayRTSP(unsigned char* dataPtr, int width, int height, int channels, LPCSTR rtspLink) {
    // 根据参数构造cv::Mat,这里假设是8位无符号整数类型
    cv::Mat img(height, width, CV_MAKETYPE(CV_8U, channels), dataPtr);
    // 后续RTSP流读取、帧处理逻辑(写入img)
}

注意:确保C#端的Mat数据缓冲区在C++操作期间不会被回收,避免内存访问错误。

方案2:C++端封装RTSP逻辑,返回字节数组给Unity

让C++ DLL内部处理RTSP流和cv::Mat,仅将图像原始字节数据返回给C#,再由C#转换为Unity支持的Texture2D:

C++ 代码

#include <opencv2/opencv.hpp>
#include <cstring>

static cv::VideoCapture cap;

extern "C" __declspec(dllexport) int InitRTSP(LPCSTR rtspLink) {
    cap.open(rtspLink);
    return cap.isOpened() ? 0 : -1;
}

extern "C" __declspec(dllexport) int GetRTSPFrame(unsigned char* outBuffer, int bufferSize, int* outWidth, int* outHeight) {
    if (!cap.isOpened()) return -1;
    
    cv::Mat frame;
    cap >> frame;
    if (frame.empty()) return -2;
    
    int requiredSize = frame.total() * frame.elemSize();
    if (bufferSize < requiredSize) {
        *outWidth = frame.cols;
        *outHeight = frame.rows;
        return requiredSize; // 返回需要的缓冲区大小
    }
    
    memcpy(outBuffer, frame.data, requiredSize);
    *outWidth = frame.cols;
    *outHeight = frame.rows;
    return 0;
}

C# 代码(Unity中)

[DllImport("OpenCVDll")]
private static extern int InitRTSP(IntPtr rtspLink);

[DllImport("OpenCVDll")]
private static extern int GetRTSPFrame(byte[] outBuffer, int bufferSize, out int width, out int height);

private Texture2D rtspTexture;
private IntPtr rtspLinkPtr;

void Start() {
    rtspLinkPtr = Marshal.StringToHGlobalAnsi("rtsp://your-stream-url");
    int initResult = InitRTSP(rtspLinkPtr);
    if (initResult != 0) {
        Debug.LogError("Failed to initialize RTSP stream");
        return;
    }
}

void Update() {
    int width = 0, height = 0;
    int requiredSize = GetRTSPFrame(null, 0, out width, out height);
    if (requiredSize <= 0) return;
    
    if (rtspTexture == null || rtspTexture.width != width || rtspTexture.height != height) {
        rtspTexture = new Texture2D(width, height, TextureFormat.RGB24, false);
    }
    
    byte[] frameData = new byte[requiredSize];
    int result = GetRTSPFrame(frameData, requiredSize, out width, out height);
    if (result != 0) return;
    
    // OpenCV默认BGR格式,转成Unity需要的RGB
    for (int i = 0; i < frameData.Length; i += 3) {
        byte temp = frameData[i];
        frameData[i] = frameData[i + 2];
        frameData[i + 2] = temp;
    }
    
    rtspTexture.LoadRawTextureData(frameData);
    rtspTexture.Apply();
    // 将texture赋值给Material或RawImage显示
}

void OnDestroy() {
    Marshal.FreeHGlobal(rtspLinkPtr);
}

二、cv::Mat转Unity支持的数据类型

常用的转换方式有三种:

  • 字节数组转Texture2D:如上面方案2所示,将cv::Mat的原始字节数据(注意BGR转RGB)传递给Unity,用Texture2D.LoadRawTextureData()加载并显示,这是最通用的方式。
  • 直接操作Unity RenderTexture:通过Unity的NativeTexturePtr获取RenderTexture的底层指针,让C++直接将cv::Mat的数据写入RenderTexture,这种方式性能更高,但需要熟悉Unity的原生渲染API和内存管理。
  • OpenCVSharp辅助转换:如果坚持用OpenCVSharp,确保使用与Unity兼容的版本(比如针对.NET Framework 4.x的版本),可以尝试Mat.ToTexture2D()方法,但要提前将OpenCVSharp的相关DLL放入Unity的Plugins目录。

三、Unity为何不原生支持RTSP

Unity的核心定位是游戏引擎,其内置的VideoPlayer组件优先支持通用性强、场景适配广的视频源(本地文件、HTTP/HTTPS流)。RTSP是实时流媒体协议,涉及复杂的会话协商、RTP数据包解析、丢包重传等逻辑,且不同RTSP服务器的实现差异较大,通用性差。Unity没有内置这些功能,是为了避免增加引擎体积和复杂度,这类需求通常交给第三方插件(如EasyRTSP、FFmpeg绑定插件)或开发者自定义实现。

内容的提问来源于stack exchange,提问作者erin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 23:34:57