Skip to content

Commit

Permalink
[.NET/VideoToolbox] Use [UnmanagedCallersOnly] instead of [MonoPInvok…
Browse files Browse the repository at this point in the history
…eCallback] for the managed callbacks called from native code.

Ref xamarin#10470.
  • Loading branch information
rolfbjarne committed Oct 8, 2021
1 parent cb475d8 commit 6a7a4ce
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 8 deletions.
42 changes: 37 additions & 5 deletions src/VideoToolbox/VTCompressionSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ protected override void Dispose (bool disposing)

// sourceFrame: It seems it's only used as a parameter to be passed into EncodeFrame so no need to strong type it
public delegate void VTCompressionOutputCallback (/* void* */ IntPtr sourceFrame, /* OSStatus */ VTStatus status, VTEncodeInfoFlags flags, CMSampleBuffer buffer);
#if !NET
delegate void CompressionOutputCallback (/* void* CM_NULLABLE */ IntPtr outputCallbackClosure, /* void* CM_NULLABLE */ IntPtr sourceFrame, /* OSStatus */ VTStatus status, VTEncodeInfoFlags infoFlags, /* CMSampleBufferRef CM_NULLABLE */ IntPtr cmSampleBufferPtr);

#region Legacy code start
//
// Here for legacy code, which would only work under duress (user had to manually ref the CMSampleBuffer on the callback)
//
Expand All @@ -75,6 +75,7 @@ protected override void Dispose (bool disposing)
return _static_CompressionOutputCallback;
}
}
#endif

static void CompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceFrame, VTStatus status, VTEncodeInfoFlags infoFlags, IntPtr cmSampleBufferPtr, bool owns)
{
Expand All @@ -88,8 +89,12 @@ static void CompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceFram
}
}

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (CompressionOutputCallback))]
#endif
#endif
static void CompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceFrame, VTStatus status, VTEncodeInfoFlags infoFlags, IntPtr cmSampleBufferPtr)
{
Expand All @@ -102,10 +107,17 @@ static void CompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceFram
VTVideoEncoderSpecification encoderSpecification = null, // hardware acceleration is default behavior on iOS. no opt-in required.
NSDictionary sourceImageBufferAttributes = null)
{
#if NET
unsafe {
return Create (width, height, codecType, compressionOutputCallback, encoderSpecification, sourceImageBufferAttributes, &NewCompressionCallback);
}
#else
return Create (width, height, codecType, compressionOutputCallback, encoderSpecification, sourceImageBufferAttributes, static_newCompressionOutputCallback);
#endif
}

#if !NET
// End region of legacy code
#endregion

static CompressionOutputCallback _static_newCompressionOutputCallback;
static CompressionOutputCallback static_newCompressionOutputCallback {
Expand All @@ -115,25 +127,34 @@ static void CompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceFram
return _static_newCompressionOutputCallback;
}
}
#endif

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (CompressionOutputCallback))]
#endif
#endif
static void NewCompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceFrame, VTStatus status, VTEncodeInfoFlags infoFlags, IntPtr cmSampleBufferPtr)
{
CompressionCallback (outputCallbackClosure, sourceFrame, status, infoFlags, cmSampleBufferPtr, false);
}

[DllImport (Constants.VideoToolboxLibrary)]
extern static VTStatus VTCompressionSessionCreate (
unsafe extern static VTStatus VTCompressionSessionCreate (
/* CFAllocatorRef */ IntPtr allocator, /* can be null */
/* int32_t */ int width,
/* int32_t */ int height,
/* CMVideoCodecType */ CMVideoCodecType codecType,
/* CFDictionaryRef */ IntPtr dictionaryEncoderSpecification, /* can be null */
/* CFDictionaryRef */ IntPtr dictionarySourceImageBufferAttributes, /* can be null */
/* CFDictionaryRef */ IntPtr compressedDataAllocator, /* can be null */
#if NET
/* VTCompressionOutputCallback */ delegate* unmanaged</* void* CM_NULLABLE */ IntPtr, /* void* CM_NULLABLE */ IntPtr, /* OSStatus */ VTStatus, VTEncodeInfoFlags, /* CMSampleBufferRef CM_NULLABLE */ IntPtr, void> outputCallback,
#else
/* VTCompressionOutputCallback */ CompressionOutputCallback outputCallback,
#endif
/* void* */ IntPtr outputCallbackClosure,
/* VTCompressionSessionRef* */ out IntPtr compressionSessionOut);

Expand All @@ -152,13 +173,24 @@ static void NewCompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceF
VTVideoEncoderSpecification encoderSpecification, // hardware acceleration is default behavior on iOS. no opt-in required.
CVPixelBufferAttributes sourceImageBufferAttributes)
{
#if NET
unsafe {
return Create (width, height, codecType, compressionOutputCallback, encoderSpecification, sourceImageBufferAttributes == null ? null : sourceImageBufferAttributes.Dictionary, &CompressionCallback);
}
#else
return Create (width, height, codecType, compressionOutputCallback, encoderSpecification, sourceImageBufferAttributes == null ? null : sourceImageBufferAttributes.Dictionary, static_CompressionOutputCallback);
#endif
}

static VTCompressionSession Create (int width, int height, CMVideoCodecType codecType,
unsafe static VTCompressionSession Create (int width, int height, CMVideoCodecType codecType,
VTCompressionOutputCallback compressionOutputCallback,
VTVideoEncoderSpecification encoderSpecification, // hardware acceleration is default behavior on iOS. no opt-in required.
NSDictionary sourceImageBufferAttributes, CompressionOutputCallback staticCback) // Undocumented options, probably always null
NSDictionary sourceImageBufferAttributes, // Undocumented options, probably always null
#if NET
delegate* unmanaged</* void* CM_NULLABLE */ IntPtr, /* void* CM_NULLABLE */ IntPtr, /* OSStatus */ VTStatus, VTEncodeInfoFlags, /* CMSampleBufferRef CM_NULLABLE */ IntPtr, void> staticCback)
#else
CompressionOutputCallback staticCback)
#endif
{
var callbackHandle = default (GCHandle);
if (compressionOutputCallback != null)
Expand Down
36 changes: 35 additions & 1 deletion src/VideoToolbox/VTDecompressionSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,15 +63,22 @@ protected override void Dispose (bool disposing)
[StructLayout(LayoutKind.Sequential)]
struct VTDecompressionOutputCallbackRecord
{
#if NET
public unsafe delegate* unmanaged</* void* */ IntPtr, /* void* */ IntPtr, /* OSStatus */ VTStatus, VTDecodeInfoFlags, /* CVImageBuffer */ IntPtr, CMTime, CMTime, void> Proc;
#else
public DecompressionOutputCallback Proc;
#endif
public IntPtr DecompressionOutputRefCon;
}

// sourceFrame: It seems it's only used as a parameter to be passed into DecodeFrame so no need to strong type it
public delegate void VTDecompressionOutputCallback (/* void* */ IntPtr sourceFrame, /* OSStatus */ VTStatus status, VTDecodeInfoFlags flags, CVImageBuffer buffer, CMTime presentationTimeStamp, CMTime presentationDuration);
#if !NET
delegate void DecompressionOutputCallback (/* void* */ IntPtr outputCallbackClosure, /* void* */ IntPtr sourceFrame, /* OSStatus */ VTStatus status,
VTDecodeInfoFlags infoFlags, /* CVImageBuffer */ IntPtr cmSampleBufferPtr, CMTime presentationTimeStamp, CMTime presentationDuration);
#endif

#if !NET
//
// Here for legacy code, which would only work under duress (user had to manually ref the CMSampleBuffer on the callback)
//
Expand All @@ -83,9 +90,14 @@ struct VTDecompressionOutputCallbackRecord
return _static_decompressionCallback;
}
}
#endif

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (DecompressionOutputCallback))]
#endif
#endif
static void DecompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceFrame, VTStatus status,
VTDecodeInfoFlags infoFlags, IntPtr imageBufferPtr, CMTime presentationTimeStamp, CMTime presentationDuration)
Expand All @@ -103,6 +115,7 @@ struct VTDecompressionOutputCallbackRecord
}
}

#if !NET
static DecompressionOutputCallback _static_newDecompressionCallback;
static DecompressionOutputCallback static_newDecompressionOutputCallback {
get {
Expand All @@ -111,9 +124,14 @@ struct VTDecompressionOutputCallbackRecord
return _static_newDecompressionCallback;
}
}
#endif

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (DecompressionOutputCallback))]
#endif
#endif
static void NewDecompressionCallback (IntPtr outputCallbackClosure, IntPtr sourceFrame, VTStatus status,
VTDecodeInfoFlags infoFlags, IntPtr imageBufferPtr, CMTime presentationTimeStamp, CMTime presentationDuration)
Expand Down Expand Up @@ -171,22 +189,38 @@ struct VTDecompressionOutputCallbackRecord
VTVideoDecoderSpecification decoderSpecification = null, // hardware acceleration is default behavior on iOS. no opt-in required.
NSDictionary destinationImageBufferAttributes = null)
{
#if NET
unsafe {
return Create (outputCallback, formatDescription, decoderSpecification, destinationImageBufferAttributes, &DecompressionCallback);
}
#else
return Create (outputCallback, formatDescription, decoderSpecification, destinationImageBufferAttributes, static_DecompressionOutputCallback);
#endif
}

public static VTDecompressionSession Create (VTDecompressionOutputCallback outputCallback,
CMVideoFormatDescription formatDescription,
VTVideoDecoderSpecification decoderSpecification, // hardware acceleration is default behavior on iOS. no opt-in required.
CVPixelBufferAttributes destinationImageBufferAttributes)
{
#if NET
unsafe {
return Create (outputCallback, formatDescription, decoderSpecification, destinationImageBufferAttributes == null ? null : destinationImageBufferAttributes.Dictionary, &NewDecompressionCallback);
}
#else
return Create (outputCallback, formatDescription, decoderSpecification, destinationImageBufferAttributes == null ? null : destinationImageBufferAttributes.Dictionary, static_newDecompressionOutputCallback);
#endif
}

static VTDecompressionSession Create (VTDecompressionOutputCallback outputCallback,
unsafe static VTDecompressionSession Create (VTDecompressionOutputCallback outputCallback,
CMVideoFormatDescription formatDescription,
VTVideoDecoderSpecification decoderSpecification, // hardware acceleration is default behavior on iOS. no opt-in required.
NSDictionary destinationImageBufferAttributes,
#if NET
delegate* unmanaged</* void* */ IntPtr, /* void* */ IntPtr, /* OSStatus */ VTStatus, VTDecodeInfoFlags, /* CVImageBuffer */ IntPtr, CMTime, CMTime, void> cback)
#else
DecompressionOutputCallback cback)
#endif
{
if (formatDescription == null)
throw new ArgumentNullException ("formatDescription");
Expand Down
18 changes: 16 additions & 2 deletions src/VideoToolbox/VTFrameSilo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,18 @@ public VTStatus GetProgressOfCurrentPass (out float progress)
return VTFrameSiloGetProgressOfCurrentPass (handle, out progress);
}

#if !NET
delegate VTStatus EachSampleBufferCallback (/* void* */ IntPtr callbackInfo, /* CMSampleBufferRef */ IntPtr sampleBufferPtr);

static EachSampleBufferCallback static_EachSampleBufferCallback = new EachSampleBufferCallback (BufferCallback);
#endif

#if NET
[UnmanagedCallersOnly]
#else
#if !MONOMAC
[MonoPInvokeCallback (typeof (EachSampleBufferCallback))]
#endif
#endif
static VTStatus BufferCallback (IntPtr callbackInfo, IntPtr sampleBufferPtr)
{
Expand All @@ -151,16 +157,24 @@ static VTStatus BufferCallback (IntPtr callbackInfo, IntPtr sampleBufferPtr)
}

[DllImport (Constants.VideoToolboxLibrary)]
extern static /* OSStatus */ VTStatus VTFrameSiloCallFunctionForEachSampleBuffer (
unsafe extern static /* OSStatus */ VTStatus VTFrameSiloCallFunctionForEachSampleBuffer (
/* VTFrameSiloRef */ IntPtr silo,
/* CMTimeRange */ CMTimeRange timeRange, // CMTimeRange.Invalid retrieves all sample buffers
/* void* */ IntPtr callbackInfo,
#if NET
/* */ delegate* unmanaged<IntPtr, IntPtr, VTStatus> callback);
#else
/* */ EachSampleBufferCallback callback);
#endif

public VTStatus ForEach (Func<CMSampleBuffer, VTStatus> callback, CMTimeRange? range = null)
public unsafe VTStatus ForEach (Func<CMSampleBuffer, VTStatus> callback, CMTimeRange? range = null)
{
callbackHandle = GCHandle.Alloc (callback);
#if NET
var foreachResult = VTFrameSiloCallFunctionForEachSampleBuffer (handle, range ?? CMTimeRange.InvalidRange, GCHandle.ToIntPtr (callbackHandle), &BufferCallback);
#else
var foreachResult = VTFrameSiloCallFunctionForEachSampleBuffer (handle, range ?? CMTimeRange.InvalidRange, GCHandle.ToIntPtr (callbackHandle), static_EachSampleBufferCallback);
#endif
callbackHandle.Free ();
return foreachResult;
}
Expand Down

0 comments on commit 6a7a4ce

Please sign in to comment.