Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VideoToolbox] Make P/Invokes have blittable signatures. #20019

Merged
merged 2 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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