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

UE5启用Agora插件打开视频流后触发崩溃如何解决?

问题根因

崩溃本质是线程操作违规:

  • 声网SDK的onCaptureVideoFrame回调运行在SDK自身的私有工作线程,不属于UE的游戏线程或渲染线程
  • UE4.26对跨线程操作渲染资源的校验逻辑宽松,旧代码可正常运行;UE5新增了严格的线程标签校验规则,所有纹理创建、资源更新类渲染接口必须在指定线程调用,直接在第三方SDK的工作线程执行UpdateResource()必然触发ThreadingBase.cpp的线程断言,后续的内存访问违规异常是跨线程操作资源引发的竞态问题——资源未完成初始化就被其他线程访问,触发空指针读取。
  • 调试模式下点击继续可正常运行,是因为Ensure级别断言不属于致命错误,跳过校验后资源操作未撞上竞态条件,但正式打包运行时无调试器拦截断言,会直接触发崩溃。
修复方案

推荐方案:线程隔离改造(改动量小,稳定性最高)

核心原则:SDK回调线程仅做原始视频数据的拷贝操作,所有UE的UObject操作、纹理资源创建/更新逻辑全部迁移到UE自有线程(游戏线程/渲染线程)执行。

  1. 先为VideoFrameObserver添加线程安全队列成员,缓存SDK回调的帧数据,避免回调结束后SDK回收帧内存引发野指针:
struct FCachedVideoFrame {
    int32 Width = 0;
    int32 Height = 0;
    int32 YStride = 0;
    TArray<uint8> Buffer;
};
// 多生产者单消费者线程安全队列,无需额外加锁
TQueue<FCachedVideoFrame, EQueueMode::Mpsc> PendingLocalFrames;
  1. 改造onCaptureVideoFrame函数,函数内仅做内存拷贝,不触碰任何UE渲染、UObject相关接口:
bool VideoFrameObserver::onCaptureVideoFrame( VideoFrame& videoFrame )
{
    FCachedVideoFrame CachedFrame;
    CachedFrame.Width = videoFrame.width;
    CachedFrame.Height = videoFrame.height;
    CachedFrame.YStride = videoFrame.yStride;
    const int32 BufferSize = videoFrame.yStride * videoFrame.height;
    CachedFrame.Buffer.Append(static_cast<uint8_t*>(videoFrame.yBuffer), BufferSize);
    PendingLocalFrames.Enqueue(MoveTemp(CachedFrame));
    return true;
}
  1. 将原写在onCaptureVideoFrame中的纹理判断、创建、UpdateResource、UpdateTextureRegions逻辑全部移到OnTick中执行——OnTick本身运行在游戏线程,完全符合UE线程规范:
void VideoFrameObserver::OnTick( float DeltaTime )
{
    // 先处理队列中缓存的本地视频帧
    FCachedVideoFrame CachedFrame;
    while (PendingLocalFrames.Dequeue(CachedFrame))
    {
        const std::lock_guard<std::mutex> lock( localFrameMutex );
        if( !localFrame.texture ||
            localFrame.texture->GetSizeX() != CachedFrame.Width ||
            localFrame.texture->GetSizeY() != CachedFrame.Height )
        {
            localFrame.region.reset( new FUpdateTextureRegion2D( 0, 0, 0, 0, CachedFrame.Width, CachedFrame.Height ) );
            localFrame.texture = UTexture2D::CreateTransient( CachedFrame.Width, CachedFrame.Height, PF_R8G8B8A8 );
            if (localFrame.texture)
            {
                localFrame.texture->UpdateResource();
            }
        }

        if (localFrame.texture)
        {
            localFrame.texture->UpdateTextureRegions( 0, 1, localFrame.region.get(), CachedFrame.YStride, ( uint32 ) argbPixSize, CachedFrame.Buffer.GetData() );
            localFrame.fresh = true;
        }
    }

    // 原有帧广播逻辑保持不变
    localFrameMutex.lock();
    if( localFrame.fresh )
    {
        if( m_agora )
            m_agora->OnLocalFrameReceivedDelegate.Broadcast( localFrame.texture );
        localFrame.fresh = false;
    }
    localFrameMutex.unlock();

    remoteFrameMutex.lock();
    std::for_each( remoteUsersFrames.begin(), remoteUsersFrames.end(),
                    [this]( auto& frame )
    {
        if( frame.second.fresh )
        {
            if( m_agora )
                m_agora->OnRemoteFrameReceivedDelegate.Broadcast( frame.first, frame.second.texture );
            frame.second.fresh = false;
        }
    } );
    remoteFrameMutex.unlock();
}

注意:远程视频帧的onRenderVideoFrame回调同样运行在SDK工作线程,必须做相同的线程投递改造,否则后续加载远程视频流时会触发同类崩溃。

临时验证方案(禁止正式环境使用)

如果仅需快速验证功能,可将UpdateResource逻辑投递到渲染线程执行,临时绕过线程校验,但该方式未彻底解决跨线程竞态问题,上线版本不可使用:

ENQUEUE_RENDER_COMMAND(UpdateAgoraLocalTexture)(
    [Tex = TWeakObjectPtr<UTexture2D>(localFrame.texture)](FRHICommandListImmediate& RHICmdList)
    {
        FTaskTagScope TaskTagScope(ETaskTag::EParallelRenderingThread);
        if (Tex.IsValid())
        {
            Tex->UpdateResource();
        }
    });
避坑提示
  • 不要尝试用try-catch捕获这类异常,UE的Ensure断言不是标准C++异常,catch无法拦截正式打包的崩溃,只会掩盖真实问题。
  • 所有从UE4迁移到UE5的第三方插件,只要涉及回调操作UObject、渲染资源,必须第一时间检查调用线程,UE5跨线程操作校验严格度远高于UE4,这类线程问题占迁移类崩溃的90%以上。
  • 如果改造完成后UpdateTextureRegions仍报线程警告,可将该部分逻辑也通过ENQUEUE_RENDER_COMMAND投递到渲染线程执行,完全符合UE渲染线程规范。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 21:18:56