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

Unity项目LibVLC原生层实例化失败求助(不使用VLC-Unity资源)

解决Unity中LibVLCSharp初始化失败问题

问题背景

在Unity项目中实现RTSP摄像头界面功能,手动导入libvlc、libvlccore及libvlcsharp相关DLL后,运行时触发以下错误:

VLCException: Failed to perform instanciation on the native side. Make sure you installed the correct VideoLAN.LibVLC.[YourPlatform] package in your platform specific project
LibVLCSharp.Shared.Internal.OnNativeInstanciationError () (at <c143e631d5a54a7ca1a10155c09a821c>:0)
LibVLCSharp.Shared.Internal..ctor (System.Func`1[TResult] create, System.Action`1[T] release) (at <c143e631d5a54a7ca1a10155c09a821c>:0)
LibVLCSharp.Shared.LibVLC..ctor (System.String[] options) (at <c143e631d5a54a7ca1a10155c09a821c>:0)
CameraLogic.Start () (at Assets/Scripts/Cameras/CameraLogic.cs:28)

需求:不安装VLC-Unity资源包的前提下解决问题,当前实现代码如下:

using System;
using System.Runtime.InteropServices;
using UnityEngine;
using LibVLCSharp.Shared;

public class CameraLogic : MonoBehaviour
{
    public Material screenMat;
    public GameObject screen;
    public float changeSpeed = 1.0f; // 纹理切换速度(秒/次)
    public bool hasSignal;
    public Texture2D[] noSignalFrames;
    private float timer = 0.0f;
    private int currentIndex = 0;
    public int id = 0;
    public string nombre = "No Signal";
    public string cameraID;
    public Texture2D cameraFrame;

    private Material selfMat;
    private LibVLC _libVLC;
    private MediaPlayer _mediaPlayer;
    private GCHandle _gcHandle;

    private void Start()
    { 
        // LibVLC选项
        _libVLC = new LibVLC();
        _mediaPlayer = new MediaPlayer(_libVLC);

        // 初始化摄像头纹理
        cameraFrame = new Texture2D(640, 480, TextureFormat.RGBA32, false);
        selfMat = new Material(screenMat);

        // 将材质分配给屏幕对象
        if (screen != null)
        {
            screen.GetComponent<Renderer>().material = selfMat;
        }
        else
        {
            Debug.LogError("未分配'screen'对象。");
        }

        // 配置VLC以渲染到Unity纹理
        _mediaPlayer.SetVideoFormat("RV32", (uint)cameraFrame.width, (uint)cameraFrame.height, (uint)(cameraFrame.width * 4));
        _gcHandle = GCHandle.Alloc(cameraFrame.GetPixels32(), GCHandleType.Pinned);

        _mediaPlayer.SetVideoCallbacks(
            (IntPtr opaque, IntPtr planes) =>
            {
                planes = _gcHandle.AddrOfPinnedObject();
                return IntPtr.Zero;
            },
            (IntPtr opaque, IntPtr picture, IntPtr planes) =>
            {
                // 若需要处理解锁逻辑可添加额外代码
            },
            (IntPtr opaque, IntPtr picture) =>
            {
                if (cameraFrame != null)
                {
                    cameraFrame.Apply();
                }
                else
                {
                    Debug.LogError("cameraFrame为空。");
                }
            }
        );

        var media = new Media(_libVLC, "此处为RTSP链接");
        _mediaPlayer.Play(media);
    }

    void Update()
    {
        if (_mediaPlayer == null)
        {
            hasSignal = false;
            Debug.LogError("MediaPlayer未初始化。");
            return;
        }

        if (cameraFrame == null)
        {
            Debug.LogError("cameraFrame未初始化。");
            return;
        }

        if (!_mediaPlayer.IsPlaying)
        {
            hasSignal = false;
            timer += Time.deltaTime;

            if (timer >= changeSpeed)
            {
                ShowNoSignal();
                timer = 0.0f;
            }
        }
        else
        {
            hasSignal = true;
            PrintImage();
        }
        if (!hasSignal)
        {
            ShowNoSignal();
        }
    }

    void ShowNoSignal()
    {
        if (noSignalFrames.Length > 0)
        {
            selfMat.mainTexture = noSignalFrames[currentIndex];
            selfMat.SetTexture("_EmissionMap", noSignalFrames[currentIndex]);
            currentIndex = (currentIndex + 1) % noSignalFrames.Length;
        }
        else
        {
            Debug.LogError("无'无信号'帧可用。");
        }
    }

    void PrintImage()
    {
        if (selfMat != null)
        {
            selfMat.mainTexture = cameraFrame;
            selfMat.SetTexture("_EmissionMap", cameraFrame);
        }
        else
        {
            Debug.LogError("selfMat未初始化。");
        }
    }

    private void OnDisable()
    {
        if (_gcHandle.IsAllocated)
        {
            _gcHandle.Free();
        }
        _mediaPlayer?.Stop();
        _mediaPlayer?.Dispose();
        _libVLC?.Dispose();
    }
}

解决方案

  • 验证原生LibVLC库的完整性与平台匹配
    错误核心是原生LibVLC库未正确加载,手动导入时需注意:

    • 确保导入的libvlc、libvlccore包含所有附属文件:比如Windows平台需要libvlc.dll、libvlccore.dll,以及完整的plugins文件夹(包含所有编解码插件)
    • 库的架构必须与Unity目标平台一致:比如Windows平台用x64版本的LibVLC,不能混用x86版本
    • 将plugins文件夹放在Unity项目的Assets/Plugins/[Platform]目录下(如Windows对应Assets/Plugins/x86_64),确保Unity能识别加载
  • 配置DLL的导入设置
    在Unity编辑器中选中所有导入的DLL文件,在Inspector面板调整:

    • 仅勾选当前目标平台(比如Windows),取消其他平台的勾选
    • 设置CPU为对应架构(x86_64)
    • 原生DLL(libvlc.dll、libvlccore.dll)设置Load Type为Runtime Only
  • 修正LibVLC初始化逻辑
    显式指定插件路径,避免Unity无法定位插件目录:

    private void Start()
    { 
        // 添加插件路径配置
        string pluginPath = Path.Combine(Application.dataPath, "Plugins/x86_64/plugins");
        _libVLC = new LibVLC(new[] { $"--plugin-path={pluginPath}" });
        _mediaPlayer = new MediaPlayer(_libVLC);
    
        // 剩余代码保持不变...
    }
    

    注意根据你的平台和插件目录结构调整路径。

  • 修复视频回调与纹理格式的兼容性问题
    当前代码中TextureFormat.RGBA32与VLC设置的RV32格式不匹配(RV32实际是BGRA字节顺序),需调整:

    1. 修改纹理初始化代码:
      cameraFrame = new Texture2D(640, 480, TextureFormat.BGRA32, false);
      
    2. 修正视频回调中的指针赋值逻辑(原代码直接赋值planes不会生效):
      _mediaPlayer.SetVideoCallbacks(
          (IntPtr opaque, IntPtr planes) =>
          {
              // 正确写入指针地址
              Marshal.WriteIntPtr(planes, _gcHandle.AddrOfPinnedObject());
              return IntPtr.Zero;
          },
          // 其他回调保持不变
      );
      
  • 完善资源释放逻辑
    在OnDestroy中补充手动创建资源的销毁,避免内存泄漏:

    private void OnDestroy()
    {
        if (_gcHandle.IsAllocated)
        {
            _gcHandle.Free();
        }
        _mediaPlayer?.Stop();
        _mediaPlayer?.Dispose();
        _libVLC?.Dispose();
        if(selfMat != null)
        {
            Destroy(selfMat);
        }
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 08:44:52