Skip to content

Commit

Permalink
feat(example): implement TextureFramePool
Browse files Browse the repository at this point in the history
  • Loading branch information
homuler committed Dec 19, 2020
1 parent 33baad5 commit 9723843
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 0 deletions.
61 changes: 61 additions & 0 deletions Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFrame.cs
Original file line number Diff line number Diff line change
@@ -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();
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

101 changes: 101 additions & 0 deletions Assets/MediaPipe/Examples/Scripts/ResourceManager/TextureFramePool.cs
Original file line number Diff line number Diff line change
@@ -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<TextureFrame> availableTextureFrames;

void Start() {
frameCount = 0;
availableTextureFrames = new Queue<TextureFrame>(poolSize);
}

public void SetDimension(int textureWidth, int textureHeight) {
lock(dimensionLock) {
this.textureWidth = textureWidth;
this.textureHeight = textureHeight;
}
}

public TextureFrameRequest RequestNextTextureFrame(Action<TextureFrame> 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<TextureFrame> 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<TextureFrame> callback) : base() {
textureFramePool.StartCoroutine(textureFramePool.WaitForTextureFrame((TextureFrame textureFrame) => {
callback(textureFrame);
this.textureFrame = textureFrame;
}));
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9723843

Please sign in to comment.