129 lines
3.9 KiB
Plaintext
129 lines
3.9 KiB
Plaintext
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
|
|
public class FFmpegVideoRecorder : MonoBehaviour
|
|
{
|
|
public Camera targetCamera; // Assign your camera in the Inspector
|
|
public int outputWidth = 1920; // Output video width
|
|
public int outputHeight = 1080; // Output video height
|
|
public int outputFrameRate = 30; // Output video frame rate
|
|
public string ffmpegPath = "ffmpeg"; // Path to the FFmpeg binary
|
|
public string outputFilePath = "output.mp4"; // Path to save the video
|
|
|
|
private RenderTexture renderTexture;
|
|
private Texture2D frameTexture;
|
|
private Process ffmpegProcess;
|
|
private BinaryWriter ffmpegInputStream;
|
|
|
|
private void Start()
|
|
{
|
|
// Setup FFmpeg process
|
|
StartFFmpeg();
|
|
|
|
// Create a RenderTexture and Texture2D for capturing frames
|
|
renderTexture = new RenderTexture(outputWidth, outputHeight, 24);
|
|
frameTexture = new Texture2D(outputWidth, outputHeight, TextureFormat.RGB24, false);
|
|
|
|
// Set the camera's target texture to render to the RenderTexture
|
|
targetCamera.targetTexture = renderTexture;
|
|
}
|
|
|
|
private void LateUpdate()
|
|
{
|
|
// Capture the camera's current frame
|
|
RenderTexture currentRT = RenderTexture.active;
|
|
RenderTexture.active = renderTexture;
|
|
targetCamera.Render();
|
|
|
|
// Read the pixels from the RenderTexture into the Texture2D
|
|
frameTexture.ReadPixels(new Rect(0, 0, outputWidth, outputHeight), 0, 0);
|
|
frameTexture.Apply();
|
|
|
|
// Write the frame's raw RGB data to the FFmpeg input stream
|
|
byte[] frameData = frameTexture.GetRawTextureData();
|
|
if (ffmpegInputStream != null)
|
|
{
|
|
ffmpegInputStream.Write(frameData);
|
|
}
|
|
|
|
// Restore the previous active RenderTexture
|
|
RenderTexture.active = currentRT;
|
|
}
|
|
|
|
private void OnApplicationQuit()
|
|
{
|
|
StopFFmpeg();
|
|
|
|
// Clean up temporary objects
|
|
if (renderTexture != null)
|
|
{
|
|
RenderTexture.ReleaseTemporary(renderTexture);
|
|
}
|
|
if (frameTexture != null)
|
|
{
|
|
Destroy(frameTexture);
|
|
}
|
|
}
|
|
|
|
private void StartFFmpeg()
|
|
{
|
|
var ffmpegStartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = ffmpegPath,
|
|
Arguments = $"-y -f rawvideo -vcodec rawvideo -pix_fmt rgb24 -s {outputWidth}x{outputHeight} -r {outputFrameRate} -i - -an -vcodec libx264 -pix_fmt yuv420p \"{outputFilePath}\"",
|
|
UseShellExecute = false,
|
|
RedirectStandardInput = true,
|
|
RedirectStandardOutput = false,
|
|
RedirectStandardError = true, // Optional: Redirect standard error for debugging
|
|
CreateNoWindow = true
|
|
};
|
|
|
|
ffmpegProcess = new Process
|
|
{
|
|
StartInfo = ffmpegStartInfo
|
|
};
|
|
|
|
ffmpegProcess.Start();
|
|
|
|
// Attach the input stream
|
|
ffmpegInputStream = new BinaryWriter(ffmpegProcess.StandardInput.BaseStream);
|
|
}
|
|
|
|
private void StopFFmpeg()
|
|
{
|
|
if (ffmpegInputStream != null)
|
|
{
|
|
try
|
|
{
|
|
// Close the input stream
|
|
ffmpegInputStream.Close();
|
|
}
|
|
catch
|
|
{
|
|
// Ignore any errors when closing the stream
|
|
}
|
|
ffmpegInputStream = null;
|
|
}
|
|
|
|
if (ffmpegProcess != null)
|
|
{
|
|
try
|
|
{
|
|
// Wait for the FFmpeg process to exit
|
|
ffmpegProcess.WaitForExit();
|
|
}
|
|
catch
|
|
{
|
|
// Ignore any errors when waiting for the process
|
|
}
|
|
finally
|
|
{
|
|
ffmpegProcess.Close();
|
|
}
|
|
|
|
ffmpegProcess = null;
|
|
}
|
|
}
|
|
} |