Files
unity-application/Assets/MediaPipeUnity/Common/Scripts/ImageSource/TextureFramePool.cs
2023-03-12 20:34:16 +00:00

162 lines
4.2 KiB
C#

// Copyright (c) 2021 homuler
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Mediapipe.Unity
{
public class TextureFramePool : MonoBehaviour
{
private const string _TAG = nameof(TextureFramePool);
[SerializeField] private int _poolSize = 10;
private readonly object _formatLock = new object();
private int _textureWidth = 0;
private int _textureHeight = 0;
private TextureFormat _format = TextureFormat.RGBA32;
private Queue<TextureFrame> _availableTextureFrames;
/// <remarks>
/// key: TextureFrame's instance ID
/// </remarks>
private Dictionary<Guid, TextureFrame> _textureFramesInUse;
/// <returns>
/// The total number of texture frames in the pool.
/// </returns>
public int frameCount
{
get
{
var availableTextureFramesCount = _availableTextureFrames == null ? 0 : _availableTextureFrames.Count;
var textureFramesInUseCount = _textureFramesInUse == null ? 0 : _textureFramesInUse.Count;
return availableTextureFramesCount + textureFramesInUseCount;
}
}
private void Start()
{
_availableTextureFrames = new Queue<TextureFrame>(_poolSize);
_textureFramesInUse = new Dictionary<Guid, TextureFrame>();
}
private void OnDestroy()
{
lock (((ICollection)_availableTextureFrames).SyncRoot)
{
_availableTextureFrames.Clear();
_availableTextureFrames = null;
}
lock (((ICollection)_textureFramesInUse).SyncRoot)
{
foreach (var textureFrame in _textureFramesInUse.Values)
{
textureFrame.OnRelease.RemoveListener(OnTextureFrameRelease);
}
_textureFramesInUse.Clear();
_textureFramesInUse = null;
}
}
public void ResizeTexture(int textureWidth, int textureHeight, TextureFormat format)
{
lock (_formatLock)
{
_textureWidth = textureWidth;
_textureHeight = textureHeight;
_format = format;
}
}
public void ResizeTexture(int textureWidth, int textureHeight)
{
ResizeTexture(textureWidth, textureHeight, _format);
}
public bool TryGetTextureFrame(out TextureFrame outFrame)
{
TextureFrame nextFrame = null;
lock (((ICollection)_availableTextureFrames).SyncRoot)
{
if (_poolSize <= frameCount)
{
while (_availableTextureFrames.Count > 0)
{
var textureFrame = _availableTextureFrames.Dequeue();
if (!IsStale(textureFrame))
{
nextFrame = textureFrame;
break;
}
}
}
else
{
nextFrame = CreateNewTextureFrame();
}
}
if (nextFrame == null)
{
outFrame = null;
return false;
}
lock (((ICollection)_textureFramesInUse).SyncRoot)
{
_textureFramesInUse.Add(nextFrame.GetInstanceID(), nextFrame);
}
nextFrame.WaitUntilReleased();
outFrame = nextFrame;
return true;
}
private void OnTextureFrameRelease(TextureFrame textureFrame)
{
lock (((ICollection)_textureFramesInUse).SyncRoot)
{
if (!_textureFramesInUse.Remove(textureFrame.GetInstanceID()))
{
// won't be run
Logger.LogWarning(_TAG, "The released texture does not belong to the pool");
return;
}
if (frameCount > _poolSize || IsStale(textureFrame))
{
return;
}
_availableTextureFrames.Enqueue(textureFrame);
}
}
private bool IsStale(TextureFrame textureFrame)
{
lock (_formatLock)
{
return textureFrame.width != _textureWidth || textureFrame.height != _textureHeight;
}
}
private TextureFrame CreateNewTextureFrame()
{
var textureFrame = new TextureFrame(_textureWidth, _textureHeight, _format);
textureFrame.OnRelease.AddListener(OnTextureFrameRelease);
return textureFrame;
}
}
}