using DirectShowLib;
using System;
using System.Runtime.InteropServices;
using System.Security;
using WPFMediaKit.DirectShow.MediaPlayers;
using WPFMediaKit.MediaFoundation.Interop;
namespace WPFMediaKit.MediaFoundation;
#region Custom COM Types
/*
[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
Guid("00000001-0000-0000-C000-000000000046"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IClassFactory
{
[PreserveSig]
int CreateInstance([In, MarshalAs(UnmanagedType.Interface)] object pUnkOuter,
ref Guid riid,
[Out, MarshalAs(UnmanagedType.Interface)] out object obj);
[PreserveSig]
int LockServer([In] bool fLock);
}
*/
[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
Guid("B92D8991-6C42-4e51-B942-E61CB8696FCB"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IEVRPresenterCallback
{
[PreserveSig]
int PresentSurfaceCB(IntPtr pSurface);
}
[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
Guid("9019EA9C-F1B4-44b5-ADD5-D25704313E48"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IEVRPresenterRegisterCallback
{
[PreserveSig]
int RegisterCallback(IEVRPresenterCallback pCallback);
}
[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity,
Guid("4527B2E7-49BE-4b61-A19D-429066D93A99"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IEVRPresenterSettings
{
[PreserveSig]
int SetBufferCount(int count);
[PreserveSig]
int GetBufferCount(out int count); // Added
[PreserveSig]
int RegisterCallback(IEVRPresenterCallback pCallback); // Added
}
#endregion Custom COM Types
[ComVisible(true)]
public class EvrPresenter : ICustomAllocator, IEVRPresenterCallback
{
private const int PRESENTER_BUFFER_COUNT = 5;
private IntPtr m_lastSurface;
private IMFVideoPresenter m_VideoPresenter;
private EvrPresenter()
{
}
~EvrPresenter()
{
Dispose(false);
}
#region Interop
///
/// The GUID of our EVR custom presenter COM object
///
private static readonly Guid EVR_PRESENTER_CLSID = new Guid(0x9807fc9c, 0x807b, 0x41e3, 0x98, 0xa8, 0x75, 0x17,
0x6f, 0x95, 0xa0, 0x63);
/*
///
/// The GUID of IUnknown
///
private static readonly Guid IUNKNOWN_GUID = new Guid("{00000000-0000-0000-C000-000000000046}");
///
/// Static method in the 32 bit dll to create our IClassFactory
///
[PreserveSig]
[DllImport("EvrPresenter32.dll", EntryPoint = "DllGetClassObject")]
private static extern int DllGetClassObject32([MarshalAs(UnmanagedType.LPStruct)] Guid clsid,
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
///
/// Static method in the 62 bit dll to create our IClassFactory
///
[PreserveSig]
[DllImport("EvrPresenter64.dll", EntryPoint = "DllGetClassObject")]
private static extern int DllGetClassObject64([MarshalAs(UnmanagedType.LPStruct)] Guid clsid,
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
[MarshalAs(UnmanagedType.IUnknown)] out object ppv);
*/
#endregion Interop
/*
///
/// Returns the bittage of this process, ie 32 or 64 bit
///
private static int ProcessBits
{
get { return IntPtr.Size * 8; }
}
*/
///
/// The custom EVR video presenter COM object
///
public IMFVideoPresenter VideoPresenter
{
get { return m_VideoPresenter; }
private set { m_VideoPresenter = value; }
}
#region ICustomAllocator Members
///
/// Invokes when a new frame has been allocated
/// to a surface
///
public event Action NewAllocatorFrame;
///
/// Invokes when a new surface has been allocated
///
public event NewAllocatorSurfaceDelegate NewAllocatorSurface;
#region IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool dispose)
{
if (dispose)
{
var settings = m_VideoPresenter as IEVRPresenterSettings;
if (settings != null)
settings.RegisterCallback(null);
}
COMUtil.TryFinalRelease(ref m_VideoPresenter);
}
public void Stop()
{
var settings = m_VideoPresenter as IEVRPresenterSettings;
if (settings != null)
settings.RegisterCallback(null);
}
#endregion IDisposable
#endregion ICustomAllocator Members
#region IEVRPresenterCallback Members
///
/// Called by the custom EVR Presenter, notifying that
/// there is a new D3D surface and/or there needs to be
/// a frame rendered
///
/// The Direct3D surface
/// A HRESULT
public int PresentSurfaceCB(IntPtr pSurface)
{
/* Check if the surface is the same as the last*/
if (m_lastSurface != pSurface)
InvokeNewAllocatorSurface(pSurface);
/* Store ref to the pointer so we can compare
* it next time this method is called */
m_lastSurface = pSurface;
InvokeNewAllocatorFrame();
return 0;
}
#endregion IEVRPresenterCallback Members
///
/// Create a new EVR video presenter
///
///
public static EvrPresenter CreateNew()
{
// object comObject;
// int hr;
/* Our exception var we use to hold the exception
* until we need to throw it (after clean up) */
// Exception exception = null;
/* A COM object we query form our native library */
// IClassFactory factory = null;
/* Create our 'helper' class */
var evrPresenter = new EvrPresenter();
IMFVideoPresenter presenter = null;
try
{
var path = System.IO.Path.GetDirectoryName(new Uri(typeof(EvrPresenter).Assembly.CodeBase).LocalPath);
var dlltoload = System.IO.Path.Combine(path, IntPtr.Size == 8 ? @"EvrPresenter64.dll" : @"EvrPresenter32.dll");
presenter = COMUtil.CreateFromDll(dlltoload, EVR_PRESENTER_CLSID);
int count;
var settings = presenter as IEVRPresenterSettings;
DsError.ThrowExceptionForHR(settings.RegisterCallback(evrPresenter));
DsError.ThrowExceptionForHR(settings.GetBufferCount(out count));
DsError.ThrowExceptionForHR(settings.SetBufferCount(PRESENTER_BUFFER_COUNT));
/* Populate the IMFVideoPresenter */
evrPresenter.VideoPresenter = presenter;
}
catch (Exception ex)
{
COMUtil.TryFinalRelease(ref presenter);
throw new WPFMediaKitException("Could not create EnhancedVideoRenderer", ex);
}
return evrPresenter;
// /* Call the DLL export to create the class factory */
/* if(ProcessBits == 32)
hr = DllGetClassObject32(EVR_PRESENTER_CLSID, IUNKNOWN_GUID, out comObject);
else if(ProcessBits == 64)
hr = DllGetClassObject64(EVR_PRESENTER_CLSID, IUNKNOWN_GUID, out comObject);
else
{
exception = new Exception(string.Format("{0} bit processes are unsupported", ProcessBits));
goto bottom;
}
*/
/* Check if our call to our DLL failed */
/* if(hr != 0 || comObject == null)
{
exception = new COMException("Could not create a new class factory.", hr);
goto bottom;
}
*/
/* Cast the COM object that was returned to a COM interface type */
/* factory = comObject as IClassFactory;
if(factory == null)
{
exception = new Exception("Could not QueryInterface for the IClassFactory interface");
goto bottom;
}
/* Get the GUID of the IMFVideoPresenter */
// Guid guidVideoPresenter = typeof(IMFVideoPresenter).GUID;
/* Creates a new instance of the IMFVideoPresenter */
// factory.CreateInstance(null, ref guidVideoPresenter, out comObject);
/* QueryInterface for the IMFVideoPresenter */
// var presenter = comObject as IMFVideoPresenter;
/* QueryInterface for our callback registration interface */
/* var registerCb = comObject as IEVRPresenterRegisterCallback;
if(registerCb == null)
{
exception = new Exception("Could not QueryInterface for IEVRPresenterRegisterCallback");
goto bottom;
}
*/
/* Register the callback to the 'helper' class we created */
// registerCb.RegisterCallback(evrPresenter);
/* Populate the IMFVideoPresenter */
// evrPresenter.VideoPresenter = presenter;
// bottom:
// if(factory != null)
// Marshal.FinalReleaseComObject(factory);
/* if(exception != null)
throw exception;
return evrPresenter;*/
}
#region Event Invokers
///
/// Fires the NewAllocatorFrame event
///
private void InvokeNewAllocatorFrame()
{
var newAllocatorFrameAction = NewAllocatorFrame;
if (newAllocatorFrameAction != null) newAllocatorFrameAction();
}
///
/// Fires the NewAlloctorSurface event
///
/// D3D surface pointer
private void InvokeNewAllocatorSurface(IntPtr pSurface)
{
var del = NewAllocatorSurface;
if (del != null) del(this, pSurface);
}
#endregion Event Invokers
}