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; } } }