Add Renderer Feature

This commit is contained in:
copecone committed 2026-05-22 19:31:44 +09:00
1 parent c9314c264d
commit 2556bc7f62
13 files changed
+727 -21

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
using System;
using System.Buffers;
using System.Diagnostics;
using System.IO;
using Unity.Collections;
namespace ADOFAIRenderer.Util
{
public class FFmpegProcess
{
public static string FFmpegPath = "";
private Process? _ffmpegProcess;
private Stream? _inputStream;
public bool IsEnd => _ffmpegProcess is { HasExited: true };
public void Execute(string command)
{
if (string.IsNullOrEmpty(command))
{
throw new ArgumentException("Command is empty");
}
if (string.IsNullOrEmpty(FFmpegPath) || !File.Exists(FFmpegPath))
{
throw new FileNotFoundException($"ffmpeg binary not found at '{FFmpegPath}'");
}
_ffmpegProcess = new Process();
_ffmpegProcess.StartInfo.FileName = FFmpegPath;
_ffmpegProcess.StartInfo.Arguments = command;
_ffmpegProcess.StartInfo.UseShellExecute = false;
_ffmpegProcess.StartInfo.RedirectStandardInput = true;
_ffmpegProcess.StartInfo.CreateNoWindow = true;
_ffmpegProcess.Start();
_inputStream = _ffmpegProcess.StandardInput.BaseStream;
}
public void SendDataFromBuffer(byte[] buffer, int length = -1)
{
if (_inputStream == null) return;
int writeLength = length < 0 ? buffer.Length : length;
_inputStream.Write(buffer, 0, writeLength);
_inputStream.Flush();
}
public void Close()
{
if (_ffmpegProcess == null || _ffmpegProcess.HasExited || _inputStream == null) return;
_inputStream.Flush();
_inputStream.Close();
_ffmpegProcess.WaitForExit();
}
public static byte[] RentRawBytes<T>(NativeArray<T> arr) where T : struct
{
var val = new NativeSlice<T>(arr).SliceConvert<byte>();
var array = ArrayPool<byte>.Shared.Rent(val.Length);
val.CopyTo(array);
return array;
}
public static byte[] ToRawBytes<T>(NativeArray<T> arr) where T : struct
{
var val = new NativeSlice<T>(arr).SliceConvert<byte>();
var array = new byte[val.Length];
val.CopyTo(array);
return array;
}
}
}
+76
View File
@@ -0,0 +1,76 @@
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Unity.Collections;
using UnityEngine;
namespace ADOFAIRenderer.Util
{
public class VideoFFmpeg : FFmpegProcess
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum Codec
{
H264_Default,
H264_NVIDIA,
H264_QSV,
HEVC_Default,
HEVC_NVIDIA,
HEVC_QSV,
AV1_Default,
AV1_NVIDIA,
AV1_QSV,
VP9_Default,
VP9_NVIDIA
}
public int Width;
public int Height;
public int FrameRate;
public int VideoFPS;
public Codec VideoCodec;
private static string Codec2String(Codec c)
{
return c switch
{
Codec.H264_Default => "-vf vflip",
Codec.H264_NVIDIA => "-c:v h264_nvenc -vf vflip",
Codec.H264_QSV => "-c:v h264_qsv -vf vflip",
Codec.HEVC_Default => "-c:v libx265 -vf vflip",
Codec.HEVC_NVIDIA => "-c:v hevc_nvenc -vf vflip",
Codec.HEVC_QSV => "-c:v hevc_qsv -vf vflip",
Codec.AV1_Default => "-c:v libaom-av1 -vf vflip",
Codec.AV1_NVIDIA => "-c:v av1_nvenc -vf vflip",
Codec.AV1_QSV => "-c:v av1_qsv -vf vflip",
Codec.VP9_Default => "-c:v libvpx-vp9 -vf vflip",
Codec.VP9_NVIDIA => "-c:v vp9_nvenc -vf vflip",
_ => "",
};
}
public VideoFFmpeg(int w, int h, int frame, int videoFrame, Codec codec)
{
Width = w;
Height = h;
FrameRate = frame;
VideoFPS = videoFrame;
VideoCodec = codec;
}
public void SendData(NativeArray<byte> source)
{
var buffer = ToRawBytes(source);
SendDataFromBuffer(buffer);
}
public void Start(string path, float bitrate)
{
if (File.Exists(path))
{
File.Delete(path);
}
var command = "-y -f rawvideo -vcodec rawvideo -pixel_format rgba -colorspace rgb -color_range 2 -video_size " + Width + "x" + Height + " -framerate " + FrameRate + " -threads 4 -loglevel quiet -i - " + Codec2String(VideoCodec) + " -pix_fmt yuv420p -fps_mode cfr " + " -r " + VideoFPS + $" -b:v {(int)bitrate}k" + " \"" + path + "\"";
Execute(command);
}
}
}