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

HoloLens 2 Unity项目如何从IDirect3DSurface获取NV12像素数据?

从HoloLens 2的IDirect3DSurface读取NV12像素数据的解决方案

核心问题原因

你的应用崩溃确实是IDirect3DSurface的跨语言封送逻辑错误导致的:C#通过UnmanagedType.Interface封送的WinRT接口是原生COM指针,和C++/WinRT封装后的winrt::IDirect3DSurface对象内存布局完全不同,直接用C++/WinRT的指针类型接收会触发非法内存访问。

修正步骤

1. 修改C++端导出函数逻辑

不要直接用winrt::IDirect3DSurface*作为参数接收,先接收到原生ABI指针后再转换为C++/WinRT封装对象:

#include <windows.graphics.directx.direct3d11.interop.h>
#include <winrt/Windows.Graphics.DirectX.Direct3D11.h>

void __stdcall Direct3DSurfaceAccess(void* d3dSurfaceAbi)
{
    winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface d3dSurface{ nullptr };
    // 将原生ABI指针绑定到C++/WinRT对象,不额外增加引用计数
    winrt::attach_abi(d3dSurface, d3dSurfaceAbi);

    try
    {
        // 现在可以正常调用接口方法
        auto surfaceDesc = d3dSurface.Description();
        auto dxgiAccess = d3dSurface.as<::Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess>();
        
        winrt::com_ptr<IDXGISurface> nativeDxgiSurface;
        winrt::check_hresult(dxgiAccess->GetInterface(IID_PPV_ARGS(nativeDxgiSurface.put())));

        // 映射纹理到CPU内存
        DXGI_MAPPED_RECT mappedRect{};
        winrt::check_hresult(nativeDxgiSurface->Map(&mappedRect, DXGI_MAP_READ));

        // NV12数据读取:Y平面在前,UV交错平面在后
        const BYTE* yPlaneData = mappedRect.pBits;
        const BYTE* uvPlaneData = mappedRect.pBits + surfaceDesc.Height * mappedRect.Pitch;
        // 此处可将数据拷贝到自有缓冲区后续处理

        // 取消映射,必须执行否则会造成GPU资源泄漏
        nativeDxgiSurface->Unmap();
    }
    catch (winrt::hresult_error const& err)
    {
        // 可通过OutputDebugStringW输出错误信息排查问题
        OutputDebugStringW(err.message().c_str());
    }

    // 解除ABI指针绑定,避免内存泄漏
    winrt::detach_abi(d3dSurface);
}

2. 修改C#端调用逻辑

调整DllImport声明,先获取WinRT接口的原生COM指针再传递到C++:

using System.Runtime.InteropServices;
using Windows.Graphics.DirectX.Direct3D11;

[DllImport("Direct3DSurfaceAccess")]
private static extern void Direct3DSurfaceAccess(IntPtr d3dSurfaceAbi);

private void Nv12FrameArrived(MediaFrameReader sender, MediaFrameArrivedEventArgs args)
{
    using var mediaFrameReference = sender.TryAcquireLatestFrame();
    var d3dSurface = mediaFrameReference?.VideoMediaFrame?.Direct3DSurface;
    if (d3dSurface == null) return;

    // 获取IDirect3DSurface的原生COM指针
    IntPtr surfacePtr = Marshal.GetComInterfaceForObject(
        d3dSurface, 
        typeof(IDirect3DSurface));
    
    Direct3DSurfaceAccess(surfacePtr);
    // 释放临时增加的引用计数
    Marshal.Release(surfacePtr);
}

额外注意事项

  • 不要在FrameArrived回调中做耗时的像素处理操作,会直接导致相机采集帧卡顿,建议将像素数据拷贝到自有缓冲区后异步处理
  • 如果你是要把帧传递给Microsoft.MixedReality.WebRTC,可以直接传递GPU纹理指针,不需要拷贝到CPU内存,能大幅降低性能损耗
  • 需确保C++项目的编译配置和Unity导出的UWP项目配置一致,目标架构为ARM64,Windows SDK版本匹配HoloLens 2的系统版本

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 12:33:03