Reputation: 11325
It's working really good but still there is a small delay in the update when it's starting over again the loop. It's almost perfect smooth looping. I'm not sure what is making this delay and how to avoid it.
Maybe the problem is that the last image is black. I did this in blender that both first frame and last frame are black. Can this cause a delay effect?
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;
public class StreamVideo : MonoBehaviour
{
public Texture[] frames; // array of textures
public float framesPerSecond = 2.0f; // delay between frames
public RawImage image;
void Start()
{
DirectoryInfo dir = new DirectoryInfo(@"C:\tmp");
// since you use ToLower() the capitalized version are quite redundant btw ;)
string[] extensions = new[] { ".jpg", ".jpeg", ".png", ".ogg" };
FileInfo[] info = dir.GetFiles().Where(f => extensions.Contains(f.Extension.ToLower())).ToArray();
if (!image)
{
//Get Raw Image Reference
image = gameObject.GetComponent<RawImage>();
}
frames = GetTextures(info);
}
private Texture[] GetTextures(FileInfo[] fileInfos)
{
var output = new Texture[fileInfos.Length];
for (var i = 0; i < fileInfos.Length; i++)
{
var bytes = File.ReadAllBytes(fileInfos[i].FullName);
output[i] = new Texture2D(1, 1);
if (!ImageConversion.LoadImage((Texture2D)output[i], bytes, false))
{
Debug.LogError($"Could not load image from {fileInfos.Length}!", this);
}
}
return output;
}
void Update()
{
int index = (int)(Time.time * framesPerSecond) % frames.Length;
image.texture = frames[index]; //Change The Image
}
}
Upvotes: 2
Views: 640
Reputation: 1637
Sending textures from RAM to GPU every frame is neither terribly ideal nor needed really.
You can upload all textures to GPU at Start()
. And then use Update()
just to occasionally update MaterialPropertyBlock
(or other kind of lightweight pointer GPU understands) to tell which (previously uploaded) texture to render from now on.
Texture2D.Apply() sends texture data from (CPU) RAM to GPU. Hence this will upload all frames:
frames = GetTextures(info);
foreach( var frame in frames )
frame.Apply( updateMipmaps:true , makeNoLongerReadable:true );
To find out which textures are black:
for( int i=0 ; i<frames.Length ; i++ )
{
var frame = frames[i];
if( IsItAllBlack(frame) )
Debug.Log($"frame #{i} is all black");
}
bool IsItAllBlack ( Texture2D tex )
{
var pixels = tex.GetPixels();
foreach( var col in pixels )
if( (col.r+col.g+col.b)>0 )
return false;
return true;
}
Btw: Remember to release memory used by those textures once they are no longer needed:
foreach( var frame in frames )
Destroy(frame);
It doesn't happen automatically when texture is loaded manually from code.
Upvotes: 1