两个脚本 一个需要挂载
FFmpeg软件在下面链接下载 需要放到streamingAsset\ffmpeg文件夹下
下面再出一个安卓调用FFmpeg生成视频的博客
using System.Collections;
using System.Diagnostics;
using System.IO;
using UnityEngine;
public class CreatVideos : MonoBehaviour
{
private string imagePath;
private string ffmpegPath;
private string videoPath;
// Use this for initialization
void Start()
{
Loom.Initialize();
imagePath = GameManager.imgffpath + "/";
ffmpegPath = @Application.streamingAssetsPath + "/ffmpeg/ffmpeg.exe";
videoPath = @Application.streamingAssetsPath + "/视频.mp4";
}
public void CreatVideo()
{
print("开始渲染");
print(imagePath);
print(videoPath);
if (File.Exists(videoPath))
{
File.Delete(videoPath);
}
Loom.RunAsync(() =>
{
//建立外部调用进程
Process p = new Process();
p.StartInfo.FileName = ffmpegPath;
string args = "-f image2 -framerate 12 -i " + imagePath + "%05d.jpg -vcodec libx264 -r 25 " + videoPath;
//%05d是指图片名称00000 00001 00002 如果是1,2,3用%01d
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();//释放资源
});
}
private void Output(object sendProcess, DataReceivedEventArgs output)
{
if (!string.IsNullOrEmpty(output.Data))
{
//处理方法...
UnityEngine.Debug.Log(output.Data);
}
}
}
下面的不需要挂载
using UnityEngine;
using System.Collections.Generic;
using System;
using System.Threading;
using System.Linq;
/// <summary>
/// 多线程
/// </summary>
public class Loom : MonoBehaviour
{
public static int maxThreads = 8;
static int numThreads;
private static Loom _current;
public static Loom Current
{
get
{
Initialize();
return _current;
}
}
//####去除Awake
// void Awake()
// {
// _current = this;
// initialized = true;
// }
static bool initialized;
/// <summary>
/// ####作为初始化方法自己调用,可在初始化场景调用一次即可
/// </summary>
public static void Initialize()
{
if (!initialized)
{
if (!Application.isPlaying)
return;
initialized = true;
GameObject g = new GameObject("Loom");
//####永不销毁
DontDestroyOnLoad(g);
_current = g.AddComponent<Loom>();
}
}
private List<Action> _actions = new List<Action>();
public struct DelayedQueueItem
{
public float time;
public Action action;
}
private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();
/// <summary>
/// 在主线程中运行
/// </summary>
/// <param name="action"></param>
public static void QueueOnMainThread(Action action)
{
QueueOnMainThread(action, 0f);
}
public static void QueueOnMainThread(Action action, float time)
{
if (time != 0)
{
if (Current != null)
{
lock (Current._delayed)
{
Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action });
}
}
}
else
{
if (Current != null)
{
lock (Current._actions)
{
Current._actions.Add(action);
}
}
}
}
public static Thread RunAsync(Action a)
{
Initialize();
while (numThreads >= maxThreads)
{
Thread.Sleep(1);
}
Interlocked.Increment(ref numThreads);
ThreadPool.QueueUserWorkItem(RunAction, a);
return null;
}
private static void RunAction(object action)
{
try
{
((Action)action)();
}
catch
{
}
finally
{
Interlocked.Decrement(ref numThreads);
}
}
void OnDisable()
{
if (_current == this)
{
_current = null;
}
}
// Use this for initialization
void Start()
{
}
List<Action> _currentActions = new List<Action>();
// Update is called once per frame
void Update()
{
lock (_actions)
{
_currentActions.Clear();
_currentActions.AddRange(_actions);
_actions.Clear();
}
foreach (var a in _currentActions)
{
a();
}
lock (_delayed)
{
_currentDelayed.Clear();
_currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));
foreach (var item in _currentDelayed)
_delayed.Remove(item);
}
foreach (var delayed in _currentDelayed)
{
delayed.action();
}
}
}