Skip to content

Commit 90a69b1

Browse files
authored
VideoEncoder: Probe encoders before encoding starts, choose first working on
Before that fix, recording on AMD cards could fail
1 parent 3e7d666 commit 90a69b1

File tree

1 file changed

+69
-10
lines changed

1 file changed

+69
-10
lines changed

Runtime/Scripts/BH_VideoEncoder.cs

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ public class BH_VideoEncoder
1717
private int maxSegments = 6; // Number of segments to keep (covering 60 seconds)
1818
private CircularBuffer<string> errorBuffer = new CircularBuffer<string>(256); // Circular buffer for stderr
1919

20+
private string _functionalEncoder = null;
21+
2022
private byte[] lastFrame;
2123
private float frameInterval;
2224

@@ -276,15 +278,65 @@ private void CleanupSegments()
276278
}
277279
}
278280

279-
private static string FindPreferredEncoder()
281+
private string FindPreferredEncoder()
282+
{
283+
string[] encoders = FindAvailableEncoders();
284+
if (!string.IsNullOrEmpty(_functionalEncoder) && encoders.Contains(_functionalEncoder))
285+
{
286+
return _functionalEncoder;
287+
}
288+
289+
// execute ffmpeg -f lavfi -i nullsrc=d=1 -c:v h264_nvenc -t 1 -f null - for each encoder on the list,
290+
// exit code 0 menas the encoder is available
291+
292+
string ffmpegPath = GetFfmpegPath();
293+
if (ffmpegPath == null)
294+
{
295+
return encoders[encoders.Length - 1];
296+
}
297+
298+
foreach (var encoder in encoders)
299+
{
300+
UnityEngine.Debug.Log($"Checking encoder: {encoder}");
301+
302+
var process = new Process();
303+
process.StartInfo.FileName = ffmpegPath;
304+
process.StartInfo.Arguments = $"-f lavfi -i nullsrc=d=1 -c:v {encoder} -t 1 -f null -";
305+
process.StartInfo.UseShellExecute = false;
306+
process.StartInfo.RedirectStandardOutput = true;
307+
process.StartInfo.CreateNoWindow = true;
308+
process.Start();
309+
310+
process.WaitForExit();
311+
312+
if (process.ExitCode == 0)
313+
{
314+
UnityEngine.Debug.Log($"Encoder {encoder} is available.");
315+
_functionalEncoder = encoder;
316+
317+
return encoder;
318+
}
319+
else
320+
{
321+
UnityEngine.Debug.Log($"Encoder {encoder} is not available.");
322+
}
323+
}
324+
325+
return encoders[encoders.Length - 1];
326+
}
327+
328+
// It returns the preferred encoder based on the available encoders in order of preference
329+
private static string[] FindAvailableEncoders()
280330
{
331+
List<string> encoders = new List<string>();
332+
281333
// Run ffmpeg to get the list of available encoders
282334
var process = new Process();
283335

284336
string ffmpegPath = GetFfmpegPath();
285337
if (ffmpegPath == null)
286338
{
287-
return "libx264";
339+
return encoders.ToArray();
288340
}
289341

290342
process.StartInfo.FileName = ffmpegPath;
@@ -300,21 +352,28 @@ private static string FindPreferredEncoder()
300352
// Check for specific hardware encoders in the output
301353
if (output.Contains("h264_nvenc"))
302354
{
303-
return "h264_nvenc";
355+
encoders.Add("h264_nvenc");
304356
}
305-
else if (output.Contains("h264_videotoolbox"))
357+
358+
if (output.Contains("h264_amf"))
306359
{
307-
return "h264_videotoolbox";
360+
encoders.Add("h264_amf");
308361
}
309-
else if (output.Contains("h264_vaapi"))
362+
363+
if (output.Contains("h264_videotoolbox"))
310364
{
311-
return "h264_vaapi";
365+
encoders.Add("h264_videotoolbox");
312366
}
313-
else
367+
368+
if (output.Contains("h264_vaapi"))
314369
{
315-
// Default to software encoding if no hardware encoder is found
316-
return "libx264";
370+
encoders.Add("h264_vaapi");
317371
}
372+
373+
// Always add libx264 as a fallback
374+
encoders.Add("libx264");
375+
376+
return encoders.ToArray();
318377
}
319378

320379
// It returns the fastest preset for the given encoder

0 commit comments

Comments
 (0)