Unity截屏调ffmpeg生成视频

12 篇文章 0 订阅

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
}

 

  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

地狱为王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值