wpfdirectxms-media-foundationsharpdxdxva

Unexpected result in DXVA GetDecoderDeviceGuids SharpDX.MediaFoundation


I am new to DirectX and currently working on a project where I need to retrieve the DXVA (DirectX Video Acceleration) decoder GUIDs using the VideoDecoderService class from the SharpDX.MediaFoundation.DirectX library. My primary goal is to list the decoders and log the information into a log file for further analysis.

Issue: While attempting to retrieve DXVA decoder GUIDs, I've encountered an issue where the count variable is reported f.e. as 42, but the guids array is effectively empty guids, except for the guid at the first index which has always filled just the first part of the guid, others part of the guid are empty (zeros).

Examples of Observed GUIDs I got:

when I run again I got quite different result:

So the first part of the first guid in array is different, others guids in array are empty always.

Can somebody help me understand why the guids array is empty, except for the GUID at the first index while the count output aims that there are much more decoder's guid than one?

full code sample:

using System;
using System.Windows;
using SharpDX.Direct3D9;
using SharpDX.MediaFoundation;
using SharpDX.MediaFoundation.DirectX;

namespace ListDecoders
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // Initialize Media Foundation
            MediaManager.Startup();

            try
            {
                // Create a Direct3D device
                using (var d3dDevice = new Device(new Direct3D(), 0, SharpDX.Direct3D9.DeviceType.Hardware, IntPtr.Zero, CreateFlags.SoftwareVertexProcessing | CreateFlags.Multithreaded | CreateFlags.FpuPreserve, new PresentParameters
                {
                    Windowed = true,
                    BackBufferWidth = 640,
                    BackBufferHeight = 480,
                    BackBufferFormat = Format.Unknown, // or specify a format
                    SwapEffect = SwapEffect.Discard,
                    PresentFlags = PresentFlags.Video
                }))
                {
                    // Create the VideoDecoderService with the Direct3D device
                    using (var videoDecoderService = new VideoDecoderService(d3dDevice))
                    {
                        // Get the DXVA decoder GUIDs
                        var guids = GetDecoderDeviceGuids(videoDecoderService);

                        // Output the GUIDs
                        foreach (var guid in guids)
                        {
                            Console.WriteLine(guid);
                        }
                    }
                }
            }
            finally
            {
                // Shutdown Media Foundation
                MediaManager.Shutdown();
            }
        }

        static Guid[] GetDecoderDeviceGuids(VideoDecoderService videoDecoderService)
        {
            var guids = new Guid[100]; // Adjust the array size as needed
            videoDecoderService.GetDecoderDeviceGuids(out int count, guids);

            // Trim the array to the actual count
            Array.Resize(ref guids, count);

            return guids;
        }
    }
}

Thanks for your help.


Solution

  • SharpDX seems to have a bug here. What you can do is use the underlying native IDirectXVideoDecoderService interface directly, like this:

    static Guid[] GetDecoderDeviceGuids(VideoDecoderService videoDecoderService)
    {
        var svc = (IDirectXVideoDecoderService)Marshal.GetObjectForIUnknown(videoDecoderService.NativePointer);
        svc.GetDecoderDeviceGuids(out var count, out var guids);
        return guids;
    }
    
    [ComImport, Guid("fc51a551-d5e7-11d9-af55-00054e43ff02"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    private interface IDirectXVideoDecoderService
    {
        void CreateSurface(); // unused, not fully defined
        void GetDecoderDeviceGuids(out int count, [Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] out Guid[] pGuids);
        // we don't need the rest
    }
    

    PS: if you're new to DirectX, you should use DirectX11 or DirectX12 instead of DirectX9, and SharpDX is now deprecated.

    Here is how to do the same thing with DirectX11 (and SharpDX):

    // adapt creation parameters to your needs
    var device = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware).QueryInterface<SharpDX.Direct3D11.VideoDevice>();
    for (var i = 0; i < device.VideoDecoderProfileCount; i++)
    {
        device.GetVideoDecoderProfile(i, out var guid);
    }