diff --git a/src/LibVLCSharp/Shared/MediaPlayer.cs b/src/LibVLCSharp/Shared/MediaPlayer.cs
index 26a1ddfaa..c145c5854 100644
--- a/src/LibVLCSharp/Shared/MediaPlayer.cs
+++ b/src/LibVLCSharp/Shared/MediaPlayer.cs
@@ -1305,6 +1305,7 @@ public void SetVideoFormat(string chroma, uint width, uint height, uint pitch)
}
LibVLCVideoFormatCb? _videoFormatCb;
+ LibVLCVideoFormatCbMultiPlane? _videoMultiPlaneFormatCb;
LibVLCVideoCleanupCb? _videoCleanupCb;
IntPtr _videoUserData = IntPtr.Zero;
@@ -1317,9 +1318,35 @@ public void SetVideoFormat(string chroma, uint width, uint height, uint pitch)
public void SetVideoFormatCallbacks(LibVLCVideoFormatCb formatCb, LibVLCVideoCleanupCb? cleanupCb)
{
_videoFormatCb = formatCb ?? throw new ArgumentNullException(nameof(formatCb));
+ _videoMultiPlaneFormatCb = null;
_videoCleanupCb = cleanupCb;
Native.LibVLCVideoSetFormatCallbacks(NativeReference, VideoFormatCallbackHandle,
- (cleanupCb == null)? null : _videoCleanupCb);
+ (cleanupCb == null)? null : VideoCleanupCallbackHandle);
+ }
+
+ ///
+ /// Set decoded video chroma and dimensions with multi-plane format access.
+ /// This variant exposes pitches and lines as IntPtr to allow direct
+ /// multi-plane access to the arrays provided by libVLC.
+ /// This only works in combination with libvlc_video_set_callbacks().
+ ///
+ /// callback to select the video format (cannot be NULL)
+ /// callback to release any allocated resources (or NULL)
+ public void SetVideoFormatCallbacksMultiPlane(LibVLCVideoFormatCbMultiPlane formatCb, LibVLCVideoCleanupCb? cleanupCb)
+ {
+ _videoMultiPlaneFormatCb = formatCb ?? throw new ArgumentNullException(nameof(formatCb));
+ _videoFormatCb = null;
+ _videoCleanupCb = cleanupCb;
+ Native.LibVLCVideoSetFormatCallbacks(NativeReference, VideoFormatCallbackHandle,
+ (cleanupCb == null)? null : VideoCleanupCallbackHandle);
+ }
+ static readonly LibVLCVideoCleanupCb VideoCleanupCallbackHandle = VideoCleanupCallback;
+
+ [MonoPInvokeCallback(typeof(LibVLCVideoCleanupCb))]
+ private static void VideoCleanupCallback(ref IntPtr opaque)
+ {
+ var mediaPlayer = MarshalUtils.GetInstance(opaque);
+ mediaPlayer?._videoCleanupCb?.Invoke(ref mediaPlayer._videoUserData);
}
///
@@ -1822,9 +1849,37 @@ private static void VideoDisplayCallback(IntPtr opaque, IntPtr picture)
private static uint VideoFormatCallback(ref IntPtr opaque, IntPtr chroma, ref uint width, ref uint height, ref uint pitches, ref uint lines)
{
var mediaPlayer = MarshalUtils.GetInstance(opaque);
- if (mediaPlayer?._videoFormatCb != null)
+ if (mediaPlayer == null)
+ return 0;
+
+ // Route to multi-plane callback
+ if (mediaPlayer._videoMultiPlaneFormatCb != null)
+ {
+ IntPtr pitchesPtr = Marshal.AllocHGlobal(sizeof(uint));
+ IntPtr linesPtr = Marshal.AllocHGlobal(sizeof(uint));
+ try
+ {
+ Marshal.WriteInt32(pitchesPtr, (int)pitches);
+ Marshal.WriteInt32(linesPtr, (int)lines);
+ uint result = mediaPlayer._videoMultiPlaneFormatCb(
+ ref mediaPlayer._videoUserData,chroma,ref width,ref height,pitchesPtr,
+ linesPtr);
+ pitches = (uint)Marshal.ReadInt32(pitchesPtr);
+ lines = (uint)Marshal.ReadInt32(linesPtr);
+ return result;
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(pitchesPtr);
+ Marshal.FreeHGlobal(linesPtr);
+ }
+ }
+
+ // Otherwise use legacy single-plane callback
+ if (mediaPlayer._videoFormatCb != null)
{
- return mediaPlayer._videoFormatCb(ref mediaPlayer._videoUserData, chroma, ref width, ref height, ref pitches, ref lines);
+ return mediaPlayer._videoFormatCb(
+ ref mediaPlayer._videoUserData,chroma,ref width,ref height,ref pitches,ref lines);
}
return 0;
@@ -2004,10 +2059,18 @@ private static void AudioCleanupCallback(IntPtr opaque)
/// to not break assumptions that might be held by optimized code
/// in the video decoders, video filters and/or video converters.
///
+
+ // Legacy single-plane callback for compatibility
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate uint LibVLCVideoFormatCb(ref IntPtr opaque, IntPtr chroma, ref uint width,
ref uint height, ref uint pitches, ref uint lines);
+ /// Callback prototype to configure picture buffers format (multi-plane variant).
+ /// Passes pitches and lines as IntPtr to allow direct multi-plane data access via Marshal or unsafe pointer arithmetic.
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ public delegate uint LibVLCVideoFormatCbMultiPlane(ref IntPtr opaque, IntPtr chroma, ref uint width,
+ ref uint height, IntPtr pitches, IntPtr lines);
+
/// Callback prototype to configure picture buffers format.
///
/// private pointer as passed to libvlc_video_set_callbacks()