using Sdcb.FFmpeg.Raw;
using Sdcb.FFmpeg.Swscales;
using Sdcb.FFmpeg.Utils;
namespace T3.VideoServices;
///
/// Converts a software-decoded planar YUV frame to packed RGBA on the CPU via swscale — RGBA8 for SDR,
/// RGBA16 (Rgba64le) for HDR/10-bit. The result is uploaded to a GPU texture by the caller. The
/// hardware-decode path instead converts NV12 on the GPU (no CPU round-trip); this is the software fallback.
/// Owned by a single decode worker; the destination frame is reused across calls.
///
public sealed class SoftwareFrameConverter : IDisposable
{
/// Packed output pixel format: Rgba (SDR) or Rgba64le (HDR).
public AVPixelFormat OutputFormat { get; }
public int BytesPerPixel { get; }
public SoftwareFrameConverter(bool hdr)
{
OutputFormat = hdr ? AVPixelFormat.Rgba64le : AVPixelFormat.Rgba;
BytesPerPixel = hdr ? 8 : 4;
}
///
/// Converts into a reused packed-RGBA frame and returns it (valid until the
/// next call). Read pixels via Data[0]/Linesize[0] or ToImageBuffer.
///
public Frame Convert(Frame source)
{
if (_destination == null || _width != source.Width || _height != source.Height)
{
_destination?.Dispose();
_width = source.Width;
_height = source.Height;
_destination = Frame.CreateVideo(_width, _height, OutputFormat);
_destination.EnsureBuffer(1);
}
_converter.ConvertFrame(source, _destination, SWS.Bilinear);
return _destination;
}
public void Dispose()
{
_destination?.Dispose();
_converter.Free();
}
private readonly VideoFrameConverter _converter = new();
private Frame? _destination;
private int _width;
private int _height;
}