[cscore] CvSink: Allow specifying output PixelFormat (#5943)

This commit is contained in:
Joseph Farkas
2023-11-22 14:35:42 -05:00
committed by GitHub
parent 25b7dca46b
commit 437cc91af5
10 changed files with 70 additions and 35 deletions

View File

@@ -19,16 +19,18 @@
using namespace cs;
CvSinkImpl::CvSinkImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry)
: SinkImpl{name, logger, notifier, telemetry} {
Notifier& notifier, Telemetry& telemetry,
VideoMode::PixelFormat pixelFormat)
: SinkImpl{name, logger, notifier, telemetry}, m_pixelFormat{pixelFormat} {
m_active = true;
// m_thread = std::thread(&CvSinkImpl::ThreadMain, this);
}
CvSinkImpl::CvSinkImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
VideoMode::PixelFormat pixelFormat,
std::function<void(uint64_t time)> processFrame)
: SinkImpl{name, logger, notifier, telemetry} {}
: SinkImpl{name, logger, notifier, telemetry}, m_pixelFormat{pixelFormat} {}
CvSinkImpl::~CvSinkImpl() {
Stop();
@@ -65,7 +67,7 @@ uint64_t CvSinkImpl::GrabFrame(cv::Mat& image) {
return 0; // signal error
}
if (!frame.GetCv(image)) {
if (!frame.GetCv(image, m_pixelFormat)) {
// Shouldn't happen, but just in case...
std::this_thread::sleep_for(std::chrono::milliseconds(20));
return 0;
@@ -91,7 +93,7 @@ uint64_t CvSinkImpl::GrabFrame(cv::Mat& image, double timeout) {
return 0; // signal error
}
if (!frame.GetCv(image)) {
if (!frame.GetCv(image, m_pixelFormat)) {
// Shouldn't happen, but just in case...
std::this_thread::sleep_for(std::chrono::milliseconds(20));
return 0;
@@ -127,20 +129,23 @@ void CvSinkImpl::ThreadMain() {
namespace cs {
CS_Sink CreateCvSink(std::string_view name, CS_Status* status) {
CS_Sink CreateCvSink(std::string_view name, VideoMode::PixelFormat pixelFormat,
CS_Status* status) {
auto& inst = Instance::GetInstance();
return inst.CreateSink(
CS_SINK_CV, std::make_shared<CvSinkImpl>(name, inst.logger, inst.notifier,
inst.telemetry));
inst.telemetry, pixelFormat));
}
CS_Sink CreateCvSinkCallback(std::string_view name,
VideoMode::PixelFormat pixelFormat,
std::function<void(uint64_t time)> processFrame,
CS_Status* status) {
auto& inst = Instance::GetInstance();
return inst.CreateSink(
CS_SINK_CV, std::make_shared<CvSinkImpl>(name, inst.logger, inst.notifier,
inst.telemetry, processFrame));
CS_SINK_CV,
std::make_shared<CvSinkImpl>(name, inst.logger, inst.notifier,
inst.telemetry, pixelFormat, processFrame));
}
static constexpr unsigned SinkMask = CS_SINK_CV | CS_SINK_RAW;
@@ -206,15 +211,19 @@ void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) {
extern "C" {
CS_Sink CS_CreateCvSink(const char* name, CS_Status* status) {
return cs::CreateCvSink(name, status);
CS_Sink CS_CreateCvSink(const char* name, enum CS_PixelFormat pixelFormat,
CS_Status* status) {
return cs::CreateCvSink(
name, static_cast<VideoMode::PixelFormat>(pixelFormat), status);
}
CS_Sink CS_CreateCvSinkCallback(const char* name, void* data,
CS_Sink CS_CreateCvSinkCallback(const char* name,
enum CS_PixelFormat pixelFormat, void* data,
void (*processFrame)(void* data, uint64_t time),
CS_Status* status) {
return cs::CreateCvSinkCallback(
name, [=](uint64_t time) { processFrame(data, time); }, status);
name, static_cast<VideoMode::PixelFormat>(pixelFormat),
[=](uint64_t time) { processFrame(data, time); }, status);
}
void CS_SetSinkDescription(CS_Sink sink, const char* description,

View File

@@ -25,9 +25,9 @@ class SourceImpl;
class CvSinkImpl : public SinkImpl {
public:
CvSinkImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry);
Telemetry& telemetry, VideoMode::PixelFormat pixelFormat);
CvSinkImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry,
Telemetry& telemetry, VideoMode::PixelFormat pixelFormat,
std::function<void(uint64_t time)> processFrame);
~CvSinkImpl() override;
@@ -42,6 +42,7 @@ class CvSinkImpl : public SinkImpl {
std::atomic_bool m_active; // set to false to terminate threads
std::thread m_thread;
std::function<void(uint64_t time)> m_processFrame;
VideoMode::PixelFormat m_pixelFormat;
};
} // namespace cs

View File

@@ -709,8 +709,9 @@ Image* Frame::GetImageImpl(int width, int height,
return ConvertImpl(cur, pixelFormat, requiredJpegQuality, defaultJpegQuality);
}
bool Frame::GetCv(cv::Mat& image, int width, int height) {
Image* rawImage = GetImage(width, height, VideoMode::kBGR);
bool Frame::GetCv(cv::Mat& image, int width, int height,
VideoMode::PixelFormat pixelFormat) {
Image* rawImage = GetImage(width, height, pixelFormat);
if (!rawImage) {
return false;
}

View File

@@ -219,10 +219,11 @@ class Frame {
defaultQuality);
}
bool GetCv(cv::Mat& image) {
return GetCv(image, GetOriginalWidth(), GetOriginalHeight());
bool GetCv(cv::Mat& image, VideoMode::PixelFormat pixelFormat) {
return GetCv(image, GetOriginalWidth(), GetOriginalHeight(), pixelFormat);
}
bool GetCv(cv::Mat& image, int width, int height);
bool GetCv(cv::Mat& image, int width, int height,
VideoMode::PixelFormat pixelFormat);
private:
Image* ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,

View File

@@ -1392,18 +1392,20 @@ Java_edu_wpi_first_cscore_CameraServerJNI_createMjpegServer
/*
* Class: edu_wpi_first_cscore_CameraServerCvJNI
* Method: createCvSink
* Signature: (Ljava/lang/String;)I
* Signature: (Ljava/lang/String;I)I
*/
JNIEXPORT jint JNICALL
Java_edu_wpi_first_cscore_CameraServerCvJNI_createCvSink
(JNIEnv* env, jclass, jstring name)
(JNIEnv* env, jclass, jstring name, jint pixelFormat)
{
if (!name) {
nullPointerEx.Throw(env, "name cannot be null");
return 0;
}
CS_Status status = 0;
auto val = cs::CreateCvSink(JStringRef{env, name}.str(), &status);
auto val = cs::CreateCvSink(
JStringRef{env, name}.str(),
static_cast<cs::VideoMode::PixelFormat>(pixelFormat), &status);
CheckStatus(env, status);
return val;
}