Commit b4efca30 authored by Martin Finkel's avatar Martin Finkel

Avoid a copy in StreamMediaInput on modern platforms

This requires unsafe code to use the newer Span APIs
parent 5240048d
......@@ -49,6 +49,7 @@ LibVLC needs to be installed separately, see VideoLAN.LibVLC.* packages.</Descri
<PackageIcon>icon.png</PackageIcon>
<PackageReleaseNotes>https://code.videolan.org/videolan/LibVLCSharp/blob/master/NEWS</PackageReleaseNotes>
<PackageTags>libvlc;vlc;videolan;native;c/c++;video;audio;player;media;mediaplayer;codec;ffmpeg;xamarin;graphics;ios;android;linux;windows;macos;cross-platform</PackageTags>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith('uap'))">
<GenerateLibraryLayout>true</GenerateLibraryLayout>
......@@ -71,6 +72,7 @@ LibVLC needs to be installed separately, see VideoLAN.LibVLC.* packages.</Descri
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' ">
<Compile Remove="Shared\MediaPlayerElement\*.*" />
<None Include="Shared\MediaPlayerElement\*.*" />
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net40' ">
<Compile Remove="Shared\MediaPlayerElement\*.*" />
......@@ -86,6 +88,10 @@ LibVLC needs to be installed separately, see VideoLAN.LibVLC.* packages.</Descri
</Page>
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net471' Or '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
<Target Name="IncludeAWindow" Condition="$(TargetFramework.StartsWith('MonoAndroid'))">
<ItemGroup>
......
......@@ -168,5 +168,31 @@ namespace LibVLCSharp.Shared.Helpers
MarshalUtils.LibVLCFree(ref nativeString);
return Encoding.UTF8.GetString(buffer, 0, buffer.Length);
}
#if !APPLE && !ANDROID && !NETSTANDARD2_1 && !NET40
/// <summary>
/// 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.
/// </summary>
/// <remarks>https://github.com/dotnet/runtime/blob/c4b9dabec8186a0d61f0cc3ea0b7efea579bf24e/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs#L720-L734</remarks>
/// <param name="stream">the .NET stream</param>
/// <param name="buffer">the buffer to read</param>
/// <returns>number of bytes read</returns>
internal static int Read(this System.IO.Stream stream, Span<byte> buffer)
{
var sharedBuffer = System.Buffers.ArrayPool<byte>.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<byte>(sharedBuffer, 0, numRead).CopyTo(buffer);
return numRead;
}
finally { System.Buffers.ArrayPool<byte>.Shared.Return(sharedBuffer); }
}
#endif
}
}
using System;
using System.IO;
using System.Runtime.InteropServices;
#if !APPLE && !ANDROID && !NETSTANDARD2_1 && !NET40
using LibVLCSharp.Shared.Helpers;
#endif
namespace LibVLCSharp.Shared
{
......@@ -10,8 +13,9 @@ namespace LibVLCSharp.Shared
public class StreamMediaInput : MediaInput
{
private readonly Stream _stream;
#if NET40
private readonly byte[] _readBuffer = new byte[0x4000];
#endif
/// <summary>
/// Initializes a new instance of <see cref="StreamMediaInput"/>, which reads from the given .NET stream.
/// </summary>
......@@ -61,14 +65,17 @@ namespace LibVLCSharp.Shared
/// <param name="buf">The buffer where read data must be written</param>
/// <param name="len">The buffer length</param>
/// <returns>The number of bytes actually read, -1 on error</returns>
public override int Read(IntPtr buf, uint len)
public unsafe override int Read(IntPtr buf, uint len)
{
try
{
#if NET40
var read = _stream.Read(_readBuffer, 0, Math.Min((int)len, _readBuffer.Length));
Marshal.Copy(_readBuffer, 0, buf, read);
return read;
#else
return _stream.Read(new Span<byte>(buf.ToPointer(), (int)Math.Min(len, int.MaxValue)));
#endif
}
catch (Exception)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment