smourier / DirectN

Direct interop Code for .NET Framework, .NET Core and .NET 5+ : DXGI, WIC, DirectX 9 to 12, Direct2D, Direct Write, Direct Composition, Media Foundation, WASAPI, CodecAPI, GDI, Spatial Audio, DVD, Windows Media Player, UWP DXInterop, WinUI3, etc.
MIT License
311 stars 28 forks source link

Various problems... #25

Closed Steph55 closed 2 years ago

Steph55 commented 2 years ago

Thank you for your last correction! I was able to progress in my test of DirectN.

1) Now it seems that DMOs are missing, like this one, for instance:

CColorConvertDMO (CLSID_CColorConvertDMO)

2) Guids are missing like: CODECAPI_AVEncCommonQuality

3) This enum of DirectN is far from user friendly:

public enum __MIDL___MIDL_itf_mfreadwrite_0000_0001_0001 { MF_SOURCE_READER_INVALID_STREAM_INDEX = -1, MF_SOURCE_READER_ALL_STREAMS = -2, MF_SOURCE_READER_ANY_STREAM = -2, MF_SOURCE_READER_FIRST_AUDIO_STREAM = -3, MF_SOURCE_READER_FIRST_VIDEO_STREAM = -4, MF_SOURCE_READER_MEDIASOURCE = -1, }

4) When I call the following function with valid parameters:

Functions.MFGetAttributeRatio(pType, MFConstants.MF_MT_FRAME_RATE_RANGE_MAX, out uint frameRateNum, out uint frameRateDem).ThrowOnError();

I get the error:

System.EntryPointNotFoundException : 'Unable to find an entry point named 'MFGetAttributeRatio' in DLL 'mfplat'.'

5) Also, in order to replace the C++ function __uuidof, I wrote the following, because I did not find how in DirectN. You can include it, if needed:

public Guid __uuidof<T>() { var attribs = Attribute.GetCustomAttributes(typeof(T), typeof(GuidAttribute)); foreach (GuidAttribute attrib in attribs) { if (attrib.GetType() == typeof(GuidAttribute)) return new Guid(attrib.Value); } return new Guid(); }

smourier commented 2 years ago

Hi,

  1. Yes, not all guids are declared in DirectN. You get get all guid values from headers or from this online tool here: https://www.magnumdb.com

  2. Same for this: https://www.magnumdb.com/search?q=*AVEncCommonQuality

  3. This depends on how they are declared in the original header files. And actually, this is how it's declared in Windows Kits\10\Include\10.0.22000.0\um\mfreadwrite.h:

enum __MIDL___MIDL_itf_mfreadwrite_0000_0001_0001
{
    MF_SOURCE_READER_INVALID_STREAM_INDEX   = 0xffffffff,
    MF_SOURCE_READER_ALL_STREAMS    = 0xfffffffe,
    MF_SOURCE_READER_ANY_STREAM = 0xfffffffe,
    MF_SOURCE_READER_FIRST_AUDIO_STREAM = 0xfffffffd,
    MF_SOURCE_READER_FIRST_VIDEO_STREAM = 0xfffffffc,
    MF_SOURCE_READER_MEDIASOURCE    = 0xffffffff
} ;
  1. The generator kinda guess where functions are defined, but there's unfortunately no magic here. In fact this one is not a function exported from a DLL, it's a native utility function implemented directly in the header, so I've updated Functions.cs to remove it. Here is its corresponding native code in Windows Kits\10\Include\10.0.22000.0\um\mfapi.h, it can be easily adapted to C#:
MFGetAttributeRatio(
    IMFAttributes*  pAttributes,
    REFGUID         guidKey,
    _Out_ UINT32*   punNumerator,
    _Out_ UINT32*   punDenominator
    )
{
    return MFGetAttribute2UINT32asUINT64(pAttributes, guidKey, punNumerator, punDenominator);
}

MFGetAttribute2UINT32asUINT64(
    IMFAttributes*  pAttributes,
    REFGUID         guidKey,
    _Out_ UINT32*   punHigh32,
    _Out_ UINT32*   punLow32
    )
{
    UINT64 unPacked;
    HRESULT hr = S_OK;

    hr = pAttributes->GetUINT64(guidKey, &unPacked);
    if (FAILED(hr)) {
        return hr;
    }
    Unpack2UINT32AsUINT64(unPacked, punHigh32, punLow32);

    return hr;
}

Unpack2UINT32AsUINT64(UINT64 unPacked, _Out_ UINT32* punHigh, _Out_ UINT32* punLow)
{
    *punHigh = HI32(unPacked);
    *punLow = LO32(unPacked);
}

HI32(UINT64 unPacked)
{
    return (UINT32)(unPacked >> 32);
}

LO32(UINT64 unPacked)
{
    return (UINT32)unPacked;
}
  1. This is not needed, in C#, typeof(AnyType).Guid will give you an interface guid.
Steph55 commented 2 years ago

Thank you very much for your answer, it is much useful! You are quite generous. Now I still have a few other things.

1) A little correction for the future version of DirectN: The following seems to be the proper signature for SetCurrentMediaType of IMFSourceReader for it to work :

[PreserveSig]
HRESULT SetCurrentMediaType(/* [annotation][in] _In_ */ uint dwStreamIndex, /* [annotation][out][in] _Reserved_ */ IntPtr pdwReserved, /* [annotation][in] _In_ */ IMFMediaType pMediaType);

When we call it, we need to pass IntPtr.Zero as the second parameter.

2) I'm having trouble with the codecApi->GetValue() and codecApi->SetValue() functions. I did not find any helper function in DirectN for the Variant type.

I saw on the following page that you already studied the subject: https://stackoverflow.com/questions/49323410/com-interop-and-marshaling-of-variantvt-ptr

Did you do something for this in DirectN, maybe I did not find it?

smourier commented 2 years ago

Hi,

  1. true. This is a bug in the .h declaration of SetCurrentMediaType in the Windows SDK. The annotation specifies it as [out][in], not optional, so the generator doesn't generate an IntPtr where it should... I've fixed the .cs.

  2. VARIANTs are normally handled by .NET (this is not the case with PROPVARIANTs). The SO post is very specific as the VARIANT used there was an invalid one.

You can use GetObjectForNativeVariant to convert from IntPtr into an object and the opposite: GetNativeVariantForObject

Steph55 commented 2 years ago

Thank you Simon!

However, it appears that it is not simple to deal with the variant variables, when I read the following three-part article: Using VARIANTs in Managed Code Part 1 | limbioliong (wordpress.com) https://limbioliong.wordpress.com/2011/09/04/using-variants-in-managed-code-part-1/

Le mar. 7 déc. 2021 à 14:38, Simon Mourier @.***> a écrit :

Hi,

1.

true. This is a bug in the .h declaration of SetCurrentMediaType in the Windows SDK. The annotation specifies it as [out][in], not optional, so the generator doesn't generate an IntPtr where it should... I've fixed the .cs. 2.

VARIANTs are normally handled by the .NET (this is not the case with PROPVARIANTs). The SO post is very specific as the VARIANT used there was an invalid one.

You can use GetObjectForNativeVariant https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.getobjectfornativevariant to convert from IntPtr into an object and the opposite: GetNativeVariantForObject

https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.getobjectfornativevariant

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/smourier/DirectN/issues/25#issuecomment-988212498, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADJJUEHP6SLFVRYTWOE6E53UPZPERANCNFSM5JKD3EKA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

smourier commented 2 years ago

From .NET this is fairly simple, just use the functions and ask again if you face any real issue.

Steph55 commented 2 years ago

Here is the code I'm trying to use:

           var codecApi = pWriter.GetServiceForStream<ICodecAPI>(writerVideoStreamIndex, new Guid(), typeof(ICodecAPI).GUID);
            if (codecApi != null)
            {
                codecApi.Object.GetValue(CODECAPI_AVEncCommonQuality, out IntPtr intPtrQualité);
                var o = Marshal.GetObjectForNativeVariant(intPtrQualité);

But the value I get for intPtrQualité is 0x0000000000000013 and I get an execution Engine Exception...

smourier commented 2 years ago

That may be an issue with ICodecAPI definition, the most simple way is to redefine it like this:

    ...
    [PreserveSig]
    HRESULT GetValue(/* [in] */ [MarshalAs(UnmanagedType.LPStruct)] Guid Api, /* [annotation][out] _Out_ */ out object Value);

    ...
    [PreserveSig]
    HRESULT SetValue(/* [in] */ [MarshalAs(UnmanagedType.LPStruct)] Guid Api, /* [annotation][in] _In_ */ ref object Value);
smourier commented 2 years ago

Closing due to inactivity