Skip to content

Commit

Permalink
[.NET/CoreMedia] Use [UnmanagedCallersOnly] instead of [MonoPInvokeCa…
Browse files Browse the repository at this point in the history
…llback] Partial Fix for #10470 (#15934)
  • Loading branch information
stephen-hawley committed Sep 13, 2022
1 parent 878d16e commit 227baba
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 9 deletions.
65 changes: 59 additions & 6 deletions src/CoreMedia/CMBufferQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,25 @@ public class CMBufferQueue : NativeObject
struct CMBufferCallbacks {
internal uint version;
internal IntPtr refcon;
#if NET
internal unsafe delegate* unmanaged<IntPtr, IntPtr, CMTime> XgetDecodeTimeStamp;
internal unsafe delegate* unmanaged<IntPtr, IntPtr, CMTime> XgetPresentationTimeStamp;
internal unsafe delegate* unmanaged<IntPtr, IntPtr, CMTime> XgetDuration;
internal unsafe delegate* unmanaged<IntPtr, IntPtr, bool> XisDataReady;
internal unsafe delegate* unmanaged<IntPtr, IntPtr, IntPtr, int> 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<IntPtr, IntPtr, nint> XgetSize;
#else
internal BufferGetSizeCallback? XgetSize;
#endif
}

// A version with no delegates, just native pointers
Expand Down Expand Up @@ -124,17 +136,34 @@ protected override void Dispose (bool disposing)
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;
Expand Down Expand Up @@ -322,8 +351,12 @@ INativeObject Surface (IntPtr v)
return queueObjects [v];
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (BufferGetTimeCallback))]
#endif
#endif
static CMTime GetDecodeTimeStamp (IntPtr buffer, IntPtr refcon)
{
Expand All @@ -333,8 +366,12 @@ static CMTime GetDecodeTimeStamp (IntPtr buffer, IntPtr refcon)
return queue.getDecodeTimeStamp (queue.Surface (buffer));
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (BufferGetTimeCallback))]
#endif
#endif
static CMTime GetPresentationTimeStamp (IntPtr buffer, IntPtr refcon)
{
Expand All @@ -344,8 +381,12 @@ static CMTime GetPresentationTimeStamp (IntPtr buffer, IntPtr refcon)
return queue.getPresentationTimeStamp (queue.Surface (buffer));
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (BufferGetTimeCallback))]
#endif
#endif
static CMTime GetDuration (IntPtr buffer, IntPtr refcon)
{
Expand All @@ -355,8 +396,12 @@ static CMTime GetDuration (IntPtr buffer, IntPtr refcon)
return queue.getDuration (queue.Surface (buffer));
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (BufferGetBooleanCallback))]
#endif
#endif
static bool GetDataReady (IntPtr buffer, IntPtr refcon)
{
Expand All @@ -366,8 +411,12 @@ static bool GetDataReady (IntPtr buffer, IntPtr refcon)
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)
{
Expand All @@ -377,8 +426,12 @@ static int Compare (IntPtr buffer1, IntPtr buffer2, IntPtr refcon)
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)
{
Expand Down
22 changes: 22 additions & 0 deletions src/CoreMedia/CMCustomBlockAllocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,47 @@ public CMCustomBlockAllocator ()
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);
}

// 1:1 mapping to the real underlying structure
[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<IntPtr, nuint, IntPtr> Allocate;
public unsafe delegate* unmanaged<IntPtr, IntPtr, nuint, void> 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)
{
Expand All @@ -72,8 +90,12 @@ public virtual IntPtr Allocate (nuint sizeInBytes)
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)
{
Expand Down
46 changes: 43 additions & 3 deletions src/CoreMedia/CMSampleBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,23 @@ protected override void Dispose (bool disposing)
[DllImport(Constants.CoreMediaLibrary)]
unsafe static extern CMSampleBufferError CMSampleBufferCallForEachSample (
/* CMSampleBufferRef */ IntPtr sbuf,
#if NET
delegate* unmanaged<IntPtr, int, IntPtr, CMSampleBufferError> 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)
{
Expand All @@ -165,7 +174,13 @@ public CMSampleBufferError CallForEachSample (Func<CMSampleBuffer,int,CMSampleBu

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 ();
}
Expand Down Expand Up @@ -586,18 +601,32 @@ public CMSampleBufferError SetDataReady ()
// 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<IntPtr, ulong, void> 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)
{
Expand All @@ -612,8 +641,13 @@ public CMSampleBufferError SetInvalidateCallback (Action<CMSampleBuffer> invalid
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,
Expand All @@ -623,7 +657,13 @@ public CMSampleBufferError SetInvalidateCallback (Action<CMSampleBuffer> invalid
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)]
Expand Down

5 comments on commit 227baba

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

Please sign in to comment.