release v0.0.1
uh it works guys!
This commit is contained in:
parent
eb76f406fe
commit
404ba1d981
9
Assets/FFmpegOut.meta
Normal file
9
Assets/FFmpegOut.meta
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc572eb7215289d4998e2ebd1f2a2dbc
|
||||
folderAsset: yes
|
||||
timeCreated: 1488810210
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
183
Assets/FFmpegOut/AudioRenderer.cs
Normal file
183
Assets/FFmpegOut/AudioRenderer.cs
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
public class AudioRenderer : MonoBehaviour
|
||||
{
|
||||
#region Fields, Properties, and Inner Classes
|
||||
// constants for the wave file header
|
||||
private const int HEADER_SIZE = 44;
|
||||
private const short BITS_PER_SAMPLE = 16;
|
||||
private const int SAMPLE_RATE = 44100;
|
||||
|
||||
// the number of audio channels in the output file
|
||||
private int channels = 2;
|
||||
|
||||
// the audio stream instance
|
||||
private MemoryStream outputStream;
|
||||
private BinaryWriter outputWriter;
|
||||
|
||||
// should this object be rendering to the output stream?
|
||||
public bool Rendering = false;
|
||||
|
||||
/// The status of a render
|
||||
public enum Status
|
||||
{
|
||||
UNKNOWN,
|
||||
SUCCESS,
|
||||
FAIL,
|
||||
ASYNC
|
||||
}
|
||||
|
||||
/// The result of a render.
|
||||
public class Result
|
||||
{
|
||||
public Status State;
|
||||
public string Message;
|
||||
|
||||
public Result(Status newState = Status.UNKNOWN, string newMessage = "")
|
||||
{
|
||||
this.State = newState;
|
||||
this.Message = newMessage;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public AudioRenderer()
|
||||
{
|
||||
this.Clear();
|
||||
}
|
||||
|
||||
// reset the renderer
|
||||
public void Clear()
|
||||
{
|
||||
this.outputStream = new MemoryStream();
|
||||
this.outputWriter = new BinaryWriter(outputStream);
|
||||
}
|
||||
|
||||
/// Write a chunk of data to the output stream.
|
||||
public void Write(float[] audioData)
|
||||
{
|
||||
// Convert numeric audio data to bytes
|
||||
for (int i = 0; i < audioData.Length; i++)
|
||||
{
|
||||
// write the short to the stream
|
||||
this.outputWriter.Write((short)(audioData[i] * (float)Int16.MaxValue));
|
||||
}
|
||||
}
|
||||
|
||||
// write the incoming audio to the output string
|
||||
void OnAudioFilterRead(float[] data, int channels)
|
||||
{
|
||||
if( this.Rendering )
|
||||
{
|
||||
// store the number of channels we are rendering
|
||||
this.channels = channels;
|
||||
|
||||
// store the data stream
|
||||
this.Write(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#region File I/O
|
||||
public AudioRenderer.Result Save(string filename)
|
||||
{
|
||||
Result result = new AudioRenderer.Result();
|
||||
|
||||
if (outputStream.Length > 0)
|
||||
{
|
||||
// add a header to the file so we can send it to the SoundPlayer
|
||||
this.AddHeader();
|
||||
|
||||
// if a filename was passed in
|
||||
if (filename.Length > 0)
|
||||
{
|
||||
// Save to a file. Print a warning if overwriting a file.
|
||||
if (File.Exists(filename))
|
||||
Debug.LogWarning("Overwriting " + filename + "...");
|
||||
|
||||
// reset the stream pointer to the beginning of the stream
|
||||
outputStream.Position = 0;
|
||||
|
||||
// write the stream to a file
|
||||
FileStream fs = File.OpenWrite(filename);
|
||||
|
||||
this.outputStream.WriteTo(fs);
|
||||
|
||||
fs.Close();
|
||||
|
||||
// for debugging only
|
||||
Debug.Log("Finished saving to " + filename + ".");
|
||||
}
|
||||
|
||||
result.State = Status.SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("There is no audio data to save!");
|
||||
|
||||
result.State = Status.FAIL;
|
||||
result.Message = "There is no audio data to save!";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// This generates a simple header for a canonical wave file,
|
||||
/// which is the simplest practical audio file format. It
|
||||
/// writes the header and the audio file to a new stream, then
|
||||
/// moves the reference to that stream.
|
||||
///
|
||||
/// See this page for details on canonical wave files:
|
||||
/// http://www.lightlink.com/tjweber/StripWav/Canon.html
|
||||
private void AddHeader()
|
||||
{
|
||||
// reset the output stream
|
||||
outputStream.Position = 0;
|
||||
|
||||
// calculate the number of samples in the data chunk
|
||||
long numberOfSamples = outputStream.Length / (BITS_PER_SAMPLE / 8);
|
||||
|
||||
// create a new MemoryStream that will have both the audio data AND the header
|
||||
MemoryStream newOutputStream = new MemoryStream();
|
||||
BinaryWriter writer = new BinaryWriter(newOutputStream);
|
||||
|
||||
writer.Write(0x46464952); // "RIFF" in ASCII
|
||||
|
||||
// write the number of bytes in the entire file
|
||||
writer.Write((int)(HEADER_SIZE + (numberOfSamples * BITS_PER_SAMPLE * channels / 8)) - 8);
|
||||
|
||||
writer.Write(0x45564157); // "WAVE" in ASCII
|
||||
writer.Write(0x20746d66); // "fmt " in ASCII
|
||||
writer.Write(16);
|
||||
|
||||
// write the format tag. 1 = PCM
|
||||
writer.Write((short)1);
|
||||
|
||||
// write the number of channels.
|
||||
writer.Write((short)channels);
|
||||
|
||||
// write the sample rate. 44100 in this case. The number of audio samples per second
|
||||
writer.Write(SAMPLE_RATE);
|
||||
|
||||
writer.Write(SAMPLE_RATE * channels * (BITS_PER_SAMPLE / 8));
|
||||
writer.Write((short)(channels * (BITS_PER_SAMPLE / 8)));
|
||||
|
||||
// 16 bits per sample
|
||||
writer.Write(BITS_PER_SAMPLE);
|
||||
|
||||
// "data" in ASCII. Start the data chunk.
|
||||
writer.Write(0x61746164);
|
||||
|
||||
// write the number of bytes in the data portion
|
||||
writer.Write((int)(numberOfSamples * BITS_PER_SAMPLE * channels / 8));
|
||||
|
||||
// copy over the actual audio data
|
||||
this.outputStream.WriteTo(newOutputStream);
|
||||
|
||||
// move the reference to the new stream
|
||||
this.outputStream = newOutputStream;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
11
Assets/FFmpegOut/AudioRenderer.cs.meta
Normal file
11
Assets/FFmpegOut/AudioRenderer.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1150ae7143196054bba8378d288fc1c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/FFmpegOut/Editor.meta
Normal file
9
Assets/FFmpegOut/Editor.meta
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ca9c13867ad2c7142a339af129c0f7d7
|
||||
folderAsset: yes
|
||||
timeCreated: 1491148560
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
63
Assets/FFmpegOut/Editor/CameraCaptureEditor.cs
Normal file
63
Assets/FFmpegOut/Editor/CameraCaptureEditor.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Linq;
|
||||
|
||||
namespace FFmpegOut
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(CameraCapture))]
|
||||
public class CameraCaptureEditor : Editor
|
||||
{
|
||||
SerializedProperty _width;
|
||||
SerializedProperty _height;
|
||||
SerializedProperty _preset;
|
||||
SerializedProperty _frameRate;
|
||||
|
||||
GUIContent[] _presetLabels;
|
||||
int[] _presetOptions;
|
||||
|
||||
// It shows the render format options when:
|
||||
// - Editing multiple objects.
|
||||
// - No target texture is specified in the camera.
|
||||
bool ShouldShowFormatOptions
|
||||
{
|
||||
get {
|
||||
if (targets.Length > 1) return true;
|
||||
var camera = ((Component)target).GetComponent<Camera>();
|
||||
return camera.targetTexture == null;
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_width = serializedObject.FindProperty("_width");
|
||||
_height = serializedObject.FindProperty("_height");
|
||||
_preset = serializedObject.FindProperty("_preset");
|
||||
_frameRate = serializedObject.FindProperty("_frameRate");
|
||||
|
||||
var presets = FFmpegPreset.GetValues(typeof(FFmpegPreset));
|
||||
_presetLabels = presets.Cast<FFmpegPreset>().
|
||||
Select(p => new GUIContent(p.GetDisplayName())).ToArray();
|
||||
_presetOptions = presets.Cast<int>().ToArray();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
if (ShouldShowFormatOptions)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_width);
|
||||
EditorGUILayout.PropertyField(_height);
|
||||
}
|
||||
|
||||
EditorGUILayout.IntPopup(_preset, _presetLabels, _presetOptions);
|
||||
EditorGUILayout.PropertyField(_frameRate);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/FFmpegOut/Editor/CameraCaptureEditor.cs.meta
Normal file
12
Assets/FFmpegOut/Editor/CameraCaptureEditor.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5e125d1c67e59c444a1e722899c8a950
|
||||
timeCreated: 1491148560
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
16
Assets/FFmpegOut/Editor/FFmpegOut.Editor.asmdef
Normal file
16
Assets/FFmpegOut/Editor/FFmpegOut.Editor.asmdef
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "FFmpegOut.Editor",
|
||||
"references": [
|
||||
"FFmpegOut"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": []
|
||||
}
|
||||
7
Assets/FFmpegOut/Editor/FFmpegOut.Editor.asmdef.meta
Normal file
7
Assets/FFmpegOut/Editor/FFmpegOut.Editor.asmdef.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 34c6485430b2eb948b8840a09f7c2fbf
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
68
Assets/FFmpegOut/Editor/FrameRateControllerEditor.cs
Normal file
68
Assets/FFmpegOut/Editor/FrameRateControllerEditor.cs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace FFmpegOut
|
||||
{
|
||||
[CanEditMultipleObjects]
|
||||
[CustomEditor(typeof(FrameRateController))]
|
||||
public class FrameRateControllerEditor : Editor
|
||||
{
|
||||
SerializedProperty _frameRate;
|
||||
SerializedProperty _offlineMode;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_frameRate = serializedObject.FindProperty("_frameRate");
|
||||
_offlineMode = serializedObject.FindProperty("_offlineMode");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(_frameRate);
|
||||
EditorGUILayout.PropertyField(_offlineMode);
|
||||
|
||||
if (!Application.isPlaying &&
|
||||
!_frameRate.hasMultipleDifferentValues &&
|
||||
!_offlineMode.hasMultipleDifferentValues)
|
||||
{
|
||||
if (_offlineMode.boolValue)
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"Offline mode enabled: Time interval will be fixed " +
|
||||
"to the specified value to keep exact speed on " +
|
||||
"recorded videos. This stops synchronizing game " +
|
||||
"time to wall clock time.", MessageType.None
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
var vSyncCount =
|
||||
((FrameRateController)target).CalculateVSyncCount();
|
||||
|
||||
if (vSyncCount == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"V-sync will be disabled because the specified " +
|
||||
"frame rate is not divisible by the screen " +
|
||||
"refresh rate.", MessageType.None
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox(
|
||||
"V-sync count will be set to " + vSyncCount,
|
||||
MessageType.None
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/FFmpegOut/Editor/FrameRateControllerEditor.cs.meta
Normal file
11
Assets/FFmpegOut/Editor/FrameRateControllerEditor.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 08d008f9408507d4886445ae32b751b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/FFmpegOut/Resources.meta
Normal file
8
Assets/FFmpegOut/Resources.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0c36e64b6a30f4a43abc488dc63a3323
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
49
Assets/FFmpegOut/Resources/Blitter.shader
Normal file
49
Assets/FFmpegOut/Resources/Blitter.shader
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
Shader "Hidden/FFmpegOut/Blitter"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex("", 2D) = "gray" {}
|
||||
}
|
||||
|
||||
HLSLINCLUDE
|
||||
|
||||
sampler2D _MainTex;
|
||||
|
||||
void Vertex(
|
||||
uint vid : SV_VertexID,
|
||||
out float4 position : SV_Position,
|
||||
out float2 texcoord : TEXCOORD
|
||||
)
|
||||
{
|
||||
float x = (vid == 1) ? 1 : 0;
|
||||
float y = (vid == 2) ? 1 : 0;
|
||||
position = float4(x * 4 - 1, y * 4 - 1, 1, 1);
|
||||
texcoord = float2(x * 2, 1 - y * 2);
|
||||
}
|
||||
|
||||
half4 Fragment(
|
||||
float4 position : SV_Position,
|
||||
float2 texcoord : TEXCOORD
|
||||
) : SV_Target
|
||||
{
|
||||
return tex2D(_MainTex, texcoord);
|
||||
}
|
||||
|
||||
ENDHLSL
|
||||
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue" = "Transparent+100" }
|
||||
Cull Off ZWrite Off ZTest Always
|
||||
Pass
|
||||
{
|
||||
HLSLPROGRAM
|
||||
#pragma vertex Vertex
|
||||
#pragma fragment Fragment
|
||||
ENDHLSL
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Assets/FFmpegOut/Resources/Blitter.shader.meta
Normal file
9
Assets/FFmpegOut/Resources/Blitter.shader.meta
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7c75f8f2de6a25741be0e5fa986fc435
|
||||
timeCreated: 1488901510
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
37
Assets/FFmpegOut/Resources/Preprocess.shader
Normal file
37
Assets/FFmpegOut/Resources/Preprocess.shader
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
Shader "Hidden/FFmpegOut/Preprocess"
|
||||
{
|
||||
Properties
|
||||
{
|
||||
_MainTex("", 2D) = "white" {}
|
||||
}
|
||||
|
||||
CGINCLUDE
|
||||
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
sampler2D _MainTex;
|
||||
|
||||
fixed4 frag_flip(v2f_img i) : SV_Target
|
||||
{
|
||||
float2 uv = i.uv;
|
||||
uv.y = 1 - uv.y;
|
||||
return tex2D(_MainTex, uv);
|
||||
}
|
||||
|
||||
ENDCG
|
||||
|
||||
SubShader
|
||||
{
|
||||
Cull Off ZWrite Off ZTest Always
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert_img
|
||||
#pragma fragment frag_flip
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Assets/FFmpegOut/Resources/Preprocess.shader.meta
Normal file
9
Assets/FFmpegOut/Resources/Preprocess.shader.meta
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a4bd3b00ad1ed53458ec6ff07694985e
|
||||
timeCreated: 1488901510
|
||||
licenseType: Pro
|
||||
ShaderImporter:
|
||||
defaultTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/FFmpegOut/Runtime.meta
Normal file
8
Assets/FFmpegOut/Runtime.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5654631662aea5c4294d86ddd75eab98
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
6
Assets/FFmpegOut/Runtime/AssemblyInfo.cs
Normal file
6
Assets/FFmpegOut/Runtime/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("FFmpegOut.Editor")]
|
||||
11
Assets/FFmpegOut/Runtime/AssemblyInfo.cs.meta
Normal file
11
Assets/FFmpegOut/Runtime/AssemblyInfo.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 535920348c7aa054cb3f13e8b09d6dc6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
200
Assets/FFmpegOut/Runtime/CameraCapture.cs
Normal file
200
Assets/FFmpegOut/Runtime/CameraCapture.cs
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace FFmpegOut
|
||||
{
|
||||
[AddComponentMenu("FFmpegOut/Camera Capture")]
|
||||
public sealed class CameraCapture : MonoBehaviour
|
||||
{
|
||||
#region Public properties
|
||||
|
||||
[SerializeField] int _width = 1920;
|
||||
|
||||
public int width {
|
||||
get { return _width; }
|
||||
set { _width = value; }
|
||||
}
|
||||
|
||||
[SerializeField] int _height = 1080;
|
||||
|
||||
public int height {
|
||||
get { return _height; }
|
||||
set { _height = value; }
|
||||
}
|
||||
|
||||
[SerializeField] FFmpegPreset _preset;
|
||||
|
||||
public FFmpegPreset preset {
|
||||
get { return _preset; }
|
||||
set { _preset = value; }
|
||||
}
|
||||
|
||||
[SerializeField] float _frameRate = 60;
|
||||
|
||||
public float frameRate {
|
||||
get { return _frameRate; }
|
||||
set { _frameRate = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private members
|
||||
|
||||
FFmpegSession _session;
|
||||
RenderTexture _tempRT;
|
||||
GameObject _blitter;
|
||||
|
||||
RenderTextureFormat GetTargetFormat(Camera camera)
|
||||
{
|
||||
return camera.allowHDR ? RenderTextureFormat.DefaultHDR : RenderTextureFormat.Default;
|
||||
}
|
||||
|
||||
int GetAntiAliasingLevel(Camera camera)
|
||||
{
|
||||
return camera.allowMSAA ? QualitySettings.antiAliasing : 1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Time-keeping variables
|
||||
|
||||
int _frameCount;
|
||||
float _startTime;
|
||||
int _frameDropCount;
|
||||
|
||||
float FrameTime {
|
||||
get { return _startTime + (_frameCount - 0.5f) / _frameRate; }
|
||||
}
|
||||
|
||||
void WarnFrameDrop()
|
||||
{
|
||||
if (++_frameDropCount != 10) return;
|
||||
|
||||
Debug.LogWarning(
|
||||
"Significant frame droppping was detected. This may introduce " +
|
||||
"time instability into output video. Decreasing the recording " +
|
||||
"frame rate is recommended."
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MonoBehaviour implementation
|
||||
|
||||
void OnValidate()
|
||||
{
|
||||
_width = Mathf.Max(8, _width);
|
||||
_height = Mathf.Max(8, _height);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (_session != null)
|
||||
{
|
||||
// Close and dispose the FFmpeg session.
|
||||
_session.Close();
|
||||
_session.Dispose();
|
||||
_session = null;
|
||||
}
|
||||
|
||||
if (_tempRT != null)
|
||||
{
|
||||
// Dispose the frame texture.
|
||||
GetComponent<Camera>().targetTexture = null;
|
||||
Destroy(_tempRT);
|
||||
_tempRT = null;
|
||||
}
|
||||
|
||||
if (_blitter != null)
|
||||
{
|
||||
// Destroy the blitter game object.
|
||||
Destroy(_blitter);
|
||||
_blitter = null;
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator Start()
|
||||
{
|
||||
// Sync with FFmpeg pipe thread at the end of every frame.
|
||||
for (var eof = new WaitForEndOfFrame();;)
|
||||
{
|
||||
yield return eof;
|
||||
_session?.CompletePushFrames();
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
var camera = GetComponent<Camera>();
|
||||
|
||||
// Lazy initialization
|
||||
if (_session == null)
|
||||
{
|
||||
// Give a newly created temporary render texture to the camera
|
||||
// if it's set to render to a screen. Also create a blitter
|
||||
// object to keep frames presented on the screen.
|
||||
if (camera.targetTexture == null)
|
||||
{
|
||||
_tempRT = new RenderTexture(_width, _height, 24, GetTargetFormat(camera));
|
||||
_tempRT.antiAliasing = GetAntiAliasingLevel(camera);
|
||||
camera.targetTexture = _tempRT;
|
||||
_blitter = Blitter.CreateInstance(camera);
|
||||
}
|
||||
|
||||
// Start an FFmpeg session.
|
||||
_session = FFmpegSession.Create(
|
||||
gameObject.name,
|
||||
camera.targetTexture.width,
|
||||
camera.targetTexture.height,
|
||||
_frameRate, preset
|
||||
);
|
||||
|
||||
_startTime = Time.time;
|
||||
_frameCount = 0;
|
||||
_frameDropCount = 0;
|
||||
}
|
||||
|
||||
var gap = Time.time - FrameTime;
|
||||
var delta = 1 / _frameRate;
|
||||
|
||||
if (gap < 0)
|
||||
{
|
||||
// Update without frame data.
|
||||
_session.PushFrame(null);
|
||||
}
|
||||
else if (gap < delta)
|
||||
{
|
||||
// Single-frame behind from the current time:
|
||||
// Push the current frame to FFmpeg.
|
||||
_session.PushFrame(camera.targetTexture);
|
||||
_frameCount++;
|
||||
}
|
||||
else if (gap < delta * 2)
|
||||
{
|
||||
// Two-frame behind from the current time:
|
||||
// Push the current frame twice to FFmpeg. Actually this is not
|
||||
// an efficient way to catch up. We should think about
|
||||
// implementing frame duplication in a more proper way. #fixme
|
||||
_session.PushFrame(camera.targetTexture);
|
||||
_session.PushFrame(camera.targetTexture);
|
||||
_frameCount += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show a warning message about the situation.
|
||||
WarnFrameDrop();
|
||||
|
||||
// Push the current frame to FFmpeg.
|
||||
_session.PushFrame(camera.targetTexture);
|
||||
|
||||
// Compensate the time delay.
|
||||
_frameCount += Mathf.FloorToInt(gap * _frameRate);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
13
Assets/FFmpegOut/Runtime/CameraCapture.cs.meta
Normal file
13
Assets/FFmpegOut/Runtime/CameraCapture.cs.meta
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a66fbd5ffe9b9d64da304996f1919f40
|
||||
timeCreated: 1488901810
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- _shader: {fileID: 4800000, guid: a4bd3b00ad1ed53458ec6ff07694985e, type: 3}
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
3
Assets/FFmpegOut/Runtime/FFmpegOut.asmdef
Normal file
3
Assets/FFmpegOut/Runtime/FFmpegOut.asmdef
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"name": "FFmpegOut"
|
||||
}
|
||||
7
Assets/FFmpegOut/Runtime/FFmpegOut.asmdef.meta
Normal file
7
Assets/FFmpegOut/Runtime/FFmpegOut.asmdef.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d927f977f87e2f4497af759c3426e00
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
88
Assets/FFmpegOut/Runtime/FFmpegPreset.cs
Normal file
88
Assets/FFmpegOut/Runtime/FFmpegPreset.cs
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
namespace FFmpegOut
|
||||
{
|
||||
public enum FFmpegPreset
|
||||
{
|
||||
H264Default,
|
||||
H264Nvidia,
|
||||
H264Lossless420,
|
||||
H264Lossless444,
|
||||
HevcDefault,
|
||||
HevcNvidia,
|
||||
ProRes422,
|
||||
ProRes4444,
|
||||
VP8Default,
|
||||
VP9Default,
|
||||
Hap,
|
||||
HapAlpha,
|
||||
HapQ
|
||||
}
|
||||
|
||||
static public class FFmpegPresetExtensions
|
||||
{
|
||||
public static string GetDisplayName(this FFmpegPreset preset)
|
||||
{
|
||||
switch (preset)
|
||||
{
|
||||
case FFmpegPreset.H264Default: return "H.264 Default (MP4)";
|
||||
case FFmpegPreset.H264Nvidia: return "H.264 NVIDIA (MP4)";
|
||||
case FFmpegPreset.H264Lossless420: return "H.264 Lossless 420 (MP4)";
|
||||
case FFmpegPreset.H264Lossless444: return "H.264 Lossless 444 (MP4)";
|
||||
case FFmpegPreset.HevcDefault: return "HEVC Default (MP4)";
|
||||
case FFmpegPreset.HevcNvidia: return "HEVC NVIDIA (MP4)";
|
||||
case FFmpegPreset.ProRes422: return "ProRes 422 (QuickTime)";
|
||||
case FFmpegPreset.ProRes4444: return "ProRes 4444 (QuickTime)";
|
||||
case FFmpegPreset.VP8Default: return "VP8 (WebM)";
|
||||
case FFmpegPreset.VP9Default: return "VP9 (WebM)";
|
||||
case FFmpegPreset.Hap: return "HAP (QuickTime)";
|
||||
case FFmpegPreset.HapAlpha: return "HAP Alpha (QuickTime)";
|
||||
case FFmpegPreset.HapQ: return "HAP Q (QuickTime)";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetSuffix(this FFmpegPreset preset)
|
||||
{
|
||||
switch (preset)
|
||||
{
|
||||
case FFmpegPreset.H264Default:
|
||||
case FFmpegPreset.H264Nvidia:
|
||||
case FFmpegPreset.H264Lossless420:
|
||||
case FFmpegPreset.H264Lossless444:
|
||||
case FFmpegPreset.HevcDefault:
|
||||
case FFmpegPreset.HevcNvidia: return ".mp4";
|
||||
case FFmpegPreset.ProRes422:
|
||||
case FFmpegPreset.ProRes4444: return ".mov";
|
||||
case FFmpegPreset.VP9Default:
|
||||
case FFmpegPreset.VP8Default: return ".webm";
|
||||
case FFmpegPreset.Hap:
|
||||
case FFmpegPreset.HapQ:
|
||||
case FFmpegPreset.HapAlpha: return ".mov";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string GetOptions(this FFmpegPreset preset)
|
||||
{
|
||||
switch (preset)
|
||||
{
|
||||
case FFmpegPreset.H264Default: return "-pix_fmt yuv420p";
|
||||
case FFmpegPreset.H264Nvidia: return "-c:v h264_nvenc -pix_fmt yuv420p";
|
||||
case FFmpegPreset.H264Lossless420: return "-pix_fmt yuv420p -preset ultrafast -crf 0";
|
||||
case FFmpegPreset.H264Lossless444: return "-pix_fmt yuv444p -preset ultrafast -crf 0";
|
||||
case FFmpegPreset.HevcDefault: return "-c:v libx265 -pix_fmt yuv420p";
|
||||
case FFmpegPreset.HevcNvidia: return "-c:v hevc_nvenc -pix_fmt yuv420p";
|
||||
case FFmpegPreset.ProRes422: return "-c:v prores_ks -pix_fmt yuv422p10le";
|
||||
case FFmpegPreset.ProRes4444: return "-c:v prores_ks -pix_fmt yuva444p10le";
|
||||
case FFmpegPreset.VP8Default: return "-c:v libvpx -pix_fmt yuv420p";
|
||||
case FFmpegPreset.VP9Default: return "-c:v libvpx-vp9";
|
||||
case FFmpegPreset.Hap: return "-c:v hap";
|
||||
case FFmpegPreset.HapAlpha: return "-c:v hap -format hap_alpha";
|
||||
case FFmpegPreset.HapQ: return "-c:v hap -format hap_q";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/FFmpegOut/Runtime/FFmpegPreset.cs.meta
Normal file
11
Assets/FFmpegOut/Runtime/FFmpegPreset.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d2b56c2e4fdc0fd4f9b1f81dd6bd785b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
196
Assets/FFmpegOut/Runtime/FFmpegSession.cs
Normal file
196
Assets/FFmpegOut/Runtime/FFmpegSession.cs
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FFmpegOut
|
||||
{
|
||||
public sealed class FFmpegSession : System.IDisposable
|
||||
{
|
||||
#region Factory methods
|
||||
|
||||
public static FFmpegSession Create(
|
||||
string name,
|
||||
int width, int height, float frameRate,
|
||||
FFmpegPreset preset
|
||||
)
|
||||
{
|
||||
name += System.DateTime.Now.ToString(" yyyy MMdd HHmmss");
|
||||
var path = name.Replace(" ", "_") + preset.GetSuffix();
|
||||
return CreateWithOutputPath(path, width, height, frameRate, preset);
|
||||
}
|
||||
|
||||
public static FFmpegSession CreateWithOutputPath(
|
||||
string outputPath,
|
||||
int width, int height, float frameRate,
|
||||
FFmpegPreset preset
|
||||
)
|
||||
{
|
||||
return new FFmpegSession(
|
||||
"-y -f rawvideo -vcodec rawvideo -pixel_format rgba"
|
||||
+ " -colorspace bt709"
|
||||
+ " -video_size " + width + "x" + height
|
||||
+ " -framerate " + frameRate
|
||||
+ " -loglevel warning -i - " + preset.GetOptions()
|
||||
+ " \"" + "C:/Users/pikmi/Downloads/temp.mp4" + "\"" //hijacked this. basically i dont want some fancy output file name (which is what the old code did) so it's just temp now lol
|
||||
);
|
||||
}
|
||||
|
||||
public static FFmpegSession CreateWithArguments(string arguments)
|
||||
{
|
||||
return new FFmpegSession(arguments);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public properties and members
|
||||
|
||||
public void PushFrame(Texture source)
|
||||
{
|
||||
if (_pipe != null)
|
||||
{
|
||||
ProcessQueue();
|
||||
if (source != null) QueueFrame(source);
|
||||
}
|
||||
}
|
||||
|
||||
public void CompletePushFrames()
|
||||
{
|
||||
_pipe?.SyncFrameData();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (_pipe != null)
|
||||
{
|
||||
var error = _pipe.CloseAndGetOutput();
|
||||
|
||||
if (!string.IsNullOrEmpty(error))
|
||||
Debug.LogWarning(
|
||||
"FFmpeg returned with warning/error messages. " +
|
||||
"See the following lines for details:\n" + error
|
||||
);
|
||||
|
||||
_pipe.Dispose();
|
||||
_pipe = null;
|
||||
}
|
||||
|
||||
if (_blitMaterial != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(_blitMaterial);
|
||||
_blitMaterial = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private objects and constructor/destructor
|
||||
|
||||
FFmpegPipe _pipe;
|
||||
Material _blitMaterial;
|
||||
|
||||
FFmpegSession(string arguments)
|
||||
{
|
||||
if (!FFmpegPipe.IsAvailable)
|
||||
Debug.LogWarning(
|
||||
"Failed to initialize an FFmpeg session due to missing " +
|
||||
"executable file. Please check FFmpeg installation."
|
||||
);
|
||||
else if (!UnityEngine.SystemInfo.supportsAsyncGPUReadback)
|
||||
Debug.LogWarning(
|
||||
"Failed to initialize an FFmpeg session due to lack of " +
|
||||
"async GPU readback support. Please try changing " +
|
||||
"graphics API to readback-enabled one."
|
||||
);
|
||||
else
|
||||
_pipe = new FFmpegPipe(arguments);
|
||||
}
|
||||
|
||||
~FFmpegSession()
|
||||
{
|
||||
if (_pipe != null)
|
||||
Debug.LogError(
|
||||
"An unfinalized FFmpegCapture object was detected. " +
|
||||
"It should be explicitly closed or disposed " +
|
||||
"before being garbage-collected."
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Frame readback queue
|
||||
|
||||
List<AsyncGPUReadbackRequest> _readbackQueue =
|
||||
new List<AsyncGPUReadbackRequest>(4);
|
||||
|
||||
void QueueFrame(Texture source)
|
||||
{
|
||||
if (_readbackQueue.Count > 6)
|
||||
{
|
||||
Debug.LogWarning("Too many GPU readback requests.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Lazy initialization of the preprocessing blit shader
|
||||
if (_blitMaterial == null)
|
||||
{
|
||||
var shader = Shader.Find("Hidden/FFmpegOut/Preprocess");
|
||||
_blitMaterial = new Material(shader);
|
||||
}
|
||||
|
||||
// Blit to a temporary texture and request readback on it.
|
||||
var rt = RenderTexture.GetTemporary
|
||||
(source.width, source.height, 0, RenderTextureFormat.ARGB32);
|
||||
Graphics.Blit(source, rt, _blitMaterial, 0);
|
||||
_readbackQueue.Add(AsyncGPUReadback.Request(rt));
|
||||
RenderTexture.ReleaseTemporary(rt);
|
||||
}
|
||||
|
||||
void ProcessQueue()
|
||||
{
|
||||
while (_readbackQueue.Count > 0)
|
||||
{
|
||||
// Check if the first entry in the queue is completed.
|
||||
if (!_readbackQueue[0].done)
|
||||
{
|
||||
// Detect out-of-order case (the second entry in the queue
|
||||
// is completed before the first entry).
|
||||
if (_readbackQueue.Count > 1 && _readbackQueue[1].done)
|
||||
{
|
||||
// We can't allow the out-of-order case, so force it to
|
||||
// be completed now.
|
||||
_readbackQueue[0].WaitForCompletion();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to do with the queue.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the first entry in the queue.
|
||||
var req = _readbackQueue[0];
|
||||
_readbackQueue.RemoveAt(0);
|
||||
|
||||
// Error detection
|
||||
if (req.hasError)
|
||||
{
|
||||
Debug.LogWarning("GPU readback error was detected.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Feed the frame to the FFmpeg pipe.
|
||||
_pipe.PushFrameData(req.GetData<byte>());
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
11
Assets/FFmpegOut/Runtime/FFmpegSession.cs.meta
Normal file
11
Assets/FFmpegOut/Runtime/FFmpegSession.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8ab25b2c3553cd446afb35cf75341bbc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
74
Assets/FFmpegOut/Runtime/FrameRateController.cs
Normal file
74
Assets/FFmpegOut/Runtime/FrameRateController.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
|
||||
namespace FFmpegOut
|
||||
{
|
||||
[AddComponentMenu("FFmpegOut/Frame Rate Controller")]
|
||||
public sealed class FrameRateController : MonoBehaviour
|
||||
{
|
||||
[SerializeField] float _frameRate = 60;
|
||||
[SerializeField] bool _offlineMode = true;
|
||||
|
||||
int _originalFrameRate;
|
||||
int _originalVSyncCount;
|
||||
|
||||
internal int CalculateVSyncCount()
|
||||
{
|
||||
// Determine the display refresh rate.
|
||||
// We assume 59=59.95Hz, 23=23.976Hz and so on.
|
||||
// Is it the right way to get fractional-number rate? Who knows.
|
||||
var i_rate = Screen.currentResolution.refreshRate;
|
||||
var f_rate = (float)i_rate;
|
||||
|
||||
switch (i_rate)
|
||||
{
|
||||
case 23: f_rate = 23.976f; break;
|
||||
case 29: f_rate = 29.970f; break;
|
||||
case 47: f_rate = 47.952f; break;
|
||||
case 59: f_rate = 59.940f; break;
|
||||
case 71: f_rate = 71.928f; break;
|
||||
case 119: f_rate = 119.88f; break;
|
||||
}
|
||||
|
||||
// Return a positive value if it's divisible by the frame rate.
|
||||
if (Mathf.Approximately(f_rate % _frameRate, 0))
|
||||
return Mathf.RoundToInt(f_rate / _frameRate);
|
||||
else
|
||||
return 0; // Don't use v-sync.
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
var ifps = Mathf.RoundToInt(_frameRate);
|
||||
|
||||
if (_offlineMode)
|
||||
{
|
||||
_originalFrameRate = Time.captureFramerate;
|
||||
Time.captureFramerate = ifps;
|
||||
}
|
||||
else
|
||||
{
|
||||
_originalFrameRate = Application.targetFrameRate;
|
||||
_originalVSyncCount = QualitySettings.vSyncCount;
|
||||
Application.targetFrameRate = ifps;
|
||||
QualitySettings.vSyncCount = CalculateVSyncCount();
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (_offlineMode)
|
||||
{
|
||||
Time.captureFramerate = _originalFrameRate;
|
||||
}
|
||||
else
|
||||
{
|
||||
Application.targetFrameRate = _originalFrameRate;
|
||||
QualitySettings.vSyncCount = _originalVSyncCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/FFmpegOut/Runtime/FrameRateController.cs.meta
Normal file
11
Assets/FFmpegOut/Runtime/FrameRateController.cs.meta
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e55bddfe16e69224c8c4b4eb165695d4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/FFmpegOut/Runtime/Internal.meta
Normal file
9
Assets/FFmpegOut/Runtime/Internal.meta
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 88f8cafe5d48d4a4f89f22b10bbc64a4
|
||||
folderAsset: yes
|
||||
timeCreated: 1491313768
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
111
Assets/FFmpegOut/Runtime/Internal/Blitter.cs
Normal file
111
Assets/FFmpegOut/Runtime/Internal/Blitter.cs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace FFmpegOut
|
||||
{
|
||||
sealed class Blitter : MonoBehaviour
|
||||
{
|
||||
#region Factory method
|
||||
|
||||
static System.Type[] _initialComponents =
|
||||
{ typeof(Camera), typeof(Blitter) };
|
||||
|
||||
public static GameObject CreateInstance(Camera source)
|
||||
{
|
||||
var go = new GameObject("Blitter", _initialComponents);
|
||||
go.hideFlags = HideFlags.HideInHierarchy;
|
||||
|
||||
var camera = go.GetComponent<Camera>();
|
||||
camera.cullingMask = 1 << UILayer;
|
||||
camera.targetDisplay = source.targetDisplay;
|
||||
|
||||
var blitter = go.GetComponent<Blitter>();
|
||||
blitter._sourceTexture = source.targetTexture;
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private members
|
||||
|
||||
// Assuming that the 5th layer is "UI". #badcode
|
||||
const int UILayer = 5;
|
||||
|
||||
Texture _sourceTexture;
|
||||
Mesh _mesh;
|
||||
Material _material;
|
||||
|
||||
void PreCull(Camera camera)
|
||||
{
|
||||
if (_mesh == null || camera != GetComponent<Camera>()) return;
|
||||
|
||||
Graphics.DrawMesh(
|
||||
_mesh, transform.localToWorldMatrix,
|
||||
_material, UILayer, camera
|
||||
);
|
||||
}
|
||||
|
||||
#if UNITY_2019_2_OR_NEWER
|
||||
void BeginCameraRendering(ScriptableRenderContext context, Camera camera)
|
||||
{
|
||||
PreCull(camera);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endregion
|
||||
|
||||
#region MonoBehaviour implementation
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_mesh == null)
|
||||
{
|
||||
// Index-only triangle mesh
|
||||
_mesh = new Mesh();
|
||||
_mesh.vertices = new Vector3[3];
|
||||
_mesh.triangles = new int [] { 0, 1, 2 };
|
||||
_mesh.bounds = new Bounds(Vector3.zero, Vector3.one);
|
||||
_mesh.UploadMeshData(true);
|
||||
|
||||
// Blitter shader material
|
||||
var shader = Shader.Find("Hidden/FFmpegOut/Blitter");
|
||||
_material = new Material(shader);
|
||||
_material.SetTexture("_MainTex", _sourceTexture);
|
||||
|
||||
// Register the camera render callback.
|
||||
#if UNITY_2019_2_OR_NEWER
|
||||
RenderPipelineManager.beginCameraRendering += BeginCameraRendering; // SRP
|
||||
#else
|
||||
UnityEngine.Experimental.Rendering.RenderPipeline.beginCameraRendering += PreCull; // SRP
|
||||
#endif
|
||||
Camera.onPreCull += PreCull; // Legacy
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
if (_mesh != null)
|
||||
{
|
||||
// Unregister the camera render callback.
|
||||
#if UNITY_2019_2_OR_NEWER
|
||||
RenderPipelineManager.beginCameraRendering -= BeginCameraRendering; // SRP
|
||||
#else
|
||||
UnityEngine.Experimental.Rendering.RenderPipeline.beginCameraRendering -= PreCull; // SRP
|
||||
#endif
|
||||
Camera.onPreCull -= PreCull; // Legacy
|
||||
|
||||
// Destroy temporary objects.
|
||||
Destroy(_mesh);
|
||||
Destroy(_material);
|
||||
_mesh = null;
|
||||
_material = null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
12
Assets/FFmpegOut/Runtime/Internal/Blitter.cs.meta
Normal file
12
Assets/FFmpegOut/Runtime/Internal/Blitter.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6dc134cd7da61a9438d65f309789d0d3
|
||||
timeCreated: 1491312926
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
234
Assets/FFmpegOut/Runtime/Internal/FFmpegPipe.cs
Normal file
234
Assets/FFmpegOut/Runtime/Internal/FFmpegPipe.cs
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
// FFmpegOut - FFmpeg video encoding plugin for Unity
|
||||
// https://github.com/keijiro/KlakNDI
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace FFmpegOut
|
||||
{
|
||||
public sealed class FFmpegPipe : System.IDisposable
|
||||
{
|
||||
#region Public methods
|
||||
|
||||
public static bool IsAvailable {
|
||||
get { return System.IO.File.Exists(ExecutablePath); }
|
||||
}
|
||||
|
||||
public FFmpegPipe(string arguments)
|
||||
{
|
||||
// Start FFmpeg subprocess.
|
||||
_subprocess = Process.Start(new ProcessStartInfo {
|
||||
FileName = ExecutablePath,
|
||||
Arguments = arguments,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardInput = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true
|
||||
});
|
||||
|
||||
// Start copy/pipe subthreads.
|
||||
_copyThread = new Thread(CopyThread);
|
||||
_pipeThread = new Thread(PipeThread);
|
||||
_copyThread.Start();
|
||||
_pipeThread.Start();
|
||||
}
|
||||
|
||||
public void PushFrameData(NativeArray<byte> data)
|
||||
{
|
||||
// Update the copy queue and notify the copy thread with a ping.
|
||||
lock (_copyQueue) _copyQueue.Enqueue(data);
|
||||
_copyPing.Set();
|
||||
}
|
||||
|
||||
public void SyncFrameData()
|
||||
{
|
||||
// Wait for the copy queue to get emptied with using pong
|
||||
// notification signals sent from the copy thread.
|
||||
while (_copyQueue.Count > 0) _copyPong.WaitOne();
|
||||
|
||||
// When using a slower codec (e.g. HEVC, ProRes), frames may be
|
||||
// queued too much, and it may end up with an out-of-memory error.
|
||||
// To avoid this problem, we wait for pipe queue entries to be
|
||||
// comsumed by the pipe thread.
|
||||
while (_pipeQueue.Count > 4) _pipePong.WaitOne();
|
||||
}
|
||||
|
||||
public string CloseAndGetOutput()
|
||||
{
|
||||
// Terminate the subthreads.
|
||||
_terminate = true;
|
||||
|
||||
_copyPing.Set();
|
||||
_pipePing.Set();
|
||||
|
||||
_copyThread.Join();
|
||||
_pipeThread.Join();
|
||||
|
||||
// Close FFmpeg subprocess.
|
||||
_subprocess.StandardInput.Close();
|
||||
_subprocess.WaitForExit();
|
||||
|
||||
var outputReader = _subprocess.StandardError;
|
||||
var error = outputReader.ReadToEnd();
|
||||
|
||||
_subprocess.Close();
|
||||
_subprocess.Dispose();
|
||||
|
||||
outputReader.Close();
|
||||
outputReader.Dispose();
|
||||
|
||||
// Nullify members (just for ease of debugging).
|
||||
_subprocess = null;
|
||||
_copyThread = null;
|
||||
_pipeThread = null;
|
||||
_copyQueue = null;
|
||||
_pipeQueue = _freeBuffer = null;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IDisposable implementation
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_terminate) CloseAndGetOutput();
|
||||
}
|
||||
|
||||
~FFmpegPipe()
|
||||
{
|
||||
if (!_terminate)
|
||||
UnityEngine.Debug.LogError(
|
||||
"An unfinalized FFmpegPipe object was detected. " +
|
||||
"It should be explicitly closed or disposed " +
|
||||
"before being garbage-collected."
|
||||
);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private members
|
||||
|
||||
Process _subprocess;
|
||||
Thread _copyThread;
|
||||
Thread _pipeThread;
|
||||
|
||||
AutoResetEvent _copyPing = new AutoResetEvent(false);
|
||||
AutoResetEvent _copyPong = new AutoResetEvent(false);
|
||||
AutoResetEvent _pipePing = new AutoResetEvent(false);
|
||||
AutoResetEvent _pipePong = new AutoResetEvent(false);
|
||||
bool _terminate;
|
||||
|
||||
Queue<NativeArray<byte>> _copyQueue = new Queue<NativeArray<byte>>();
|
||||
Queue<byte[]> _pipeQueue = new Queue<byte[]>();
|
||||
Queue<byte[]> _freeBuffer = new Queue<byte[]>();
|
||||
|
||||
public static string ExecutablePath
|
||||
{
|
||||
get {
|
||||
var basePath = UnityEngine.Application.streamingAssetsPath;
|
||||
var platform = UnityEngine.Application.platform;
|
||||
|
||||
if (platform == UnityEngine.RuntimePlatform.OSXPlayer ||
|
||||
platform == UnityEngine.RuntimePlatform.OSXEditor)
|
||||
return basePath + "/FFmpegOut/macOS/ffmpeg";
|
||||
|
||||
if (platform == UnityEngine.RuntimePlatform.LinuxPlayer ||
|
||||
platform == UnityEngine.RuntimePlatform.LinuxEditor)
|
||||
return basePath + "/FFmpegOut/Linux/ffmpeg";
|
||||
|
||||
return basePath + "/FFmpegOut/Windows/ffmpeg.exe";
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Subthread entry points
|
||||
|
||||
// CopyThread - Copies frames given from the readback queue to the pipe
|
||||
// queue. This is required because readback buffers are not under our
|
||||
// control -- they'll be disposed before being processed by us. They
|
||||
// have to be buffered by end-of-frame.
|
||||
void CopyThread()
|
||||
{
|
||||
while (!_terminate)
|
||||
{
|
||||
// Wait for ping from the main thread.
|
||||
_copyPing.WaitOne();
|
||||
|
||||
// Process all entries in the copy queue.
|
||||
while (_copyQueue.Count > 0)
|
||||
{
|
||||
// Retrieve an copy queue entry without dequeuing it.
|
||||
// (We don't want to notify the main thread at this point.)
|
||||
NativeArray<byte> source;
|
||||
lock (_copyQueue) source = _copyQueue.Peek();
|
||||
|
||||
// Try allocating a buffer from the free buffer list.
|
||||
byte[] buffer = null;
|
||||
if (_freeBuffer.Count > 0)
|
||||
lock (_freeBuffer) buffer = _freeBuffer.Dequeue();
|
||||
|
||||
// Copy the contents of the copy queue entry.
|
||||
if (buffer == null || buffer.Length != source.Length)
|
||||
buffer = source.ToArray();
|
||||
else
|
||||
source.CopyTo(buffer);
|
||||
|
||||
// Push the buffer entry to the pipe queue.
|
||||
lock (_pipeQueue) _pipeQueue.Enqueue(buffer);
|
||||
_pipePing.Set(); // Ping the pipe thread.
|
||||
|
||||
// Dequeue the copy buffer entry and ping the main thread.
|
||||
lock (_copyQueue) _copyQueue.Dequeue();
|
||||
_copyPong.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PipeThread - Receives frame entries from the copy thread and push
|
||||
// them into the FFmpeg pipe.
|
||||
void PipeThread()
|
||||
{
|
||||
var pipe = _subprocess.StandardInput.BaseStream;
|
||||
|
||||
while (!_terminate)
|
||||
{
|
||||
// Wait for the ping from the copy thread.
|
||||
_pipePing.WaitOne();
|
||||
|
||||
// Process all entries in the pipe queue.
|
||||
while (_pipeQueue.Count > 0)
|
||||
{
|
||||
// Retrieve a frame entry.
|
||||
byte[] buffer;
|
||||
lock (_pipeQueue) buffer = _pipeQueue.Dequeue();
|
||||
|
||||
// Write it into the FFmpeg pipe.
|
||||
try
|
||||
{
|
||||
pipe.Write(buffer, 0, buffer.Length);
|
||||
pipe.Flush();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Pipe.Write could raise an IO exception when ffmpeg
|
||||
// is terminated for some reason. We just ignore this
|
||||
// situation and assume that it will be resolved in the
|
||||
// main thread. #badcode
|
||||
}
|
||||
|
||||
// Add the buffer to the free buffer list to reuse later.
|
||||
lock (_freeBuffer) _freeBuffer.Enqueue(buffer);
|
||||
_pipePong.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
12
Assets/FFmpegOut/Runtime/Internal/FFmpegPipe.cs.meta
Normal file
12
Assets/FFmpegOut/Runtime/Internal/FFmpegPipe.cs.meta
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fffc00cbe6345c64a8d3898031c46d8a
|
||||
timeCreated: 1491121325
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
|
|
@ -7526,6 +7526,51 @@ MonoBehaviour:
|
|||
m_XAdvance: 0
|
||||
m_YAdvance: 0
|
||||
m_FeatureLookupFlags: -11456224
|
||||
- m_FirstAdjustmentRecord:
|
||||
m_GlyphIndex: 57
|
||||
m_GlyphValueRecord:
|
||||
m_XPlacement: 0
|
||||
m_YPlacement: 0
|
||||
m_XAdvance: 0.90000004
|
||||
m_YAdvance: 0
|
||||
m_SecondAdjustmentRecord:
|
||||
m_GlyphIndex: 10
|
||||
m_GlyphValueRecord:
|
||||
m_XPlacement: 0
|
||||
m_YPlacement: 0
|
||||
m_XAdvance: 0
|
||||
m_YAdvance: 0
|
||||
m_FeatureLookupFlags: -2056572640
|
||||
- m_FirstAdjustmentRecord:
|
||||
m_GlyphIndex: 57
|
||||
m_GlyphValueRecord:
|
||||
m_XPlacement: 0
|
||||
m_YPlacement: 0
|
||||
m_XAdvance: 0.90000004
|
||||
m_YAdvance: 0
|
||||
m_SecondAdjustmentRecord:
|
||||
m_GlyphIndex: 62
|
||||
m_GlyphValueRecord:
|
||||
m_XPlacement: 0
|
||||
m_YPlacement: 0
|
||||
m_XAdvance: 0
|
||||
m_YAdvance: 0
|
||||
m_FeatureLookupFlags: -2056572640
|
||||
- m_FirstAdjustmentRecord:
|
||||
m_GlyphIndex: 57
|
||||
m_GlyphValueRecord:
|
||||
m_XPlacement: 0
|
||||
m_YPlacement: 0
|
||||
m_XAdvance: 0.90000004
|
||||
m_YAdvance: 0
|
||||
m_SecondAdjustmentRecord:
|
||||
m_GlyphIndex: 122
|
||||
m_GlyphValueRecord:
|
||||
m_XPlacement: 0
|
||||
m_YPlacement: 0
|
||||
m_XAdvance: 0
|
||||
m_YAdvance: 0
|
||||
m_FeatureLookupFlags: -2056572640
|
||||
m_MarkToBaseAdjustmentRecords: []
|
||||
m_MarkToMarkAdjustmentRecords: []
|
||||
m_ShouldReimportFontFeatures: 0
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ RenderTexture:
|
|||
m_DownscaleFallback: 0
|
||||
m_IsAlphaChannelOptional: 0
|
||||
serializedVersion: 5
|
||||
m_Width: 947
|
||||
m_Height: 533
|
||||
m_Width: 974
|
||||
m_Height: 547
|
||||
m_AntiAliasing: 2
|
||||
m_MipCount: -1
|
||||
m_DepthStencilFormat: 92
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@ RenderTexture:
|
|||
m_DownscaleFallback: 0
|
||||
m_IsAlphaChannelOptional: 0
|
||||
serializedVersion: 5
|
||||
m_Width: 1420
|
||||
m_Height: 799
|
||||
m_Width: 1461
|
||||
m_Height: 820
|
||||
m_AntiAliasing: 1
|
||||
m_MipCount: -1
|
||||
m_DepthStencilFormat: 92
|
||||
|
|
|
|||
|
|
@ -83,6 +83,6 @@ Material:
|
|||
- _ZWrite: 1
|
||||
m_Colors:
|
||||
- _AddColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
- _Color: {r: 0.9528302, g: 0.87130237, b: 0.7775454, a: 1}
|
||||
- _Color: {r: 0.9529412, g: 0.87058824, b: 0.7764706, a: 1}
|
||||
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
|
|
|
|||
|
|
@ -8906,7 +8906,7 @@ MonoBehaviour:
|
|||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 14
|
||||
m_fontSize: 9.65
|
||||
m_fontSizeBase: 14.3
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 1
|
||||
|
|
@ -18420,6 +18420,36 @@ GameObject:
|
|||
m_CorrespondingSourceObject: {fileID: 6052331674369862802, guid: 720073bc7682b1441bece7116681f72c, type: 3}
|
||||
m_PrefabInstance: {fileID: 631525709}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
--- !u!114 &631525720
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 631525712}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 5ebf035b10ec113418cebc7dff510693, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
recorder: {fileID: 631525723}
|
||||
audioRenderer: {fileID: 1699860728}
|
||||
--- !u!114 &631525723
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 631525712}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a66fbd5ffe9b9d64da304996f1919f40, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_width: 1920
|
||||
_height: 1080
|
||||
_preset: 0
|
||||
_frameRate: 60
|
||||
--- !u!1 &632795495
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -32707,7 +32737,7 @@ RectTransform:
|
|||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0.5}
|
||||
m_AnchorMax: {x: 1, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 142.32655}
|
||||
m_AnchoredPosition: {x: 0, y: 90.48979}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 1}
|
||||
--- !u!222 &1154875945
|
||||
|
|
@ -43455,8 +43485,8 @@ MonoBehaviour:
|
|||
m_TargetGraphic: {fileID: 1220118245}
|
||||
m_HandleRect: {fileID: 1220118244}
|
||||
m_Direction: 2
|
||||
m_Value: 1.0000008
|
||||
m_Size: 0.78099126
|
||||
m_Value: 1.0000002
|
||||
m_Size: 0.35148686
|
||||
m_NumberOfSteps: 0
|
||||
m_OnValueChanged:
|
||||
m_PersistentCalls:
|
||||
|
|
@ -44971,6 +45001,19 @@ CanvasRenderer:
|
|||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1695786878}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1699860728
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 631525713}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 1150ae7143196054bba8378d288fc1c3, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
Rendering: 0
|
||||
--- !u!1 &1700641149
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
using System;
|
||||
|
||||
public static class AppInfo {
|
||||
public const string Version = "0.0.1018";
|
||||
public static readonly DateTime Date = new DateTime(2024, 01, 15, 19, 39, 36, 317, DateTimeKind.Utc);
|
||||
public const string Version = "1.0.8";
|
||||
public static readonly DateTime Date = new DateTime(2024, 02, 01, 03, 33, 35, 379, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
8
Assets/Scripts/LevelEditor/HeavenRecorder.meta
Normal file
8
Assets/Scripts/LevelEditor/HeavenRecorder.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 84f50102f80683a4db6a365fefd779cf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using FFmpegOut;
|
||||
using System.IO;
|
||||
|
||||
namespace FFmpegOut
|
||||
{
|
||||
public class HeavenRecorderController : MonoBehaviour
|
||||
{
|
||||
public CameraCapture recorder;
|
||||
public AudioRenderer audioRenderer;
|
||||
|
||||
bool exporting = true;
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
recorder.enabled = false;
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
if(Input.GetKeyDown(KeyCode.L))
|
||||
{
|
||||
if(recorder.enabled)
|
||||
{
|
||||
print("recording stopped!");
|
||||
recorder.enabled = false;
|
||||
audioRenderer.Rendering = false;
|
||||
if(audioRenderer.Save("C:/Users/pikmi/Downloads/temp.wav").State == AudioRenderer.Status.SUCCESS && exporting == true)
|
||||
{
|
||||
Merge();
|
||||
audioRenderer.Clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(File.Exists("C:/Users/pikmi/Downloads/temp.wav"))
|
||||
{
|
||||
File.Delete("C:/Users/pikmi/Downloads/temp.wav");
|
||||
}
|
||||
if(File.Exists("C:/Users/pikmi/Downloads/temp.mp4"))
|
||||
{
|
||||
File.Delete("C:/Users/pikmi/Downloads/temp.mp4");
|
||||
}
|
||||
audioRenderer.Rendering = true;
|
||||
print("recording started!");
|
||||
recorder.enabled = true;
|
||||
exporting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Merge()
|
||||
{
|
||||
exporting = false;
|
||||
FFmpegSession _session;
|
||||
_session = FFmpegSession.CreateWithArguments("-y -i C:/Users/pikmi/Downloads/temp.mp4 -i C:/Users/pikmi/Downloads/temp.wav -c:v copy -c:a aac C:/Users/pikmi/Downloads/output.mp4");
|
||||
_session.Close();
|
||||
_session.Dispose();
|
||||
_session = null;
|
||||
File.Delete("C:/Users/pikmi/Downloads/temp.wav");
|
||||
File.Delete("C:/Users/pikmi/Downloads/temp.mp4");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5ebf035b10ec113418cebc7dff510693
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -134,7 +134,7 @@ PlayerSettings:
|
|||
16:10: 1
|
||||
16:9: 1
|
||||
Others: 1
|
||||
bundleVersion: 1.0.1
|
||||
bundleVersion: 1.0.8
|
||||
preloadedAssets:
|
||||
- {fileID: 102900000, guid: 5348c08b82446e0478cee8bda6c02cfc, type: 3}
|
||||
metroInputSource: 0
|
||||
|
|
@ -158,11 +158,11 @@ PlayerSettings:
|
|||
applicationIdentifier:
|
||||
Standalone: com.RHeavenStudio.Heaven-Studio
|
||||
buildNumber:
|
||||
Standalone: 1018
|
||||
Standalone: 100008
|
||||
iPhone: 0
|
||||
tvOS: 0
|
||||
overrideDefaultApplicationIdentifier: 0
|
||||
AndroidBundleVersionCode: 1018
|
||||
AndroidBundleVersionCode: 100008
|
||||
AndroidMinSdkVersion: 22
|
||||
AndroidTargetSdkVersion: 0
|
||||
AndroidPreferredInstallLocation: 1
|
||||
|
|
|
|||
|
|
@ -17,275 +17,9 @@ MonoBehaviour:
|
|||
DenseViewWidthThreshold: 512
|
||||
_disableAutoReloadInBackground: 0
|
||||
ImportedScriptPaths:
|
||||
- Assets/Scripts/Minigames.cs
|
||||
- Assets/Editor/CreateAssetBundles.cs
|
||||
- Assets/Editor/CreateMinigameScriptTemplate.cs
|
||||
- Assets/Scripts/Games/Minigame.cs
|
||||
- Assets/Scripts/Games/FanClub/FanClub.cs
|
||||
- Assets/Scripts/GameManager.cs
|
||||
- Assets/Editor/SpritesheetScaler.cs
|
||||
- Assets/Scripts/USG.g/LoadMinigames.Minigames.MinigameLoaderGenerator.g.cs
|
||||
- Assets/Scripts/Games/TheDazzles/TheDazzles.cs
|
||||
- Assets/Scripts/Games/FirstContact/FirstContact.cs
|
||||
- Assets/Scripts/SourceGenerators/ControllerLoaderGenerator.cs
|
||||
- Assets/Scripts/InputSystem/PlayerInput.cs
|
||||
- Assets/Scripts/JudgementManager.cs
|
||||
- Assets/Scripts/LevelEditor/RemixPropertiesDialog/PropertyPrefabs/RatingScreenPropertyDialog.cs
|
||||
- Assets/Scripts/GlobalGameManager.cs
|
||||
- Assets/Scripts/Games/KarateMan/KarateMan.cs
|
||||
- Assets/Scripts/Games/KarateMan/KarateManJoe.cs
|
||||
- Assets/Scripts/Games/KarateMan/KarateManNoriController.cs
|
||||
- Assets/Scripts/Util/BeatAction.cs
|
||||
- Assets/Scripts/Games/TossBoys/TossBoys.cs
|
||||
- Assets/Scripts/Games/DoubleDate/DoubleDate.cs
|
||||
- Assets/Scripts/Games/AirRally/AirRally.cs
|
||||
- Assets/Scripts/LevelEditor/Editor.cs
|
||||
- Assets/Scripts/Common/MemRenderer.cs
|
||||
- Assets/Scripts/Games/BoardMeeting/BoardMeeting.cs
|
||||
- Assets/Scripts/PersistentDataManager.cs
|
||||
- Assets/Scripts/UI/Overlays/OverlaysManager.cs
|
||||
- Assets/Scripts/TitleManager.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/SpecialTmeline/SectionDialog.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/SpecialTmeline/TimelineObjs/SectionTimelineObj.cs
|
||||
- Assets/Scripts/Games/DJSchool/Student.cs
|
||||
- Assets/Scripts/UI/PauseMenu.cs
|
||||
- Assets/Scripts/Util/Sound.cs
|
||||
- Assets/Scripts/Conductor.cs
|
||||
- Assets/Scripts/EventCaller.cs
|
||||
- Assets/Scripts/Games/TrickClass/TrickClass.cs
|
||||
- Assets/Scripts/GameInitializer.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/Timeline.cs
|
||||
- Assets/Scripts/Games/PlayerActionEvent.cs
|
||||
- Assets/Scripts/Games/KarateMan/KarateManPot.cs
|
||||
- Assets/Scripts/Games/DJSchool/DJSchool.cs
|
||||
- Assets/Scripts/LevelEditor/Commands/TestCommand.cs
|
||||
- Assets/Scripts/Games/ClappyTrio/ClappyTrioPlayer.cs
|
||||
- Assets/Scripts/Games/GleeClub/GleeClub.cs
|
||||
- Assets/Scripts/Games/DoubleDate/Basketball.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCBackgroundManager.cs
|
||||
- Assets/Scripts/Games/Spaceball/SpaceballBall.cs
|
||||
- Assets/Scripts/Games/QuizShow/QuizShow.cs
|
||||
- Assets/Scripts/InputSystem/ControllerTypes/InputJoyshock.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCEndTotem.cs
|
||||
- Assets/Editor/BuildScript.cs
|
||||
- Assets/Scripts/LevelEditor/Selections.cs
|
||||
- Assets/Scripts/Games/NightWalkRvl/RvlNightWalk.cs
|
||||
- Assets/Plugins/Starpelly/Math.cs
|
||||
- Assets/Scripts/Games/GleeClub/ChorusKid.cs
|
||||
- Assets/Scripts/LevelEditor/EventSelector/GridGameSelector.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/TimelineZoom.cs
|
||||
- Assets/Scripts/Games/CheerReaders/RvlCharacter.cs
|
||||
- Assets/Scripts/Games/MrUpbeat/MrUpbeat.cs
|
||||
- Assets/Scripts/Games/CatchyTune/CatchyTune.cs
|
||||
- Assets/GUIWindows/Scripts/GUIWindow.cs
|
||||
- Assets/Scripts/Games/AirRally/CloudsManager.cs
|
||||
- Assets/Scripts/Games/DogNinja/ThrowObject.cs
|
||||
- Assets/Scripts/Games/RhythmTweezers/Hair.cs
|
||||
- Assets/Scripts/Games/Rockers/RockersInput.cs
|
||||
- Assets/Scripts/UI/Overlays/GoForAPerfect.cs
|
||||
- Assets/Scripts/Games/SpaceSoccer/Ball.cs
|
||||
- Assets/Scripts/Games/TossBoys/TossKid.cs
|
||||
- Assets/Scripts/Games/CropStomp/Farmer.cs
|
||||
- Assets/Scripts/Games/SpaceSoccer/SpaceSoccer.cs
|
||||
- Assets/Scripts/UI/LeftClickTMP_Dropdown.cs
|
||||
- Assets/Scripts/Games/RhythmTweezers/NoPeekingSign.cs
|
||||
- Assets/Scripts/Games/Fireworks/FireworksBomb.cs
|
||||
- Assets/Scripts/Transform/ScaleByVelocity.cs
|
||||
- Assets/Scripts/Games/BuiltToScaleDS/BuiltToScaleDS.cs
|
||||
- Assets/Scripts/Games/Global/Textbox.cs
|
||||
- Assets/Scripts/LevelEditor/RemixPropertiesDialog/PropertyPrefabs/ImageChartResourcePrefab.cs
|
||||
- Assets/Scripts/Games/CropStomp/Veggie.cs
|
||||
- Assets/Scripts/OpeningManager.cs
|
||||
- Assets/Scripts/Games/BlueBear/BlueBear.cs
|
||||
- Assets/Scripts/Games/DoubleDate/Football.cs
|
||||
- Assets/Plugins/JoyShockLibrary/JoyShockLibrary.cs
|
||||
- Assets/Scripts/StretchCameraVFX.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/TimelineEventObj.cs
|
||||
- Assets/Scripts/Games/TapTrial/TapTrial.cs
|
||||
- Assets/Scripts/Games/AirRally/RvlIsland.cs
|
||||
- Assets/Scripts/LevelEditor/EventSelector/PropertyPrefabs/StringPropertyPrefab.cs
|
||||
- Assets/Scripts/Games/DoubleDate/DoubleDateWeasels.cs
|
||||
- Assets/Scripts/Games/Rockers/RockersRocker.cs
|
||||
- Assets/Scripts/Games/TapTroupe/TapTroupe.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCTotem.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/BlockDeleteFX.cs
|
||||
- Assets/Scripts/UI/Overlays/SectionMedalsManager.cs
|
||||
- Assets/Scripts/Games/AirRally/IslandsManager.cs
|
||||
- Assets/Scripts/Games/CallAndResponseHandler.cs
|
||||
- Assets/Scripts/Games/RhythmTweezers/LongHair.cs
|
||||
- Assets/Scripts/Games/SneakySpirits/SneakySpiritsGhost.cs
|
||||
- Assets/Scripts/Games/ForkLifter/Pea.cs
|
||||
- Assets/Scripts/LevelEditor/WaveformVisual.cs
|
||||
- Assets/Scripts/Games/CatchyTune/Fruit.cs
|
||||
- Assets/Scripts/Games/FanClub/NtrIdolFan.cs
|
||||
- Assets/Scripts/Games/PajamaParty/PajamaParty.cs
|
||||
- Assets/Scripts/Games/SneakySpirits/SneakySpirits.cs
|
||||
- Assets/Scripts/LevelEditor/Commands/Block.cs
|
||||
- Assets/Scripts/LevelEditor/EventSelector/PropertyPrefabs/ColorPropertyPrefab.cs
|
||||
- Assets/Scripts/Games/LaunchParty/LaunchParty.cs
|
||||
- Assets/Scripts/Games/Rockers/Rockers.cs
|
||||
- Assets/Scripts/Games/SamuraiSliceNtr/NtrSamuraiObject.cs
|
||||
- Assets/Scripts/Games/ForkLifter/ForkLifterHand.cs
|
||||
- Assets/Scripts/LevelEditor/RemixPropertiesDialog/PropertyPrefabs/EnumChartPropertyPrefab.cs
|
||||
- Assets/Scripts/Games/Global/Filter.cs
|
||||
- Assets/Scripts/Games/NightWalkAgb/AgbPlatform.cs
|
||||
- Assets/Scripts/Games/PajamaParty/CtrPillowMonkey.cs
|
||||
- Assets/Scripts/Games/MarchingOrders/MarchingOrders.cs
|
||||
- Assets/Scripts/LevelEditor/SnapDialog/SnapChangeButton.cs
|
||||
- Assets/Plugins/StandaloneFileBrowser/StandaloneFileBrowserWindows.cs
|
||||
- Assets/Scripts/Games/WorkingDough/NPCDoughBall.cs
|
||||
- Assets/Scripts/ScreenTiling.cs
|
||||
- Assets/Scripts/Games/AirRally/Shuttlecock.cs
|
||||
- Assets/Scripts/Games/WizardsWaltz/WizardsWaltz.cs
|
||||
- Assets/Scripts/Games/NightWalkAgb/AgbPlayYan.cs
|
||||
- Assets/Scripts/Games/CoinToss/CoinToss.cs
|
||||
- Assets/Scripts/Games/BuiltToScaleDS/Blocks.cs
|
||||
- Assets/Scripts/LevelEditor/EventSelector/PropertyPrefabs/EnumPropertyPrefab.cs
|
||||
- Assets/Scripts/Games/TapTrial/TapTrialPlayer.cs
|
||||
- Assets/Scripts/LevelEditor/RemixPropertiesDialog/PropertyPrefabs/NumberChartPropertyPrefab.cs
|
||||
- Assets/Plugins/Starpelly/Colors.cs
|
||||
- Assets/Scripts/Games/AirRally/RvlBirds.cs
|
||||
- Assets/Scripts/Games/GleeClub/GleeClubSingInput.cs
|
||||
- Assets/Scripts/LevelEditor/RemixPropertiesDialog/PropertyPrefabs/StringChartPropertyPrefab.cs
|
||||
- Assets/Scripts/Games/Splashdown/NtrSplash.cs
|
||||
- Assets/Scripts/Games/WorkingDough/PlayerEnterDoughBall.cs
|
||||
- Assets/Scripts/Games/FlipperFlop/FlipperFlopFlipper.cs
|
||||
- Assets/Scripts/Games/NightWalkAgb/AgbNightWalk.cs
|
||||
- Assets/Scripts/Games/TramAndPauline/AgbAnimalKid.cs
|
||||
- Assets/Scripts/LevelEditor/HeavenRecorder/HeavenRecorderController.cs
|
||||
- Assets/FFmpegOut/Runtime/FFmpegSession.cs
|
||||
- Assets/FFmpegOut/AudioRenderer.cs
|
||||
- Assets/Scripts/AppInfo.cs
|
||||
- Assets/Scripts/Games/SeeSaw/SeeSaw.cs
|
||||
- Assets/Scripts/Util/AnimationHelpers.cs
|
||||
- Assets/Scripts/Games/TossBoys/TossBoysBall.cs
|
||||
- Assets/Scripts/LevelEditor/BPMText.cs
|
||||
- Assets/Scripts/Games/NightWalkAgb/AgbPlatformHandler.cs
|
||||
- Assets/Scripts/Games/CheerReaders/CheerReaders.cs
|
||||
- Assets/Scripts/Games/SpaceSoccer/Kicker.cs
|
||||
- Assets/Scripts/InputSystem/ControllerTypes/InputMouse.cs
|
||||
- Assets/Scripts/Games/DogNinja/DogNinja.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/SpecialTmeline/TempoDialog.cs
|
||||
- Assets/Scripts/LevelEditor/EventSelector/PropertyPrefabs/NumberPropertyPrefab.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCDragon.cs
|
||||
- Assets/Scripts/LevelEditor/BoxSelection.cs
|
||||
- Assets/Scripts/Games/ForkLifter/ForkLifter.cs
|
||||
- Assets/Scripts/Games/DrummingPractice/DrummingPractice.cs
|
||||
- Assets/Scripts/LevelEditor/DisableSelectOnHover.cs
|
||||
- Assets/Scripts/LevelEditor/Theme.cs
|
||||
- Assets/Scripts/Games/BoardMeeting/BMExecutive.cs
|
||||
- Assets/Scripts/Common/CanvasScroll.cs
|
||||
- Assets/Scripts/GameCamera.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCJumper.cs
|
||||
- Assets/Scripts/Games/MeatGrinder/MeatGrinder.cs
|
||||
- Assets/Scripts/UI/RightClickDropdownObject.cs
|
||||
- Assets/Scripts/StaticCamera.cs
|
||||
- Assets/Scripts/Games/Spaceball/SpaceballPlayer.cs
|
||||
- Assets/Scripts/Util/SoundByte.cs
|
||||
- Assets/Scripts/LevelEditor/EventSelector/PropertyPrefabs/BoolPropertyPrefab.cs
|
||||
- Assets/Scripts/Games/Splashdown/NtrSynchrette.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/SpecialTmeline/TimelineObjs/VolumeTimelineObj.cs
|
||||
- Assets/Scripts/LevelEditor/DialogHelpers/Dialog.cs
|
||||
- Assets/Scripts/UI/SettingsDialog/Tabs/EditorSettings.cs
|
||||
- Assets/Scripts/StudioDance/ChoreographyInfo.cs
|
||||
- Assets/Scripts/Games/CropStomp/CropStomp.cs
|
||||
- Assets/Scripts/Games/Global/Flash.cs
|
||||
- Assets/Scripts/LevelEditor/Commands/ICommand.cs
|
||||
- Assets/Scripts/StudioDance/StudioDanceManager.cs
|
||||
- Assets/Scripts/Games/SeeSaw/SeeSawGuy.cs
|
||||
- Assets/Scripts/Games/DrummingPractice/Drummer.cs
|
||||
- Assets/Scripts/Games/RhythmRally/Paddlers.cs
|
||||
- Assets/Scripts/UI/SettingsDialog/Tabs/DispAudioSettings.cs
|
||||
- Assets/Scripts/Util/SavWav.cs
|
||||
- Assets/Scripts/Util/EntityTypes.cs
|
||||
- Assets/Scripts/Games/PajamaParty/CtrPillowPlayer.cs
|
||||
- Assets/Scripts/Games/Ringside/Ringside.cs
|
||||
- Assets/Scripts/Games/LaunchParty/LaunchPartyRocket.cs
|
||||
- Assets/Scripts/Games/Spaceball/Spaceball.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCGroundManager.cs
|
||||
- Assets/Scripts/Games/TramAndPauline/TramAndPauline.cs
|
||||
- Assets/Scripts/Games/BlueBear/Treat.cs
|
||||
- Assets/Scripts/PostProcessingVFX.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/SpecialTmeline/SpecialTimeline.cs
|
||||
- Assets/Scripts/SourceGenerators/MinigameLoaderGenerator.cs
|
||||
- Assets/Scripts/InputSystem/ControllerTypes/InputKeyboard.cs
|
||||
- Assets/Scripts/LevelEditor/EditorTheme.cs
|
||||
- Assets/Scripts/Games/TrickClass/MobTrickObj.cs
|
||||
- Assets/Scripts/Games/OctopusMachine/Octopus.cs
|
||||
- Assets/Scripts/Games/WizardsWaltz/Plant.cs
|
||||
- Assets/Scripts/UI/SettingsDialog/Tabs/CreditsLegalSettings.cs
|
||||
- Assets/Scripts/Games/TapTroupe/TapTroupeZoomOut.cs
|
||||
- Assets/Scripts/Games/MeatGrinder/Meat.cs
|
||||
- Assets/Plugins/StandaloneFileBrowser/StandaloneFileBrowser.cs
|
||||
- Assets/Scripts/Games/TheDazzles/TheDazzlesGirl.cs
|
||||
- Assets/Scripts/LevelEditor/Commands/SpecialMarker.cs
|
||||
- Assets/Scripts/UI/SettingsDialog/SettingsDialog.cs
|
||||
- Assets/Scripts/UI/Overlays/ChartSectionDisplay.cs
|
||||
- Assets/Scripts/LevelEditor/RemixPropertiesDialog/PropertyPrefabs/ColorChartPropertyPrefab.cs
|
||||
- Assets/GUIWindows/Scripts/GUIWindowHandle.cs
|
||||
- Assets/Scripts/Games/Kitties/Kitties.cs
|
||||
- Assets/Scripts/Games/QuizShow/QSTimer.cs
|
||||
- Assets/Scripts/CircleCursor.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCBirdManager.cs
|
||||
- Assets/Plugins/StandaloneFileBrowser/StandaloneFileBrowserLinux.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/SpecialTmeline/TimelineObjs/SpecialTimelineObj.cs
|
||||
- Assets/Scripts/Games/RhythmTweezers/RhythmTweezers.cs
|
||||
- Assets/Scripts/Games/SamuraiSliceNtr/SamuraiSliceNtr.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/TimelineBlockManager.cs
|
||||
- Assets/Scripts/Games/Rockers/RockerBendInput.cs
|
||||
- Assets/Scripts/LevelEditor/RemixPropertiesDialog/Tabs/ChartInfoProperties.cs
|
||||
- Assets/Plugins/StandaloneFileBrowser/StandaloneFileBrowserEditor.cs
|
||||
- Assets/Scripts/Games/Kitties/CtrTeppanPlayer.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/SpecialTmeline/TimelineObjs/TempoTimelineObj.cs
|
||||
- Assets/Scripts/LevelEditor/Timeline/SpecialTmeline/VolumeDialog.cs
|
||||
- Assets/Scripts/Games/Splashdown/Splashdown.cs
|
||||
- Assets/Plugins/StandaloneFileBrowser/StandaloneFileBrowserMac.cs
|
||||
- Assets/Scripts/Games/AirRally/Cloud.cs
|
||||
- Assets/Scripts/InputSystem/InputController.cs
|
||||
- Assets/Scripts/UI/Overlays/SkillStarManager.cs
|
||||
- Assets/Scripts/LevelEditor/BeatGrid.cs
|
||||
- Assets/Scripts/Games/RhythmRally/RhythmRally.cs
|
||||
- Assets/Scripts/Games/SamuraiSliceNtr/NtrSamurai.cs
|
||||
- Assets/Scripts/Games/TapTroupe/TapTroupeCorner.cs
|
||||
- Assets/Scripts/Games/FanClub/NtrIdolAmie.cs
|
||||
- Assets/GUIWindows/Scripts/GUIWindowUtils.cs
|
||||
- Assets/Scripts/Games/Tambourine/Tambourine.cs
|
||||
- Assets/Scripts/Util/MultiSound.cs
|
||||
- Assets/Scripts/Games/Fireworks/Rocket.cs
|
||||
- Assets/Scripts/Games/RhythmSomen/RhythmSomen.cs
|
||||
- Assets/Scripts/Games/Tunnel/Tunnel.cs
|
||||
- Assets/Scripts/Games/ClappyTrio/ClappyTrio.cs
|
||||
- Assets/Scripts/LevelEditor/RemixPropertiesDialog/RemixPropertiesDialog.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TotemClimb.cs
|
||||
- Assets/Plugins/StandaloneFileBrowser/IStandaloneFileBrowser.cs
|
||||
- Assets/Scripts/LevelEditor/Commands/CommandManager.cs
|
||||
- Assets/Scripts/Games/FirstContact/Translator.cs
|
||||
- Assets/Scripts/LevelEditor/TooltipGiver.cs
|
||||
- Assets/Scripts/InputSystem/USG.g/InitInputControllers.PlayerInput.ControllerLoaderGenerator.g.cs
|
||||
- Assets/Scripts/Games/DrummingPractice/DrummerHit.cs
|
||||
- Assets/Scripts/LevelEditor/TempoFinder/TempoFinder.cs
|
||||
- Assets/Scripts/LevelEditor/EventSelector/EventParameterManager.cs
|
||||
- Assets/Scripts/StudioDance/Dancer.cs
|
||||
- Assets/Scripts/LevelEditor/EventSelector/EventPropertyPrefab.cs
|
||||
- Assets/Scripts/Games/Lockstep/Lockstep.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCTotemManager.cs
|
||||
- Assets/Scripts/UI/Overlays/TimingAccuracyDisplay.cs
|
||||
- Assets/Scripts/Games/MunchyMonk/MunchyMonk.cs
|
||||
- Assets/Scripts/Games/ForkLifter/ForkLifterPlayer.cs
|
||||
- Assets/Scripts/Games/DoubleDate/SoccerBall.cs
|
||||
- Assets/Scripts/Games/RhythmTweezers/Tweezers.cs
|
||||
- Assets/Scripts/Games/WorkingDough/WorkingDough.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCFrog.cs
|
||||
- Assets/Scripts/UI/SettingsDialog/Tabs/ControllerSettings.cs
|
||||
- Assets/Scripts/Games/SpaceDance/SpaceDance.cs
|
||||
- Assets/Scripts/Games/MrUpbeat/UpbeatMan.cs
|
||||
- Assets/Scripts/Games/OctopusMachine/OctopusMachine.cs
|
||||
- Assets/Scripts/Games/TotemClimb/TCPillarManager.cs
|
||||
- Assets/Scripts/Games/Fireworks/Fireworks.cs
|
||||
- Assets/Scripts/Games/FlipperFlop/FlipperFlop.cs
|
||||
- Assets/Scripts/Games/WizardsWaltz/Wizard.cs
|
||||
- Assets/Scripts/Games/MonkeyWatch/MonkeyWatch.cs
|
||||
- Assets/Scripts/Games/MonkeyWatch/WatchMonkeyHandler.cs
|
||||
- Assets/Scripts/Games/MonkeyWatch/WatchBackgroundHandler.cs
|
||||
- Assets/Scripts/Games/MonkeyWatch/MonkeyClockArrow.cs
|
||||
- Assets/Scripts/Games/MonkeyWatch/BalloonHandler.cs
|
||||
- Assets/Scripts/Games/MonkeyWatch/WatchMonkey.cs
|
||||
PathsToSkipImportEvent: []
|
||||
PathsToIgnoreOverwriteSettingOnAttribute: []
|
||||
|
|
|
|||
BIN
output.mp4
Normal file
BIN
output.mp4
Normal file
Binary file not shown.
Loading…
Reference in a new issue