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()