using UnityEngine; namespace FFmpegOut { [RequireComponent(typeof(Camera))] [AddComponentMenu("FFmpegOut/Camera Capture")] public class CameraCapture : MonoBehaviour { #region Editable properties [SerializeField] bool _setResolution = true; [SerializeField] int _width = 1280; [SerializeField] int _height = 720; [SerializeField] int _frameRate = 30; [SerializeField] bool _allowSlowDown = true; [SerializeField] public FFmpegPipe.Codec _codec; #endregion public void SetResolution(int w,int h) { _width = w; _height = h; } #region Private members [SerializeField, HideInInspector] Shader _shader; Material _material; FFmpegPipe _pipe; float _elapsed; RenderTexture _tempTarget; GameObject _tempBlitter; static int _activePipeCount; #endregion #region MonoBehavior functions public float recordTime; private float updateIntervalTime; private long CurrentFrameCount; //private Camera RenderCamera; void OnValidate() { } void OnEnable() { if (!FFmpegConfig.CheckAvailable) { Debug.LogError( "ffmpeg.exe is missing. " + "Please refer to the installation instruction. " + "https://github.com/keijiro/FFmpegOut" ); enabled = false; } updateIntervalTime = 1 / (float)_frameRate; //Application.targetFrameRate = _frameRate; //RenderCamera = GetComponent(); SetResolution(Screen.width,Screen.height); } void OnDisable() { if (_pipe != null) ClosePipe(); } void OnDestroy() { if (_pipe != null) ClosePipe(); } void Start() { _material = new Material(_shader); //_frameRate = Application.targetFrameRate; } public void StartCapture(string filename) { if (_pipe == null) OpenPipe(filename); } public void StopCapture() { if (_pipe != null) ClosePipe(); } void OnRenderImage(RenderTexture source, RenderTexture destination) { if (_pipe != null) { if ((Time.time - recordTime) / updateIntervalTime >= CurrentFrameCount) { var tempRT = RenderTexture.GetTemporary(source.width, source.height); Graphics.Blit(source, tempRT, _material, 0); var tempTex = new Texture2D(source.width, source.height, TextureFormat.RGB24, false); tempTex.ReadPixels(new Rect(0, 0, source.width, source.height), 0, 0, false); tempTex.Apply(); byte[] writeByte = tempTex.GetRawTextureData(); _pipe.Write(writeByte); Destroy(tempTex); RenderTexture.ReleaseTemporary(tempRT); CurrentFrameCount++; } } Graphics.Blit(source, destination); } #endregion #region Private methods void OpenPipe(string filename) { if (_pipe != null) return; var camera = GetComponent(); var width = _width; var height = _height; // Apply the screen resolution settings. if (_setResolution) { _tempTarget = RenderTexture.GetTemporary(width, height); camera.targetTexture = _tempTarget; _tempBlitter = Blitter.CreateGameObject(camera); } else { width = camera.pixelWidth; height = camera.pixelHeight; } // Open an output stream. _pipe = new FFmpegPipe(filename, width, height, _frameRate, _codec); _activePipeCount++; // Change the application frame rate on the first pipe. if (_activePipeCount == 1) { if (_allowSlowDown) Time.captureFramerate = _frameRate; //else //Application.targetFrameRate = _frameRate; } recordTime = Time.time; Debug.Log("Capture started (" + _pipe.Filename + ")"); } void ClosePipe() { var camera = GetComponent(); // Destroy the blitter object. if (_tempBlitter != null) { Destroy(_tempBlitter); _tempBlitter = null; } // Release the temporary render target. if (_tempTarget != null && _tempTarget == camera.targetTexture) { camera.targetTexture = null; RenderTexture.ReleaseTemporary(_tempTarget); _tempTarget = null; } // Close the output stream. if (_pipe != null) { CurrentFrameCount = 0; Debug.Log("Capture ended (" + _pipe.Filename + ")"); StartCoroutine(_pipe.Close()); _activePipeCount--; if (!string.IsNullOrEmpty(_pipe.Error)) { Debug.LogWarning( "ffmpeg returned with a warning or an error message. " + "See the following lines for details:\n" + _pipe.Error ); } _pipe = null; // Reset the application frame rate on the last pipe. if (_activePipeCount == 0) { if (_allowSlowDown) Time.captureFramerate = 0; //else //Application.targetFrameRate = -1; //Application.targetFrameRate = _frameRate; } } } #endregion } }