简单易用~原理是在unity里按一定的时间间隔截图,然后用ffmpeg.exe去生成视频~~
本代码使用简单,
一、开发时把ffmpeg.exe放在工程目录下,运行exe时放在同目录下。
二、把movieRecord脚本挂在场景中
三、movieRecord.Inst.StartRecord(); 启动
四、录得差不多的时候movieRecord.Inst.StopRecord();停止
五、movieRecord.OnMovieCreateOver 是视频生成结束的回调,传递的参数是生成的视频的位置
下面是代码:
namespace YangXun {
using UnityEngine;
using System.Collections;
using System.Diagnostics;
using System;
using System.IO;
public class movieRecord:MonoBehaviour {
public static void CreateMovie(string path,string comName,string outFileName) {
Process p = new Process();
string curDir = System.Environment.CurrentDirectory;
p.StartInfo.FileName = curDir + @"/ffmpeg.exe";
//print(System.Environment.CurrentDirectory + @"/ffmpeg.exe");
string arg = string.Format("-i {0}/{1}/{2}%d.jpg -r 25 -vcodec mpeg4 {3}", curDir,path, comName, outFileName);
p.StartInfo.Arguments = arg;//参数
p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动
p.StartInfo.RedirectStandardError = true;//重定向标准错误流
p.StartInfo.CreateNoWindow = true;
p.ErrorDataReceived += new DataReceivedEventHandler(Output);//输出流的事件
p.Start();//启动
p.BeginErrorReadLine();//开始异步读取
p.WaitForExit();//阻塞等待进程结束
p.Close();
p.Dispose();
if (OnMovieCreateOver != null) {
OnMovieCreateOver(outFileName);
}
}
private static void Output(object sendProcess, DataReceivedEventArgs output) {
if (!String.IsNullOrEmpty(output.Data)) {
UnityEngine.Debug.Log(output.Data);
}
}
int state = -1;
int rate = 25;
private static movieRecord inst;
public static movieRecord Inst {
get { return inst; }
}
public static Action OnMovieCreateOver;
void Awake() {
inst = this;
if (!Directory.Exists("tImg"))
Directory.CreateDirectory("tImg");
if (!Directory.Exists("movie"))
Directory.CreateDirectory("movie");
curSpan = 1.0f / 25;
StartCoroutine(Loop());
}
public void StartRecord() {
state = 1;
Directory.Delete("tImg", true);
Directory.CreateDirectory("tImg");
}
//public void PauseRecord() {
// state = 0;
//}
public void StopRecord() {
state = -1;
index = 0;
CreateMovie("tImg", "img", string.Format("movie/{0}.mp4",DateTime.Now.ToString("yyyyMMddhhmmss")));
}
public void SetRate() {
}
float curSpan = 0;
float nowTime = 0;
int index = 0;
IEnumerator Loop() {
while (true) {
yield return new WaitForEndOfFrame();
if (state == 1) {
nowTime += Time.deltaTime;
if (nowTime > curSpan) {
nowTime = 0;
Texture2D t = capTex();
//t.Apply();
SaveJpg(t, "tImg/img", index);
index++;
Resources.UnloadUnusedAssets();
}
}
}
}
Texture2D capTex() {
Texture2D t = new Texture2D(Screen.width, Screen.height);
t.ReadPixels(new Rect(0,0,Screen.width,Screen.height), 0, 0);
return t;
}
void SaveJpg(Texture2D tex,string comName,int index) {
var bytes = tex.EncodeToJPG();
FileStream fs = new FileStream(comName+index+".jpg",FileMode.Create);
fs.Write(bytes, 0, bytes.Length);
fs.Flush();
fs.Close();
}
}
}
using UnityEngine;
using System.Collections;
using YangXun;
public class Test_movieRecord : MonoBehaviour {
public Transform cube;
// Use this for initialization
IEnumerator Start () {
movieRecord.OnMovieCreateOver = (str) => {
Debug.Log("生成的视频路径为:"+str);
};
movieRecord.Inst.StartRecord();
yield return new WaitForSeconds(10);
movieRecord.Inst.StopRecord();
}
// Update is called once per frame
void Update () {
if(cube)
cube.transform.Rotate(0, 10, 0);
}
}
效果图:
就是这样~~~
2015/11/7 略有修改
namespace YangXun {
using UnityEngine;
using System.Collections;
using System.Diagnostics;
using System;
using System.IO;
using System.Threading;
public class movieRecord:MonoBehaviour {
public Func overrideGetTex;
public Action overrideSaveJPG;
static Process p;
static string outFileName;
public static void CreateMovie(string path,string comName,string outFileName) {
p = new Process();
movieRecord.outFileName = outFileName;
string curDir = System.Environment.CurrentDirectory;
p.StartInfo.FileName = curDir + @"\ffmpeg.exe";
DirectoryInfo dir = new DirectoryInfo(curDir + "\\" + path + "\\" + comName);
FileInfo[] fcount = dir.GetFiles("*.jpg");
UnityEngine.Debug.Log(fcount.Length);
int rate = (int)(fcount.Length / 10f);
//print(System.Environment.CurrentDirectory + @"/ffmpeg.exe");
//string arg = string.Format("-i {0}/{1}/{2}%d.jpg -r {3} -vcodec mpeg4 {4}", curDir,path, comName,rate, outFileName);
string arg = string.Format("-f image2 -r {3} -i {0}\\{1}\\{2}%d.jpg -vcodec mpeg4 {4}", curDir, path, comName, rate, outFileName);
UnityEngine.Debug.LogFormat("-f image2 -r {3} -i {0}\\{1}\\{2}%d.jpg -vcodec mpeg4 {4}", curDir, path, comName, rate, outFileName);
p.StartInfo.Arguments = arg;//参数
p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动
//p.StartInfo.RedirectStandardError = true;//重定向标准错误流
p.StartInfo.CreateNoWindow = true;
//p.ErrorDataReceived += new DataReceivedEventHandler(Output);//输出流的事件
p.Start();//启动
//p.BeginErrorReadLine();//开始异步读取
//p.WaitForExit();//阻塞等待进程结束
//p.Close();
//p.Dispose();
CoroutineWrapper.Inst.OnPerFrame += CheckPExited;
}
private static void CheckPExited() {
if (p.HasExited) {
OnMovieCreateOver(outFileName);
CoroutineWrapper.Inst.OnPerFrame -= CheckPExited;
}
}
//
public static void Mp42Ogg(string path) {
Process p = new Process();
string curDir = System.Environment.CurrentDirectory;
p.StartInfo.FileName = curDir + @"\ffmpeg.exe";
string outFilePath = path.Replace(".mp4", ".ogg");
string arg = string.Format("-i {0} -vcodec h263 -r {1} {2}", path, 25, outFilePath);
p.StartInfo.Arguments = arg;//参数
p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动
p.StartInfo.RedirectStandardError = true;//重定向标准错误流
p.StartInfo.CreateNoWindow = true;
p.ErrorDataReceived += new DataReceivedEventHandler(Output);//输出流的事件
p.Start();//启动
p.BeginErrorReadLine();//开始异步读取
p.WaitForExit();//阻塞等待进程结束
p.Close();
p.Dispose();
if (OnMovieCreateOver != null) {
OnMovieCreateOver(outFilePath);
}
}
//
private static void Output(object sendProcess, DataReceivedEventArgs output) {
if (!String.IsNullOrEmpty(output.Data)) {
UnityEngine.Debug.Log(output.Data);
}
}
int state = -1;
int rate = 25;
private static movieRecord inst;
public static movieRecord Inst {
get {
if (inst == null) {
var obj = new GameObject("movieRecord");
inst = obj.AddComponent();
inst.overrideGetTex = inst.capTex;
}
return inst;
}
}
public Camera tarCamera;
public static Action OnMovieCreateOver;
void Awake() {
inst = this;
if (!Directory.Exists("tImg"))
Directory.CreateDirectory("tImg");
if (!Directory.Exists("movie"))
Directory.CreateDirectory("movie");
curSpan = 1.0f / 25;
StartCoroutine(Loop());
}
public void StartRecord() {
state = 1;
Directory.Delete("tImg", true);
Directory.CreateDirectory("tImg");
}
//public void PauseRecord() {
// state = 0;
//}
public void StopRecord() {
state = -1;
index = 0;
overrideSaveJPG("tImg\\", () => {
CreateMovie("tImg", "", string.Format("movie\\{0}.mp4", DateTime.Now.ToString("yyyyMMddhhmmss")));
});
}
public void SetRate() {
}
float curSpan = 0;
float nowTime = 0;
public int index = 0;
IEnumerator Loop() {
while (true) {
//yield return new WaitForEndOfFrame();
//if (state == 1) {
// nowTime += Time.deltaTime;
// if (nowTime > curSpan) {
// nowTime = 0;
// Texture2D t = capTex();
// //t.Apply();
// SaveJpg(t, "tImg\\", index);
// index++;
// Resources.UnloadUnusedAssets();
// }
//}
yield return new WaitForSeconds(0.04f);
if (state == 1) {
Texture2D t = overrideGetTex();
//t.Apply();
//SaveJpg(t, "tImg\\", index);
index++;
}
}
}
Texture2D capTex() {
//Texture2D t = new Texture2D(Screen.width, Screen.height);
//t.ReadPixels(new Rect(0,0,Screen.width,Screen.height), 0, 0);
//return t;
if (tarCamera != null)
return imgTools.getCamRender(tarCamera, new Rect(0, 0, Screen.width, Screen.height));
else {
Texture2D t = new Texture2D(Screen.width, Screen.height);
t.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);
return t;
}
}
void SaveJpg(Texture2D tex,string comName,int index) {
var bytes = tex.EncodeToJPG();
FileStream fs = new FileStream(comName+index+".jpg",FileMode.Create);
fs.Write(bytes, 0, bytes.Length);
fs.Flush();
fs.Close();
}
}
}