412 lines
12 KiB
C#
412 lines
12 KiB
C#
/* Copyright (c) 2019-present Evereal. All rights reserved. */
|
|
|
|
using System;
|
|
using System.Linq;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
|
|
using Debug = UnityEngine.Debug;
|
|
|
|
namespace Evereal.VideoCapture
|
|
{
|
|
public class Utils
|
|
{
|
|
private static System.Random random = new System.Random();
|
|
|
|
/// <summary>
|
|
/// Save render texture to PNG image file.
|
|
/// </summary>
|
|
/// <param name="rtex">RenderTexture.</param>
|
|
/// <param name="fileName">File name.</param>
|
|
public static void RenderTextureToPNG(RenderTexture rtex, string fileName)
|
|
{
|
|
Texture2D tex = new Texture2D(rtex.width, rtex.height, TextureFormat.RGB24, false);
|
|
RenderTexture.active = rtex;
|
|
tex.ReadPixels(new Rect(0, 0, rtex.width, rtex.height), 0, 0, false);
|
|
RenderTexture.active = null;
|
|
TextureToPNG(tex, fileName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save texture to PNG image file.
|
|
/// </summary>
|
|
/// <param name="tex">Tex.</param>
|
|
/// <param name="fileName">File name.</param>
|
|
public static void TextureToPNG(Texture2D tex, string fileName)
|
|
{
|
|
string filePath = "Captures/" + fileName;
|
|
byte[] imageBytes = tex.EncodeToPNG();
|
|
System.IO.File.WriteAllBytes(filePath, imageBytes);
|
|
Debug.Log("Save texture " + filePath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save render texture to JPG image file.
|
|
/// </summary>
|
|
/// <param name="rtex">RenderTexture.</param>
|
|
/// <param name="fileName">File name.</param>
|
|
public static void RenderTextureToJPG(RenderTexture rtex, string fileName)
|
|
{
|
|
Texture2D tex = new Texture2D(rtex.width, rtex.height, TextureFormat.RGB24, false);
|
|
RenderTexture.active = rtex;
|
|
tex.ReadPixels(new Rect(0, 0, rtex.width, rtex.height), 0, 0, false);
|
|
RenderTexture.active = null;
|
|
TextureToJPG(tex, fileName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Save texture to JPG image file.
|
|
/// </summary>
|
|
/// <param name="tex">Tex.</param>
|
|
/// <param name="fileName">File name.</param>
|
|
public static void TextureToJPG(Texture2D tex, string fileName)
|
|
{
|
|
string filePath = "Captures/" + fileName;
|
|
byte[] imageBytes = tex.EncodeToJPG();
|
|
System.IO.File.WriteAllBytes(filePath, imageBytes);
|
|
Debug.Log("Save texture " + filePath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create materials which will be used for equirect and cubemap generation.
|
|
/// </summary>
|
|
/// <param name="sName"> shader name </param>
|
|
/// <param name="m2Create"> material </param>
|
|
/// <returns></returns>
|
|
public static Material CreateMaterial(string sName, Material m2Create)
|
|
{
|
|
if (m2Create && (m2Create.shader.name == sName))
|
|
return m2Create;
|
|
Shader s = Shader.Find(sName);
|
|
return CreateMaterial(s, m2Create);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create materials which will be used for equirect and cubemap generation.
|
|
/// </summary>
|
|
/// <param name="s"> shader code </param>
|
|
/// <param name="m2Create"> material </param>
|
|
/// <returns></returns>
|
|
public static Material CreateMaterial(Shader s, Material m2Create)
|
|
{
|
|
if (!s)
|
|
{
|
|
Debug.Log("Create material missing shader!");
|
|
return null;
|
|
}
|
|
|
|
if (m2Create && (m2Create.shader == s) && (s.isSupported))
|
|
return m2Create;
|
|
|
|
if (!s.isSupported)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (m2Create != null)
|
|
{
|
|
UnityEngine.Object.Destroy(m2Create);
|
|
}
|
|
|
|
m2Create = new Material(s);
|
|
m2Create.hideFlags = HideFlags.DontSave;
|
|
|
|
return m2Create;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create RenderTexture.
|
|
/// </summary>
|
|
/// <param name="width"></param>
|
|
/// <param name="height"></param>
|
|
/// <param name="depth"></param>
|
|
/// <param name="antiAliasing"></param>
|
|
/// <param name="t2Create"></param>
|
|
/// <param name="create"></param>
|
|
/// <returns></returns>
|
|
public static RenderTexture CreateRenderTexture(int width, int height, int depth, int antiAliasing, RenderTexture t2Create, bool create = true)
|
|
{
|
|
if (t2Create &&
|
|
(t2Create.width == width) && (t2Create.height == height) && (t2Create.depth == depth) &&
|
|
(t2Create.antiAliasing == antiAliasing) && (t2Create.IsCreated() == create))
|
|
return t2Create;
|
|
|
|
if (t2Create != null)
|
|
{
|
|
UnityEngine.Object.Destroy(t2Create);
|
|
}
|
|
|
|
t2Create = new RenderTexture(width, height, depth, RenderTextureFormat.ARGB32);
|
|
//t2Create = new RenderTexture(width, height, depth, RenderTextureFormat.Default);
|
|
t2Create.antiAliasing = antiAliasing;
|
|
t2Create.hideFlags = HideFlags.HideAndDontSave;
|
|
|
|
// Make sure render texture is created.
|
|
if (create)
|
|
t2Create.Create();
|
|
|
|
return t2Create;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create Cubemap.
|
|
/// </summary>
|
|
/// <param name="cubemapSize"></param>
|
|
/// <param name="c2Create"></param>
|
|
/// <returns></returns>
|
|
public static Cubemap CreateCubemap(int cubemapSize, Cubemap c2Create)
|
|
{
|
|
if (c2Create && c2Create.width == cubemapSize)
|
|
return c2Create;
|
|
|
|
if (c2Create != null)
|
|
{
|
|
UnityEngine.Object.Destroy(c2Create);
|
|
}
|
|
|
|
c2Create = new Cubemap(cubemapSize, TextureFormat.RGB24, false);
|
|
|
|
return c2Create;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create Texture2D.
|
|
/// </summary>
|
|
/// <param name="width"></param>
|
|
/// <param name="height"></param>
|
|
/// <param name="t2Create"></param>
|
|
/// <returns></returns>
|
|
public static Texture2D CreateTexture(int width, int height, Texture2D t2Create)
|
|
{
|
|
if (t2Create && (t2Create.width == width) && (t2Create.height == height))
|
|
return t2Create;
|
|
|
|
if (t2Create != null)
|
|
{
|
|
UnityEngine.Object.Destroy(t2Create);
|
|
}
|
|
|
|
t2Create = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
|
t2Create.hideFlags = HideFlags.HideAndDontSave;
|
|
|
|
return t2Create;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Generate random string.
|
|
/// </summary>
|
|
/// <param name="length">random string length</param>
|
|
/// <returns></returns>
|
|
public static string GetRandomString(int length)
|
|
{
|
|
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
return new string(Enumerable.Repeat(chars, length)
|
|
.Select(s => s[random.Next(s.Length)]).ToArray());
|
|
}
|
|
|
|
public static string GetTimeString()
|
|
{
|
|
return DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
|
}
|
|
|
|
public static string GetTimestampString()
|
|
{
|
|
return DateTime.Now.ToString("yyyyMMddHHmmssff");
|
|
}
|
|
|
|
public static int GetClosestEvenNumber(int n)
|
|
{
|
|
if (n % 2 == 1)
|
|
return n - 1;
|
|
return n;
|
|
}
|
|
|
|
public static bool isWindows64Bit()
|
|
{
|
|
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
|
|
string sysInfo = SystemInfo.operatingSystem;
|
|
return sysInfo.Substring(sysInfo.Length - 5).Equals("64bit");
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
public static void EncodeVideo4K(string videoFile)
|
|
{
|
|
if (string.IsNullOrEmpty(videoFile))
|
|
{
|
|
return;
|
|
}
|
|
if (!System.IO.File.Exists(videoFile))
|
|
{
|
|
Debug.LogWarning("Video file " + videoFile + " is not found");
|
|
return;
|
|
}
|
|
Debug.Log("Start encode video " + videoFile + " to 4K");
|
|
string ext = System.IO.Path.GetExtension(videoFile);
|
|
Process.Start(FFmpeg.path, " -i \"" + videoFile + "\" -s 4096x2160 \"" + videoFile.Replace(ext, "_4K" + ext) + "\"");
|
|
}
|
|
|
|
public static void EncodeVideo8K(string videoFile)
|
|
{
|
|
if (string.IsNullOrEmpty(videoFile))
|
|
{
|
|
return;
|
|
}
|
|
if (!System.IO.File.Exists(videoFile))
|
|
{
|
|
Debug.LogWarning("Video file " + videoFile + " is not found");
|
|
return;
|
|
}
|
|
Debug.Log("Start encode video " + videoFile + " to 8K");
|
|
string ext = System.IO.Path.GetExtension(videoFile);
|
|
Process.Start(FFmpeg.path, " -i \"" + videoFile + "\" -s 7680x4320 \"" + videoFile.Replace(ext, "_8K" + ext) + "\"");
|
|
}
|
|
|
|
public static void ConvertVideoWmv(string videoFile)
|
|
{
|
|
if (string.IsNullOrEmpty(videoFile))
|
|
{
|
|
return;
|
|
}
|
|
if (!System.IO.File.Exists(videoFile))
|
|
{
|
|
Debug.LogWarning("Video file " + videoFile + " is not found");
|
|
return;
|
|
}
|
|
Debug.Log("Start convert video " + videoFile + " to WMV");
|
|
string ext = System.IO.Path.GetExtension(videoFile);
|
|
Process.Start(FFmpeg.path, " -i \"" + videoFile + "\" -qscale 2 -vcodec msmpeg4 -acodec wmav2 \"" + videoFile.Replace(ext, ".wmv") + "\"");
|
|
}
|
|
|
|
public static void ConvertVideoAvi(string videoFile)
|
|
{
|
|
if (string.IsNullOrEmpty(videoFile))
|
|
{
|
|
return;
|
|
}
|
|
if (!System.IO.File.Exists(videoFile))
|
|
{
|
|
Debug.LogWarning("Video file " + videoFile + " is not found");
|
|
return;
|
|
}
|
|
Debug.Log("Start convert video " + videoFile + " to AVI");
|
|
string ext = System.IO.Path.GetExtension(videoFile);
|
|
Process.Start(FFmpeg.path, " -i \"" + videoFile + "\" -vcodec copy -acodec copy \"" + videoFile.Replace(ext, ".avi") + "\"");
|
|
}
|
|
|
|
public static void ConvertVideoFlv(string videoFile)
|
|
{
|
|
if (string.IsNullOrEmpty(videoFile))
|
|
{
|
|
return;
|
|
}
|
|
if (!System.IO.File.Exists(videoFile))
|
|
{
|
|
Debug.LogWarning("Video file " + videoFile + " is not found");
|
|
return;
|
|
}
|
|
Debug.Log("Start convert video " + videoFile + " to FLV");
|
|
string ext = System.IO.Path.GetExtension(videoFile);
|
|
Process.Start(FFmpeg.path, " -i \"" + videoFile + "\" -c:v libx264 -crf 19 \"" + videoFile.Replace(ext, ".flv") + "\"");
|
|
}
|
|
|
|
public static void ConvertVideoMkv(string videoFile)
|
|
{
|
|
if (string.IsNullOrEmpty(videoFile))
|
|
{
|
|
return;
|
|
}
|
|
if (!System.IO.File.Exists(videoFile))
|
|
{
|
|
Debug.LogWarning("Video file " + videoFile + " is not found");
|
|
return;
|
|
}
|
|
Debug.Log("Start convert video " + videoFile + " to MKV");
|
|
string ext = System.IO.Path.GetExtension(videoFile);
|
|
Process.Start(FFmpeg.path, " -i \"" + videoFile + "\" -vcodec copy -acodec copy \"" + videoFile.Replace(ext, ".mkv") + "\"");
|
|
}
|
|
|
|
public static void ConvertVideoGif(string videoFile)
|
|
{
|
|
if (string.IsNullOrEmpty(videoFile))
|
|
{
|
|
return;
|
|
}
|
|
if (!System.IO.File.Exists(videoFile))
|
|
{
|
|
Debug.LogWarning("Video file " + videoFile + " is not found");
|
|
return;
|
|
}
|
|
Debug.Log("Start convert video " + videoFile + " to GIF");
|
|
string ext = System.IO.Path.GetExtension(videoFile);
|
|
Process.Start(FFmpeg.path, " -i \"" + videoFile + "\" -s 1280x720 -pix_fmt rgb24 \"" + videoFile.Replace(ext, ".gif") + "\"");
|
|
}
|
|
|
|
public static string GetEncoderPresetExt(EncoderPreset preset)
|
|
{
|
|
switch (preset)
|
|
{
|
|
case EncoderPreset.H264_MP4:
|
|
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
|
case EncoderPreset.H264_NVIDIA_MP4:
|
|
#endif
|
|
case EncoderPreset.H264_LOSSLESS_MP4:
|
|
case EncoderPreset.H265_MP4:
|
|
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
|
case EncoderPreset.H265_NVIDIA_MP4:
|
|
#endif
|
|
return "mp4";
|
|
case EncoderPreset.VP8_WEBM:
|
|
case EncoderPreset.VP9_WEBM:
|
|
return "webm";
|
|
case EncoderPreset.FFV1_MKV:
|
|
return "mkv";
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static string CreateFolder(string f2Create)
|
|
{
|
|
string folder = f2Create;
|
|
if (string.IsNullOrEmpty(folder))
|
|
{
|
|
folder = "Captures/";
|
|
}
|
|
if (!folder.EndsWith("/") && !folder.EndsWith("\\"))
|
|
{
|
|
folder += "/";
|
|
}
|
|
if (!Directory.Exists(folder))
|
|
{
|
|
Directory.CreateDirectory(folder);
|
|
}
|
|
return Path.GetFullPath(folder);
|
|
}
|
|
|
|
public static void BrowseFolder(string folder)
|
|
{
|
|
if (string.IsNullOrEmpty(folder))
|
|
{
|
|
folder = "Captures/";
|
|
}
|
|
string fullPath = Path.GetFullPath(folder);
|
|
if (Directory.Exists(fullPath))
|
|
{
|
|
Process.Start(Path.GetFullPath(folder));
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("Folder " + fullPath + " not existed!");
|
|
}
|
|
}
|
|
|
|
public static void WriteLogToDisk(string msg)
|
|
{
|
|
StreamWriter writer = new StreamWriter("UnityLog.txt", true);
|
|
writer.WriteLine(msg);
|
|
writer.Close();
|
|
}
|
|
}
|
|
} |