502 lines
20 KiB
C#
502 lines
20 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
|
|
// VavCore Wrapper types - copied from VavCore.Wrapper for standalone testing
|
|
namespace VavCore.Wrapper
|
|
{
|
|
public enum DecoderType
|
|
{
|
|
AUTO = 0,
|
|
DAV1D = 1,
|
|
NVDEC = 2,
|
|
VPL = 3,
|
|
AMF = 4,
|
|
MEDIA_FOUNDATION = 5
|
|
}
|
|
|
|
public enum SurfaceType
|
|
{
|
|
None = 0,
|
|
Vulkan = 1,
|
|
OpenGL = 2,
|
|
D3D11 = 3,
|
|
Metal = 4
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct PerformanceMetrics
|
|
{
|
|
public float CurrentFPS;
|
|
public uint DroppedFrames;
|
|
public uint TotalFrames;
|
|
public float AverageDecodeTime;
|
|
}
|
|
|
|
public static class VavCore
|
|
{
|
|
private const string DllName = "VavCore-debug.dll";
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern IntPtr vavcore_get_version_string();
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern int vavcore_initialize();
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern void vavcore_cleanup();
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern IntPtr vavcore_create_player();
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern void vavcore_destroy_player(IntPtr player);
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern int vavcore_set_decoder_type(IntPtr player, DecoderType decoderType);
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern int vavcore_supports_surface_type(IntPtr player, SurfaceType surfaceType);
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern SurfaceType vavcore_get_optimal_surface_type(IntPtr player);
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern PerformanceMetrics vavcore_get_performance_metrics(IntPtr player);
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern int vavcore_open_file(IntPtr player, [MarshalAs(UnmanagedType.LPStr)] string filePath);
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern void vavcore_close_file(IntPtr player);
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern int vavcore_is_open(IntPtr player);
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct VavCoreVideoFrame
|
|
{
|
|
// Legacy CPU fields
|
|
public IntPtr y_plane; // uint8_t*
|
|
public IntPtr u_plane; // uint8_t*
|
|
public IntPtr v_plane; // uint8_t*
|
|
|
|
public int y_stride; // int
|
|
public int u_stride; // int
|
|
public int v_stride; // int
|
|
|
|
// Frame metadata
|
|
public int width; // int
|
|
public int height; // int
|
|
|
|
public ulong timestamp_us; // uint64_t
|
|
public ulong frame_number; // uint64_t
|
|
|
|
// Surface type
|
|
public SurfaceType surface_type; // VavCoreSurfaceType
|
|
|
|
// Union - mapped as fixed-size byte array (largest union member is ~64 bytes)
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
|
|
public byte[] surface_data; // Union data for all surface types
|
|
}
|
|
|
|
// Helper structures for accessing union data safely
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct D3D11SurfaceData
|
|
{
|
|
public IntPtr d3d11_texture; // ID3D11Texture2D*
|
|
public IntPtr d3d11_device; // ID3D11Device*
|
|
public uint subresource_index;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct VulkanSurfaceData
|
|
{
|
|
public IntPtr vk_image; // VkImage
|
|
public IntPtr vk_device; // VkDevice
|
|
public IntPtr vk_device_memory; // VkDeviceMemory
|
|
public uint memory_offset;
|
|
}
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct OpenGLSurfaceData
|
|
{
|
|
public uint texture_id; // GLuint
|
|
public uint target; // GL_TEXTURE_2D
|
|
public IntPtr gl_context; // OpenGL context
|
|
}
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern int vavcore_decode_next_frame(IntPtr player, ref VavCoreVideoFrame frame);
|
|
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
public struct VideoMetadata
|
|
{
|
|
public int width;
|
|
public int height;
|
|
public double frame_rate;
|
|
public double duration_seconds;
|
|
public ulong total_frames;
|
|
public IntPtr codec_name; // const char*
|
|
}
|
|
|
|
[DllImport(DllName, CallingConvention = CallingConvention.Cdecl)]
|
|
private static extern int vavcore_get_metadata(IntPtr player, ref VideoMetadata metadata);
|
|
|
|
public static string GetVersion()
|
|
{
|
|
IntPtr ptr = vavcore_get_version_string();
|
|
return Marshal.PtrToStringAnsi(ptr) ?? "Unknown";
|
|
}
|
|
|
|
public static bool Initialize()
|
|
{
|
|
return vavcore_initialize() == 0;
|
|
}
|
|
|
|
public static void Cleanup()
|
|
{
|
|
vavcore_cleanup();
|
|
}
|
|
|
|
public static IntPtr CreatePlayer()
|
|
{
|
|
return vavcore_create_player();
|
|
}
|
|
|
|
public static void DestroyPlayer(IntPtr player)
|
|
{
|
|
vavcore_destroy_player(player);
|
|
}
|
|
|
|
public static bool SetDecoderType(IntPtr player, DecoderType decoderType)
|
|
{
|
|
return vavcore_set_decoder_type(player, decoderType) == 0;
|
|
}
|
|
|
|
public static bool SupportsSurfaceType(IntPtr player, SurfaceType surfaceType)
|
|
{
|
|
return vavcore_supports_surface_type(player, surfaceType) != 0;
|
|
}
|
|
|
|
public static SurfaceType GetOptimalSurfaceType(IntPtr player)
|
|
{
|
|
return vavcore_get_optimal_surface_type(player);
|
|
}
|
|
|
|
public static PerformanceMetrics GetPerformanceMetrics(IntPtr player)
|
|
{
|
|
return vavcore_get_performance_metrics(player);
|
|
}
|
|
|
|
public static bool OpenFile(IntPtr player, string filePath)
|
|
{
|
|
return vavcore_open_file(player, filePath) == 0;
|
|
}
|
|
|
|
public static void CloseFile(IntPtr player)
|
|
{
|
|
vavcore_close_file(player);
|
|
}
|
|
|
|
public static bool IsOpen(IntPtr player)
|
|
{
|
|
return vavcore_is_open(player) != 0;
|
|
}
|
|
|
|
public static bool DecodeNextFrame(IntPtr player, ref VavCoreVideoFrame frame)
|
|
{
|
|
return vavcore_decode_next_frame(player, ref frame) == 0;
|
|
}
|
|
|
|
// Helper method to create a properly initialized VavCoreVideoFrame
|
|
public static VavCoreVideoFrame CreateVideoFrame()
|
|
{
|
|
return new VavCoreVideoFrame
|
|
{
|
|
y_plane = IntPtr.Zero,
|
|
u_plane = IntPtr.Zero,
|
|
v_plane = IntPtr.Zero,
|
|
y_stride = 0,
|
|
u_stride = 0,
|
|
v_stride = 0,
|
|
width = 0,
|
|
height = 0,
|
|
timestamp_us = 0,
|
|
frame_number = 0,
|
|
surface_type = SurfaceType.None,
|
|
surface_data = new byte[64] // Initialize the union data array
|
|
};
|
|
}
|
|
|
|
// Helper method to extract D3D11 surface data from union
|
|
public static D3D11SurfaceData GetD3D11SurfaceData(VavCoreVideoFrame frame)
|
|
{
|
|
if (frame.surface_type != SurfaceType.D3D11 || frame.surface_data == null)
|
|
return new D3D11SurfaceData();
|
|
|
|
unsafe
|
|
{
|
|
fixed (byte* ptr = frame.surface_data)
|
|
{
|
|
return *(D3D11SurfaceData*)ptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper method to extract Vulkan surface data from union
|
|
public static VulkanSurfaceData GetVulkanSurfaceData(VavCoreVideoFrame frame)
|
|
{
|
|
if (frame.surface_type != SurfaceType.Vulkan || frame.surface_data == null)
|
|
return new VulkanSurfaceData();
|
|
|
|
unsafe
|
|
{
|
|
fixed (byte* ptr = frame.surface_data)
|
|
{
|
|
return *(VulkanSurfaceData*)ptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Helper method to extract OpenGL surface data from union
|
|
public static OpenGLSurfaceData GetOpenGLSurfaceData(VavCoreVideoFrame frame)
|
|
{
|
|
if (frame.surface_type != SurfaceType.OpenGL || frame.surface_data == null)
|
|
return new OpenGLSurfaceData();
|
|
|
|
unsafe
|
|
{
|
|
fixed (byte* ptr = frame.surface_data)
|
|
{
|
|
return *(OpenGLSurfaceData*)ptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static VideoMetadata GetMetadata(IntPtr player)
|
|
{
|
|
var metadata = new VideoMetadata();
|
|
int result = vavcore_get_metadata(player, ref metadata);
|
|
if (result != 0)
|
|
{
|
|
throw new InvalidOperationException($"Failed to get metadata, error code: {result}");
|
|
}
|
|
return metadata;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Simple console test to verify VavCore DLL connection
|
|
class TestVavCoreDLL
|
|
{
|
|
static void Main(string[] args)
|
|
{
|
|
Console.WriteLine("VavCore DLL Connection Test");
|
|
Console.WriteLine("===========================");
|
|
|
|
try
|
|
{
|
|
// Set DLL directory to help find the VavCore DLL
|
|
string dllPath = @"D:\Project\video-av1\vav2\godot_extension\libs\windows-x86_64";
|
|
Environment.SetEnvironmentVariable("PATH", dllPath + ";" + Environment.GetEnvironmentVariable("PATH"));
|
|
|
|
Console.WriteLine($"Looking for VavCore DLL in: {dllPath}");
|
|
|
|
// Test VavCore DLL connection
|
|
Console.WriteLine("Testing VavCore DLL connection...");
|
|
|
|
// Get version string
|
|
var version = VavCore.Wrapper.VavCore.GetVersion();
|
|
Console.WriteLine($"VavCore version: {version}");
|
|
|
|
// Initialize VavCore
|
|
Console.WriteLine("Initializing VavCore...");
|
|
bool initSuccess = VavCore.Wrapper.VavCore.Initialize();
|
|
Console.WriteLine($"VavCore initialization: {(initSuccess ? "SUCCESS" : "FAILED")}");
|
|
|
|
if (initSuccess)
|
|
{
|
|
// Test player creation
|
|
Console.WriteLine("Creating VavCore player...");
|
|
var player = VavCore.Wrapper.VavCore.CreatePlayer();
|
|
Console.WriteLine($"Player creation: {(player != IntPtr.Zero ? "SUCCESS" : "FAILED")}");
|
|
|
|
if (player != IntPtr.Zero)
|
|
{
|
|
// Test decoder type setting
|
|
Console.WriteLine("Setting decoder type to AUTO...");
|
|
bool setDecoderSuccess = VavCore.Wrapper.VavCore.SetDecoderType(player, VavCore.Wrapper.DecoderType.AUTO);
|
|
Console.WriteLine($"Set decoder type: {(setDecoderSuccess ? "SUCCESS" : "FAILED")}");
|
|
|
|
// Test surface type support
|
|
Console.WriteLine("Checking Vulkan surface support...");
|
|
bool vulkanSupported = VavCore.Wrapper.VavCore.SupportsSurfaceType(player, VavCore.Wrapper.SurfaceType.Vulkan);
|
|
Console.WriteLine($"Vulkan surface support: {(vulkanSupported ? "SUPPORTED" : "NOT SUPPORTED")}");
|
|
|
|
Console.WriteLine("Checking D3D11 surface support...");
|
|
bool d3d11Supported = VavCore.Wrapper.VavCore.SupportsSurfaceType(player, VavCore.Wrapper.SurfaceType.D3D11);
|
|
Console.WriteLine($"D3D11 surface support: {(d3d11Supported ? "SUPPORTED" : "NOT SUPPORTED")}");
|
|
|
|
// Get optimal surface type
|
|
Console.WriteLine("Getting optimal surface type...");
|
|
var optimalSurface = VavCore.Wrapper.VavCore.GetOptimalSurfaceType(player);
|
|
Console.WriteLine($"Optimal surface type: {optimalSurface}");
|
|
|
|
// Test performance metrics
|
|
Console.WriteLine("Getting performance metrics...");
|
|
var metrics = VavCore.Wrapper.VavCore.GetPerformanceMetrics(player);
|
|
Console.WriteLine($"Performance metrics - FPS: {metrics.CurrentFPS:F2}, Dropped: {metrics.DroppedFrames}");
|
|
|
|
// Keep the player for video decoding test
|
|
Console.WriteLine("Keeping player for video decoding test...");
|
|
}
|
|
|
|
Console.WriteLine("\n=== VavCore DLL Connection Test COMPLETED SUCCESSFULLY ===");
|
|
|
|
// Now test actual AV1 video file decoding using the same player
|
|
Console.WriteLine("\n" + new string('=', 50));
|
|
Console.WriteLine("TESTING REAL AV1 VIDEO FILE DECODING");
|
|
Console.WriteLine(new string('=', 50));
|
|
|
|
TestAV1VideoDecoding(player);
|
|
|
|
// Clean up player after all tests
|
|
Console.WriteLine("Destroying player...");
|
|
VavCore.Wrapper.VavCore.DestroyPlayer(player);
|
|
Console.WriteLine("Player destroyed");
|
|
}
|
|
|
|
// Clean up VavCore
|
|
Console.WriteLine("Cleaning up VavCore...");
|
|
VavCore.Wrapper.VavCore.Cleanup();
|
|
Console.WriteLine("VavCore cleanup completed");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"\n=== VavCore DLL Connection Test FAILED ===");
|
|
Console.WriteLine($"Error: {ex.Message}");
|
|
Console.WriteLine($"Stack trace: {ex.StackTrace}");
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine("\nPress any key to exit...");
|
|
Console.ReadKey();
|
|
}
|
|
|
|
static void TestAV1VideoDecoding(IntPtr player)
|
|
{
|
|
try
|
|
{
|
|
// Test with available AV1 video files
|
|
string[] testFiles = {
|
|
@"D:\Project\video-av1\sample\simple_test.webm",
|
|
@"D:\Project\video-av1\sample\output.webm"
|
|
};
|
|
|
|
foreach (string testFile in testFiles)
|
|
{
|
|
Console.WriteLine($"\nTesting video file: {System.IO.Path.GetFileName(testFile)}");
|
|
|
|
if (!System.IO.File.Exists(testFile))
|
|
{
|
|
Console.WriteLine($"File not found: {testFile}");
|
|
continue;
|
|
}
|
|
|
|
// Try to open the video file
|
|
Console.WriteLine("Opening video file...");
|
|
bool openSuccess = VavCore.Wrapper.VavCore.OpenFile(player, testFile);
|
|
Console.WriteLine($"File open: {(openSuccess ? "SUCCESS" : "FAILED")}");
|
|
|
|
if (openSuccess)
|
|
{
|
|
// Check if file is properly opened
|
|
bool isOpen = VavCore.Wrapper.VavCore.IsOpen(player);
|
|
Console.WriteLine($"File is open: {isOpen}");
|
|
|
|
if (isOpen)
|
|
{
|
|
try
|
|
{
|
|
// Get video metadata
|
|
Console.WriteLine("Getting video metadata...");
|
|
var metadata = VavCore.Wrapper.VavCore.GetMetadata(player);
|
|
Console.WriteLine($"Video dimensions: {metadata.width}x{metadata.height}");
|
|
Console.WriteLine($"Framerate: {metadata.frame_rate:F2} fps");
|
|
Console.WriteLine($"Duration: {metadata.duration_seconds:F2} seconds");
|
|
Console.WriteLine($"Total frames: {metadata.total_frames}");
|
|
|
|
string codecName = metadata.codec_name != IntPtr.Zero
|
|
? Marshal.PtrToStringAnsi(metadata.codec_name) ?? "Unknown"
|
|
: "Unknown";
|
|
Console.WriteLine($"Codec: {codecName}");
|
|
|
|
// Try to decode a few frames with the proper VideoFrame structure
|
|
Console.WriteLine("Testing frame decoding...");
|
|
try
|
|
{
|
|
for (int frameIndex = 0; frameIndex < 3; frameIndex++)
|
|
{
|
|
var frame = VavCore.Wrapper.VavCore.CreateVideoFrame();
|
|
bool decodeSuccess = VavCore.Wrapper.VavCore.DecodeNextFrame(player, ref frame);
|
|
|
|
if (decodeSuccess)
|
|
{
|
|
Console.WriteLine($"Frame {frameIndex + 1}: {frame.width}x{frame.height}, " +
|
|
$"timestamp: {frame.timestamp_us}us, " +
|
|
$"surface_type: {frame.surface_type}");
|
|
|
|
// Check CPU plane data availability
|
|
if (frame.surface_type == VavCore.Wrapper.SurfaceType.None &&
|
|
frame.y_plane != IntPtr.Zero)
|
|
{
|
|
Console.WriteLine($" CPU YUV data - Y stride: {frame.y_stride}, " +
|
|
$"U stride: {frame.u_stride}, V stride: {frame.v_stride}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Frame {frameIndex + 1}: Decode failed");
|
|
break;
|
|
}
|
|
}
|
|
Console.WriteLine("Frame decoding test completed successfully");
|
|
}
|
|
catch (Exception decodeEx)
|
|
{
|
|
Console.WriteLine($"Frame decoding error: {decodeEx.Message}");
|
|
}
|
|
|
|
// Get updated performance metrics
|
|
Console.WriteLine("Getting updated performance metrics...");
|
|
var metrics = VavCore.Wrapper.VavCore.GetPerformanceMetrics(player);
|
|
Console.WriteLine($"Performance metrics - FPS: {metrics.CurrentFPS:F2}, Dropped: {metrics.DroppedFrames}, Total: {metrics.TotalFrames}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"Error during video processing: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
// Close the file
|
|
Console.WriteLine("Closing video file...");
|
|
VavCore.Wrapper.VavCore.CloseFile(player);
|
|
|
|
bool isStillOpen = VavCore.Wrapper.VavCore.IsOpen(player);
|
|
Console.WriteLine($"File closed successfully: {!isStillOpen}");
|
|
}
|
|
|
|
Console.WriteLine($"Completed test for: {System.IO.Path.GetFileName(testFile)}");
|
|
Console.WriteLine(new string('-', 40));
|
|
}
|
|
|
|
Console.WriteLine("\n=== AV1 Video Decoding Test COMPLETED ===");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"\n=== AV1 Video Decoding Test FAILED ===");
|
|
Console.WriteLine($"Error: {ex.Message}");
|
|
Console.WriteLine($"Stack trace: {ex.StackTrace}");
|
|
}
|
|
}
|
|
} |