C# ScheduleVideoFrame output wrong color and position

Ask software engineering and SDK questions for developers working on Mac OS X, Windows or Linux.
  • Author
  • Message
Offline

alberto_cocco

  • Posts: 2
  • Joined: Wed May 05, 2021 6:46 am
  • Real Name: Alberto Cocco

C# ScheduleVideoFrame output wrong color and position

PostWed May 05, 2021 7:39 am

Hello,
I have a Decklink Quad 2 and I'm trying to push frames from a video file to his SDI output.
I downloaded the example projects and I tried editing SignalGenCSharp, I am currently able to extract frames from the video, convert them to a Bitmap (Format32bppArgb) and push them to the SDI output using pixel format bmdFormat8BitARGB.
When I watch the result on my Blackmagic video assist the image is out of offset and it seems like there is a red filter covering it.
I tried different formats and resolutions but I found similar results.


how I enable the video output

Code: Select all
            m_selectedDevice.deckLinkOutput.EnableVideoOutput(m_selectedDisplayMode.GetDisplayMode(), _BMDVideoOutputFlags.bmdVideoOutputFlagDefault);



how I convert the Bitmap to argb32

Code: Select all

Bitmap original = imageData.ToBitmap();
Trace.WriteLine("PixelFormat " + original.PixelFormat); //Format24bppRgb

Bitmap clone = new Bitmap(original.Width, original.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

using (Graphics gr = Graphics.FromImage(clone))
       {
          gr.DrawImage(original, new System.Drawing.Rectangle(0, 0, clone.Width, clone.Height));
        }
               

using (var stream = new MemoryStream())
        {
         clone.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
         m_currentFrame = stream.ToArray();
         }


m_videoFrameBars = CreateOutputVideoFrame(FillVideoFrame);



how I create the decklink frame (CreateOutputVideoFrame)

Code: Select all
private IDeckLinkMutableVideoFrame CreateOutputVideoFrame(Action<IDeckLinkVideoFrame> fillFrame)
        {
m_selectedDevice.deckLinkOutput.CreateVideoFrame(m_frameWidth, m_frameHeight, m_frameWidth * 4, _BMDPixelFormat.bmdFormat8BitARGB, _BMDFrameFlags.bmdFrameFlagFlipVertical, out scheduleFrame);

fillFrame(scheduleFrame);
return scheduleFrame;
}


m_currentFrame is a byte array that stores the Argb frame, I used that to fill the frame

Code: Select all

void FillVideoFrame(IDeckLinkVideoFrame theFrame)
        {
            IntPtr buffer;
            theFrame.GetBytes(out buffer);
            Marshal.Copy(m_currentFrame, 0, buffer, m_currentFrame.Length);
        }



This is the result, a couple of pixel offset on the X and with the red filter

Image

This is m_currentFrame when I save it to my computer

Image

Any help would be appreciated.
Thank you for your time.
Offline

Cameron Nichols

Blackmagic Design

  • Posts: 442
  • Joined: Mon Sep 04, 2017 4:05 am

Re: C# ScheduleVideoFrame output wrong color and position

PostFri May 07, 2021 1:00 am

Hi Alberto,

It looks like the mapping of pixel format is reversed, can you try using format bmdFormat8BitBGRA?

Please also have a look at StillsCSharp sample, this sample creates a IDeckLinkVideoFrame wrapper of BitmapData.Scan0, providing zero-copy solution to output frames.

Regards
Cameron
Offline

alberto_cocco

  • Posts: 2
  • Joined: Wed May 05, 2021 6:46 am
  • Real Name: Alberto Cocco

Re: C# ScheduleVideoFrame output wrong color and position

PostFri May 07, 2021 9:55 am

Hi Cameron,

Thank you, this totally solved the problem, as a workaround I was able to correct the color swapping channels red with alpha and blue with green but it wasn't very efficient.

Code: Select all
        //this is a workaround find a better way of doing this
        public static void RGBtoBGR(Bitmap bmp)
        {
            BitmapData data = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height),
           ImageLockMode.ReadWrite, bmp.PixelFormat);

            int length = Math.Abs(data.Stride) * bmp.Height;

            unsafe
            {
                byte* rgbValues = (byte*)data.Scan0.ToPointer();

                for (int i = 0; i < length; i += 4)
                {
                    byte dummy = rgbValues[i + 2];
                    rgbValues[i + 2] = rgbValues[i + 3];
                    rgbValues[i + 3] = dummy;


                    dummy = rgbValues[i + 1];
                    rgbValues[i + 1] = rgbValues[i];
                    rgbValues[i] = dummy;
                }
            }

            bmp.UnlockBits(data);
        }


The IDeckLinkVideoFrame wrapper found in the StillsCSharp sample works great and it only takes 1 ms to execute, I'll post the code as this may help someone else

Code: Select all
 
Bitmap playbackBitmap = getCurrentVideoFrameBitmap();
BitmapData playbackBitmapData = null;
try
      {
         var rect = new System.Drawing.Rectangle(0, 0, playbackBitmap.Width, playbackBitmap.Height);
         playbackBitmapData = playbackBitmap.LockBits(rect, ImageLockMode.ReadOnly, playbackBitmap.PixelFormat);

        //Create BGRA32 video frame based on bitmap data
        m_videoFrame = new Bgra32VideoFrame(playbackBitmap.Width, playbackBitmap.Height, _BMDFrameFlags.bmdFrameFlagDefault, playbackBitmapData.Scan0);
       
        m_selectedDevice.deckLinkOutput.ScheduleVideoFrame(m_videoFrame, (m_totalFramesScheduled * m_frameDuration), m_frameDuration, m_frameTimescale);
          }
          catch (Exception e)
          {
           //todo handle error
           }
           finally
           {
                    if (playbackBitmap != null)
                    {
                        playbackBitmap.UnlockBits(playbackBitmapData);
                        //don't need to Dispose as it will loop
                        //playbackBitmap.Dispose();
                    }
           }

Return to Software Developers

Who is online

Users browsing this forum: No registered users and 6 guests