Tanoda
CameraInput.cs
Go to the documentation of this file.
1/*
2* NatCorder
3* Copyright (c) 2020 Yusuf Olokoba.
4*/
5
6using System;
7using System.Collections;
9using UnityEngine;
10using UnityEngine.Rendering;
11using Object = UnityEngine.Object;
12
14{
18 public sealed class CameraInput : IDisposable
19 {
20 // DEPLOY
21
22 #region --Client API--
23
28 public int frameSkip;
29
36 public CameraInput(IMediaRecorder recorder, IClock clock, params Camera[] cameras)
37 {
38 // Sort cameras by depth
39 Array.Sort(cameras, (a, b) => (int) (10 * (a.depth - b.depth)));
40 var (width, height) = recorder.frameSize;
41 // Save state
42 this.recorder = recorder;
43 this.clock = clock;
44 this.cameras = cameras;
45 frameDescriptor = new RenderTextureDescriptor(width, height, RenderTextureFormat.ARGB32, 24);
46 readbackBuffer = SystemInfo.supportsAsyncGPUReadback
47 ? null
48 : new Texture2D(width, height, TextureFormat.RGBA32, false, false);
49 attachment = cameras[0].gameObject.AddComponent<CameraInputAttachment>();
50 pixelBuffer = new byte[width * height * 4];
51 // Start recording
52 frameDescriptor.sRGB = true;
53 attachment.StartCoroutine(OnFrame());
54 }
55
59 public void Dispose()
60 {
61 Object.Destroy(attachment);
62 Object.Destroy(readbackBuffer);
63 pixelBuffer = null;
64 }
65
66 #endregion
67
68
69 #region --Operations--
70
71 private readonly IMediaRecorder recorder;
72 private readonly IClock clock;
73 private readonly Camera[] cameras;
74 private readonly RenderTextureDescriptor frameDescriptor;
75 private readonly Texture2D readbackBuffer;
76 private readonly CameraInputAttachment attachment;
77 private byte[] pixelBuffer;
78 private int frameCount;
79
80 private IEnumerator OnFrame()
81 {
82 var endOfFrame = new WaitForEndOfFrame();
83 while (true)
84 {
85 // Check frame index
86 yield return endOfFrame;
87 if (frameCount++ % (frameSkip + 1) != 0)
88 continue;
89 // Render every camera
90 var frameBuffer = RenderTexture.GetTemporary(frameDescriptor);
91 for (var i = 0; i < cameras.Length; i++)
92 {
93 var prevTarget = cameras[i].targetTexture;
94 cameras[i].targetTexture = frameBuffer;
95 cameras[i].Render();
96 cameras[i].targetTexture = prevTarget;
97 }
98
99 // Readback and commit
100 var timestamp = clock.timestamp;
101 if (SystemInfo.supportsAsyncGPUReadback)
102 {
103 AsyncGPUReadback.Request(frameBuffer, 0, request =>
104 {
105 if (pixelBuffer != null)
106 {
107 request.GetData<byte>().CopyTo(pixelBuffer);
108 recorder.CommitFrame(pixelBuffer, timestamp);
109 }
110 });
111 }
112 else
113 {
114 var prevActive = RenderTexture.active;
115 RenderTexture.active = frameBuffer;
116 readbackBuffer.ReadPixels(new Rect(0, 0, frameBuffer.width, frameBuffer.height), 0, 0, false);
117 readbackBuffer.GetRawTextureData<byte>().CopyTo(pixelBuffer);
118 recorder.CommitFrame(pixelBuffer, timestamp);
119 RenderTexture.active = prevActive;
120 }
121
122 RenderTexture.ReleaseTemporary(frameBuffer);
123 }
124 }
125
126 private sealed class CameraInputAttachment : MonoBehaviour
127 {
128 }
129
130 #endregion
131 }
132}
Recorder input for recording video frames from one or more game cameras.
Definition: CameraInput.cs:19
void Dispose()
Stop recorder input and release resources.
Definition: CameraInput.cs:59
int frameSkip
Control number of successive camera frames to skip while recording. This is very useful for GIF recor...
Definition: CameraInput.cs:28
CameraInput(IMediaRecorder recorder, IClock clock, params Camera[] cameras)
Create a video recording input from a game camera.
Definition: CameraInput.cs:36
Clock for generating recording timestamps. Clocks are important for synchronizing audio and video tra...
Definition: IClock.cs:14
A recorder capable of recording video frames, and optionally audio frames, to a media output....
UnityEngine.Object Object