贵港路建设路地下商业街网上演练
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

266 lines
7.9 KiB

using UnityEngine;
using System;
using System.IO;
using System.Text;
namespace FFmpeg.Demo.REC
{
//[RequireComponent(typeof(RecMicAudio), typeof(RecSystemAudio))]
public class FFmpegREC : MonoBehaviour, IFFmpegHandler
{
//Data
[Header("Targeted FPS")]
public int FPS = 30;
float actualFPS;
[Header("0 for max resolution")]
public int width ;
public int height ;
[Header("Change before initialization")]
public RecAudioSource recAudioSource = RecAudioSource.System;
Rect camRect;
//References
IRecAudio soundRecorder;
Texture2D frameBuffer;
//Paths
const string FILE_FORMAT = "{0}_Frame.jpg";
const string SOUND_NAME = "RecordedAudio.wav";
[HideInInspector]
public string VIDEO_NAME = "ScreenCapture.mp4";
string cashDir, imgFilePathFormat, firstImgFilePath, soundPath, outputVideoPath;
//Variables
int framesCount;
float startTime, frameInterval, frameTimer, totalTime;
public bool isREC { get; private set; }
public bool isProducing { get; private set; }
#if !UNITY_EDITOR
int initialWidth, initialHeight;
public bool overrideResolution { get { return width > 0 || height > 0; } }
#endif
//References
Action<string> onOutput, onFinish;
//PUBLIC INTERFACE
//------------------------------
public RecSavePanel RecSavePanel;
public void Init(Action<string> _onOutput, Action<string> _onFinish)
{
//Subscription to FFmpeg callbacks
FFmpegParser.Handler = this;
width = Screen.width;
height = Screen.height;
//Paths initialization
string path = Application.streamingAssetsPath + "/RECFile/" + GameSettings.othersSettings.mode.ToString() + "/" + CurrentUserInfo.room.Id.ToString();
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
cashDir = Path.Combine(path, "RecordingCash");
imgFilePathFormat = Path.Combine(cashDir, FILE_FORMAT);
firstImgFilePath = String.Format(imgFilePathFormat, "%0d");
soundPath = Path.Combine(cashDir, SOUND_NAME);
outputVideoPath = Path.Combine(path, VIDEO_NAME);
#if !UNITY_EDITOR
initialWidth = Screen.width;
initialHeight = Screen.height;
#endif
//Sound source initialization
if (recAudioSource == RecAudioSource.Mic)
{
soundRecorder = GetComponent<RecMicAudio>();
}
else if (recAudioSource == RecAudioSource.System)
{
soundRecorder = GetComponent<RecSystemAudio>();
}
else if (recAudioSource == RecAudioSource.None)
{
soundRecorder = null;
}
onOutput = _onOutput;
onFinish = _onFinish;
}
void Clear()
{
if (Directory.Exists(cashDir))
Directory.Delete(cashDir, true);
}
public void StartREC()
{
if (!isREC && !isProducing)
{
Clear();
Directory.CreateDirectory(cashDir);
Debug.Log("CashDir created: " + cashDir);
#if !UNITY_EDITOR
if (overrideResolution)
{
//Low level operation of resolution change
Screen.SetResolution(width, height, Screen.fullScreen);
}
else
#endif
{
width = Screen.width;
height = Screen.height;
}
frameBuffer = new Texture2D(width, height, TextureFormat.RGB24, false, true);
camRect = new Rect(0, 0, width, height);
startTime = Time.time;
framesCount = 0;
frameInterval = 1.0f / FPS;
frameTimer = frameInterval;
isREC = true;
if (recAudioSource != RecAudioSource.None)
{
soundRecorder.StartRecording();
}
RecSavePanel.BeginTime = TIME_SYNC.time;
}
}
public void StopREC()
{
isREC = false;
isProducing = true;
totalTime = Time.time - startTime;
actualFPS = framesCount / totalTime;
Debug.Log("Actual FPS: " + actualFPS);
if (recAudioSource != RecAudioSource.None)
{
soundRecorder.StopRecording(soundPath);
}
RecSavePanel.gameObject.SetActive(true);
//CreateVideo();
#if !UNITY_EDITOR
if (overrideResolution)
//Return to initial screen resolution
Screen.SetResolution(initialWidth, initialHeight, Screen.fullScreen);
#endif
}
//INTERNAL IMPLEMENTATION
//------------------------------
void OnPostRender()
{
if (isREC && (frameTimer += Time.deltaTime) > frameInterval)
{
frameTimer -= frameInterval;
frameBuffer.ReadPixels(camRect, 0, 0);
File.WriteAllBytes(NextImgFilePath(), frameBuffer.EncodeToJPG());
}
}
string NextImgFilePath()
{
return String.Format(imgFilePathFormat, framesCount++);
}
public void CreateVideo()
{
StringBuilder command = new StringBuilder();
Debug.Log("firstImgFilePath: " + firstImgFilePath);
Debug.Log("soundPath: " + soundPath);
Debug.Log("outputVideoPath:------------ " + outputVideoPath);
//Input Image sequence params
command.
Append("-y -framerate ").
Append(actualFPS.ToString()).
Append(" -f image2 -i ").
Append(AddQuotation(firstImgFilePath));
//Input Audio params
if (recAudioSource != RecAudioSource.None)
{
command.
Append(" -i ").
Append(AddQuotation(soundPath)).
Append(" -ss 0 -t ").
Append(totalTime);
}
//Output Video params
command.
Append(" -vcodec libx264 -crf 25 -pix_fmt yuv420p ").
Append(AddQuotation(outputVideoPath));
Debug.Log(command.ToString());
FFmpegCommands.DirectInput(command.ToString());
}
string AddQuotation(string path)
{
if (string.IsNullOrEmpty(path))
{
throw new Exception("Empty path.");
}
#if UNITY_EDITOR || UNITY_STANDALONE
const char DOUBLE_QUOTATION = '\"';
if (path[0] != DOUBLE_QUOTATION)
{
return DOUBLE_QUOTATION + path + DOUBLE_QUOTATION;
}
#endif
return path;
}
//FFmpeg processing callbacks
//------------------------------
//Begining of video processing
public void OnStart()
{
onOutput("VideoProducing Started\n");
}
//You can make custom progress bar here (parse msg)
public void OnProgress(string msg)
{
onOutput(msg);
}
//Notify user about failure here
public void OnFailure(string msg)
{
onOutput(msg);
}
//Notify user about success here
public void OnSuccess(string msg)
{
onOutput(msg);
}
//Last callback - do whatever you need next
public void OnFinish()
{
onFinish(outputVideoPath);
Clear();
isProducing = false;
}
}
}