Skip to content

Commit

Permalink
[VideoToolbox] Make P/Invokes have blittable signatures. (#20019)
Browse files Browse the repository at this point in the history
  • Loading branch information
rolfbjarne committed Feb 2, 2024
1 parent b9ddc53 commit fd65e35
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 101 deletions.
53 changes: 30 additions & 23 deletions src/VideoToolbox/VTCompressionSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
// Copyright 2014 Xamarin Inc.
//
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

using CoreFoundation;
Expand Down Expand Up @@ -150,7 +151,7 @@ unsafe extern static VTStatus VTCompressionSessionCreate (
/* VTCompressionOutputCallback */ CompressionOutputCallback? outputCallback,
#endif
/* void* */ IntPtr outputCallbackClosure,
/* VTCompressionSessionRef* */ out IntPtr compressionSessionOut);
/* VTCompressionSessionRef* */ IntPtr* compressionSessionOut);

#if false // Disabling for now until we have some tests on this
public static VTCompressionSession? Create (int width, int height, CMVideoCodecType codecType,
Expand Down Expand Up @@ -187,13 +188,14 @@ unsafe extern static VTStatus VTCompressionSessionCreate (
if (compressionOutputCallback is not null)
callbackHandle = GCHandle.Alloc (compressionOutputCallback);

IntPtr ret;
var result = VTCompressionSessionCreate (IntPtr.Zero, width, height, codecType,
encoderSpecification.GetHandle (),
sourceImageBufferAttributes.GetHandle (),
IntPtr.Zero,
callbackHandle.IsAllocated ? (staticCback) : null,
GCHandle.ToIntPtr (callbackHandle),
out var ret);
&ret);

if (result == VTStatus.Ok && ret != IntPtr.Zero)
return new VTCompressionSession (ret, true) {
Expand Down Expand Up @@ -243,14 +245,14 @@ public VTStatus PrepareToEncodeFrames ()
}

[DllImport (Constants.VideoToolboxLibrary)]
extern static VTStatus VTCompressionSessionEncodeFrame (
unsafe extern static VTStatus VTCompressionSessionEncodeFrame (
/* VTCompressionSessionRef */ IntPtr session,
/* CVImageBufferRef */ IntPtr imageBuffer,
/* CMTime */ CMTime presentation,
/* CMTime */ CMTime duration, // can ve CMTime.Invalid
/* CFDictionaryRef */ IntPtr dict, // can be null, undocumented options
/* void* */ IntPtr sourceFrame,
/* VTEncodeInfoFlags */ out VTEncodeInfoFlags flags);
/* VTEncodeInfoFlags */ VTEncodeInfoFlags* flags);

public VTStatus EncodeFrame (CVImageBuffer imageBuffer, CMTime presentationTimestamp, CMTime duration,
NSDictionary frameProperties, CVImageBuffer sourceFrame, out VTEncodeInfoFlags infoFlags)
Expand All @@ -267,9 +269,12 @@ public VTStatus EncodeFrame (CVImageBuffer imageBuffer, CMTime presentationTimes
if (imageBuffer is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (imageBuffer));

return VTCompressionSessionEncodeFrame (GetCheckedHandle (), imageBuffer.Handle, presentationTimestamp, duration,
frameProperties.GetHandle (),
sourceFrame, out infoFlags);
infoFlags = default;
unsafe {
return VTCompressionSessionEncodeFrame (GetCheckedHandle (), imageBuffer.Handle, presentationTimestamp, duration,
frameProperties.GetHandle (),
sourceFrame, (VTEncodeInfoFlags*) Unsafe.AsPointer<VTEncodeInfoFlags> (ref infoFlags));
}
}

#if false // Disabling for now until we have some tests on this
Expand Down Expand Up @@ -366,16 +371,7 @@ public VTStatus BeginPass (VTCompressionSessionOptionFlags flags)
[SupportedOSPlatform ("maccatalyst")]
#endif
[DllImport (Constants.VideoToolboxLibrary)]
extern static VTStatus VTCompressionSessionEndPass (IntPtr session, out byte furtherPassesRequestedOut, IntPtr reserved);

#if NET
[SupportedOSPlatform ("macos")]
[SupportedOSPlatform ("ios")]
[SupportedOSPlatform ("tvos")]
[SupportedOSPlatform ("maccatalyst")]
#endif
[DllImport (Constants.VideoToolboxLibrary)]
extern static VTStatus VTCompressionSessionEndPass (IntPtr session, IntPtr ptrByte, IntPtr reserved);
unsafe extern static VTStatus VTCompressionSessionEndPass (IntPtr session, byte* furtherPassesRequestedOut, IntPtr reserved);

#if NET
[SupportedOSPlatform ("macos")]
Expand All @@ -385,15 +381,21 @@ public VTStatus BeginPass (VTCompressionSessionOptionFlags flags)
#endif
public VTStatus EndPass (out bool furtherPassesRequested)
{
var result = VTCompressionSessionEndPass (GetCheckedHandle (), out var b, IntPtr.Zero);
byte b;
VTStatus result;
unsafe {
result = VTCompressionSessionEndPass (GetCheckedHandle (), &b, IntPtr.Zero);
}
furtherPassesRequested = b != 0;
return result;
}

// Like EndPass, but this will be the final pass, so the encoder will skip the evaluation.
public VTStatus EndPassAsFinal ()
{
return VTCompressionSessionEndPass (GetCheckedHandle (), IntPtr.Zero, IntPtr.Zero);
unsafe {
return VTCompressionSessionEndPass (GetCheckedHandle (), null, IntPtr.Zero);
}
}

#if NET
Expand All @@ -403,10 +405,10 @@ public VTStatus EndPassAsFinal ()
[SupportedOSPlatform ("maccatalyst")]
#endif
[DllImport (Constants.VideoToolboxLibrary)]
extern static VTStatus VTCompressionSessionGetTimeRangesForNextPass (
unsafe extern static VTStatus VTCompressionSessionGetTimeRangesForNextPass (
/* VTCompressionSessionRef */ IntPtr session,
/* CMItemCount* */ out int itemCount,
/* const CMTimeRange** */ out IntPtr target);
/* CMItemCount* */ int* itemCount,
/* const CMTimeRange** */ IntPtr* target);

#if NET
[SupportedOSPlatform ("macos")]
Expand All @@ -416,7 +418,12 @@ extern static VTStatus VTCompressionSessionGetTimeRangesForNextPass (
#endif
public VTStatus GetTimeRangesForNextPass (out CMTimeRange []? timeRanges)
{
var v = VTCompressionSessionGetTimeRangesForNextPass (GetCheckedHandle (), out var count, out var target);
VTStatus v;
int count;
IntPtr target;
unsafe {
v = VTCompressionSessionGetTimeRangesForNextPass (GetCheckedHandle (), &count, &target);
}
if (v != VTStatus.Ok) {
timeRanges = null;
return v;
Expand Down
63 changes: 38 additions & 25 deletions src/VideoToolbox/VTDecompressionSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#nullable enable

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

using CoreFoundation;
Expand Down Expand Up @@ -61,7 +62,7 @@ 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;
public IntPtr Proc;
#endif
public IntPtr DecompressionOutputRefCon;
}
Expand Down Expand Up @@ -151,13 +152,13 @@ static void NewDecompressionCallback (IntPtr outputCallbackClosure, IntPtr sourc
}

[DllImport (Constants.VideoToolboxLibrary)]
extern static VTStatus VTDecompressionSessionCreate (
unsafe extern static VTStatus VTDecompressionSessionCreate (
/* CFAllocatorRef */ IntPtr allocator, // can be null
/* CMVideoFormatDescriptionRef */ IntPtr videoFormatDescription,
/* CFDictionaryRef */ IntPtr videoDecoderSpecification, // can be null
/* CFDictionaryRef */ IntPtr destinationImageBufferAttributes, // can be null
/* const VTDecompressionOutputCallbackRecord* */ ref VTDecompressionOutputCallbackRecord outputCallback,
/* VTDecompressionSessionRef* */ out IntPtr decompressionSessionOut);
/* const VTDecompressionOutputCallbackRecord* */ VTDecompressionOutputCallbackRecord* outputCallback,
/* VTDecompressionSessionRef* */ IntPtr* decompressionSessionOut);

#if false // Disabling for now until we have some tests on this
public static VTDecompressionSession Create (CMVideoFormatDescription formatDescription,
Expand All @@ -171,11 +172,14 @@ public static VTDecompressionSession Create (CMVideoFormatDescription formatDesc

IntPtr ret;

var result = VTDecompressionSessionCreate (IntPtr.Zero, formatDescription.Handle,
decoderSpecification is not null ? decoderSpecification.Dictionary.Handle : IntPtr.Zero,
destinationImageBufferAttributes.GetHandle (),
ref callbackStruct,
out ret);
VTStatus result;
unsafe {
result = VTDecompressionSessionCreate (IntPtr.Zero, formatDescription.Handle,
decoderSpecification is not null ? decoderSpecification.Dictionary.Handle : IntPtr.Zero,
destinationImageBufferAttributes.GetHandle (),
&callbackStruct,
&ret);
}

return result == VTStatus.Ok && ret != IntPtr.Zero
? new VTDecompressionSession (ret, true)
Expand All @@ -190,7 +194,7 @@ public static VTDecompressionSession Create (CMVideoFormatDescription formatDesc
VTVideoDecoderSpecification? decoderSpecification = null, // hardware acceleration is default behavior on iOS. no opt-in required.
NSDictionary? destinationImageBufferAttributes = null)
{
return Create (outputCallback, formatDescription, decoderSpecification, destinationImageBufferAttributes, static_DecompressionOutputCallback);
return Create (outputCallback, formatDescription, decoderSpecification, destinationImageBufferAttributes, Marshal.GetFunctionPointerForDelegate (static_DecompressionOutputCallback));
}
#endif // !NET

Expand All @@ -209,7 +213,7 @@ public static VTDecompressionSession Create (CMVideoFormatDescription formatDesc
return Create (outputCallback, formatDescription, decoderSpecification, destinationImageBufferAttributes?.Dictionary, &NewDecompressionCallback);
}
#else
return Create (outputCallback, formatDescription, decoderSpecification, destinationImageBufferAttributes?.Dictionary, static_newDecompressionOutputCallback);
return Create (outputCallback, formatDescription, decoderSpecification, destinationImageBufferAttributes?.Dictionary, Marshal.GetFunctionPointerForDelegate (static_newDecompressionOutputCallback));
#endif
}

Expand All @@ -220,7 +224,7 @@ public static VTDecompressionSession Create (CMVideoFormatDescription formatDesc
#if NET
delegate* unmanaged</* void* */ IntPtr, /* void* */ IntPtr, /* OSStatus */ VTStatus, VTDecodeInfoFlags, /* CVImageBuffer */ IntPtr, CMTime, CMTime, void> cback)
#else
DecompressionOutputCallback cback)
IntPtr cback)
#endif
{
if (outputCallback is null)
Expand All @@ -236,11 +240,14 @@ public static VTDecompressionSession Create (CMVideoFormatDescription formatDesc
};
IntPtr ret;

var result = VTDecompressionSessionCreate (IntPtr.Zero, formatDescription.Handle,
decoderSpecification.GetHandle (),
destinationImageBufferAttributes.GetHandle (),
ref callbackStruct,
out ret);
VTStatus result;
unsafe {
result = VTDecompressionSessionCreate (IntPtr.Zero, formatDescription.Handle,
decoderSpecification.GetHandle (),
destinationImageBufferAttributes.GetHandle (),
&callbackStruct,
&ret);
}

if (result == VTStatus.Ok && ret != IntPtr.Zero)
return new VTDecompressionSession (ret, true) {
Expand All @@ -255,19 +262,22 @@ public static VTDecompressionSession Create (CMVideoFormatDescription formatDesc
extern static void VTDecompressionSessionInvalidate (IntPtr sesion);

[DllImport (Constants.VideoToolboxLibrary)]
extern static VTStatus VTDecompressionSessionDecodeFrame (
unsafe extern static VTStatus VTDecompressionSessionDecodeFrame (
/* VTDecompressionSessionRef */ IntPtr session,
/* CMSampleBufferRef */ IntPtr sampleBuffer,
/* VTDecodeFrameFlags */ VTDecodeFrameFlags decodeFlags,
/* void* */ IntPtr sourceFrame,
/* VTDecodeInfoFlags */ out VTDecodeInfoFlags infoFlagsOut);
/* VTDecodeInfoFlags */ VTDecodeInfoFlags* infoFlagsOut);

public VTStatus DecodeFrame (CMSampleBuffer sampleBuffer, VTDecodeFrameFlags decodeFlags, IntPtr sourceFrame, out VTDecodeInfoFlags infoFlags)
{
if (sampleBuffer is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (sampleBuffer));

return VTDecompressionSessionDecodeFrame (GetCheckedHandle (), sampleBuffer.Handle, decodeFlags, sourceFrame, out infoFlags);
infoFlags = default;
unsafe {
return VTDecompressionSessionDecodeFrame (GetCheckedHandle (), sampleBuffer.Handle, decodeFlags, sourceFrame, (VTDecodeInfoFlags*) Unsafe.AsPointer<VTDecodeInfoFlags> (ref infoFlags));
}
}
#if false // Disabling for now until we have some tests on this
[DllImport (Constants.VideoToolboxLibrary)]
Expand Down Expand Up @@ -342,11 +352,15 @@ public VTStatus WaitForAsynchronousFrames ()
}

[DllImport (Constants.VideoToolboxLibrary)]
extern static VTStatus VTDecompressionSessionCopyBlackPixelBuffer (IntPtr sesion, out IntPtr pixelBufferOut);
unsafe extern static VTStatus VTDecompressionSessionCopyBlackPixelBuffer (IntPtr sesion, IntPtr* pixelBufferOut);

public VTStatus CopyBlackPixelBuffer (out CVPixelBuffer? pixelBuffer)
{
var result = VTDecompressionSessionCopyBlackPixelBuffer (GetCheckedHandle (), out var ret);
VTStatus result;
IntPtr ret;
unsafe {
result = VTDecompressionSessionCopyBlackPixelBuffer (GetCheckedHandle (), &ret);
}
pixelBuffer = Runtime.GetINativeObject<CVPixelBuffer> (ret, true);
return result;
}
Expand All @@ -366,8 +380,7 @@ public VTStatus SetDecompressionProperties (VTDecompressionProperties options)
[SupportedOSPlatform ("maccatalyst")]
#endif
[DllImport (Constants.VideoToolboxLibrary)]
[return: MarshalAs (UnmanagedType.U1)]
extern static bool VTIsHardwareDecodeSupported (CMVideoCodecType codecType);
extern static byte VTIsHardwareDecodeSupported (CMVideoCodecType codecType);

#if NET
[SupportedOSPlatform ("macos")]
Expand All @@ -377,7 +390,7 @@ public VTStatus SetDecompressionProperties (VTDecompressionProperties options)
#endif
public static bool IsHardwareDecodeSupported (CMVideoCodecType codecType)
{
return VTIsHardwareDecodeSupported (codecType);
return VTIsHardwareDecodeSupported (codecType) != 0;
}
}
}
22 changes: 15 additions & 7 deletions src/VideoToolbox/VTFrameSilo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#nullable enable

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

using CoreFoundation;
Expand Down Expand Up @@ -44,21 +45,25 @@ internal VTFrameSilo (NativeHandle handle, bool owns)
}

[DllImport (Constants.VideoToolboxLibrary)]
extern static /* OSStatus */ VTStatus VTFrameSiloCreate (
unsafe extern static /* OSStatus */ VTStatus VTFrameSiloCreate (
/* CFAllocatorRef */ IntPtr allocator, /* can be null */
/* CFURLRef */ IntPtr fileUrl, /* can be null */
/* CMTimeRange */ CMTimeRange timeRange, /* can be kCMTimeRangeInvalid */
/* CFDictionaryRef */ IntPtr options, /* Reserved, always null */
/* VTFrameSiloRef */ out IntPtr siloOut);
/* VTFrameSiloRef */ IntPtr* siloOut);

public static VTFrameSilo? Create (NSUrl? fileUrl = null, CMTimeRange? timeRange = null)
{
var status = VTFrameSiloCreate (
VTStatus status;
IntPtr ret;
unsafe {
status = VTFrameSiloCreate (
IntPtr.Zero,
fileUrl.GetHandle (),
timeRange ?? CMTimeRange.InvalidRange,
IntPtr.Zero,
out var ret);
&ret);
}

if (status != VTStatus.Ok)
return null;
Expand Down Expand Up @@ -99,13 +104,16 @@ public unsafe VTStatus SetTimeRangesForNextPass (CMTimeRange [] ranges)
}

[DllImport (Constants.VideoToolboxLibrary)]
extern static /* OSStatus */ VTStatus VTFrameSiloGetProgressOfCurrentPass (
unsafe extern static /* OSStatus */ VTStatus VTFrameSiloGetProgressOfCurrentPass (
/* VTFrameSiloRef */ IntPtr silo,
/* Float32* */ out float progressOut);
/* Float32* */ float* progressOut);

public VTStatus GetProgressOfCurrentPass (out float progress)
{
return VTFrameSiloGetProgressOfCurrentPass (Handle, out progress);
progress = default;
unsafe {
return VTFrameSiloGetProgressOfCurrentPass (Handle, (float*) Unsafe.AsPointer<float> (ref progress));
}
}

#if !NET
Expand Down
12 changes: 8 additions & 4 deletions src/VideoToolbox/VTMultiPassStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ protected override void Dispose (bool disposing)
}

[DllImport (Constants.VideoToolboxLibrary)]
extern static /* OSStatus */ VTStatus VTMultiPassStorageCreate (
unsafe extern static /* OSStatus */ VTStatus VTMultiPassStorageCreate (
/* CFAllocatorRef */IntPtr allocator, /* can be null */
/* CFURLRef */ IntPtr fileUrl, /* can be null */
/* CMTimeRange */ CMTimeRange timeRange, /* can be kCMTimeRangeInvalid */
/* CFDictionaryRef */ IntPtr options, /* can be null */
/* VTMultiPassStorageRef */ out IntPtr multiPassStorageOut);
/* VTMultiPassStorageRef */ IntPtr* multiPassStorageOut);

// Convenience method taking a strong dictionary
public static VTMultiPassStorage? Create (
Expand All @@ -75,12 +75,16 @@ protected override void Dispose (bool disposing)
CMTimeRange? timeRange = null,
NSDictionary? options = null)
{
var status = VTMultiPassStorageCreate (
VTStatus status;
IntPtr ret;
unsafe {
status = VTMultiPassStorageCreate (
IntPtr.Zero,
fileUrl.GetHandle (),
timeRange ?? CMTimeRange.InvalidRange,
options.GetHandle (),
out var ret);
&ret);
}

if (status != VTStatus.Ok)
return null;
Expand Down
Loading

6 comments on commit fd65e35

@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.

@vs-mobiletools-engineering-service2

This comment was marked as outdated.

Please sign in to comment.