Created
April 5, 2023 04:03
-
-
Save matthewrdev/53d02656639bc931d20d8fc37fad5edf to your computer and use it in GitHub Desktop.
Copies an OpenCV Mat frame from BGR format into an RGBA buffer.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using OpenCvSharp; | |
namespace MyApp | |
{ | |
public static class VideoFrameDecoderHelper | |
{ | |
/// <summary> | |
/// Performs a pointer arithmetic based decoding operation from the <paramref name="frame"/> into the frame buffer. | |
/// <para/> | |
/// Assumes that the <paramref name="frameBuffer"/> is initialised and at the correct size. | |
/// </summary> | |
/// <param name="frame"></param> | |
/// <param name="frameBuffer"></param> | |
/// <exception cref="ArgumentNullException"></exception> | |
public static void DecodeInto(Mat frame, ref byte[] frameBuffer) | |
{ | |
if (frame is null) | |
{ | |
throw new ArgumentNullException(nameof(frame)); | |
} | |
if (frameBuffer is null) | |
{ | |
throw new ArgumentNullException(nameof(frameBuffer)); | |
} | |
var imageHeight = frame.Rows; | |
var imageWidth = frame.Cols; | |
const int destinationBytesPerPixel = 4; // Output frame pixels are in RGBA format. | |
const int sourceBytesPerPixel = 3; // OpenCV frame pixels are in BGR format. | |
var imageSizeInBytes = imageHeight * imageWidth * destinationBytesPerPixel; | |
long sourceBytesPerRow = frame.Step(); | |
long destinationBytesPerRow = imageWidth * destinationBytesPerPixel; | |
// TODO: Pixel type detection? | |
byte r, g, b, a; | |
a = 0; | |
unsafe | |
{ | |
// The following code block performs a buffer copy of the open CV frame using pointer dereferencing (rather than C#'s array derefencing operator). | |
// This code AOT compiles in release mode and will run 30x-60x faster than in debug mode. | |
// Debug mode may be 50-60ms, release may be between 1-2ms. | |
fixed (byte* destinationFramePointer = &frameBuffer[0]) | |
{ | |
byte* sourceFramePointer = frame.DataPointer; | |
for (int currRow = 0; currRow < imageHeight; currRow++) | |
{ | |
long currRowOffset = sourceBytesPerRow * currRow; | |
long sourceRowOffset = sourceBytesPerRow * currRow; | |
long destinationRowOffset = destinationBytesPerRow * currRow; | |
for (int currCol = 0; currCol < imageWidth; currCol++) | |
{ | |
b = *(sourceFramePointer + sourceRowOffset + (sourceBytesPerPixel * currCol)); | |
g = *(sourceFramePointer + sourceRowOffset + (sourceBytesPerPixel * currCol + 1)); | |
r = *(sourceFramePointer + sourceRowOffset + (sourceBytesPerPixel * currCol + 2)); | |
a = 0; | |
*(destinationFramePointer + destinationRowOffset + (destinationBytesPerPixel * currCol)) = r; | |
*(destinationFramePointer + destinationRowOffset + (destinationBytesPerPixel * currCol + 1)) = g; | |
*(destinationFramePointer + destinationRowOffset + (destinationBytesPerPixel * currCol + 2)) = b; | |
*(destinationFramePointer + destinationRowOffset + (destinationBytesPerPixel * currCol + 3)) = a; | |
} | |
} | |
} | |
} | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment