#nullable enable
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using T3.Core.Logging;
using T3.Core.Model;
using T3.Core.Video;
namespace T3.Editor.Gui.Windows.RenderExport;
///
/// Resolves — off the UI thread — how the FFmpeg encoder will serve each on this
/// machine (hardware vs. in-process software), so the render window can show an inline indicator without stalling a
/// draw frame on the one-shot hardware-encoder probe (a GPU-encoder open). Results are cached for the session.
///
internal static class VideoEncoderAvailabilityCache
{
/// The cached availability for , or null while it is still being probed.
public static VideoEncoderAvailability? Get(VideoExportCodec codec)
{
if (_results.TryGetValue(codec, out var result))
return result;
// First request for this codec: kick the probe onto a background thread exactly once.
if (_pending.TryAdd(codec, true))
Task.Run(() => Probe(codec));
return null;
}
/// Resolves availability synchronously, using the cache. For the export decision (off the UI thread,
/// where a one-time blocking probe is acceptable); the UI uses to avoid stalling a frame.
public static VideoEncoderAvailability GetBlocking(VideoExportCodec codec)
{
if (_results.TryGetValue(codec, out var result))
return result;
var resolved = Resolve(codec);
_results[codec] = resolved;
return resolved;
}
private static void Probe(VideoExportCodec codec)
{
_results[codec] = Resolve(codec);
_pending.TryRemove(codec, out _);
}
private static VideoEncoderAvailability Resolve(VideoExportCodec codec)
{
try
{
var factory = VideoExport.Factory;
if (factory == null)
{
// Same eager-registration nudge the export path uses: the Video package's [ModuleInitializer]
// may not have run yet in a project that never touched a video operator.
foreach (var package in SymbolPackage.AllPackages)
package.AssemblyInformation.RunModuleInitializers();
factory = VideoExport.Factory;
}
return factory?.GetAvailability(codec) ?? new VideoEncoderAvailability { Kind = VideoEncoderKind.Unavailable };
}
catch (Exception e)
{
Log.Warning("Failed to probe video encoder availability: " + e.Message);
return new VideoEncoderAvailability { Kind = VideoEncoderKind.Unavailable };
}
}
private static readonly ConcurrentDictionary _results = new();
private static readonly ConcurrentDictionary _pending = new();
}