From b6e75925d4f2e6ab5fc50a74f83e8c8a1f726166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20VIGNELLES?= Date: Sun, 16 Aug 2020 21:20:59 +0200 Subject: [PATCH] Avoid a copy in StreamMediaInput on modern platforms. This requires unsafe code to use the newer Span APIs netstandard1.1 is also removed --- src/LibVLCSharp/Helpers/MarshalExtensions.cs | 26 ++++++++++++++++++++ src/LibVLCSharp/LibVLCSharp.csproj | 10 +++++++- src/LibVLCSharp/StreamMediaInput.cs | 12 ++++----- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/LibVLCSharp/Helpers/MarshalExtensions.cs b/src/LibVLCSharp/Helpers/MarshalExtensions.cs index 94cc5db..22f0027 100644 --- a/src/LibVLCSharp/Helpers/MarshalExtensions.cs +++ b/src/LibVLCSharp/Helpers/MarshalExtensions.cs @@ -166,5 +166,31 @@ namespace LibVLCSharp.Helpers MarshalUtils.LibVLCFree(ref nativeString); return Encoding.UTF8.GetString(buffer, 0, buffer.Length); } + +#if !APPLE && !ANDROID && !NETSTANDARD2_1 + /// + /// The Span-based APIs on Stream are not available on older targets. Span can be backported on older TFMs through the System.Memory package, + /// but System.IO does not provide the same benefit. This code is extracted from dotnet/runtime to allow efficient media callbacks implementation. + /// + /// https://github.com/dotnet/runtime/blob/c4b9dabec8186a0d61f0cc3ea0b7efea579bf24e/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs#L720-L734 + /// the .NET stream + /// the buffer to read + /// number of bytes read + internal static int Read(this System.IO.Stream stream, Span buffer) + { + var sharedBuffer = System.Buffers.ArrayPool.Shared.Rent(buffer.Length); + try + { + var numRead = stream.Read(sharedBuffer, 0, buffer.Length); + if ((uint)numRead > (uint)buffer.Length) + { + throw new System.IO.IOException("StreamTooLong"); + } + new Span(sharedBuffer, 0, numRead).CopyTo(buffer); + return numRead; + } + finally { System.Buffers.ArrayPool.Shared.Return(sharedBuffer); } + } +#endif } } diff --git a/src/LibVLCSharp/LibVLCSharp.csproj b/src/LibVLCSharp/LibVLCSharp.csproj index a5cfac1..e086715 100644 --- a/src/LibVLCSharp/LibVLCSharp.csproj +++ b/src/LibVLCSharp/LibVLCSharp.csproj @@ -28,7 +28,7 @@ This package also contains the views for the following platforms: If you need Xamarin.Forms support, see LibVLCSharp.Forms. LibVLC needs to be installed separately, see VideoLAN.LibVLC.* packages. - netstandard2.1;netstandard2.0;netstandard1.1 + netstandard2.1;netstandard2.0 $(TargetFrameworks);MonoAndroid81;Xamarin.iOS10;Xamarin.Mac20;Xamarin.TVOS10 $(TargetFrameworks);uap10.0;uap10.0.16299;net45;net471 $(TargetsForTfmSpecificBuildOutput);IncludeAWindow @@ -49,6 +49,7 @@ LibVLC needs to be installed separately, see VideoLAN.LibVLC.* packages.icon.png https://code.videolan.org/videolan/LibVLCSharp/blob/master/NEWS libvlc;vlc;videolan;native;c/c++;video;audio;player;media;mediaplayer;codec;ffmpeg;xamarin;graphics;ios;android;linux;windows;macos;cross-platform + true true @@ -60,6 +61,7 @@ LibVLC needs to be installed separately, see VideoLAN.LibVLC.* packages.True + @@ -86,7 +88,13 @@ LibVLC needs to be installed separately, see VideoLAN.LibVLC.* packages. + + + + + + diff --git a/src/LibVLCSharp/StreamMediaInput.cs b/src/LibVLCSharp/StreamMediaInput.cs index f17552b..6f30b2f 100644 --- a/src/LibVLCSharp/StreamMediaInput.cs +++ b/src/LibVLCSharp/StreamMediaInput.cs @@ -1,7 +1,9 @@ using System; using System.IO; using System.Runtime.InteropServices; - +#if !APPLE && !ANDROID && !NETSTANDARD2_1 +using LibVLCSharp.Helpers; +#endif namespace LibVLCSharp { /// @@ -10,7 +12,6 @@ namespace LibVLCSharp public class StreamMediaInput : MediaInput { private readonly Stream _stream; - private readonly byte[] _readBuffer = new byte[0x4000]; /// /// Initializes a new instance of , which reads from the given .NET stream. @@ -61,14 +62,11 @@ namespace LibVLCSharp /// The buffer where read data must be written /// The buffer length /// The number of bytes actually read, -1 on error - public override int Read(IntPtr buf, uint len) + public unsafe override int Read(IntPtr buf, uint len) { try { - var read = _stream.Read(_readBuffer, 0, Math.Min((int)len, _readBuffer.Length)); - Marshal.Copy(_readBuffer, 0, buf, read); - - return read; + return _stream.Read(new Span(buf.ToPointer(), (int)Math.Min(len, int.MaxValue))); } catch (Exception) { -- GitLab