SHA256
119 lines
3.5 KiB
C#
119 lines
3.5 KiB
C#
using System;
|
|
using System.Buffers;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using Unity.Collections;
|
|
|
|
namespace ADOFAIRenderer.Util.FFmpeg
|
|
{
|
|
public class FFmpegProcess : IDisposable
|
|
{
|
|
public static string FFmpegPath = "";
|
|
|
|
private Process? _ffmpegProcess;
|
|
private Stream? _inputStream;
|
|
|
|
public bool IsEnd => _ffmpegProcess is { HasExited: true };
|
|
|
|
protected 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;
|
|
var writeLength = length < 0 ? buffer.Length : length;
|
|
_inputStream.Write(buffer, 0, writeLength);
|
|
_inputStream.Flush();
|
|
}
|
|
|
|
public void Close()
|
|
{
|
|
if (_ffmpegProcess == null || _ffmpegProcess.HasExited || _inputStream == null) return;
|
|
try
|
|
{
|
|
_inputStream.Flush();
|
|
_inputStream.Close();
|
|
|
|
// Allow FFmpeg to finish encoding and exit gracefully without any timeout to prevent video corruption
|
|
_ffmpegProcess.WaitForExit();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Ignore any issues during termination
|
|
}
|
|
finally
|
|
{
|
|
_ffmpegProcess.Dispose();
|
|
_ffmpegProcess = null;
|
|
_inputStream = null;
|
|
}
|
|
}
|
|
|
|
public void Kill()
|
|
{
|
|
try
|
|
{
|
|
if (_ffmpegProcess != null && !_ffmpegProcess.HasExited)
|
|
{
|
|
_ffmpegProcess.Kill();
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Ignore process already exited or access denied errors during cleanup
|
|
}
|
|
finally
|
|
{
|
|
try
|
|
{
|
|
_inputStream?.Close();
|
|
}
|
|
catch
|
|
{
|
|
// Ignore
|
|
}
|
|
_ffmpegProcess?.Dispose();
|
|
_ffmpegProcess = null;
|
|
_inputStream = null;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Kill();
|
|
}
|
|
|
|
public static byte[] RentRawBytes(int size)
|
|
{
|
|
var array = ArrayPool<byte>.Shared.Rent(size);
|
|
return array;
|
|
}
|
|
|
|
protected 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;
|
|
}
|
|
}
|
|
}
|