#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(); }