diff --git a/CHANGELOG.md b/CHANGELOG.md index 28e1b343..236bec18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Current Stable Release: 3.5.0 (March 2024) ----------------------------------------------- Release: 3.6.X (August 2024) +- [ENH] MediaFoundation: More bindings improvements, add callback supports - [ENH] MediaFoundation: Add VirtualCamera support (mfvirtualcamera.h) - [ENH] General: Drop .net7 support - [ENH] Vortice.Dxc: Handle correctly IDxcCompilerArgs bindings and improve interop diff --git a/Directory.Build.props b/Directory.Build.props index 490d1c4d..a605d6b1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -16,7 +16,7 @@ - 3.5.11 + 3.5.12 beta diff --git a/Directory.Packages.props b/Directory.Packages.props index ce890cf6..685cfab0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,15 +5,15 @@ - + - + - + - - + + diff --git a/src/Vortice.MediaFoundation/IMFAttributes.cs b/src/Vortice.MediaFoundation/IMFAttributes.cs index f8527f95..ae6c2e89 100644 --- a/src/Vortice.MediaFoundation/IMFAttributes.cs +++ b/src/Vortice.MediaFoundation/IMFAttributes.cs @@ -46,7 +46,7 @@ public RegisterTypeInfo MediaType return; } - SetBlob(CaptureDeviceAttributeKeys.MediaType, (IntPtr)Unsafe.AsPointer(ref value), (uint)sizeof(RegisterTypeInfo)); + SetBlob(CaptureDeviceAttributeKeys.MediaType, ref value); } } @@ -140,44 +140,100 @@ public string SymbolicLink public AudioStreamCategory AudioCategory { - get => Get(MediaEngineAttributeKeys.AudioCategory); - set => Set(MediaEngineAttributeKeys.AudioCategory, value); + get => GetEnumValue(MediaEngineAttributeKeys.AudioCategory); + set => SetEnumValue(MediaEngineAttributeKeys.AudioCategory, value); } public AudioEndpointRole AudioEndpointRole { - get => Get(MediaEngineAttributeKeys.AudioEndpointRole); - set => Set(MediaEngineAttributeKeys.AudioEndpointRole, value); + get => GetEnumValue(MediaEngineAttributeKeys.AudioEndpointRole); + set => SetEnumValue(MediaEngineAttributeKeys.AudioEndpointRole, value); } public MediaEngineProtectionFlags ContentProtectionFlags { - get => Get(MediaEngineAttributeKeys.ContentProtectionFlags); - set => Set(MediaEngineAttributeKeys.ContentProtectionFlags, value); + get => GetEnumValue(MediaEngineAttributeKeys.ContentProtectionFlags); + set => SetEnumValue(MediaEngineAttributeKeys.ContentProtectionFlags, value); } - public IUnknown ContentProtectionManager + public ComObject? ContentProtectionManager { - get => Get(MediaEngineAttributeKeys.ContentProtectionManager); - set => Set(MediaEngineAttributeKeys.ContentProtectionManager, value); + get => GetUnknown(MediaEngineAttributeKeys.ContentProtectionManager.Guid); + set => Set(MediaEngineAttributeKeys.ContentProtectionManager.Guid, value); } - public IMFDXGIDeviceManager DxgiManager + public IMFDXGIDeviceManager? DxgiManager { - get => Get(MediaEngineAttributeKeys.DxgiManager); - set => Set(MediaEngineAttributeKeys.DxgiManager, value); + get => GetUnknown(MediaEngineAttributeKeys.DxgiManager.Guid); + set => Set(MediaEngineAttributeKeys.DxgiManager.Guid, value); } - public IMFMediaEngineExtension Extension + public IMFMediaEngineExtension? Extension { - get => Get(MediaEngineAttributeKeys.Extension); - set => Set(MediaEngineAttributeKeys.Extension, value); + get => GetUnknown(MediaEngineAttributeKeys.Extension.Guid); + set => Set(MediaEngineAttributeKeys.Extension.Guid, value); + } + + public IMFSourceReaderCallback? AsyncCallback + { + get => GetICallbackable(SourceReaderAttributeKeys.AsyncCallback); + set => Set(SourceReaderAttributeKeys.AsyncCallback, value); } public Format VideoOutputFormat { - get => Get(MediaEngineAttributeKeys.VideoOutputFormat); - set => Set(MediaEngineAttributeKeys.VideoOutputFormat, value); + get => GetEnumValue(MediaEngineAttributeKeys.VideoOutputFormat); + set => SetEnumValue(MediaEngineAttributeKeys.VideoOutputFormat, value); + } + + /// HRESULT IMFAttributes::GetAllocatedBlob([In] const GUID& guidKey, [Out, Buffer, Optional] unsigned char** ppBuf, [Out] UINT32* pcbSize) + /// IMFAttributes::GetAllocatedBlob + public Span GetAllocatedBlob(Guid guidKey) + { + GetAllocatedBlob(guidKey, out nint buff, out uint pcbSize).CheckError(); + return new Span(buff.ToPointer(), (int)pcbSize); + } + + /// HRESULT IMFAttributes::GetAllocatedString([In] const GUID& guidKey, [Out, Buffer, Optional] wchar_t** ppwszValue, [Out] UINT32* pcchLength) + /// IMFAttributes::GetAllocatedString + public string? GetAllocatedString(Guid guidKey) + { + char* pwszValue = default; + GetAllocatedString(guidKey, &pwszValue, out uint pcchLength).CheckError(); + if (pcchLength > 0 && pwszValue != null) + return new string(pwszValue, 0, (int)pcchLength); + + return default; + } + + /// HRESULT IMFAttributes::GetBlobSize([In] const GUID& guidKey, [Out] UINT32* pcbBlobSize) + /// IMFAttributes::GetBlobSize + public Result GetBlob(Guid guidKey, byte[] buffer) + { + fixed (void* pBuffer = buffer) + return GetBlob(guidKey, pBuffer, (uint)buffer.Length, IntPtr.Zero); + } + + /// HRESULT IMFAttributes::GetBlobSize([In] const GUID& guidKey, [Out] UINT32* pcbBlobSize) + /// IMFAttributes::GetBlobSize + public byte[] GetBlob(Guid guidKey) + { + int length = (int)GetBlobSize(guidKey); + byte[] buffer = new byte[length]; + fixed (void* pBuffer = buffer) + { + GetBlob(guidKey, pBuffer, (uint)buffer.Length, IntPtr.Zero).CheckError(); + } + + return buffer; + } + + /// HRESULT IMFAttributes::GetBlobSize([In] const GUID& guidKey, [Out] UINT32* pcbBlobSize) + /// IMFAttributes::GetBlobSize + public Result GetBlob(Guid guidKey, Span buffer) + { + fixed (void* pBuffer = buffer) + return GetBlob(guidKey, pBuffer, (uint)buffer.Length, IntPtr.Zero); } /// HRESULT IMFAttributes::GetUINT32([In] const GUID& guidKey, [Out] UINT32* punValue) @@ -188,6 +244,24 @@ public uint GetUInt32(Guid guidKey) return value; } + /// HRESULT IMFAttributes::GetUINT32([In] const GUID& guidKey, [Out] UINT32* punValue) + /// IMFAttributes::GetUINT32 + public T GetEnumValue(Guid guidKey) + where T : unmanaged, Enum + { + GetUInt32(guidKey, out uint value).CheckError(); + return (T)(object)value; + } + + /// HRESULT IMFAttributes::GetUINT32([In] const GUID& guidKey, [Out] UINT32* punValue) + /// IMFAttributes::GetUINT32 + public T GetEnumValue(MediaAttributeKey key) + where T : unmanaged, Enum + { + GetUInt32(key.Guid, out uint value).CheckError(); + return (T)(object)value; + } + /// HRESULT IMFAttributes::GetUINT64([In] const GUID& guidKey, [Out] unsigned long long* punValue) /// IMFAttributes::GetUINT64 public ulong GetUInt64(Guid guidKey) @@ -204,328 +278,135 @@ public double GetDouble(Guid guidKey) return value; } - /// - /// Gets an item value - /// - /// GUID of the key. - /// The value associated to this key. - /// IMFAttributes::GetItem - public object Get(Guid guidKey) + /// HRESULT IMFAttributes::GetGUID([In] const GUID& guidKey, [Out] GUID* pguidValue) + /// IMFAttributes::GetGUID + public Guid GetGUID(Guid guidKey) { - AttributeType itemType = GetItemType(guidKey); - switch (itemType) - { - case AttributeType.Uint32: - return Get(guidKey); - case AttributeType.Uint64: - return Get(guidKey); - case AttributeType.Double: - return Get(guidKey); - case AttributeType.Guid: - return Get(guidKey); - case AttributeType.Blob: - return Get(guidKey); - case AttributeType.String: - return Get(guidKey); - case AttributeType.Iunknown: - return Get(guidKey); - default: - break; - } - throw new ArgumentException("The type of the value is not supported"); + GetGUID(guidKey, out Guid value).CheckError(); + return value; } - /// - ///

Applies to: desktop apps | Metro style apps

Retrieves an attribute at the specified index.

- ///
- ///

Index of the attribute to retrieve. To get the number of attributes, call .

- ///

Receives the that identifies this attribute.

- /// The value associated to this index - /// - ///

To enumerate all of an object's attributes in a thread-safe way, do the following:

  1. Call to prevent another thread from adding or deleting attributes.

  2. Call to find the number of attributes.

  3. Call GetItemByIndex to get each attribute by index.

  4. Call to unlock the attribute store.

This interface is available on the following platforms if the Windows Media Format 11 SDK redistributable components are installed:

  • Windows?XP with Service Pack?2 (SP2) and later.
  • Windows?XP Media Center Edition?2005 with KB900325 (Windows?XP Media Center Edition?2005) and KB925766 (October 2006 Update Rollup for Windows?XP Media Center Edition) installed.
- ///
- public object GetByIndex(uint index, out Guid guidKey) + public string GetString(Guid guidKey) { - guidKey = GetItemByIndex(index, IntPtr.Zero); - return Get(guidKey); + uint length = GetStringLength(guidKey); + char* wstr = stackalloc char[(int)length + 1]; + GetString(guidKey, wstr, length + 1, IntPtr.Zero); + return Marshal.PtrToStringUni(new IntPtr(wstr)) ?? string.Empty; } - // TODO: Get/Set add typed methods like Get + public string GetString(MediaAttributeKey guidKey) => GetString(guidKey.Guid); - /// - /// Gets an item value - /// - /// GUID of the key. - /// The value associated to this key. - public unsafe T Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(Guid guidKey) - { - // Perform conversions to supported types - // int - // long - // string - // byte[] - // double - // ComObject - // Guid - - if (typeof(T) == typeof(bool) || - typeof(T) == typeof(byte) || - typeof(T) == typeof(uint) || - typeof(T) == typeof(short) || - typeof(T) == typeof(ushort) || - typeof(T) == typeof(byte) || - typeof(T) == typeof(sbyte)) - { - return (T)Convert.ChangeType(GetUInt32(guidKey), typeof(T)); - } - - if(typeof(T) == typeof(int)) - { - return (T)Convert.ChangeType(unchecked((int)GetUInt32(guidKey)), typeof(T)); - } - - if (typeof(T).IsEnum) - { - return (T)Enum.ToObject(typeof(T), GetUInt32(guidKey)); - } - - if (typeof(T) == typeof(IntPtr)) - { - return (T)(object)new IntPtr(unchecked((long)GetUInt64(guidKey))); - } - - if (typeof(T) == typeof(UIntPtr)) - { - return (T)(object)new UIntPtr(GetUInt64(guidKey)); - } - - if(typeof(T) == typeof(long)) - { - return (T)Convert.ChangeType(unchecked((long)GetUInt64(guidKey)), typeof(T)); - } - - if (typeof(T) == typeof(ulong)) - { - return (T)Convert.ChangeType(GetUInt64(guidKey), typeof(T)); - } + /// HRESULT IMFAttributes::GetBlobSize([In] const GUID& guidKey, [Out] UINT32* pcbBlobSize) + /// IMFAttributes::GetBlobSize + public uint GetBlobSize(Guid guidKey) + { + GetBlobSize(guidKey, out uint blobSize).CheckError(); + return blobSize; + } - if (typeof(T) == typeof(Guid)) + public ComObject? GetUnknown(Guid guidKey) + { + Result result = GetUnknown(guidKey, typeof(IUnknown).GUID, out nint nativePtr); + if (result.Success) { - return (T)(object)GetGUID(guidKey); + return new ComObject(nativePtr); } - if (typeof(T) == typeof(string)) - { - uint length = GetStringLength(guidKey); - char* wstr = stackalloc char[(int)length + 1]; - GetString(guidKey, new IntPtr(wstr), length + 1, IntPtr.Zero); - return (T)(object)Marshal.PtrToStringUni(new IntPtr(wstr)); - } + return default; + } - if (typeof(T) == typeof(double) || typeof(T) == typeof(float)) + public T? GetUnknown<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(Guid guidKey) + where T : ComObject + { + Result result = GetUnknown(guidKey, typeof(T).GUID, out nint nativePtr); + if (result.Success) { - return (T)Convert.ChangeType(GetDouble(guidKey), typeof(T)); + return MarshallingHelpers.FromPointer(nativePtr)!; } - if (typeof(T) == typeof(byte[])) - { - int length = (int)GetBlobSize(guidKey); - byte[] buffer = new byte[length]; - fixed (void* pBuffer = buffer) - { - GetBlob(guidKey, pBuffer, (uint)buffer.Length, IntPtr.Zero); - } - - return (T)(object)buffer; - } + return default; + } - if (typeof(T).IsValueType) + public Result GetUnknown<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(Guid guidKey, out T? unknown) + where T : ComObject + { + Result result = GetUnknown(guidKey, typeof(T).GUID, out nint nativePtr); + if (result.Success) { - int length = (int)GetBlobSize(guidKey); - if (length != Unsafe.SizeOf()) - { - throw new ArgumentException("Size of the structure doesn't match the size of stored value"); - } - - T? value = default; - GetBlob(guidKey, Unsafe.AsPointer(ref value), (uint)Unsafe.SizeOf(), IntPtr.Zero); - return value!; + unknown = MarshallingHelpers.FromPointer(nativePtr)!; + return result; } - if (typeof(T) == typeof(ComObject)) - { - IntPtr ptr = GetUnknown(guidKey, typeof(IUnknown).GUID); - return (T)(object)new ComObject(ptr); - } + unknown = default; + return result; + } - if (typeof(T).IsSubclassOf(typeof(ComObject))) + public T? GetICallbackable<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(Guid guidKey) + where T : ICallbackable + { + Result result = GetUnknown(guidKey, typeof(T).GUID, out nint nativePtr); + if (result.Success) { - IntPtr ptr = GetUnknown(guidKey, typeof(T).GUID); - return (T)Activator.CreateInstance(typeof(T), ptr); + return CppObjectShadow.ToCallback(nativePtr); } - throw new ArgumentException("The type of the value is not supported"); + return default; } /// - /// Gets an item value + ///

Applies to: desktop apps | Metro style apps

Retrieves an attribute at the specified index.

///
- /// GUID of the key. - /// The value associated to this key. - /// ms704598 - /// HRESULT IMFAttributes::GetItem([In] const GUID& guidKey,[In] void* pValue) - /// IMFAttributes::GetItem - public T Get<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(MediaAttributeKey guidKey) - { - return Get(guidKey.Guid); - } - public string GetString(Guid guidKey) + ///

Index of the attribute to retrieve. To get the number of attributes, call .

+ ///

Receives the that identifies this attribute.

+ /// The value associated to this index + /// + ///

To enumerate all of an object's attributes in a thread-safe way, do the following:

  1. Call to prevent another thread from adding or deleting attributes.

  2. Call to find the number of attributes.

  3. Call GetItemByIndex to get each attribute by index.

  4. Call to unlock the attribute store.

This interface is available on the following platforms if the Windows Media Format 11 SDK redistributable components are installed:

  • Windows?XP with Service Pack?2 (SP2) and later.
  • Windows?XP Media Center Edition?2005 with KB900325 (Windows?XP Media Center Edition?2005) and KB925766 (October 2006 Update Rollup for Windows?XP Media Center Edition) installed.
+ ///
+ public Variant GetItemByIndex(uint index, out Guid guidKey) { - uint length = GetStringLength(guidKey); - char* wstr = stackalloc char[(int)length + 1]; - GetString(guidKey, new IntPtr(wstr), length + 1, IntPtr.Zero); - return Marshal.PtrToStringUni(new IntPtr(wstr)); + Variant result = default; + GetItemByIndex(index, out guidKey, &result).CheckError(); + return result; } - public string GetString(MediaAttributeKey guidKey) - { - return GetString(guidKey.Guid); - } + public Result Set(Guid guidKey, bool value) => Set(guidKey, value ? 1u : 0u); + public Result Set(Guid guidKey, float value) => Set(guidKey, (double)value); - public void Set(Guid guidKey, float value) + /// HRESULT IMFAttributes::SetUINT32([In] const GUID& guidKey, [In] UINT32 unValue) + /// IMFAttributes::SetUINT32 + public Result SetEnumValue(Guid guidKey, T value) + where T : unmanaged, Enum { - Set(guidKey, (double)value); + return Set(guidKey, Convert.ToUInt32(value)); } - public void Set(Guid guidKey, bool value) + /// HRESULT IMFAttributes::SetUINT32([In] const GUID& guidKey, [In] UINT32 unValue) + /// IMFAttributes::SetUINT32 + public Result SetEnumValue(MediaAttributeKey key, T value) + where T : unmanaged, Enum { - SetUInt32(guidKey, value ? 1u : 0u); + return Set(key.Guid, Convert.ToUInt32(value)); } - public void Set(Guid guidKey, uint value) + /// HRESULT IMFAttributes::SetBlob([In] const GUID& guidKey, [In] const unsigned char* pBuf, [In] UINT32 cbBufSize) + /// IMFAttributes::SetBlob + public Result SetBlob(Guid guidKey, byte[] buffer) { - SetUInt32(guidKey, value); + fixed (void* pBuffer = buffer) + return SetBlob(guidKey, pBuffer, (uint)buffer.Length); } - /// - ///

Applies to: desktop apps | Metro style apps

Adds an attribute value with a specified key.

- ///
- ///

A that identifies the value to set. If this key already exists, the method overwrites the old value.

- ///

A that contains the attribute value. The method copies the value. The type must be one of the types listed in the enumeration.

- ///

The method returns an . Possible values include, but are not limited to, those in the following table.

Return codeDescription

The method succeeded.

E_OUTOFMEMORY

Insufficient memory.

MF_E_INVALIDTYPE

Invalid attribute type.

?

- /// - ///

This method checks whether the type is one of the attribute types defined in , and fails if an unsupported type is used. However, this method does not check whether the is the correct type for the specified attribute . (There is no programmatic way to associate attribute GUIDs with property types.) For a list of Media Foundation attributes and their data types, see Media Foundation Attributes.

This interface is available on the following platforms if the Windows Media Format 11 SDK redistributable components are installed:

  • Windows?XP with Service Pack?2 (SP2) and later.
  • Windows?XP Media Center Edition?2005 with KB900325 (Windows?XP Media Center Edition?2005) and KB925766 (October 2006 Update Rollup for Windows?XP Media Center Edition) installed.
- ///
- /// bb970346 - /// HRESULT IMFAttributes::SetItem([In] const GUID& guidKey,[In] const PROPVARIANT& Value) - /// IMFAttributes::SetItem - public void Set(Guid guidKey, T value) - { - // Perform conversions to supported types - // int - // long - // string - // byte[] - // double - // ComObject - // Guid - - if (typeof(T) == typeof(int) || typeof(T) == typeof(bool) || typeof(T) == typeof(byte) || typeof(T) == typeof(short) || typeof(T) == typeof(ushort) || typeof(T) == typeof(byte) || typeof(T) == typeof(sbyte) - || typeof(T).IsEnum) - { - SetUInt32(guidKey, Convert.ToUInt32(value)); - return; - } - - if (value is int intValue) - { - SetUInt32(guidKey, unchecked((uint)intValue)); - return; - } - - if (value is uint uivalue) - { - SetUInt32(guidKey, uivalue); - return; - } - - if (value is long lvalue) - { - SetUInt64(guidKey, unchecked((ulong)lvalue)); - return; - } - - if (value is ulong ulvalue) - { - SetUInt64(guidKey, ulvalue); - return; - } - - if (typeof(T) == typeof(nint)) - { - SetUInt64(guidKey, unchecked((ulong)((IntPtr)(object)value).ToInt64())); - return; - } - - if (typeof(T) == typeof(Guid)) - { - Set(guidKey, (Guid)(object)value); - return; - } - - if (typeof(T) == typeof(string)) - { - Set(guidKey, value.ToString()); - return; - } - - if (typeof(T) == typeof(double) || typeof(T) == typeof(float)) - { - Set(guidKey, Convert.ToDouble(value)); - return; - } - - if (typeof(T) == typeof(byte[])) - { - var arrayValue = ((byte[])(object)value); - fixed (void* pBuffer = arrayValue) - { - SetBlob(guidKey, (IntPtr)pBuffer, (uint)arrayValue.Length); - } - - return; - } - - - if (typeof(T).IsValueType) - { - SetBlob(guidKey, (IntPtr)Unsafe.AsPointer(ref value), (uint)Unsafe.SizeOf()); - return; - } - - if (typeof(T) == typeof(ComObject) || typeof(IUnknown).IsAssignableFrom(typeof(T))) - { - Set(guidKey, (IUnknown)value!); - return; - } - - throw new ArgumentException("The type of the value is not supported"); + /// HRESULT IMFAttributes::SetBlob([In] const GUID& guidKey, [In] const unsigned char* pBuf, [In] UINT32 cbBufSize) + /// IMFAttributes::SetBlob + public Result SetBlob(Guid guidKey, Span buffer) + { + fixed (void* pBuffer = buffer) + return SetBlob(guidKey, pBuffer, (uint)buffer.Length); } - /// - ///

Applies to: desktop apps | Metro style apps

Adds an attribute value with a specified key.

- ///
- ///

A that identifies the value to set. If this key already exists, the method overwrites the old value.

- ///

A that contains the attribute value. The method copies the value. The type must be one of the types listed in the enumeration.

- ///

The method returns an . Possible values include, but are not limited to, those in the following table.

Return codeDescription

The method succeeded.

E_OUTOFMEMORY

Insufficient memory.

MF_E_INVALIDTYPE

Invalid attribute type.

?

- /// - ///

This method checks whether the type is one of the attribute types defined in , and fails if an unsupported type is used. However, this method does not check whether the is the correct type for the specified attribute . (There is no programmatic way to associate attribute GUIDs with property types.) For a list of Media Foundation attributes and their data types, see Media Foundation Attributes.

This interface is available on the following platforms if the Windows Media Format 11 SDK redistributable components are installed:

  • Windows?XP with Service Pack?2 (SP2) and later.
  • Windows?XP Media Center Edition?2005 with KB900325 (Windows?XP Media Center Edition?2005) and KB925766 (October 2006 Update Rollup for Windows?XP Media Center Edition) installed.
- ///
- /// bb970346 - /// HRESULT IMFAttributes::SetItem([In] const GUID& guidKey,[In] const PROPVARIANT& Value) - /// IMFAttributes::SetItem - public void Set(MediaAttributeKey guidKey, T value) + public Result SetBlob(Guid guidKey, ref T value) + where T : unmanaged { - Set(guidKey.Guid, value); + return SetBlob(guidKey, Unsafe.AsPointer(ref value), (uint)sizeof(T)); } } diff --git a/src/Vortice.MediaFoundation/IMFCaptureEngine.cs b/src/Vortice.MediaFoundation/IMFCaptureEngine.cs new file mode 100644 index 00000000..6c55589b --- /dev/null +++ b/src/Vortice.MediaFoundation/IMFCaptureEngine.cs @@ -0,0 +1,37 @@ +// Copyright (c) Amer Koleci and Contributors. +// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information. + +using SharpGen.Runtime; +using Vortice.Mathematics; + +namespace Vortice.MediaFoundation; + +public delegate void CaptureEngineOnEventDelegate(IMFMediaEvent @event); + +public unsafe partial class IMFCaptureEngine +{ + private readonly CaptureEngineOnEventImpl? _captureEngineOnEventImpl; + + public event CaptureEngineOnEventDelegate? CaptureEngineEvent; + + public IMFCaptureEngine(IMFCaptureEngineClassFactory factory) + { + NativePointer = factory.CreateInstance(ClsidMFCaptureEngine, typeof(IMFCaptureEngine).GUID); + _captureEngineOnEventImpl = new CaptureEngineOnEventImpl(this); + } + + private void OnEvent(IMFMediaEvent @event) + { + CaptureEngineEvent?.Invoke(@event); + } + + internal class CaptureEngineOnEventImpl(IMFCaptureEngine engine) : CallbackBase, IMFCaptureEngineOnEventCallback + { + private readonly IMFCaptureEngine _engine = engine; + + public void OnEvent(IMFMediaEvent @event) + { + _engine.OnEvent(@event); + } + } +} diff --git a/src/Vortice.MediaFoundation/IMFGetService.cs b/src/Vortice.MediaFoundation/IMFGetService.cs new file mode 100644 index 00000000..f4e15449 --- /dev/null +++ b/src/Vortice.MediaFoundation/IMFGetService.cs @@ -0,0 +1,30 @@ +// Copyright (c) Amer Koleci and Contributors. +// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information. + +using SharpGen.Runtime; + +namespace Vortice.MediaFoundation; + +public unsafe partial class IMFGetService +{ + public Result GetService<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(Guid guidService, out T? service) + where T : ComObject + { + Result result = GetService(guidService,typeof(T).GUID, out IntPtr devicePtr); + if (result.Failure) + { + service = default; + return result; + } + + service = MarshallingHelpers.FromPointer(devicePtr); + return result; + } + + public T GetService<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(Guid guidService) + where T : ComObject + { + GetService(guidService, typeof(T).GUID, out IntPtr devicePtr).CheckError(); + return MarshallingHelpers.FromPointer(devicePtr)!; + } +} diff --git a/src/Vortice.MediaFoundation/IMFMediaEngineClassFactory.cs b/src/Vortice.MediaFoundation/IMFMediaEngineClassFactory.cs index 35eee0fb..a60d4d51 100644 --- a/src/Vortice.MediaFoundation/IMFMediaEngineClassFactory.cs +++ b/src/Vortice.MediaFoundation/IMFMediaEngineClassFactory.cs @@ -27,7 +27,7 @@ public IMFMediaEngine CreateInstance( try { - attributes.Set(MediaEngineAttributeKeys.Callback, mediaEngineNotifyImpl); + attributes.Set(MediaEngineAttributeKeys.Callback.Guid, mediaEngineNotifyImpl); CreateInstance(createFlags, attributes, out IMFMediaEngine engine).CheckError(); mediaEngineNotifyImpl.MediaEngine = engine; diff --git a/src/Vortice.MediaFoundation/IMFSourceReader.cs b/src/Vortice.MediaFoundation/IMFSourceReader.cs new file mode 100644 index 00000000..b32add43 --- /dev/null +++ b/src/Vortice.MediaFoundation/IMFSourceReader.cs @@ -0,0 +1,194 @@ +// Copyright (c) Amer Koleci and Contributors. +// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information. + +using SharpGen.Runtime.Win32; + +namespace Vortice.MediaFoundation; + +public unsafe partial class IMFSourceReader +{ + internal IMFByteStream? _byteStream; + + /// + ///

Applies to: desktop apps | Metro style apps

Gets a format that is supported natively by the media source.

+ ///
+ ///

Specifies which stream to query. The value can be any of the following.

ValueMeaning
0?0xFFFFFFFB

The zero-based index of a stream.

0xFFFFFFFC

The first video stream.

0xFFFFFFFD

The first audio stream.

?

+ ///

The zero-based index of the media type to retrieve.

+ ///

Receives a reference to the interface. The caller must release the interface.

+ /// + ///

This method queries the underlying media source for its native output format. Potentially, each source stream can produce more than one output format. Use the dwMediaTypeIndex parameter to loop through the available formats. Generally, file sources offer just one format per stream, but capture devices might offer several formats.

The method returns a copy of the media type, so it is safe to modify the object received in the ppMediaType parameter.

To set the output type for a stream, call the method.

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374661 + /// HRESULT IMFSourceReader::GetNativeMediaType([In] unsigned int dwStreamIndex,[In] unsigned int dwMediaTypeIndex,[Out] IMFMediaType** ppMediaType) + /// IMFSourceReader::GetNativeMediaType + public IMFMediaType GetNativeMediaType(SourceReaderIndex readerIndex, int dwMediaTypeIndex) + { + return GetNativeMediaType((int)readerIndex, dwMediaTypeIndex); + } + + /// + ///

Applies to: desktop apps | Metro style apps

Selects or deselects one or more streams.

+ ///
+ ///

The stream to set. The value can be any of the following.

ValueMeaning
0?0xFFFFFFFB

The zero-based index of a stream.

0xFFFFFFFC

The first video stream.

0xFFFFFFFD

The first audio stream.

0xFFFFFFFE

All streams.

?

+ ///

Specify TRUE to select streams or to deselect streams. If a stream is deselected, it will not generate data.

+ ///

If this method succeeds, it returns . Otherwise, it returns an error code.

+ /// + ///

There are two common uses for this method:

  • To change the default stream selection. Some media files contain multiple streams of the same type. For example, a file might include audio streams for multiple languages. You can use this method to change which of the streams is selected. To get information about each stream, call or .
  • If you will not need data from one of the streams, it is a good idea to deselect that stream. If the stream is selected, the media source might hold onto a queue of unread data, and the queue might grow indefinitely, consuming memory.

For an example of deselecting a stream, see Tutorial: Decoding Audio.

If a stream is deselected, the method returns MF_E_INVALIDREQUEST for that stream. Other methods are valid for deselected streams.

Stream selection does not affect how the source reader loads or unloads decoders in memory. In particular, deselecting a stream does not force the source reader to unload the decoder for that stream.

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374669 + /// HRESULT IMFSourceReader::SetStreamSelection([In] unsigned int dwStreamIndex,[In] BOOL fSelected) + /// IMFSourceReader::SetStreamSelection + public void SetStreamSelection(SourceReaderIndex readerIndex, bool fSelected) + { + SetStreamSelection((int)readerIndex, fSelected); + } + + /// + ///

Applies to: desktop apps | Metro style apps

Sets the media type for a stream.

This media type defines that format that the Source Reader produces as output. It can differ from the native format provided by the media source. See Remarks for more information.

+ ///
+ /// No documentation. + /// No documentation. + ///

The method returns an . Possible values include, but are not limited to, those in the following table.

Return codeDescription

The method succeeded.

MF_E_INVALIDMEDIATYPE

At least one decoder was found for the native stream type, but the type specified by pMediaType was rejected.

MF_E_INVALIDREQUEST

One or more sample requests are still pending.

MF_E_INVALIDSTREAMNUMBER

The dwStreamIndex parameter is invalid.

MF_E_TOPO_CODEC_NOT_FOUND

Could not find a decoder for the native stream type.

?

+ /// + ///

For each stream, you can set the media type to any of the following:

  • One of the native types offered by the media source. To enumerate the native types, call .
  • If the native media type is compressed, you can specify a corresponding uncompressed format. The Source Reader will search for a decoder that can decode from the native format to the specified uncompressed format.

The source reader does not support audio resampling. If you need to resample the audio, you can use the Audio Resampler DSP.

If you set the attribute to TRUE when you create the Source Reader, the Source Reader will convert YUV video to RGB-32. This conversion is not optimized for real-time video playback.

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374667 + /// HRESULT IMFSourceReader::SetCurrentMediaType([In] unsigned int dwStreamIndex,[In] unsigned int* pdwReserved,[In] IMFMediaType* pMediaType) + /// IMFSourceReader::SetCurrentMediaType + public void SetCurrentMediaType(SourceReaderIndex readerIndex, IMFMediaType mediaTypeRef) + { + SetCurrentMediaType((int)readerIndex, mediaTypeRef); + } + + /// + ///

Applies to: desktop apps | Metro style apps

Seeks to a new position in the media source.

+ ///
+ /// The position from which playback will be started. 100-nanosecond units. + /// + ///

The SetCurrentPosition method does not guarantee exact seeking. The accuracy of the seek depends on the media content. If the media content contains a video stream, the SetCurrentPosition method typically seeks to the nearest key frame before the desired position. The distance between key frames depends on several factors, including the encoder implementation, the video content, and the particular encoding settings used to encode the content. The distance between key frame can vary within a single video file (for example, depending on scene complexity).

After seeking, the application should call and advance to the desired position.

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374668 + /// HRESULT IMFSourceReader::SetCurrentPosition([In] const GUID& guidTimeFormat,[In] const PROPVARIANT& varPosition) + /// IMFSourceReader::SetCurrentPosition + public void SetCurrentPosition(long position) + { + SetCurrentPosition(Guid.Empty, new Variant { Value = position }); + } + + /// + ///

Applies to: desktop apps | Metro style apps

Gets the current media type for a stream.

+ ///
+ ///

The stream to query. The value can be any of the following.

ValueMeaning
0?0xFFFFFFFB

The zero-based index of a stream.

0xFFFFFFFC

The first video stream.

0xFFFFFFFD

The first audio stream.

?

+ ///

Receives a reference to the interface. The caller must release the interface.

+ /// + ///

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374660 + /// HRESULT IMFSourceReader::GetCurrentMediaType([In] unsigned int dwStreamIndex,[Out] IMFMediaType** ppMediaType) + /// IMFSourceReader::GetCurrentMediaType + public IMFMediaType GetCurrentMediaType(SourceReaderIndex readerIndex) + { + return GetCurrentMediaType((int)readerIndex); + } + + /// + ///

Applies to: desktop apps | Metro style apps

Reads the next sample from the media source.

+ ///
+ ///

The stream to pull data from. The value can be any of the following.

ValueMeaning
0?0xFFFFFFFB

The zero-based index of a stream.

0xFFFFFFFC

The first video stream.

0xFFFFFFFD

The first audio stream.

0xFFFFFFFE

Get the next available sample, regardless of which stream.

?

+ ///

A bitwise OR of zero or more flags from the enumeration.

+ ///

Receives the zero-based index of the stream.

+ ///

Receives a bitwise OR of zero or more flags from the enumeration.

+ ///

Receives the time stamp of the sample, or the time of the stream event indicated in pdwStreamFlags. The time is given in 100-nanosecond units.

+ ///

Receives a reference to the interface or the value null (see Remarks). If this parameter receives a non-null reference, the caller must release the interface.

+ /// + ///

If the requested stream is not selected, the return code is MF_E_INVALIDREQUEST. See .

This method can complete synchronously or asynchronously. If you provide a callback reference when you create the source reader, the method is asynchronous. Otherwise, the method is synchronous. For more information about setting the callback reference, see .

Asynchronous Mode

In asynchronous mode:

  • All of the [out] parameters must be null. Otherwise, the method returns E_INVALIDARG.
  • The method returns immediately.
  • When the operation completes, the application's method is called.
  • If an error occurs, the method can fail either synchronously or asynchronously. Check the return value of ReadSample, and also check the hrStatus parameter of .
Synchronous Mode

In synchronous mode:

  • The pdwStreamFlags and ppSample parameters cannot be null. Otherwise, the method returns E_POINTER.
  • The pdwActualStreamIndex and pllTimestamp parameters can be null.
  • The method blocks until the next sample is available.

In synchronous mode, if the dwStreamIndex parameter is , you should pass a non-null value for pdwActualStreamIndex, so that you know which stream delivered the sample.

This method can return flags in the pdwStreamFlags parameter without returning a media sample in ppSample. Therefore, the ppSample parameter can receive a null reference even when the method succeeds. For example, when the source reader reaches the end of the stream, it returns the flag in pdwStreamFlags and sets ppSample to null.

If there is a gap in the stream, pdwStreamFlags receives the flag, ppSample is null, and pllTimestamp indicates the time when the gap occurred.

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374665 + /// HRESULT IMFSourceReader::ReadSample([In] unsigned int dwStreamIndex,[In] unsigned int dwControlFlags,[Out, Optional] unsigned int* pdwActualStreamIndex,[Out, Optional] unsigned int* pdwStreamFlags,[Out, Optional] longlong* pllTimestamp,[Out, Optional] IMFSample** ppSample) + /// IMFSourceReader::ReadSample + public IMFSample ReadSample(SourceReaderIndex dwStreamIndex, SourceReaderControlFlag dwControlFlags, out int dwActualStreamIndexRef, out SourceReaderFlag dwStreamFlagsRef, out long llTimestampRef) + { + return ReadSample((int)dwStreamIndex, dwControlFlags, out dwActualStreamIndexRef, out dwStreamFlagsRef, out llTimestampRef); + } + + /// + ///

Applies to: desktop apps | Metro style apps

Flushes one or more streams.

+ ///
+ ///

The stream to flush. The value can be any of the following.

ValueMeaning
0?0xFFFFFFFB

The zero-based index of a stream.

0xFFFFFFFC

The first video stream.

0xFFFFFFFD

The first audio stream.

0xFFFFFFFE

All streams.

?

+ ///

If this method succeeds, it returns . Otherwise, it returns an error code.

+ /// + ///

The Flush method discards all queued samples and cancels all pending sample requests.

This method can complete either synchronously or asynchronously. If you provide a callback reference when you create the source reader, the method is asynchronous. Otherwise, the method is synchronous. For more information about the setting the callback reference, see .

In synchronous mode, the method blocks until the operation is complete.

In asynchronous mode, the application's method is called when the flush operation completes. While a flush operation is pending, the method returns MF_E_NOTACCEPTING.

Note??In Windows?7, there was a bug in the implementation of this method, which causes OnFlush to be called before the flush operation completes. A hotfix is available that fixes this bug. For more information, see http://support.microsoft.com/kb/979567.

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374659 + /// HRESULT IMFSourceReader::Flush([In] unsigned int dwStreamIndex) + /// IMFSourceReader::Flush + public void Flush(SourceReaderIndex dwStreamIndex) + { + Flush((int)dwStreamIndex); + } + + /// + ///

Applies to: desktop apps | Metro style apps

Queries the underlying media source or decoder for an interface.

+ ///
+ ///

The stream or object to query. If the value is , the method queries the media source. Otherwise, it queries the decoder that is associated with the specified stream. The following values are possible.

ValueMeaning
0?0xFFFFFFFB

The zero-based index of a stream.

0xFFFFFFFC

The first video stream.

0xFFFFFFFD

The first audio stream.

0xFFFFFFFF

The media source.

?

+ ///

A service identifier . If the value is GUID_NULL, the method calls QueryInterface to get the requested interface. Otherwise, the method calls the method. For a list of service identifiers, see Service Interfaces.

+ ///

The interface identifier (IID) of the interface being requested.

+ ///

Receives a reference to the requested interface. The caller must release the interface.

+ /// + ///

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374663 + /// HRESULT IMFSourceReader::GetServiceForStream([In] unsigned int dwStreamIndex,[In] const GUID& guidService,[In] const GUID& riid,[Out] void** ppvObject) + /// IMFSourceReader::GetServiceForStream + public nint GetServiceForStream(SourceReaderIndex streamIndex, Guid guidService, Guid riid) + { + return GetServiceForStream((int)streamIndex, guidService, riid); + } + + /// + ///

Applies to: desktop apps | Metro style apps

Gets an attribute from the underlying media source.

+ ///
+ ///

The stream or object to query. The value can be any of the following.

ValueMeaning
0?0xFFFFFFFB

The zero-based index of a stream.

0xFFFFFFFC

The first video stream.

0xFFFFFFFD

The first audio stream.

0xFFFFFFFF

The media source.

?

+ ///

A that identifies the attribute to retrieve. If the dwStreamIndex parameter equals , guidAttribute can specify one of the following:

  • A presentation descriptor attribute. For a list of values, see Presentation Descriptor Attributes.
  • . Use this value to get characteristics flags from the media source.

Otherwise, if the dwStreamIndex parameter specifies a stream, guidAttribute specifies a stream descriptor attribute. For a list of values, see Stream Descriptor Attributes.

+ /// a that receives the value of the attribute. + /// + ///

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374662 + /// HRESULT IMFSourceReader::GetPresentationAttribute([In] unsigned int dwStreamIndex,[In] const GUID& guidAttribute,[Out] PROPVARIANT* pvarAttribute) + /// IMFSourceReader::GetPresentationAttribute + public T GetPresentationAttribute(SourceReaderIndex streamIndex, MediaAttributeKey guidAttribute) + { + Variant variant = GetPresentationAttribute((int)streamIndex, guidAttribute.Guid); + + return (T)Convert.ChangeType(variant.Value, typeof(T)); + } + + /// + ///

Applies to: desktop apps | Metro style apps

Gets an attribute from the underlying media source.

+ ///
+ ///

The stream or object to query. The value can be any of the following.

ValueMeaning
0?0xFFFFFFFB

The zero-based index of a stream.

0xFFFFFFFC

The first video stream.

0xFFFFFFFD

The first audio stream.

0xFFFFFFFF

The media source.

?

+ ///

A that identifies the attribute to retrieve. If the dwStreamIndex parameter equals , guidAttribute can specify one of the following:

  • A presentation descriptor attribute. For a list of values, see Presentation Descriptor Attributes.
  • . Use this value to get characteristics flags from the media source.

Otherwise, if the dwStreamIndex parameter specifies a stream, guidAttribute specifies a stream descriptor attribute. For a list of values, see Stream Descriptor Attributes.

+ /// a that receives the value of the attribute. + /// + ///

This interface is available on Windows?Vista if Platform Update Supplement for Windows?Vista is installed.

+ ///
+ /// dd374662 + /// HRESULT IMFSourceReader::GetPresentationAttribute([In] unsigned int dwStreamIndex,[In] const GUID& guidAttribute,[Out] PROPVARIANT* pvarAttribute) + /// IMFSourceReader::GetPresentationAttribute + public Variant GetPresentationAttribute(SourceReaderIndex dwStreamIndex, Guid guidAttribute) + { + return GetPresentationAttribute((int)dwStreamIndex, guidAttribute); + } + + protected override void DisposeCore(nint nativePointer, bool disposing) + { + base.DisposeCore(nativePointer, disposing); + + if (_byteStream != null) + { + _byteStream.Dispose(); + _byteStream = null; + } + } +} diff --git a/src/Vortice.MediaFoundation/IMFSourceReaderCallbackBase.cs b/src/Vortice.MediaFoundation/IMFSourceReaderCallbackBase.cs new file mode 100644 index 00000000..97a6f38d --- /dev/null +++ b/src/Vortice.MediaFoundation/IMFSourceReaderCallbackBase.cs @@ -0,0 +1,44 @@ +// Copyright (c) Amer Koleci and Contributors. +// Licensed under the MIT License (MIT). See LICENSE in the repository root for more information. + +using SharpGen.Runtime; +using SharpGen.Runtime.Win32; + +namespace Vortice.MediaFoundation; + +public abstract class IMFSourceReaderCallbackBase : CallbackBase, IMFSourceReaderCallback +{ + public virtual void OnEvent(SourceReaderIndex streamIndex, IMFMediaEvent @event) + { + + } + + public virtual void OnFlush(SourceReaderIndex streamIndex) + { + + } + + public virtual void OnReadSample(Result hrStatus, + SourceReaderIndex streamIndex, + SourceReaderFlag streamFlags, long llTimestamp, IMFSample sample) + { + + } + + #region IMFSourceReaderCallback Members + void IMFSourceReaderCallback.OnEvent(int streamIndex, IMFMediaEvent @event) + { + OnEvent((SourceReaderIndex)streamIndex, @event); + } + + void IMFSourceReaderCallback.OnFlush(int streamIndex) + { + OnFlush((SourceReaderIndex)streamIndex); + } + + void IMFSourceReaderCallback.OnReadSample(Result hrStatus, int streamIndex, int streamFlags, long timestamp, IMFSample sample) + { + OnReadSample(hrStatus, (SourceReaderIndex)streamIndex, (SourceReaderFlag)streamFlags, timestamp, sample); + } + #endregion +} diff --git a/src/Vortice.MediaFoundation/MFByteStream.cs b/src/Vortice.MediaFoundation/MFByteStream.cs index 728ad7d6..75ae6c9b 100644 --- a/src/Vortice.MediaFoundation/MFByteStream.cs +++ b/src/Vortice.MediaFoundation/MFByteStream.cs @@ -4,6 +4,7 @@ using System.Runtime.InteropServices; using SharpGen.Runtime; using SharpGen.Runtime.Win32; +using static Vortice.MediaFoundation.MediaFactory; namespace Vortice.MediaFoundation; @@ -11,6 +12,7 @@ public unsafe partial class MFByteStream { private Stream? _sourceStream; private readonly bool _disposeStream; + private ComStream? _comStream; private ComStreamProxy? _streamProxy; /// @@ -24,12 +26,12 @@ public MFByteStream(Stream sourceStream, bool disposeStream = false) if (PlatformDetection.IsAppContainerProcess) { //var randomAccessStream = sourceStream.AsRandomAccessStream(); - //MediaFactory.MFCreateMFByteStreamOnStreamEx(new ComObject(Marshal.GetIUnknownForObject(randomAccessStream)), this); + //MFCreateMFByteStreamOnStreamEx(new ComObject(Marshal.GetIUnknownForObject(randomAccessStream)), this); } else { _streamProxy = new ComStreamProxy(sourceStream); - MediaFactory.MFCreateMFByteStreamOnStream(_streamProxy, this); + MFCreateMFByteStreamOnStream(_streamProxy, this); } } @@ -49,6 +51,18 @@ public MFByteStream(string fileName) { } + /// + /// Instantiates a new instance from a . + /// + /// hh162754 + /// HRESULT MFCreateMFByteStreamOnStreamEx([In] IUnknown* punkStream,[Out] IMFByteStream** ppByteStream) + /// MFCreateMFByteStreamOnStreamEx + public MFByteStream(ComStream sourceStream) + { + _comStream = sourceStream; + MFCreateMFByteStreamOnStream(sourceStream, this); + } + protected override unsafe void DisposeCore(IntPtr nativePointer, bool disposing) { base.DisposeCore(nativePointer, disposing); @@ -66,6 +80,14 @@ protected override unsafe void DisposeCore(IntPtr nativePointer, bool disposing) } } + public uint Read(Span bRef, int offset, uint count) + { + fixed (void* ptr = &bRef[offset]) + { + return Read((IntPtr)ptr, count); + } + } + public uint Read(byte[] bRef, int offset, uint count) { fixed (void* ptr = &bRef[offset]) @@ -74,6 +96,14 @@ public uint Read(byte[] bRef, int offset, uint count) } } + public void BeginRead(Span bRef, int offset, uint count, IMFAsyncCallback callback, object? context = default) + { + fixed (void* ptr = &bRef[offset]) + { + BeginRead((IntPtr)ptr, count, callback, context != null ? Marshal.GetIUnknownForObject(context) : IntPtr.Zero); + } + } + public void BeginRead(byte[] bRef, int offset, uint count, IMFAsyncCallback callback, object? context = default) { fixed (void* ptr = &bRef[offset]) @@ -82,6 +112,14 @@ public void BeginRead(byte[] bRef, int offset, uint count, IMFAsyncCallback call } } + public uint Write(Span bRef, int offset, uint count) + { + fixed (void* ptr = &bRef[offset]) + { + return Write((IntPtr)ptr, count); + } + } + public uint Write(byte[] bRef, int offset, uint count) { fixed (void* ptr = &bRef[offset]) @@ -90,6 +128,14 @@ public uint Write(byte[] bRef, int offset, uint count) } } + public void BeginWrite(Span bRef, int offset, uint count, IMFAsyncCallback callback, object? context = default) + { + fixed (void* ptr = &bRef[offset]) + { + BeginWrite((IntPtr)ptr, count, callback, context != null ? Marshal.GetIUnknownForObject(context) : IntPtr.Zero); + } + } + public void BeginWrite(byte[] bRef, int offset, uint count, IMFAsyncCallback callback, object? context = default) { fixed (void* ptr = &bRef[offset]) diff --git a/src/Vortice.MediaFoundation/Mappings.xml b/src/Vortice.MediaFoundation/Mappings.xml index 146723da..7aa4f7ed 100644 --- a/src/Vortice.MediaFoundation/Mappings.xml +++ b/src/Vortice.MediaFoundation/Mappings.xml @@ -32,7 +32,7 @@ - + @@ -538,8 +538,8 @@ new System.Guid("$1") - new System.Guid("$1") - new System.Guid("$1") + new System.Guid("$1") + new System.Guid("$1") new MediaAttributeKey<long>("$1", "DescrambleData") new MediaAttributeKey<int>("$1", "SampleKeyID") @@ -606,10 +606,19 @@ StreamRenderingError SupportedRates AudioendPointChange + IUnknown + EndOfStream + NewStream + NativeMediaTypeChanged + CurrentMediaTypeChanged + StreamTick + AllEffectsRemoved + MediaSink + NoResolution + UpStream + DownStream - - @@ -656,7 +665,16 @@ - + + + + + + + + + + @@ -678,6 +696,8 @@ + + @@ -689,15 +709,37 @@ - + + + + + + + + + + + + + + + + + + + + + @@ -715,37 +757,39 @@ - - - - + + + + + + - - + - + - + - + - - - + + + + - + @@ -759,9 +803,21 @@ + + + + + + + + - + + + + + @@ -784,7 +840,7 @@ - + @@ -803,7 +859,7 @@ - + @@ -968,7 +1024,7 @@ - + @@ -977,14 +1033,14 @@ - + - + diff --git a/src/Vortice.MediaFoundation/MediaFactory.cs b/src/Vortice.MediaFoundation/MediaFactory.cs index 96c04f2a..5baab6ba 100644 --- a/src/Vortice.MediaFoundation/MediaFactory.cs +++ b/src/Vortice.MediaFoundation/MediaFactory.cs @@ -219,7 +219,7 @@ public static Result MFGetAttribute2UInt32asUInt64(IMFAttributes attributes, Gui public static Result MFSetAttribute2UInt32asUInt64(IMFAttributes attributes, Guid guidKey, uint unHigh32, uint unLow32) { - return attributes.SetUInt64(guidKey, Pack2UInt32AsUInt64(unHigh32, unLow32)); + return attributes.Set(guidKey, Pack2UInt32AsUInt64(unHigh32, unLow32)); } public static Result MFGetAttributeRatio(IMFAttributes attributes, Guid guidKey, out uint numerator, out uint denominator) @@ -242,6 +242,32 @@ public static Result MFSetAttributeSize(IMFAttributes attributes, Guid guidKey, return MFSetAttribute2UInt32asUInt64(attributes, guidKey, width, height); } + #region IMFSourceReader + public static unsafe IMFSourceReader MFCreateSourceReaderFromByteStream(byte[] buffer, IMFAttributes? attributes = null) + { + var byteStream = new MFByteStream(new MemoryStream(buffer)); + IMFSourceReader reader = MFCreateSourceReaderFromByteStream(byteStream, attributes); + reader._byteStream = byteStream; + return reader; + } + + public static unsafe IMFSourceReader MFCreateSourceReaderFromByteStream(Stream buffer, IMFAttributes? attributes = null) + { + var byteStream = new MFByteStream(buffer); + IMFSourceReader reader = MFCreateSourceReaderFromByteStream(byteStream, attributes); + reader._byteStream = byteStream; + return reader; + } + + public static unsafe IMFSourceReader MFCreateSourceReaderFromByteStream(ComStream comStream, IMFAttributes attributes = null) + { + var byteStream = new MFByteStream(comStream); + IMFSourceReader reader = MFCreateSourceReaderFromByteStream(byteStream, attributes); + reader._byteStream = byteStream; + return reader; + } + #endregion + public static IMFVirtualCamera MFCreateVirtualCamera( VirtualCameraType type, VirtualCameraLifetime lifetime,