From 972384368459628b151b79c7f799f2f9547b93fd Mon Sep 17 00:00:00 2001 From: homuler Date: Sun, 25 Oct 2020 18:15:57 +0900 Subject: [PATCH] feat(example): implement TextureFramePool --- .../Scripts/ResourceManager/TextureFrame.cs | 61 +++++++++++ .../ResourceManager/TextureFrame.cs.meta | 11 ++ .../ResourceManager/TextureFramePool.cs | 101 ++++++++++++++++++ .../ResourceManager/TextureFramePool.cs.meta | 11 ++ 4 files changed, 184 insertions(+) create mode 100644 Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFrame.cs create mode 100644 Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFrame.cs.meta create mode 100644 Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFramePool.cs create mode 100644 Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFramePool.cs.meta diff --git a/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFrame.cs b/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFrame.cs new file mode 100644 index 000000000..61cc6282b --- /dev/null +++ b/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFrame.cs @@ -0,0 +1,61 @@ +using Mediapipe; +using System; +using System.Runtime.InteropServices; +using UnityEngine; + +using MpGlSyncToken = System.IntPtr; + +public class TextureFrame { + private Texture2D texture; + private GCHandle releaseCallbackHandle; + + public int width { + get { return texture.width; } + } + + public int height { + get { return texture.height; } + } + + public TextureFrame(int width, int height) { + this.texture = new Texture2D(width, height, TextureFormat.BGRA32, false); + releaseCallbackHandle = GCHandle.Alloc((GlTextureBuffer.DeletionCallback)this.OnRelease, GCHandleType.Pinned); + } + + ~TextureFrame() { + if (releaseCallbackHandle != null && releaseCallbackHandle.IsAllocated) { + releaseCallbackHandle.Free(); + } + } + + public void CopyTexture(Texture dst) { + Graphics.CopyTexture(texture, dst); + } + + public void CopyTextureFrom(WebCamTexture src) { + // TODO: Convert format on GPU + texture.SetPixels32(src.GetPixels32()); + texture.Apply(); + } + + public Color32[] GetPixels32() { + return texture.GetPixels32(); + } + + public IntPtr GetNativeTexturePtr() { + return texture.GetNativeTexturePtr(); + } + + public GpuBufferFormat gpuBufferformat { + get { + return GpuBufferFormat.kBGRA32; + } + } + + public void OnRelease(MpGlSyncToken ptr) { + Debug.Log("OnRelease"); + var glSyncToken = new GlSyncToken(ptr); + + glSyncToken.Wait(); + } +} diff --git a/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFrame.cs.meta b/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFrame.cs.meta new file mode 100644 index 000000000..203bfd96f --- /dev/null +++ b/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFrame.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa7e0da68d497cd578438e238b6a6e7c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFramePool.cs b/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFramePool.cs new file mode 100644 index 000000000..febda8bec --- /dev/null +++ b/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFramePool.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class TextureFramePool : MonoBehaviour { + [SerializeField] int poolSize = 20; + public int frameCount { get; private set; } + private readonly object frameCountLock = new object(); + + private int textureWidth = 0; + private int textureHeight = 0; + private readonly object dimensionLock = new object(); + private Queue availableTextureFrames; + + void Start() { + frameCount = 0; + availableTextureFrames = new Queue(poolSize); + } + + public void SetDimension(int textureWidth, int textureHeight) { + lock(dimensionLock) { + this.textureWidth = textureWidth; + this.textureHeight = textureHeight; + } + } + + public TextureFrameRequest RequestNextTextureFrame(Action callback) { + return new TextureFrameRequest(this, callback); + } + + public void OnTextureFrameReleased(TextureFrame textureFrame) { + lock(frameCountLock) { + if (frameCount > poolSize || IsStale(textureFrame)) { + frameCount--; + return; + } + + availableTextureFrames.Enqueue(textureFrame); + } + } + + private bool IsStale(TextureFrame textureFrame) { + lock(dimensionLock) { + return textureFrame.width != textureWidth || textureFrame.height != textureHeight; + } + } + + private TextureFrame CreateNewTextureFrame() { + lock(dimensionLock) { + return new TextureFrame(textureWidth, textureHeight); + } + } + + private IEnumerator WaitForTextureFrame(Action callback) { + TextureFrame nextFrame = null; + + lock(((ICollection)availableTextureFrames).SyncRoot) { + yield return new WaitUntil(() => { + return poolSize > frameCount || availableTextureFrames.Count > 0; + }); + + lock(frameCountLock) { + while (availableTextureFrames.Count > 0) { + var textureFrame = availableTextureFrames.Dequeue(); + + if (!IsStale(textureFrame)) { + nextFrame = textureFrame; + break; + } + + frameCount--; + } + + if (nextFrame == null) { + nextFrame = CreateNewTextureFrame(); + frameCount++; + } + } + } + + callback(nextFrame); + } + + public class TextureFrameRequest : CustomYieldInstruction { + public TextureFrame textureFrame { get; private set; } + private TextureFramePool textureFramePool; + + public override bool keepWaiting { + get { return textureFrame == null; } + } + + public TextureFrameRequest(TextureFramePool textureFramePool, Action callback) : base() { + textureFramePool.StartCoroutine(textureFramePool.WaitForTextureFrame((TextureFrame textureFrame) => { + callback(textureFrame); + + this.textureFrame = textureFrame; + })); + } + } +} diff --git a/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFramePool.cs.meta b/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFramePool.cs.meta new file mode 100644 index 000000000..b4bf52818 --- /dev/null +++ b/Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFramePool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d5da564da19cb6b7d8e4f97f269edc5d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: