[cscore] Add BGRA support (#6365)

This commit is contained in:
Thad House
2024-02-12 23:42:17 -08:00
committed by GitHub
parent fb947fe998
commit 9ed0631ec9
17 changed files with 371 additions and 129 deletions

View File

@@ -36,11 +36,16 @@ public class CvSink extends ImageSink {
switch (pixelFormat) {
case kYUYV:
case kRGB565:
case kY16:
case kUYVY:
type = CvType.CV_8UC2;
break;
case kBGR:
type = CvType.CV_8UC3;
break;
case kBGRA:
type = CvType.CV_8UC4;
break;
case kGray:
case kMJPEG:
default:

View File

@@ -40,16 +40,16 @@ public class CvSource extends ImageSource {
}
/**
* Put an OpenCV image and notify sinks.
* Put an OpenCV image and notify sinks
*
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images are supported. If the
* format, depth or channel order is different, use Mat.convertTo() and/or cvtColor() to convert
* it first.
* <p>The image format is guessed from the number of channels. The channel mapping is as follows.
* 1: kGray 2: kYUYV 3: BGR 4: BGRA Any other channel numbers will throw an error. If your image
* is an in alternate format, use the overload that takes a PixelFormat.
*
* @param image OpenCV image
* @param image OpenCV Image
*/
public void putFrame(Mat image) {
// We only support 8-bit images, convert if necessary
// We only support 8 bit channels
boolean cleanupRequired = false;
Mat finalImage;
if (image.depth() == 0) {
@@ -64,22 +64,64 @@ public class CvSource extends ImageSource {
int channels = finalImage.channels();
PixelFormat format;
if (channels == 1) {
// 1 channel is assumed Graysacle
format = PixelFormat.kGray;
} else if (channels == 2) {
// 2 channels is assumed YUYV
format = PixelFormat.kYUYV;
} else if (channels == 3) {
// 3 channels is assumed BGR
format = PixelFormat.kBGR;
} else if (channels == 4) {
// 4 channels is assumed BGRA
format = PixelFormat.kBGRA;
} else {
throw new VideoException("Unsupported image type");
throw new VideoException("Unable to get pixel format for " + channels + " channels");
}
// TODO old code supported BGRA, but the only way I can support that is slow.
// Update cscore to support BGRA for raw frames
putFrame(finalImage, format, true);
} finally {
if (cleanupRequired) {
finalImage.release();
}
}
}
/**
* Put an OpenCV image and notify sinks.
*
* <p>The format of the Mat must match the PixelFormat. You will corrupt memory if they dont. With
* skipVerification false, we will verify the number of channels matches the pixel format. If
* skipVerification is true, this step is skipped and is passed straight through.
*
* @param image OpenCV image
* @param format The pixel format of the image
* @param skipVerification skip verifying pixel format
*/
public void putFrame(Mat image, PixelFormat format, boolean skipVerification) {
// We only support 8-bit images, convert if necessary
boolean cleanupRequired = false;
Mat finalImage;
if (image.depth() == 0) {
finalImage = image;
} else {
finalImage = new Mat();
image.convertTo(finalImage, 0);
cleanupRequired = true;
}
try {
if (!skipVerification) {
verifyFormat(finalImage, format);
}
long step = image.step1() * image.elemSize1();
CameraServerJNI.putRawSourceFrameData(
m_handle,
finalImage.dataAddr(),
(int) finalImage.total() * channels,
(int) finalImage.total() * finalImage.channels(),
finalImage.width(),
finalImage.height(),
image.width(),
(int) step,
format.getValue());
} finally {
@@ -88,4 +130,52 @@ public class CvSource extends ImageSource {
}
}
}
private void verifyFormat(Mat image, PixelFormat pixelFormat) {
int channels = image.channels();
switch (pixelFormat) {
case kBGR:
if (channels == 3) {
return;
}
break;
case kBGRA:
if (channels == 4) {
return;
}
break;
case kGray:
if (channels == 1) {
return;
}
break;
case kRGB565:
if (channels == 2) {
return;
}
break;
case kUYVY:
if (channels == 2) {
return;
}
break;
case kY16:
if (channels == 2) {
return;
}
break;
case kYUYV:
if (channels == 2) {
return;
}
break;
case kMJPEG:
if (channels == 1) {
return;
}
break;
default:
break;
}
}
}

View File

@@ -314,6 +314,54 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
}
}
break;
case VideoMode::kBGRA:
// If source is RGB565, YUYV, UYVY, Gray or Y16, need to convert to BGR
// first
if (cur->pixelFormat == VideoMode::kRGB565) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
} else {
cur = ConvertRGB565ToBGR(cur);
}
} else if (cur->pixelFormat == VideoMode::kYUYV) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
} else {
cur = ConvertYUYVToBGR(cur);
}
} else if (cur->pixelFormat == VideoMode::kUYVY) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
} else {
cur = ConvertUYVYToBGR(cur);
}
} else if (cur->pixelFormat == VideoMode::kGray) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
} else {
cur = ConvertGrayToBGR(cur);
}
} else if (cur->pixelFormat == VideoMode::kY16) {
// Check to see if BGR version already exists...
if (Image* newImage =
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
cur = newImage;
} else if (Image* newImage = GetExistingImage(cur->width, cur->height,
VideoMode::kGray)) {
cur = ConvertGrayToBGR(newImage);
} else {
cur = ConvertGrayToBGR(ConvertY16ToGray(cur));
}
}
return ConvertBGRToBGRA(cur);
case VideoMode::kYUYV:
case VideoMode::kUYVY:
default:
@@ -664,6 +712,28 @@ Image* Frame::ConvertY16ToGray(Image* image) {
return rv;
}
Image* Frame::ConvertBGRToBGRA(Image* image) {
if (!image || image->pixelFormat != VideoMode::kBGR) {
return nullptr;
}
// Allocate a RGB565 image
auto newImage =
m_impl->source.AllocImage(VideoMode::kBGRA, image->width, image->height,
image->width * image->height * 4);
// Convert
cv::cvtColor(image->AsMat(), newImage->AsMat(), cv::COLOR_BGR2BGRA);
// Save the result
Image* rv = newImage.release();
if (m_impl) {
std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
}
Image* Frame::GetImageImpl(int width, int height,
VideoMode::PixelFormat pixelFormat,
int requiredJpegQuality, int defaultJpegQuality) {
@@ -727,3 +797,16 @@ void Frame::ReleaseFrame() {
m_impl->source.ReleaseFrameImpl(std::unique_ptr<Impl>(m_impl));
m_impl = nullptr;
}
namespace cs {
std::unique_ptr<Image> CreateImageFromBGRA(cs::SourceImpl* source, size_t width,
size_t height, size_t stride,
const uint8_t* data) {
cv::Mat finalImage{static_cast<int>(height), static_cast<int>(width), CV_8UC4,
const_cast<uint8_t*>(data), stride};
std::unique_ptr<Image> dest = source->AllocImage(
VideoMode::PixelFormat::kBGR, width, height, width * height * 3);
cv::cvtColor(finalImage, dest->AsMat(), cv::COLOR_BGRA2BGR);
return dest;
}
} // namespace cs

View File

@@ -22,6 +22,10 @@ namespace cs {
class SourceImpl;
std::unique_ptr<Image> CreateImageFromBGRA(cs::SourceImpl* source, size_t width,
size_t height, size_t stride,
const uint8_t* data);
class Frame {
friend class SourceImpl;
@@ -206,6 +210,7 @@ class Frame {
Image* ConvertGrayToMJPEG(Image* image, int quality);
Image* ConvertGrayToY16(Image* image);
Image* ConvertY16ToGray(Image* image);
Image* ConvertBGRToBGRA(Image* image);
Image* GetImage(int width, int height, VideoMode::PixelFormat pixelFormat) {
if (pixelFormat == VideoMode::kMJPEG) {

View File

@@ -63,6 +63,9 @@ class Image {
case VideoMode::kBGR:
type = CV_8UC3;
break;
case VideoMode::kBGRA:
type = CV_8UC4;
break;
case VideoMode::kGray:
case VideoMode::kMJPEG:
default:
@@ -81,6 +84,8 @@ class Image {
return 2 * width;
case VideoMode::kBGR:
return 3 * width;
case VideoMode::kBGRA:
return 4 * width;
case VideoMode::kGray:
return width;
case VideoMode::kMJPEG:

View File

@@ -457,6 +457,9 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
case VideoMode::kBGR:
os << "BGR";
break;
case VideoMode::kBGRA:
os << "BGRA";
break;
case VideoMode::kGray:
os << "gray";
break;

View File

@@ -22,31 +22,10 @@ RawSourceImpl::RawSourceImpl(std::string_view name, wpi::Logger& logger,
RawSourceImpl::~RawSourceImpl() = default;
void RawSourceImpl::PutFrame(const WPI_RawFrame& image) {
int type;
switch (image.pixelFormat) {
case VideoMode::kYUYV:
case VideoMode::kRGB565:
case VideoMode::kY16:
case VideoMode::kUYVY:
type = CV_8UC2;
break;
case VideoMode::kBGR:
type = CV_8UC3;
break;
case VideoMode::kGray:
case VideoMode::kMJPEG:
default:
type = CV_8UC1;
break;
}
cv::Mat finalImage{image.height, image.width, type, image.data,
static_cast<size_t>(image.stride)};
std::unique_ptr<Image> dest =
AllocImage(static_cast<VideoMode::PixelFormat>(image.pixelFormat),
image.width, image.height, image.size);
finalImage.copyTo(dest->AsMat());
SourceImpl::PutFrame(std::move(dest), wpi::Now());
auto currentTime = wpi::Now();
std::string_view data_view{reinterpret_cast<char*>(image.data), image.size};
SourceImpl::PutFrame(static_cast<VideoMode::PixelFormat>(image.pixelFormat),
image.width, image.height, data_view, currentTime);
}
namespace cs {

View File

@@ -196,6 +196,8 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
mode.pixelFormat = cs::VideoMode::kRGB565;
} else if (wpi::equals_lower(str, "bgr")) {
mode.pixelFormat = cs::VideoMode::kBGR;
} else if (wpi::equals_lower(str, "bgra")) {
mode.pixelFormat = cs::VideoMode::kBGRA;
} else if (wpi::equals_lower(str, "gray")) {
mode.pixelFormat = cs::VideoMode::kGray;
} else if (wpi::equals_lower(str, "y16")) {
@@ -361,6 +363,9 @@ wpi::json SourceImpl::GetConfigJsonObject(CS_Status* status) {
case VideoMode::kBGR:
pixelFormat = "bgr";
break;
case VideoMode::kBGRA:
pixelFormat = "bgra";
break;
case VideoMode::kGray:
pixelFormat = "gray";
break;
@@ -450,6 +455,15 @@ std::unique_ptr<Image> SourceImpl::AllocImage(
void SourceImpl::PutFrame(VideoMode::PixelFormat pixelFormat, int width,
int height, std::string_view data, Frame::Time time) {
if (pixelFormat == VideoMode::PixelFormat::kBGRA) {
// Write BGRA as BGR to save a copy
auto image =
CreateImageFromBGRA(this, width, height, width * 4,
reinterpret_cast<const uint8_t*>(data.data()));
PutFrame(std::move(image), time);
return;
}
auto image = AllocImage(pixelFormat, width, height, data.size());
// Copy in image data

View File

@@ -12,7 +12,6 @@
#include <wpi/SmallString.h>
#include <wpi/jni_util.h>
#include "cscore_cv.h"
#include "cscore_raw.h"
#include "cscore_runloop.h"
#include "edu_wpi_first_cscore_CameraServerJNI.h"

View File

@@ -68,7 +68,8 @@ struct VideoMode : public CS_VideoMode {
kBGR = WPI_PIXFMT_BGR,
kGray = WPI_PIXFMT_GRAY,
kY16 = WPI_PIXFMT_Y16,
kUYVY = WPI_PIXFMT_UYVY
kUYVY = WPI_PIXFMT_UYVY,
kBGRA = WPI_PIXFMT_BGRA,
};
VideoMode() {
pixelFormat = 0;

View File

@@ -44,15 +44,36 @@ class CvSource : public ImageSource {
int height, int fps);
/**
* Put an OpenCV image and notify sinks.
* Put an OpenCV image and notify sinks
*
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
* are supported. If the format, depth or channel order is different, use
* cv::Mat::convertTo() and/or cv::cvtColor() to convert it first.
* <p>
* The image format is guessed from the number of channels. The channel
* mapping is as follows. 1: kGray 2: kYUYV 3: BGR 4: BGRA Any other channel
* numbers will throw an error. If your image is an in alternate format, use
* the overload that takes a PixelFormat.
*
* @param image OpenCV image
* @param image OpenCV Image
*/
void PutFrame(cv::Mat& image);
/**
* Put an OpenCV image and notify sinks.
*
* <p>
* The format of the Mat must match the PixelFormat. You will corrupt memory
* if they dont. With skipVerification false, we will verify the number of
* channels matches the pixel format. If skipVerification is true, this step
* is skipped and is passed straight through.
*
* @param image OpenCV image
* @param pixelFormat The pixel format of the image
* @param skipVerification skip verifying pixel format
*/
void PutFrame(cv::Mat& image, VideoMode::PixelFormat pixelFormat,
bool skipVerification);
private:
static bool VerifyFormat(cv::Mat& image, VideoMode::PixelFormat pixelFormat);
};
/**
@@ -131,6 +152,8 @@ class CvSink : public ImageSink {
uint64_t GrabFrameNoTimeoutDirect(cv::Mat& image);
private:
constexpr int GetCvFormat(WPI_PixelFormat pixelFormat);
wpi::RawFrame rawFrame;
VideoMode::PixelFormat pixelFormat;
};
@@ -145,6 +168,56 @@ inline CvSource::CvSource(std::string_view name, VideoMode::PixelFormat format,
&m_status);
}
inline bool CvSource::VerifyFormat(cv::Mat& image,
VideoMode::PixelFormat pixelFormat) {
int channels = image.channels();
switch (pixelFormat) {
case VideoMode::PixelFormat::kBGR:
if (channels == 3) {
return true;
}
break;
case VideoMode::PixelFormat::kBGRA:
if (channels == 4) {
return true;
}
break;
case VideoMode::PixelFormat::kGray:
if (channels == 1) {
return true;
}
break;
case VideoMode::PixelFormat::kRGB565:
if (channels == 2) {
return true;
}
break;
case VideoMode::PixelFormat::kUYVY:
if (channels == 2) {
return true;
}
break;
case VideoMode::PixelFormat::kY16:
if (channels == 2) {
return true;
}
break;
case VideoMode::PixelFormat::kYUYV:
if (channels == 2) {
return true;
}
break;
case VideoMode::PixelFormat::kMJPEG:
if (channels == 1) {
return true;
}
break;
default:
break;
}
return false;
}
inline void CvSource::PutFrame(cv::Mat& image) {
// We only support 8-bit images; convert if necessary.
cv::Mat finalImage;
@@ -155,27 +228,54 @@ inline void CvSource::PutFrame(cv::Mat& image) {
}
int channels = finalImage.channels();
WPI_PixelFormat format;
VideoMode::PixelFormat format;
if (channels == 1) {
format = WPI_PIXFMT_GRAY;
// 1 channel is assumed Graysacle
format = VideoMode::PixelFormat::kGray;
} else if (channels == 2) {
// 2 channels is assumed YUYV
format = VideoMode::PixelFormat::kYUYV;
} else if (channels == 3) {
format = WPI_PIXFMT_BGR;
// 3 channels is assumed BGR
format = VideoMode::PixelFormat::kBGR;
} else if (channels == 4) {
// 4 channels is assumed BGRA
format = VideoMode::PixelFormat::kBGRA;
} else {
// TODO Error
return;
}
// TODO old code supported BGRA, but the only way I can support that is slow.
// Update cscore to support BGRA for raw frames
PutFrame(finalImage, format, true);
}
inline void CvSource::PutFrame(cv::Mat& image,
VideoMode::PixelFormat pixelFormat,
bool skipVerification) {
// We only support 8-bit images; convert if necessary.
cv::Mat finalImage;
if (image.depth() == CV_8U) {
finalImage = image;
} else {
image.convertTo(finalImage, CV_8U);
}
if (!skipVerification) {
if (!VerifyFormat(finalImage, pixelFormat)) {
// TODO Error
return;
}
}
WPI_RawFrame frame; // use WPI_Frame because we don't want the destructor
frame.data = finalImage.data;
frame.freeFunc = nullptr;
frame.freeCbData = nullptr;
frame.size = finalImage.total() * channels;
frame.size = finalImage.total() * finalImage.channels();
frame.width = finalImage.cols;
frame.height = finalImage.rows;
frame.stride = finalImage.cols;
frame.pixelFormat = format;
frame.stride = finalImage.step;
frame.pixelFormat = pixelFormat;
m_status = 0;
PutSourceFrame(m_handle, frame, &m_status);
}
@@ -209,16 +309,21 @@ inline uint64_t CvSink::GrabFrameNoTimeout(cv::Mat& image) {
return retVal;
}
inline constexpr int GetCvFormat(WPI_PixelFormat pixelFormat) {
inline constexpr int CvSink::GetCvFormat(WPI_PixelFormat pixelFormat) {
int type = 0;
switch (pixelFormat) {
case WPI_PIXFMT_YUYV:
case WPI_PIXFMT_RGB565:
case WPI_PIXFMT_Y16:
case WPI_PIXFMT_UYVY:
type = CV_8UC2;
break;
case WPI_PIXFMT_BGR:
type = CV_8UC3;
break;
case WPI_PIXFMT_BGRA:
type = CV_8UC4;
break;
case WPI_PIXFMT_GRAY:
case WPI_PIXFMT_MJPEG:
default:
@@ -231,31 +336,33 @@ inline constexpr int GetCvFormat(WPI_PixelFormat pixelFormat) {
inline uint64_t CvSink::GrabFrameDirect(cv::Mat& image, double timeout) {
rawFrame.height = 0;
rawFrame.width = 0;
rawFrame.stride = 0;
rawFrame.pixelFormat = pixelFormat;
m_status = GrabSinkFrameTimeout(m_handle, rawFrame, timeout, &m_status);
if (m_status <= 0) {
return m_status;
auto timestamp = GrabSinkFrameTimeout(m_handle, rawFrame, timeout, &m_status);
if (m_status != CS_OK) {
return 0;
}
image =
cv::Mat{rawFrame.height, rawFrame.width,
GetCvFormat(static_cast<WPI_PixelFormat>(rawFrame.pixelFormat)),
rawFrame.data};
return m_status;
rawFrame.data, static_cast<size_t>(rawFrame.stride)};
return timestamp;
}
inline uint64_t CvSink::GrabFrameNoTimeoutDirect(cv::Mat& image) {
rawFrame.height = 0;
rawFrame.width = 0;
rawFrame.stride = 0;
rawFrame.pixelFormat = pixelFormat;
m_status = GrabSinkFrame(m_handle, rawFrame, &m_status);
if (m_status <= 0) {
return m_status;
auto timestamp = GrabSinkFrame(m_handle, rawFrame, &m_status);
if (m_status != CS_OK) {
return 0;
}
image =
cv::Mat{rawFrame.height, rawFrame.width,
GetCvFormat(static_cast<WPI_PixelFormat>(rawFrame.pixelFormat)),
rawFrame.data};
return m_status;
rawFrame.data, static_cast<size_t>(rawFrame.stride)};
return timestamp;
}
} // namespace cs

View File

@@ -80,6 +80,8 @@ static VideoMode::PixelFormat ToPixelFormat(__u32 pixelFormat) {
return VideoMode::kRGB565;
case V4L2_PIX_FMT_BGR24:
return VideoMode::kBGR;
case V4L2_PIX_FMT_ABGR32:
return VideoMode::kBGRA;
case V4L2_PIX_FMT_GREY:
return VideoMode::kGray;
case V4L2_PIX_FMT_Y16:
@@ -102,6 +104,8 @@ static __u32 FromPixelFormat(VideoMode::PixelFormat pixelFormat) {
return V4L2_PIX_FMT_RGB565;
case VideoMode::kBGR:
return V4L2_PIX_FMT_BGR24;
case VideoMode::kBGRA:
return V4L2_PIX_FMT_ABGR32;
case VideoMode::kGray:
return V4L2_PIX_FMT_GREY;
case VideoMode::kY16:

View File

@@ -7,9 +7,6 @@
#include <wpi/timestamp.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
@implementation UsbCameraDelegate
- (id)init {
@@ -24,6 +21,8 @@
(void)sampleBuffer;
(void)connection;
auto currentTime = wpi::Now();
auto sharedThis = self.cppImpl.lock();
if (!sharedThis) {
return;
@@ -52,16 +51,12 @@
return;
}
size_t currSize = width * 3 * height;
auto tmpMat = cv::Mat(height, width, CV_8UC4, baseaddress, rowBytes);
auto image = sharedThis->AllocImage(cs::VideoMode::PixelFormat::kBGR, width,
height, currSize);
cv::cvtColor(tmpMat, image->AsMat(), cv::COLOR_BGRA2BGR);
std::unique_ptr<cs::Image> image = cs::CreateImageFromBGRA(
sharedThis.get(), width, height, rowBytes, reinterpret_cast<uint8_t*>(baseaddress));
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
sharedThis->objcPutFrame(std::move(image), wpi::Now());
sharedThis->objcPutFrame(std::move(image), currentTime);
}
@end

View File

@@ -18,7 +18,6 @@
#include "Instance.h"
#include "c_util.h"
#include "cscore_cpp.h"
#include "opencv2/imgproc.hpp"
#include "UsbCameraImpl.h"
namespace cs {

View File

@@ -21,9 +21,6 @@
#include <Dbt.h>
#include <Dshow.h>
#include <Windows.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <wpi/ConvertUTF.h>
#include <wpi/MemAlloc.h>
#include <wpi/SmallString.h>
@@ -284,6 +281,8 @@ void UsbCameraImpl::ProcessFrame(IMFSample* videoSample,
return;
}
auto currentTime = wpi::Now();
ComPtr<IMFMediaBuffer> buf;
if (!SUCCEEDED(videoSample->ConvertToContiguousBuffer(buf.GetAddressOf()))) {
@@ -339,56 +338,9 @@ void UsbCameraImpl::ProcessFrame(IMFSample* videoSample,
}
}
cv::Mat tmpMat;
std::unique_ptr<Image> dest;
bool doFinalSet = true;
switch (mode.pixelFormat) {
case cs::VideoMode::PixelFormat::kMJPEG: {
// Special case
PutFrame(VideoMode::kMJPEG, mode.width, mode.height,
{reinterpret_cast<char*>(ptr), length}, wpi::Now());
doFinalSet = false;
break;
}
case cs::VideoMode::PixelFormat::kGray:
tmpMat = cv::Mat(mode.height, mode.width, CV_8UC1, ptr, pitch);
dest = AllocImage(VideoMode::kGray, tmpMat.cols, tmpMat.rows,
tmpMat.total());
tmpMat.copyTo(dest->AsMat());
break;
case cs::VideoMode::PixelFormat::kY16:
tmpMat = cv::Mat(mode.height, mode.width, CV_8UC2, ptr, pitch);
dest =
AllocImage(VideoMode::kY16, tmpMat.cols, tmpMat.rows, tmpMat.total());
tmpMat.copyTo(dest->AsMat());
break;
case cs::VideoMode::PixelFormat::kBGR:
tmpMat = cv::Mat(mode.height, mode.width, CV_8UC3, ptr, pitch);
dest = AllocImage(VideoMode::kBGR, tmpMat.cols, tmpMat.rows,
tmpMat.total() * 3);
tmpMat.copyTo(dest->AsMat());
break;
case cs::VideoMode::PixelFormat::kYUYV:
tmpMat = cv::Mat(mode.height, mode.width, CV_8UC2, ptr, pitch);
dest = AllocImage(VideoMode::kYUYV, tmpMat.cols, tmpMat.rows,
tmpMat.total() * 2);
tmpMat.copyTo(dest->AsMat());
break;
case cs::VideoMode::PixelFormat::kUYVY:
tmpMat = cv::Mat(mode.height, mode.width, CV_8UC2, ptr, pitch);
dest = AllocImage(VideoMode::kUYVY, tmpMat.cols, tmpMat.rows,
tmpMat.total() * 2);
tmpMat.copyTo(dest->AsMat());
break;
default:
doFinalSet = false;
break;
}
if (doFinalSet) {
PutFrame(std::move(dest), wpi::Now());
}
std::string_view data_view{reinterpret_cast<char*>(ptr), length};
SourceImpl::PutFrame(static_cast<VideoMode::PixelFormat>(mode.pixelFormat),
mode.width, mode.height, data_view, currentTime);
if (buffer2d) {
buffer2d->Unlock2D();
@@ -480,8 +432,6 @@ static cs::VideoMode::PixelFormat GetFromGUID(const GUID& guid) {
return cs::VideoMode::PixelFormat::kY16;
} else if (IsEqualGUID(guid, MFVideoFormat_YUY2)) {
return cs::VideoMode::PixelFormat::kYUYV;
} else if (IsEqualGUID(guid, MFVideoFormat_RGB24)) {
return cs::VideoMode::PixelFormat::kBGR;
} else if (IsEqualGUID(guid, MFVideoFormat_MJPG)) {
return cs::VideoMode::PixelFormat::kMJPEG;
} else if (IsEqualGUID(guid, MFVideoFormat_RGB565)) {

View File

@@ -21,7 +21,9 @@ public enum PixelFormat {
/** Grayscale, 16 bpp. */
kY16(6),
/** YUV 4:2:2, 16 bpp. */
kUYVY(7);
kUYVY(7),
/** BGRA 8-8-8-8. 32 bpp. */
kBGRA(8);
private final int value;

View File

@@ -55,6 +55,7 @@ enum WPI_PixelFormat {
WPI_PIXFMT_GRAY, // Grayscale, 8 bpp
WPI_PIXFMT_Y16, // Grayscale, 16 bpp
WPI_PIXFMT_UYVY, // YUV 4:2:2, 16 bpp
WPI_PIXFMT_BGRA, // BGRA 8-8-8-8-, 32 bpp
};
// Returns nonzero if the frame data was allocated/reallocated