sipsorcery-org / SIPSorceryMedia.FFmpeg

GNU Lesser General Public License v2.1
34 stars 26 forks source link

Converting SIPSorceryMedia.Abstractions.RawImage to IronSoftware.Drawing.AnyBitmap #47

Open mail2mhossain opened 1 year ago

mail2mhossain commented 1 year ago

It is possible to convert SIPSorceryMedia.Abstractions.RawImage to System.Drawing.Bitmap as follows:

System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap(rawImage.Width, rawImage.Height, rawImage.Stride, System.Drawing.Imaging.PixelFormat.Format24bppRgb, rawImage.Sample);

Now I want to convert SIPSorceryMedia.Abstractions.RawImage to IronSoftware.Drawing.AnyBitmap.

Any help in this regard.

ChristopheI commented 1 year ago

SIPSorceryMedia.Abstractions.RawImage contains all necessary info about an image in AV_PIX_FMT_BGR24 format (format in FFmpeg context)

So 8 bits for B, 8 bits for G, 8 bits for R (=> 24 bits for one pixel), it's size (width and height) and it's stride

As an example, This AV_PIX_FMT_BGR24 format is the same as this one PixelFormat.Format24bppRgb in System.Drawing.Imaging context.

According the library, you must use an equivalent:

About stride, read this: https://learn.microsoft.com/en-us/dotnet/api/system.drawing.bitmap.-ctor?view=dotnet-plat-ext-7.0#system-drawing-bitmap-ctor(system-int32-system-int32-system-int32-system-drawing-imaging-pixelformat-system-intptr)

mail2mhossain commented 1 year ago

Trying to convert AV_PIX_FMT_BGR24 to 32-bit color with the format BGRA:

        AnyBitmap anyImage;
        int width = rawImage.Width;
        int height = rawImage.Height;
    int stride = rawImage.Stride;

        byte[] bgr24 = rawImage.GetBuffer(); 
        byte[] bgra32 = new byte[width * height * 4]; 

        for (int y = 0; y < height; y++)
        {
            int bgr24RowIndex = y * stride;
            int bgra32RowIndex = y * width * 4;

            for (int x = 0; x < width; x++)
            {
                int bgr24Index = bgr24RowIndex + x * 3;
                int bgra32Index = bgra32RowIndex + x * 4;

                bgra32[bgra32Index] = bgr24[bgr24Index + 2]; // blue channel
                bgra32[bgra32Index + 1] = bgr24[bgr24Index + 1]; // green channel
                bgra32[bgra32Index + 2] = bgr24[bgr24Index]; // red channel
                bgra32[bgra32Index + 3] = 255; // alpha channel (fully opaque)
            }
        }

        SKImageInfo info = new SKImageInfo(rawImage.Width, rawImage.Height, SKColorType.Bgra8888);  

        using (SKData data = SKData.CreateCopy(bgra32))
        {
            using (SKImage image = SKImage.FromPixels(info, data, rawImage.Width * 4))
            {
                using (SKBitmap bitmap = SKBitmap.FromImage(image))
                {
                    anyImage = bitmap;
                }
            }
        }

But getting blueish color in image and taking to long to convert too.

Any suggestions please.

mail2mhossain commented 1 year ago

Solution:

  1. First, you need to install the SixLabors.ImageSharp NuGet package to your project
  2. Then, you can use the following code to convert the RawImage object to a SixLabors.ImageSharp.Image:

public static unsafe Image ConvertRawImageToImageSharp (SIPSorceryMedia.Abstractions.RawImage rawImage) { int expectedStride = rawImage.Width * 3; // 3 bytes per pixel for Bgr24 format if (rawImage.Stride != expectedStride) { throw new InvalidOperationException("Stride of the raw image does not match the expected stride for ImageSharp Bgr24 format."); }

        // Create a new memory span from the rawImage Sample pointer
        var pixelDataSpan = new Span<byte>(rawImage.Sample.ToPointer(), rawImage.Height * rawImage.Stride);

        // Load the pixel data from the span
        var image = Image.LoadPixelData<Bgr24>(pixelDataSpan, rawImage.Width, rawImage.Height);

        return image;
    }
  1. Now convert the ImageSharp Image to an Avalonia Bitmap: public static Bitmap ConvertImageSharpToAvaloniaBitmap (Image image) { // Create a new WriteableBitmap with the same dimensions as the ImageSharp image var writeableBitmap = new WriteableBitmap(new PixelSize(image.Width, image.Height), new Vector(96, 96), Avalonia.Platform.PixelFormat.Rgba8888, Avalonia.Platform.AlphaFormat.Opaque);

        // Lock the WriteableBitmap's pixel buffer for direct access
        using (var buffer = writeableBitmap.Lock())
        {
            // Copy the pixel data from the ImageSharp image to the WriteableBitmap
            for (int y = 0; y < image.Height; y++)
            {
                Span<Bgr24> pixelRowSpan = image.GetPixelRowSpan(y);
                IntPtr pixelRowPtr = buffer.Address + y * buffer.RowBytes;
    
                for (int x = 0; x < pixelRowSpan.Length; x++)
                {
                    Bgr24 pixel = pixelRowSpan[x];
                    byte[] rgbaPixel = { pixel.R, pixel.G, pixel.B, 255 };
                    Marshal.Copy(rgbaPixel, 0, pixelRowPtr + x * 4, 4);
                }
            }
        }
    
        return writeableBitmap;
    }

Thanks to ChatGPT-4