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

Unity中基于SDL获取显微镜视频流RGB原始数据并解析的问题

解析显微镜视频流并在Unity中显示

我通过SDL库获取到了显微镜的视频流frameData数据,但不知道如何解析这些数据,生成Unity可使用的视频内容。相关代码如下:

public class CameraStreamManager : MonoBehaviour
{
    private Thread cameraThread;
    private bool isRunning = false; 
    private SLcamNet.NetCamera _camera; 
    private Texture2D videoTexture;

    public RawImage videoImage; 

    private List<NetInfo> _infos;
    private CameraInfo _cameraInfo;
    private SDLPanel sdlPanel; 
    private Task _task; 

    private int width = 1920;  
    private int height = 1080;
    private bool frameReady = false;

    public void InitializeCamera()
    {
        SLcamNet.NetCamera.InitNet();
        _infos = SLcamNet.NetCamera.SearchAvailableCameras();
        if (_infos.Count < 1)
        {
            Thread.Sleep(100);
            _infos = SLcamNet.NetCamera.SearchAvailableCameras();
        }
    }

    public void OpenCamera()
    {
        sdlPanel?.Dispose();
        sdlPanel = new SDLPanel
        {
            Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right
        };

        Debug.LogError("_infos>>>>  " + _infos.Count);
        if (_infos.Count < 1)
        {
            Thread.Sleep(100);
            _infos = SLcamNet.NetCamera.SearchAvailableCameras();
            return;
        }

        CameraSettings settings = new CameraSettings
        {
            netInfo = _infos[0],
            resolution = new CameraResolution(1920, 1080),
            streamFormat = StreamFormat.kMJPEG,
            pixFormat = PixFormat.kRGBA8888,
            rcMode = "cbr",
            quality = "high",
            frameRate = 25,
            bitrate = 86000,
            keyFrameInterval = 90
        };
        settings.netInfo.Username = "admin";
        settings.netInfo.Password = "123456";

        _camera = SLcamNet.NetCamera.Create(settings.netInfo.Model);
        _camera.SetCameraSettings(settings);
        _camera.Login();
        _cameraInfo = _camera.GetNetCameraAllInfo();
        _camera.Open();

        isRunning = true;
        _task = Task.Run(() => StartCameraCapture());
    }

    private void StartCameraCapture()
    {
        Task.Run(() =>
        {
            Thread.Sleep(500); 
            IntPtr frameDataPtr = IntPtr.Zero;

            while (isRunning)
            {
                try
                {
                    if (!_camera.GetVideoFrameData(ref frameDataPtr))
                        continue;

                    SLcamNet.l_md_data_t frameData = SLcamNet.l_md_data_t.FromIntPtr(frameDataPtr);
                    Debug.LogError("frameData>>>>>" + frameData.p_rgb);
                }
                catch (Exception ex)
                {
                    Debug.LogError($"Error in StartCameraCapture: {ex.Message}");
                }
            }
        });
    }

    private void OnApplicationQuit()
    {
        isRunning = false;
        _task = null;

        if (sdlPanel != null)
        {
            sdlPanel.Dispose(true);
            sdlPanel = null;
        }

        _camera?.Close();
    }
}

解析与显示实现方案

你的代码已经拿到了帧数据指针frameData.p_rgb,结合Unity的纹理系统,只需完成数据复制→主线程更新纹理两个核心步骤,即可实现实时视频显示:

1. 新增线程安全数据缓存变量

在类中添加用于缓存帧数据的线程安全变量:

private byte[] frameBuffer;
private object bufferLock = new object();

2. 初始化Texture2D

在OpenCamera方法中,相机启动后初始化与分辨率匹配的Texture2D,并绑定到RawImage:

// 在_camera.Open()之后添加
videoTexture = new Texture2D(width, height, TextureFormat.RGBA32, false);
videoImage.texture = videoTexture;

3. 子线程复制帧数据

修改StartCameraCapture中的帧处理逻辑,将非托管指针的RGBA数据复制到托管数组,标记帧就绪状态:

private void StartCameraCapture()
{
    Task.Run(() =>
    {
        Thread.Sleep(500); 
        IntPtr frameDataPtr = IntPtr.Zero;

        while (isRunning)
        {
            try
            {
                if (!_camera.GetVideoFrameData(ref frameDataPtr))
                    continue;

                SLcamNet.l_md_data_t frameData = SLcamNet.l_md_data_t.FromIntPtr(frameDataPtr);
                int dataLength = width * height * 4; // RGBA8888每个像素4字节

                lock(bufferLock)
                {
                    if(frameBuffer == null || frameBuffer.Length != dataLength)
                    {
                        frameBuffer = new byte[dataLength];
                    }
                    // 从非托管内存复制数据到托管数组
                    System.Runtime.InteropServices.Marshal.Copy(frameData.p_rgb, frameBuffer, 0, dataLength);
                    frameReady = true;
                }

                // 关键:记得调用SDK的帧释放方法(根据SDK文档调整)
                // _camera.ReleaseVideoFrameData(frameDataPtr);
            }
            catch (Exception ex)
            {
                Debug.LogError($"Error in StartCameraCapture: {ex.Message}");
            }
        }
    });
}

4. 主线程更新纹理

添加Update方法,在主线程中检测帧就绪状态,更新Texture2D:

private void Update()
{
    if(frameReady)
    {
        lock(bufferLock)
        {
            videoTexture.LoadRawTextureData(frameBuffer);
            videoTexture.Apply();
            frameReady = false;
        }
    }
}

关键注意事项

  • 线程安全:Unity的Texture操作必须在主线程执行,子线程仅负责数据复制,绝对不能直接修改Texture
  • 内存释放:务必调用SDK提供的帧数据释放方法(注释中的ReleaseVideoFrameData),避免内存泄漏
  • 格式匹配:确保TextureFormat.RGBA32与相机设置的PixFormat.kRGBA8888完全匹配,否则会出现画面错乱
  • 分辨率适配:如果相机分辨率动态变化,需要重新创建Texture2D和frameBuffer

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 02:08:11