Unity从VideoPlayer获取当前帧纹理
Video Player
Video Player在Unity5.6版本正式加入用以取代之前的MovieTexture
。在视频导入编辑和播放等功能上比之前的MovieTexture
已经好上很多。
相关介绍链接:https://blog.csdn.net/f_957995490/article/details/108112467
每一帧的纹理
具体操作,如下:
- 通过将
VideoPlayer.sendFrameReadyEvents
设置为true
来启用新的帧事件。 - 订阅
VideoPlayer.frameReady
活动。 - 当新帧可用时,将调用您分配给
VideoPlayer.frameReady
事件的功能.只需从VideoPlayer
访问视频帧,它将通过将VideoPlayer.texture
转换为Texture2D
传递给参数。
在代码中:
在VideoPlayer.Play()
之前添加以下内容:
//Enable new frame Event
videoPlayer.sendFrameReadyEvents = true;
//Subscribe to the new frame Event
videoPlayer.frameReady += OnNewFrame;
这是您的OnNewFrame
函数签名:
void OnNewFrame(VideoPlayer source, long frameIdx)
{
Texture2D videoFrame = (Texture2D)source.texture;
//Do anything with the videoFrame Texture.
}
值得注意的是,启用该事件的成本很高.在执行此操作之前,请确保您需要每个框架。
编辑:
Texture2D videoFrame =(Texture2D)source.texture;
和Texture2D videoFrame = source.texture;
作为Texture2D;失败.
我把Debug.Log(source.texture);
在OnNewFrame
函数内部得到:
TempBuffer 294 320×240 (UnityEngine.RenderTexture)
因此,看起来Video.texture
属性返回RenderTexture类型而不是像它应该的纹理类型。
我们必须将RenderTexture转换为Texture2D。
void Start()
{
videoFrame = new Texture2D(2, 2);
}
Texture2D videoFrame;
void OnNewFrame(VideoPlayer source, long frameIdx)
{
RenderTexture renderTexture = source.texture as RenderTexture;
if (videoFrame.width != renderTexture.width || videoFrame.height != renderTexture.height)
{
videoFrame.Resize(renderTexture.width, renderTexture.height);
}
RenderTexture.active = renderTexture;
videoFrame.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
videoFrame.Apply();
RenderTexture.active = null;
}
项目完整代码
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Video;
public class VideoTest : MonoBehaviour
{
private VideoPlayer m_videoPlayer = null;
public RawImage m_rawImage;
void Awake()
{
videoFrame = new Texture2D(2, 2);
}
private void OnEnable()
{
if (null == m_videoPlayer)
{
m_videoPlayer = m_rawImage.gameObject.GetComponent<VideoPlayer>();
}
m_videoPlayer.sendFrameReadyEvents = true;
m_videoPlayer.frameReady += OnNewFrame;
m_videoPlayer.Play();
}
Texture2D videoFrame;
private void OnNewFrame(VideoPlayer source, long frameIdx)
{
RenderTexture renderTexture = source.texture as RenderTexture;
if (null == renderTexture)
{
Debug.LogError("空的?" + source.name);
}
if (videoFrame.width != renderTexture.width || videoFrame.height != renderTexture.height)
{
videoFrame.Resize(renderTexture.width, renderTexture.height);
}
RenderTexture.active = renderTexture;
videoFrame.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
videoFrame.Apply();
RenderTexture.active = null;
SaveToFile("test.png", videoFrame.EncodeToPNG());
}
private void OnDisable()
{
m_videoPlayer.frameReady -= OnNewFrame;
m_videoPlayer.sendFrameReadyEvents = false;
if (null != m_videoPlayer)
m_videoPlayer.Stop();
}
/// <summary>
/// 保存文件
/// </summary>
/// <param name="file">文件名</param>
/// <param name="data">字节数组</param>
private void SaveToFile(string file, byte[] data)
{
string path = Application.persistentDataPath + file;
string outFileDirectory = path.Remove(path.LastIndexOf('/'));
if (!File.Exists(outFileDirectory))
{//防止路径不存在,则创建拷贝目标所需路径
Directory.CreateDirectory(outFileDirectory);
}
File.WriteAllBytes(path, data);
}
}