killapp/Assets/Scripts/Video/MainThreadDispatcher.cs
“虞渠成” 4726107e19 feat(video,android): 视频下载转码播放 + 列表下载/播放按钮
- 集成 ffmpeg-kit-full-gpl 6.0.3(arm64),用 libx264 重编码修复 .h264 缺 SPS/PPS 导致的播放卡死

- 新增 VideoDownloadPlayService/VideoCacheManager,.mp4 直下直播、.h264 下载后转 mp4 缓存,转码完成后删除临时 .h264

- FFmpegKitBridge 走主线程 JNI 调用规避 IL2CPP 后台线程 FindClass 不稳定

- 视频列表按缓存状态显示 下载/播放 按钮,下载中亮色条显示百分比;播放面板原下载按钮改为保存到相册
2026-09-08 13:31:31 +08:00

67 lines
2.2 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Threading;
using UnityEngine;
namespace Kill.Video
{
/// <summary>
/// 把任意 Action 排到 Unity 主线程执行。
/// 背景:IL2CPP 的自建后台线程 JVM attach 不可靠,AndroidJavaClass/AndroidJNI
/// 在这些线程上 FindClass 会偶发返回空,导致"类未找到/偶尔成功偶尔失败"。
/// 用它在主线程上跑所有 JNI 调用即可稳定。
/// </summary>
public static class MainThreadDispatcher
{
private static readonly ConcurrentQueue<Action> _pending = new ConcurrentQueue<Action>();
private static int _mainThreadId = -1;
private static bool _ensured;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
private static void Ensure()
{
if (_ensured) return;
_mainThreadId = Thread.CurrentThread.ManagedThreadId;
var go = new GameObject("MainThreadDispatcher");
go.hideFlags = HideFlags.HideAndDontSave;
UnityEngine.Object.DontDestroyOnLoad(go);
go.AddComponent<DispatcherBehaviour>();
_ensured = true;
}
public static bool IsMainThread =>
!_ensured || Thread.CurrentThread.ManagedThreadId == _mainThreadId;
/// <summary>在主线程执行 action;若调用方已是主线程则直接内联执行。</summary>
public static void RunOnMainThread(Action action)
{
if (action == null) return;
if (IsMainThread)
{
action();
return;
}
using (var done = new ManualResetEventSlim(false))
{
_pending.Enqueue(() =>
{
try { action(); }
finally { done.Set(); }
});
done.Wait();
}
}
private class DispatcherBehaviour : MonoBehaviour
{
private void Update()
{
while (_pending.TryDequeue(out var a))
{
try { a(); }
catch (Exception e) { Debug.LogException(e); }
}
}
}
}
}