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

Unity+Vuforia运行时创建Image Target后Android端VideoPlayer异常排查

问题描述

我使用Unity 2022.3.15f搭配Vuforia 10.22.5,通过API在运行时创建Image Target,并为每个目标绑定带有VideoPlayer的Quad。该功能在Unity编辑器中运行完全正常,但打包为Android版本后,VideoPlayer的表现极差(卡顿、无法播放等)。我曾在Unity 2019.4.0f中开发过同类应用,当时是通过Vuforia Target Manager下载的数据库创建目标,未出现此问题,请问问题可能出在哪里?

相关代码
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Video;
using Vuforia;

public class GetJson : MonoBehaviour
{
    [SerializeField] private string url = "https://api.arstudio.kz/api/ar?groupId=82";
    [SerializeField] private RootObject loadinfolist = new RootObject();
    public GameObject Model;
    public UnityEngine.UI.Image LoadingLogo;

    private string path;
    private float loadProgress = 0.0f;

    private void Start()
    {
        path = Application.persistentDataPath; // Установка пути один раз
        VuforiaApplication.Instance.OnVuforiaInitialized += OnVuforiaInitialized;
    }

    void OnVuforiaInitialized(VuforiaInitError error)
    {
        StartCoroutine(SendReq());
    }

    private IEnumerator SendReq()
    {
        using (UnityWebRequest request = UnityWebRequest.Get(url))
        {
            yield return request.SendWebRequest();

            if (request.result != UnityWebRequest.Result.Success)
            {
                Debug.Log(request.error);
            }
            else
            {
                loadinfolist = JsonUtility.FromJson<RootObject>(request.downloadHandler.text);
                StartCoroutine(WebAR());
            }
        }
    }

    private IEnumerator WebAR()
    {
        foreach (Datum data in loadinfolist.data)
        {
            yield return StartCoroutine(DownloadAndSetupContent(data));
        }
    }

    private IEnumerator DownloadAndSetupContent(Datum data)
    {
        yield return StartCoroutine(DownloadVideo(data.video_path, data.id, data.group_id));
        yield return StartCoroutine(DownloadImageAndCreateTarget(data.file_path, data.id, data.group_id));
    }

    private IEnumerator DownloadVideo(string videoPath, int id, int groupId)
    {
        string savePath = $"{path}/{id}_{groupId}.mp4";
        using (UnityWebRequest uwr = UnityWebRequest.Get(videoPath))
        {
            yield return uwr.SendWebRequest();
            if (uwr.result == UnityWebRequest.Result.Success)
            {
                System.IO.File.WriteAllBytes(savePath, uwr.downloadHandler.data);
                loadProgress += 1.0f / loadinfolist.data.Length;
                LoadingLogo.fillAmount = loadProgress;
                Debug.Log("Video downloaded to: " + savePath);
            }
            else
            {
                Debug.Log(uwr.error);
            }
        }
    }

    private IEnumerator DownloadImageAndCreateTarget(string imagePath, int id, int groupId)
    {
        using (UnityWebRequest uwr = UnityWebRequestTexture.GetTexture(imagePath))
        {
            yield return uwr.SendWebRequest();
            if (uwr.result == UnityWebRequest.Result.Success)
            {
                Texture2D texture = DownloadHandlerTexture.GetContent(uwr);
                CreateImageTargetFromDownloadedTexture(id, $"{path}/{id}_{groupId}.mp4", texture);
            }
            else
            {
                Debug.Log(uwr.error);
            }
        }
    }

    void CreateImageTargetFromDownloadedTexture(int id, string videoUrl, Texture2D img)
    {
        var mTarget = VuforiaBehaviour.Instance.ObserverFactory.CreateImageTarget(img, 1.0f, id.ToString());
        mTarget.gameObject.AddComponent<DefaultObserverEventHandler>();
        GameObject cube = Instantiate(Model, mTarget.transform);
        cube.transform.localScale = new Vector3(mTarget.GetSize().x, mTarget.GetSize().y, 1.0f);

        VideoPlayer player = cube.GetComponent<VideoPlayer>();
        player.url = videoUrl;
        EventHandler eventHandler = mTarget.gameObject.AddComponent<EventHandler>();
        Debug.Log("Target with video player created for: " + id);
    }
}
[System.Serializable]
public class Group
{

    [SerializeField] public int id;
    [SerializeField] public string name;
    [SerializeField] public string created_at;
    [SerializeField] public string updated_at;
    [SerializeField] public int user_id;
}
[System.Serializable]
public class Datum
{
    [SerializeField] public int id ;
    [SerializeField] public int group_id ;
    [SerializeField] public int user_id ;
    [SerializeField] public string file_path ;
    [SerializeField] public string video_path ;
    [SerializeField] public string mind_file_path ;
    [SerializeField] public string status ;
    [SerializeField] public int is_deleted ;
    [SerializeField] public string created_at ;
    [SerializeField] public string updated_at ;
    [SerializeField] public int width ;
    [SerializeField] public int height ;
}
可能的问题排查方向
  • VideoPlayer平台配置与编码兼容性

    • Unity 2022的VideoPlayer在Android平台的默认渲染模式可能不适合AR场景,建议将Render Mode切换为Material Override(编辑器里用Overlay能正常运行,但Android 3D空间中的Quad需要Material模式)。
    • 检查视频编码:Android设备对H.265的支持不如H.264广泛,确保下载的MP4采用H.264 Baseline Profile编码,同时控制码率和分辨率匹配设备性能。
  • 运行时资源加载与性能优化

    • Vuforia 10运行时动态创建Image Target的性能开销比旧版本更高,同时未压缩的纹理会占用大量内存。在下载纹理后,添加texture.Compress(true)将其转换为Android兼容的压缩格式(如ETC2),减少内存占用。
    • 视频下载完成后,建议添加文件完整性校验(对比服务器返回的文件大小与本地文件大小),避免因文件损坏导致播放异常。
  • Android存储路径与权限

    • Android 10及以上的存储权限变更可能影响VideoPlayer读取本地文件,尝试给视频路径添加file://前缀:player.url = "file://" + videoUrl;。
    • 确保在AndroidManifest中添加了READ_EXTERNAL_STORAGE权限(针对旧设备),或者使用Unity的Persistent Data Path的正确访问方式。
  • Vuforia与Unity版本适配

    • Vuforia 10.22.5与Unity 2022.3.15f可能存在兼容性bug,尝试升级Vuforia到适配Unity 2022的最新版本,或降级Unity到2022.3的更早小版本测试。
  • 事件处理组件冲突

    • 创建Image Target时同时添加了DefaultObserverEventHandler和自定义EventHandler,两者可能在目标识别/丢失时重复触发视频控制逻辑,导致播放混乱。建议只保留一个事件处理组件,或检查自定义EventHandler的逻辑是否与Default组件冲突。

内容的提问来源于stack exchange,提问作者Сакен Карленов

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 23:33:16