145 lines
5.3 KiB
C#
145 lines
5.3 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using Vav1Player.Native;
|
|
|
|
namespace Vav1Player.Decoder
|
|
{
|
|
public class Dav1dDecoder : IDisposable
|
|
{
|
|
private IntPtr _context = IntPtr.Zero;
|
|
private bool _disposed = false;
|
|
|
|
public bool Initialize(int threads = 0)
|
|
{
|
|
if (_context != IntPtr.Zero)
|
|
return false;
|
|
|
|
try
|
|
{
|
|
// Initialize all fields to zero before calling dav1d_default_settings
|
|
var settings = new Dav1dSettings();
|
|
|
|
// Now call dav1d_default_settings to populate with library defaults
|
|
Dav1dNative.dav1d_default_settings(ref settings);
|
|
|
|
// Override with user-specified values
|
|
if (threads > 0)
|
|
{
|
|
settings.n_threads = Math.Min(threads, 256); // Cap at library maximum
|
|
}
|
|
else if (settings.n_threads <= 0)
|
|
{
|
|
settings.n_threads = Math.Min(Environment.ProcessorCount, 8); // Conservative default
|
|
}
|
|
|
|
settings.max_frame_delay = 1; // Low latency
|
|
|
|
System.Diagnostics.Debug.WriteLine($"Final settings - Threads: {settings.n_threads}, Frame Delay: {settings.max_frame_delay}");
|
|
System.Diagnostics.Debug.WriteLine(Dav1dSettingsValidator.GetSettingsSummary(settings));
|
|
|
|
int result = Dav1dNative.dav1d_open(out _context, ref settings);
|
|
|
|
if (result != 0)
|
|
{
|
|
string errorMsg = $"dav1d_open failed with error code: {result}\n" +
|
|
$"Description: {Dav1dErrorCodes.GetOpenErrorDescription(result)}\n" +
|
|
$"Suggestion: {Dav1dErrorCodes.GetTroubleshootingSuggestion(result)}\n" +
|
|
$"Recoverable: {Dav1dErrorCodes.IsRecoverable(result)}";
|
|
|
|
System.Diagnostics.Debug.WriteLine(errorMsg);
|
|
Console.WriteLine($"[DAV1D ERROR] {errorMsg}");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch (DllNotFoundException ex)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine($"dav1d.dll not found: {ex.Message}");
|
|
return false;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine($"Decoder initialization failed: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public unsafe bool DecodeFrame(byte[] data, out DecodedFrame? frame)
|
|
{
|
|
frame = null;
|
|
|
|
if (_context == IntPtr.Zero || data == null || data.Length == 0)
|
|
return false;
|
|
|
|
fixed (byte* dataPtr = data)
|
|
{
|
|
var dav1dData = new Dav1dData();
|
|
int result = Dav1dNative.dav1d_data_wrap(out dav1dData, (IntPtr)dataPtr, (nuint)data.Length, IntPtr.Zero, IntPtr.Zero);
|
|
if (result != 0)
|
|
return false;
|
|
|
|
result = Dav1dNative.dav1d_send_data(_context, ref dav1dData);
|
|
if (result != 0 && result != -11) // -11 is EAGAIN (need more data)
|
|
{
|
|
string errorMsg = $"[Dav1dDecoder] dav1d_send_data failed with error: {result}";
|
|
errorMsg += $"\n[Dav1dDecoder] Data size: {data.Length} bytes";
|
|
var hexData = string.Join(" ", data.Take(Math.Min(32, data.Length)).Select(b => b.ToString("X2")));
|
|
errorMsg += $"\n[Dav1dDecoder] Data prefix: {hexData}";
|
|
errorMsg += $"\n[Dav1dDecoder] Error details: {Dav1dErrorCodes.GetErrorDescription(result)}";
|
|
|
|
System.Diagnostics.Debug.WriteLine(errorMsg);
|
|
Console.WriteLine(errorMsg); // Also print to console so it shows in test output
|
|
|
|
Dav1dNative.dav1d_data_unref(ref dav1dData);
|
|
return false;
|
|
}
|
|
|
|
var picture = new Dav1dPicture();
|
|
result = Dav1dNative.dav1d_get_picture(_context, out picture);
|
|
if (result == 0)
|
|
{
|
|
frame = new DecodedFrame
|
|
{
|
|
Picture = picture,
|
|
Width = picture.p.w,
|
|
Height = picture.p.h,
|
|
PixelLayout = picture.p.layout,
|
|
BitDepth = picture.p.bpc
|
|
};
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
System.Diagnostics.Debug.WriteLine($"[Dav1dDecoder] dav1d_get_picture failed with error: {result}");
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (!_disposed && _context != IntPtr.Zero)
|
|
{
|
|
Dav1dNative.dav1d_close(ref _context);
|
|
_context = IntPtr.Zero;
|
|
_disposed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public struct DecodedFrame
|
|
{
|
|
public Dav1dPicture Picture;
|
|
public int Width;
|
|
public int Height;
|
|
public Dav1dPixelLayout PixelLayout;
|
|
public int BitDepth;
|
|
|
|
public void Release()
|
|
{
|
|
Dav1dNative.dav1d_picture_unref(ref Picture);
|
|
}
|
|
}
|
|
} |