From 227baba0b97bd83f0508655d093f345d89e271b9 Mon Sep 17 00:00:00 2001 From: Steve Hawley Date: Tue, 13 Sep 2022 09:29:37 -0400 Subject: [PATCH] [.NET/CoreMedia] Use [UnmanagedCallersOnly] instead of [MonoPInvokeCallback] Partial Fix for #10470 (#15934) --- src/CoreMedia/CMBufferQueue.cs | 65 ++++++++++++++++++++++--- src/CoreMedia/CMCustomBlockAllocator.cs | 22 +++++++++ src/CoreMedia/CMSampleBuffer.cs | 46 +++++++++++++++-- 3 files changed, 124 insertions(+), 9 deletions(-) diff --git a/src/CoreMedia/CMBufferQueue.cs b/src/CoreMedia/CMBufferQueue.cs index 39115a9891..738ca2a93f 100644 --- a/src/CoreMedia/CMBufferQueue.cs +++ b/src/CoreMedia/CMBufferQueue.cs @@ -61,13 +61,25 @@ namespace CoreMedia { struct CMBufferCallbacks { internal uint version; internal IntPtr refcon; +#if NET + internal unsafe delegate* unmanaged XgetDecodeTimeStamp; + internal unsafe delegate* unmanaged XgetPresentationTimeStamp; + internal unsafe delegate* unmanaged XgetDuration; + internal unsafe delegate* unmanaged XisDataReady; + internal unsafe delegate* unmanaged Xcompare; +#else internal BufferGetTimeCallback? XgetDecodeTimeStamp; internal BufferGetTimeCallback? XgetPresentationTimeStamp; internal BufferGetTimeCallback? XgetDuration; internal BufferGetBooleanCallback? XisDataReady; internal BufferCompareCallback? Xcompare; +#endif internal IntPtr cfStringPtr_dataBecameReadyNotification; +#if NET + internal unsafe delegate* unmanaged XgetSize; +#else internal BufferGetSizeCallback? XgetSize; +#endif } // A version with no delegates, just native pointers @@ -124,17 +136,34 @@ namespace CoreMedia { CMBufferGetBool? isDataReady, CMBufferCompare? compare, NSString dataBecameReadyNotification, CMBufferGetSize? getTotalSize) { var bq = new CMBufferQueue (count); +#if NET + CMBufferCallbacks cbacks; + unsafe { + cbacks = new CMBufferCallbacks () { + version = (uint) (getTotalSize is null ? 0 : 1), + refcon = GCHandle.ToIntPtr (bq.gch), + XgetDecodeTimeStamp = getDecodeTimeStamp is not null ? &GetDecodeTimeStamp : null, + XgetPresentationTimeStamp = getPresentationTimeStamp is not null ? &GetPresentationTimeStamp : null, + XgetDuration = getDuration is not null ? &GetDuration : null, + XisDataReady = isDataReady is not null ? &GetDataReady : null, + Xcompare = compare is not null ? &Compare : null, + cfStringPtr_dataBecameReadyNotification = dataBecameReadyNotification is null ? IntPtr.Zero : dataBecameReadyNotification.Handle, + XgetSize = getTotalSize is not null ? &GetTotalSize : null + }; + } +#else var cbacks = new CMBufferCallbacks () { version = (uint) (getTotalSize is null ? 0 : 1), refcon = GCHandle.ToIntPtr (bq.gch), - XgetDecodeTimeStamp = getDecodeTimeStamp is null ? (BufferGetTimeCallback?) null : GetDecodeTimeStamp, - XgetPresentationTimeStamp = getPresentationTimeStamp is null ? (BufferGetTimeCallback?) null : GetPresentationTimeStamp, - XgetDuration = getDuration is null ? (BufferGetTimeCallback?) null : GetDuration, - XisDataReady = isDataReady is null ? (BufferGetBooleanCallback?) null : GetDataReady, - Xcompare = compare is null ? (BufferCompareCallback?) null : Compare, + XgetDecodeTimeStamp = getDecodeTimeStamp is not null ? GetDecodeTimeStamp : null, + XgetPresentationTimeStamp = getPresentationTimeStamp is not null ? GetPresentationTimeStamp : null, + XgetDuration = getDuration is not null ? GetDuration : null, + XisDataReady = isDataReady is not null ? GetDataReady : null, + Xcompare = compare is not null ? Compare : null, cfStringPtr_dataBecameReadyNotification = dataBecameReadyNotification is null ? IntPtr.Zero : dataBecameReadyNotification.Handle, - XgetSize = getTotalSize is null ? (BufferGetSizeCallback?) null : GetTotalSize + XgetSize = getTotalSize is not null ? GetTotalSize : null }; +#endif bq.getDecodeTimeStamp = getDecodeTimeStamp; bq.getPresentationTimeStamp = getPresentationTimeStamp; @@ -322,8 +351,12 @@ namespace CoreMedia { return queueObjects [v]; } +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (BufferGetTimeCallback))] +#endif #endif static CMTime GetDecodeTimeStamp (IntPtr buffer, IntPtr refcon) { @@ -333,8 +366,12 @@ namespace CoreMedia { return queue.getDecodeTimeStamp (queue.Surface (buffer)); } +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (BufferGetTimeCallback))] +#endif #endif static CMTime GetPresentationTimeStamp (IntPtr buffer, IntPtr refcon) { @@ -344,8 +381,12 @@ namespace CoreMedia { return queue.getPresentationTimeStamp (queue.Surface (buffer)); } +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (BufferGetTimeCallback))] +#endif #endif static CMTime GetDuration (IntPtr buffer, IntPtr refcon) { @@ -355,8 +396,12 @@ namespace CoreMedia { return queue.getDuration (queue.Surface (buffer)); } +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (BufferGetBooleanCallback))] +#endif #endif static bool GetDataReady (IntPtr buffer, IntPtr refcon) { @@ -366,8 +411,12 @@ namespace CoreMedia { return queue.isDataReady (queue.Surface (buffer)); } +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (BufferCompareCallback))] +#endif #endif static int Compare (IntPtr buffer1, IntPtr buffer2, IntPtr refcon) { @@ -377,8 +426,12 @@ namespace CoreMedia { return queue.compare (queue.Surface (buffer1), queue.Surface (buffer2)); } +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (BufferGetSizeCallback))] +#endif #endif static nint GetTotalSize (IntPtr buffer, IntPtr refcon) { diff --git a/src/CoreMedia/CMCustomBlockAllocator.cs b/src/CoreMedia/CMCustomBlockAllocator.cs index 18994c7c23..ded49438cb 100644 --- a/src/CoreMedia/CMCustomBlockAllocator.cs +++ b/src/CoreMedia/CMCustomBlockAllocator.cs @@ -35,8 +35,15 @@ namespace CoreMedia { gch = GCHandle.Alloc (this); // kCMBlockBufferCustomBlockSourceVersion = 0 <- this is the only and current value Cblock.Version = 0; +#if NET + unsafe { + Cblock.Allocate = &AllocateCallback; + Cblock.Free = &FreeCallback; + } +#else Cblock.Allocate = static_AllocateCallback; Cblock.Free = static_FreeCallback; +#endif Cblock.RefCon = GCHandle.ToIntPtr (gch); } @@ -44,20 +51,31 @@ namespace CoreMedia { [StructLayout (LayoutKind.Sequential, Pack = 4)] // it's 28 bytes (not 32) on 64 bits iOS internal struct CMBlockBufferCustomBlockSource { public uint Version; +#if NET + public unsafe delegate* unmanaged Allocate; + public unsafe delegate* unmanaged Free; +#else public CMAllocateCallback Allocate; public CMFreeCallback Free; +#endif public IntPtr RefCon; } internal CMBlockBufferCustomBlockSource Cblock; +#if !NET internal delegate IntPtr CMAllocateCallback (/* void* */ IntPtr refCon, /* size_t */ nuint sizeInBytes); internal delegate void CMFreeCallback (/* void* */ IntPtr refCon, /* void* */ IntPtr doomedMemoryBlock, /* size_t */ nuint sizeInBytes); static CMAllocateCallback static_AllocateCallback = AllocateCallback; static CMFreeCallback static_FreeCallback = FreeCallback; +#endif +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (CMAllocateCallback))] +#endif #endif static IntPtr AllocateCallback (IntPtr refCon, nuint sizeInBytes) { @@ -72,8 +90,12 @@ namespace CoreMedia { return Marshal.AllocHGlobal ((int)sizeInBytes); } +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (CMFreeCallback))] +#endif #endif static void FreeCallback (IntPtr refCon, IntPtr doomedMemoryBlock, nuint sizeInBytes) { diff --git a/src/CoreMedia/CMSampleBuffer.cs b/src/CoreMedia/CMSampleBuffer.cs index ea535461d4..61b2951cd3 100644 --- a/src/CoreMedia/CMSampleBuffer.cs +++ b/src/CoreMedia/CMSampleBuffer.cs @@ -139,14 +139,23 @@ namespace CoreMedia { [DllImport(Constants.CoreMediaLibrary)] unsafe static extern CMSampleBufferError CMSampleBufferCallForEachSample ( /* CMSampleBufferRef */ IntPtr sbuf, +#if NET + delegate* unmanaged callback, +#else CMSampleBufferCallForEachSampleCallback callback, +#endif /* void* */ IntPtr refcon); - +#if !NET delegate CMSampleBufferError CMSampleBufferCallForEachSampleCallback (/* CMSampleBufferRef */ IntPtr sampleBuffer, int index, /* void* */ IntPtr refcon); +#endif +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (CMSampleBufferCallForEachSampleCallback))] +#endif #endif static CMSampleBufferError ForEachSampleHandler (IntPtr sbuf, int index, IntPtr refCon) { @@ -165,7 +174,13 @@ namespace CoreMedia { GCHandle h = GCHandle.Alloc (Tuple.Create (callback, this)); try { +#if NET + unsafe { + return CMSampleBufferCallForEachSample (Handle, &ForEachSampleHandler, (IntPtr) h); + } +#else return CMSampleBufferCallForEachSample (Handle, ForEachSampleHandler, (IntPtr) h); +#endif } finally { h.Free (); } @@ -586,18 +601,32 @@ namespace CoreMedia { // however there was already a similar call that we did not bound (not sure why) // and can provide the same feature (since iOS 4 not 8.0) [DllImport(Constants.CoreMediaLibrary)] +#if NET + extern unsafe static /* OSStatus */ CMSampleBufferError CMSampleBufferSetInvalidateCallback ( +#else extern static /* OSStatus */ CMSampleBufferError CMSampleBufferSetInvalidateCallback ( +#endif /* CMSampleBufferRef */ IntPtr sbuf, +#if NET + delegate* unmanaged invalidateCallback, +#else /* CMSampleBufferInvalidateCallback */ CMSampleBufferInvalidateCallback? invalidateCallback, +#endif /* uint64_t */ ulong invalidateRefCon); +#if !NET delegate void CMSampleBufferInvalidateCallback (/* CMSampleBufferRef */ IntPtr sbuf, /* uint64_t */ ulong invalidateRefCon); static CMSampleBufferInvalidateCallback invalidate_handler = InvalidateHandler; +#endif +#if NET + [UnmanagedCallersOnly] +#else #if !MONOMAC [MonoPInvokeCallback (typeof (CMSampleBufferInvalidateCallback))] +#endif #endif static void InvalidateHandler (IntPtr sbuf, ulong invalidateRefCon) { @@ -612,8 +641,13 @@ namespace CoreMedia { if (invalidateHandler is null) { if (invalidate.IsAllocated) invalidate.Free (); - - return CMSampleBufferSetInvalidateCallback (Handle, null, 0); +#if NET + unsafe { +#endif + return CMSampleBufferSetInvalidateCallback (Handle, null, 0); +#if NET + } +#endif } // only one callback can be assigned - and ObjC does not let you re-assign a different one, @@ -623,7 +657,13 @@ namespace CoreMedia { return CMSampleBufferError.RequiredParameterMissing; invalidate = GCHandle.Alloc (Tuple.Create (invalidateHandler, this)); +#if NET + unsafe { + return CMSampleBufferSetInvalidateCallback (Handle, &InvalidateHandler, (ulong)(IntPtr)invalidate); + } +#else return CMSampleBufferSetInvalidateCallback (Handle, invalidate_handler, (ulong)(IntPtr)invalidate); +#endif } [DllImport(Constants.CoreMediaLibrary)]