TripleAntigen
TripleAntigen

Reputation: 2301

How to change code that uses Span to use byte array instead

I want to try a code sample for libvlcsharp, found here: https://code.videolan.org/mfkl/libvlcsharp-samples/-/blob/master/PreviewThumbnailExtractor/Program.cs#L113

I want to try it in a Framework 4.6.1 project, but the sample is targeted at .NET 6. I am having trouble getting one line to compile. The section in question is here:

    private static async Task ProcessThumbnailsAsync(string destination, CancellationToken token)
            {
                var frameNumber = 0;
                while (!token.IsCancellationRequested)
                {
                    if (FilesToProcess.TryDequeue(out var file))
                    {
                        using (var image = new Image<SixLabors.ImageSharp.PixelFormats.Bgra32>((int)(Pitch / BytePerPixel), (int)Lines))
                        using (var sourceStream = file.file.CreateViewStream())
                        {
                            var mg = image.GetPixelMemoryGroup();
                            for(int i = 0; i < mg.Count; i++)
                            {
                                sourceStream.Read(MemoryMarshal.AsBytes(mg[i].Span));
                            }
    
                            Console.WriteLine($"Writing {frameNumber:0000}.jpg");
                            var fileName = Path.Combine(destination, $"{frameNumber:0000}.jpg");
                            using (var outputFile = File.Open(fileName, FileMode.Create))
                            {
                                image.Mutate(ctx => ctx.Crop((int)Width, (int)Height));
                                image.SaveAsJpeg(outputFile);
                            }
                        }
                        file.accessor.Dispose();
                        file.file.Dispose();
                        frameNumber++;
                    }
                    else
                    {
                        await Task.Delay(TimeSpan.FromSeconds(1), token);
                    }
                }
            }

The troublesome line is :

sourceStream.Read(MemoryMarshal.AsBytes(mg[i].Span));

In .NET 6 there are two overloads,

Read(Span) Reads all the bytes of this unmanaged memory stream into the specified span of bytes.

Read(Byte[], Int32, Int32) Reads the specified number of bytes into the specified array.

but in .NET Framework 4.x there is just one

Read(Byte[], Int32, Int32)

I am having trouble understanding what is going on here, can someone please suggest a way to convert the line from the Read(Span) style to the Read(Byte[], Int32, Int32) style so that it works the same? I don't have experience with C#.

Thanks for any advice.

Upvotes: 0

Views: 3816

Answers (1)

Ray
Ray

Reputation: 8844

To understand what's happening, consider the following .NET 4.6.1 code which would achieve the same:

var mg = image.GetPixelMemoryGroup();
for(int i = 0; i < mg.Count; i++)
{
    Span<byte> span = MemoryMarshal.AsBytes(mg[i].Span);
    byte[] buffer = new byte[span.Length];
    sourceStream.Read(buffer, 0, buffer.Length);
    buffer.CopyTo(span);
}

This is just for demonstration though as it would allocate lots of byte arrays. You're better off "backporting" what new .NET does by default, s. this answer. Especially since you'll run into this again as the SixLabors libraries were written with .NET Core in mind, AFAIK. It may also not be as performant as what new .NET can do in case memory mapped file streams remove the need for the one copy done by default.

Also note that .NET 4.6.1 is no longer supported, and if you consider upgrading, you may find switching to .NET (Core) easier than pursuing backporting a whole library.

Upvotes: 1

Related Questions