Optimizing video capture in Unity 3D application: How to speed up the process?

My application uses Unity 3D to generate/compose animations. Basically, the application receives a string of actions as a parameter, where each action is mapped to a bundle. This list of bundles is then played, resulting in a final animation. However, I need to capture the generated animation. Currently, I take a screenshot of each generated frame, using something like that:

using UnityEngine;
using System.Collections;
public class HiResScreenShots : MonoBehaviour {
     public int resWidth = 2550;
     public int resHeight = 3300;
     private bool takeHiResShot = false;
     public static string ScreenShotName(int width, int height) {
         return string.Format("{0}/screenshots/screen_{1}x{2}_{3}.png",
                              Application.dataPath,
                              width, height,
                              System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
     }
     public void TakeHiResShot() {
         takeHiResShot = true;
     }
     void LateUpdate() {
         if (takeHiResShot) {
             RenderTexture rt = new RenderTexture(resWidth, resHeight, 24);
             camera.targetTexture = rt;
             Texture2D screenShot = new Texture2D(resWidth, resHeight, TextureFormat.RGB24, false);
             camera.Render();
             RenderTexture.active = rt;
             screenShot.ReadPixels(new Rect(0, 0, resWidth, resHeight), 0, 0);
             camera.targetTexture = null;
             RenderTexture.active = null; 
             Destroy(rt);
             byte[] bytes = screenShot.EncodeToPNG();
             string filename = ScreenShotName(resWidth, resHeight);
             System.IO.File.WriteAllBytes(filename, bytes);
             Debug.Log(string.Format("Took screenshot to: {0}", filename));
             takeHiResShot = false;
         }
     }
}

But this approach is very slow, as the total processing time is equal to the duration of the generated animation. Is there any way to optimize this process?

Hello,
by using LateUpdate(), you’re effectively running your method in realtime.
Try using FixedUpdate() for which the frequency is set in the settings (Time) instead.
You can also try using asyncs, which can allow you to render multiple frames at the same time.
I cannot help much with asyncs though.

If you want to go faster just don’t write to disk during the capture, it will consume more memory though. There are other strategies available. One is to write everything into a single file, possibly a mp4. Another is to have a separated process for writing to disk. You can also compare the pixels with the previous capture and only write the diff to disk. If it is for personal use only you can consider writing to a SSD. Also you don’t have to encode to PNG now you can do it after the capture.

There is also an Unity Recorder you might like but I’ve never used it: Working with the Unity Recorder - 2019.3 - Unity Learn

1 Like