Download FFmpeg for Windows
Unity 代码
using System.Diagnostics;
using System.IO;
using UnityEngine;
public class Test : MonoBehaviour
{
private int width = 1280;
private int height = 720;
private Texture2D frame;
private float fireRate = 0.04F;
private float nextFire = 0.0F;
RenderTexture rt;
Rect rect;
byte[] bytes;
bool isReady = false;
int index = 0;
private string imagePath;
private string ffmpegPath;
private string videoPath;
// Use this for initialization
void Start()
{
Loom.Initialize();
imagePath = @Application.streamingAssetsPath + "/Images/";
ffmpegPath = @Application.streamingAssetsPath + "/ffmpeg/ffmpeg.exe";
videoPath = @Application.streamingAssetsPath + "/test.mp4";
if (!Directory.Exists(imagePath.TrimEnd('/')))
{
Directory.CreateDirectory(imagePath.TrimEnd('/'));
}
rect = new Rect(0, 0, width, height);
// 创建一个RenderTexture对象
rt = new RenderTexture(width, height, 0);
frame = new Texture2D(width, height, TextureFormat.RGBA32, false);
isReady = true;
//CreatVideo();
}
// Update is called once per frame
void Update()
{
}
private void FixedUpdate()
{
if (isReady && Time.time > nextFire)
{
nextFire = Time.time + fireRate;
CaptureCamera(Camera.main, index);
index++;
}
}
/// <summary>
/// 对相机截图。
/// </summary>
/// <returns>The screenshot2.</returns>
/// <param name="camera">Camera.要被截屏的相机</param>
/// <param name="rect">Rect.截屏的区域</param>
void CaptureCamera(Camera camera, int index)
{
// 临时设置相关相机的targetTexture为rt, 并手动渲染相关相机
camera.targetTexture = rt;
camera.Render();
//ps: --- 如果这样加上第二个相机,可以实现只截图某几个指定的相机一起看到的图像。
//ps: camera2.targetTexture = rt;
//ps: camera2.Render();
//ps: -------------------------------------------------------------------
// 激活这个rt, 并从中中读取像素。
RenderTexture.active = rt;
frame.ReadPixels(rect, 0, 0);// 注:这个时候,它是从RenderTexture.active中读取像素
frame.Apply();
// 重置相关参数,以使用camera继续在屏幕上显示
camera.targetTexture = null;
//ps: camera2.targetTexture = null;
RenderTexture.active = null; // JC: added to avoid errors
最后将这些纹理数据,成一个png图片文件
bytes = frame.EncodeToJPG();
Loom.RunAsync(() =>
{
//string filename = Application.dataPath + "/Screenshot.png";
System.IO.File.WriteAllBytes(imagePath + index + ".jpg", bytes);
//Debug.Log(string.Format("截屏了一张照片: {0}", filename));
});
}
private void OnApplicationQuit()
{
CreatVideo();
}
void CreatVideo()
{
Loom.RunAsync(() =>
{
//建立外部调用进程
Process p = new Process();
p.StartInfo.FileName = ffmpegPath;
string args = "-f image2 -i " + imagePath + "%d.jpg -vcodec libx264 -r 25 " + videoPath;
p.StartInfo.Arguments = args;
p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...)
p.StartInfo.CreateNoWindow = true;//不创建进程窗口
p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
p.Start();//启动线程
p.BeginErrorReadLine();//开始异步读取
p.WaitForExit();//阻塞等待进程结束
p.Close();//关闭进程
p.Dispose();//释放资源
DirectoryInfo dir = new DirectoryInfo(imagePath);
dir.Delete(true);
Directory.CreateDirectory(imagePath.TrimEnd('/'));
});
}
private void Output(object sendProcess, DataReceivedEventArgs output)
{
if (!string.IsNullOrEmpty(output.Data))
{
//处理方法...
UnityEngine.Debug.Log(output.Data);
}
}
}
参考文章
直接录制应用程序窗口,仅用于Windows程序和编辑器 2019.12.6
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using UnityEngine;
/// <summary>
/// 录制本程序窗口,仅用于Windows程序和编辑器
/// </summary>
public class CaptureWindow : MonoBehaviour
{
private string ffmpegPath;
private string videoPath;
private int processId;
private Process process;
// Use this for initialization
void Start()
{
ffmpegPath = @Application.streamingAssetsPath + "/ffmpeg/ffmpeg.exe";
videoPath = @Application.streamingAssetsPath + "/test.mp4";
IntPtr handle = GetForegroundWindow();
SetWindowText(handle.ToInt32(), Application.productName);
}
public void OnGUI()
{
if (GUILayout.Button("开始录制"))
{
process = new Process();
process.StartInfo.FileName = ffmpegPath;
string args = " -f gdigrab -framerate 30 -i title=" + Application.productName + " -f mp4 " + videoPath;
//string args = " -f gdigrab -framerate 30 -i desktop -f mp4 " + videoPath;
process.StartInfo.Arguments = args;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.ErrorDataReceived += new DataReceivedEventHandler(Output);
process.Start();
processId = process.Id;
UnityEngine.Debug.Log("processId:" + processId);
process.BeginErrorReadLine();
//process.StandardInput.WriteLine("q");
//process.WaitForExit();
}
if (GUILayout.Button("停止录制"))
{
if (process != null)
{
process.StandardInput.WriteLine("q");
process.WaitForExit();
process.Close();
process = null;
}
}
}
// Update is called once per frame
void Update()
{
}
private void OnApplicationQuit()
{
if (process != null)
{
process.StandardInput.WriteLine("q");
process.WaitForExit();
process.Close();
//process.Kill();
}
}
private void Output(object sendProcess, DataReceivedEventArgs output)
{
if (!string.IsNullOrEmpty(output.Data))
{
UnityEngine.Debug.Log(output.Data);
}
}
#region
/// <summary>
/// 设置窗口名
/// </summary>
/// <param name="hwnd"></param>
/// <param name="lpString"></param>
/// <returns></returns>
[DllImport("user32.dll", EntryPoint = "SetWindowText", CharSet = CharSet.Ansi)]
public static extern int SetWindowText(int hwnd, string lpString);
/// <summary>
/// 获得本窗体的句柄
/// </summary>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
#endregion
}