mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-01 02:41:48 +00:00
Implement CvSink.
* Make CvSink constructor explicit. * Add SetDescription function.
This commit is contained in:
@@ -189,6 +189,8 @@ void CS_ReleaseSink(CS_Sink sink, CS_Status* status);
|
||||
//
|
||||
// OpenCV Sink Functions
|
||||
//
|
||||
void CS_SetSinkDescription(CS_Sink sink, const char* description,
|
||||
CS_Status* status);
|
||||
uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image, CS_Status* status);
|
||||
char* CS_GetSinkError(CS_Sink sink, CS_Status* status);
|
||||
void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status);
|
||||
|
||||
@@ -182,6 +182,8 @@ void ReleaseSink(CS_Sink sink, CS_Status* status);
|
||||
//
|
||||
// OpenCV Sink Functions
|
||||
//
|
||||
void SetSinkDescription(CS_Sink sink, llvm::StringRef description,
|
||||
CS_Status* status);
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status);
|
||||
std::string GetSinkError(CS_Sink sink, CS_Status* status);
|
||||
llvm::StringRef GetSinkError(CS_Sink sink, llvm::SmallVectorImpl<char>& buf,
|
||||
|
||||
@@ -340,7 +340,7 @@ class CvSink : public VideoSink {
|
||||
/// WaitForFrame() must be called on the created sink to get each new
|
||||
/// image.
|
||||
/// @param name Source name (arbitrary unique identifier)
|
||||
CvSink(llvm::StringRef name);
|
||||
explicit CvSink(llvm::StringRef name);
|
||||
|
||||
/// Create a sink for accepting OpenCV images in a separate thread.
|
||||
/// A thread will be created that calls WaitForFrame() and calls the
|
||||
@@ -352,6 +352,10 @@ class CvSink : public VideoSink {
|
||||
/// unusual circumstances) WaitForImage().
|
||||
CvSink(llvm::StringRef name, std::function<void(uint64_t time)> processFrame);
|
||||
|
||||
/// Set sink description.
|
||||
/// @param description Description
|
||||
void SetDescription(llvm::StringRef description);
|
||||
|
||||
/// Wait for the next frame and get the image.
|
||||
/// @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
/// message);
|
||||
|
||||
@@ -290,6 +290,11 @@ inline CvSink::CvSink(llvm::StringRef name,
|
||||
m_handle = CreateCvSinkCallback(name, processFrame, &m_status);
|
||||
}
|
||||
|
||||
inline void CvSink::SetDescription(llvm::StringRef description) {
|
||||
m_status = 0;
|
||||
SetSinkDescription(m_handle, description, &m_status);
|
||||
}
|
||||
|
||||
inline uint64_t CvSink::GrabFrame(cv::Mat& image) const {
|
||||
m_status = 0;
|
||||
return GrabSinkFrame(m_handle, image, &m_status);
|
||||
|
||||
@@ -742,6 +742,19 @@ JNIEXPORT void JNICALL Java_edu_wpi_cameraserver_CameraServerJNI_releaseSink
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cameraserver_CameraServerJNI
|
||||
* Method: setSinkDescription
|
||||
* Signature: (ILjava/lang/String;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_cameraserver_CameraServerJNI_setSinkDescription
|
||||
(JNIEnv *env, jclass, jint sink, jstring description)
|
||||
{
|
||||
CS_Status status = 0;
|
||||
cs::SetSinkDescription(sink, JStringRef{env, description}, &status);
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cameraserver_CameraServerJNI
|
||||
* Method: grabSinkFrame
|
||||
|
||||
@@ -148,6 +148,7 @@ public class CameraServerJNI {
|
||||
//
|
||||
// OpenCV Sink Functions
|
||||
//
|
||||
public static native void setSinkDescription(int sink, String description);
|
||||
public static native long grabSinkFrame(int sink, long imageNativeObj);
|
||||
public static native String getSinkError(int sink);
|
||||
public static native void setSinkEnabled(int sink, boolean enabled);
|
||||
|
||||
@@ -32,6 +32,12 @@ public class CvSink extends VideoSink {
|
||||
// super(CameraServerJNI.createCvSinkCallback(name, processFrame));
|
||||
//}
|
||||
|
||||
/// Set sink description.
|
||||
/// @param description Description
|
||||
public void setDescription(String description) {
|
||||
CameraServerJNI.setSinkDescription(m_handle, description);
|
||||
}
|
||||
|
||||
/// Wait for the next frame and get the image.
|
||||
/// @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
/// message);
|
||||
|
||||
175
src/CvSinkImpl.cpp
Normal file
175
src/CvSinkImpl.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "CvSinkImpl.h"
|
||||
|
||||
#include "llvm/SmallString.h"
|
||||
#include "opencv2/core/core.hpp"
|
||||
#include "opencv2/highgui/highgui.hpp"
|
||||
|
||||
#include "cameraserver_cpp.h"
|
||||
#include "c_util.h"
|
||||
#include "Handle.h"
|
||||
#include "Log.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
CvSinkImpl::CvSinkImpl(llvm::StringRef name) : SinkImpl{name} {
|
||||
m_active = true;
|
||||
// m_thread = std::thread(&CvSinkImpl::ThreadMain, this);
|
||||
}
|
||||
|
||||
CvSinkImpl::CvSinkImpl(llvm::StringRef name,
|
||||
std::function<void(uint64_t time)> processFrame)
|
||||
: SinkImpl{name} {}
|
||||
|
||||
CvSinkImpl::~CvSinkImpl() { Stop(); }
|
||||
|
||||
void CvSinkImpl::Stop() {
|
||||
m_active = false;
|
||||
|
||||
// wake up any waiters by forcing an empty frame to be sent
|
||||
if (auto source = GetSource())
|
||||
source->Wakeup();
|
||||
|
||||
// join thread
|
||||
if (m_thread.joinable()) m_thread.join();
|
||||
}
|
||||
|
||||
uint64_t CvSinkImpl::GrabFrame(cv::Mat& image) {
|
||||
SetEnabled(true);
|
||||
auto source = GetSource();
|
||||
if (!source) return 0;
|
||||
auto frame = source->GetNextFrame(); // blocks
|
||||
if (!frame) return 0; // signal error
|
||||
cv::imdecode(cv::InputArray{frame.data(), static_cast<int>(frame.size())},
|
||||
cv::IMREAD_COLOR, &image);
|
||||
return frame.time();
|
||||
}
|
||||
|
||||
// Send HTTP response and a stream of JPG-frames
|
||||
void CvSinkImpl::ThreadMain() {
|
||||
Enable();
|
||||
while (m_active) {
|
||||
auto source = GetSource();
|
||||
if (!source) {
|
||||
// Source disconnected; sleep for one second
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
continue;
|
||||
}
|
||||
DEBUG4("Cv: waiting for frame");
|
||||
Frame frame = source->GetNextFrame(); // blocks
|
||||
if (!m_active) break;
|
||||
if (!frame) {
|
||||
// Bad frame; sleep for 10 ms so we don't consume all processor time.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
continue;
|
||||
}
|
||||
// TODO m_processFrame();
|
||||
}
|
||||
Disable();
|
||||
}
|
||||
|
||||
namespace cs {
|
||||
|
||||
CS_Sink CreateCvSink(llvm::StringRef name, CS_Status* status) {
|
||||
auto sink = std::make_shared<CvSinkImpl>(name);
|
||||
return Sinks::GetInstance().Allocate(SinkData::kCv, sink);
|
||||
}
|
||||
|
||||
CS_Sink CreateCvSinkCallback(llvm::StringRef name,
|
||||
std::function<void(uint64_t time)> processFrame,
|
||||
CS_Status* status) {
|
||||
auto sink = std::make_shared<CvSinkImpl>(name, processFrame);
|
||||
return Sinks::GetInstance().Allocate(SinkData::kCv, sink);
|
||||
}
|
||||
|
||||
void SetSinkDescription(CS_Sink sink, llvm::StringRef description,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data || data->type != SinkData::kCv) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
static_cast<CvSinkImpl&>(*data->sink).SetDescription(description);
|
||||
}
|
||||
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data || data->type != SinkData::kCv) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
return static_cast<CvSinkImpl&>(*data->sink).GrabFrame(image);
|
||||
}
|
||||
|
||||
std::string GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data || data->type != SinkData::kCv) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
}
|
||||
return static_cast<CvSinkImpl&>(*data->sink).GetError();
|
||||
}
|
||||
|
||||
llvm::StringRef GetSinkError(CS_Sink sink, llvm::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data || data->type != SinkData::kCv) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return llvm::StringRef{};
|
||||
}
|
||||
return static_cast<CvSinkImpl&>(*data->sink).GetError(buf);
|
||||
}
|
||||
|
||||
void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data || data->type != SinkData::kCv) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
static_cast<CvSinkImpl&>(*data->sink).SetEnabled(enabled);
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
extern "C" {
|
||||
|
||||
CS_Sink CS_CreateCvSink(const char* name, CS_Status* status) {
|
||||
return cs::CreateCvSink(name, status);
|
||||
}
|
||||
|
||||
CS_Sink CS_CreateCvSinkCallback(const char* name, void* data,
|
||||
void (*processFrame)(void* data, uint64_t time),
|
||||
CS_Status* status) {
|
||||
return cs::CreateCvSinkCallback(
|
||||
name, [=](uint64_t time) { processFrame(data, time); }, status);
|
||||
}
|
||||
|
||||
void CS_SetSinkDescription(CS_Sink sink, const char* description,
|
||||
CS_Status* status) {
|
||||
return cs::SetSinkDescription(sink, description, status);
|
||||
}
|
||||
|
||||
uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image,
|
||||
CS_Status* status) {
|
||||
auto mat = cv::cvarrToMat(image);
|
||||
return cs::GrabSinkFrame(sink, mat, status);
|
||||
}
|
||||
|
||||
char* CS_GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
llvm::SmallString<128> buf;
|
||||
auto str = cs::GetSinkError(sink, buf, status);
|
||||
if (*status != 0) return nullptr;
|
||||
return cs::ConvertToC(str);
|
||||
}
|
||||
|
||||
void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status) {
|
||||
return cs::SetSinkEnabled(sink, enabled, status);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
53
src/CvSinkImpl.h
Normal file
53
src/CvSinkImpl.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CAMERASERVER_CVSINKIMPL_H_
|
||||
#define CAMERASERVER_CVSINKIMPL_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/raw_ostream.h"
|
||||
#include "llvm/SmallVector.h"
|
||||
#include "llvm/StringRef.h"
|
||||
#include "support/raw_istream.h"
|
||||
#include "support/raw_socket_ostream.h"
|
||||
#include "tcpsockets/NetworkAcceptor.h"
|
||||
#include "tcpsockets/NetworkStream.h"
|
||||
|
||||
#include "SinkImpl.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class SourceImpl;
|
||||
|
||||
class CvSinkImpl : public SinkImpl {
|
||||
public:
|
||||
CvSinkImpl(llvm::StringRef name);
|
||||
CvSinkImpl(llvm::StringRef name,
|
||||
std::function<void(uint64_t time)> processFrame);
|
||||
~CvSinkImpl() override;
|
||||
|
||||
void Stop();
|
||||
|
||||
uint64_t GrabFrame(cv::Mat& image);
|
||||
|
||||
private:
|
||||
void ThreadMain();
|
||||
|
||||
std::atomic_bool m_active; // set to false to terminate threads
|
||||
std::thread m_thread;
|
||||
std::function<void(uint64_t time)> m_processFrame;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CAMERASERVER_CVSINKIMPL_H_
|
||||
@@ -176,17 +176,6 @@ void CS_ReleaseSource(CS_Source source, CS_Status* status) {
|
||||
return cs::ReleaseSource(source, status);
|
||||
}
|
||||
|
||||
CS_Sink CS_CreateCvSink(const char* name, CS_Status* status) {
|
||||
return cs::CreateCvSink(name, status);
|
||||
}
|
||||
|
||||
CS_Sink CS_CreateCvSinkCallback(const char* name, void* data,
|
||||
void (*processFrame)(void* data, uint64_t time),
|
||||
CS_Status* status) {
|
||||
return cs::CreateCvSinkCallback(
|
||||
name, [=](uint64_t time) { processFrame(data, time); }, status);
|
||||
}
|
||||
|
||||
char* CS_GetSinkName(CS_Sink sink, CS_Status* status) {
|
||||
llvm::SmallString<128> buf;
|
||||
auto str = cs::GetSinkName(sink, buf, status);
|
||||
@@ -222,23 +211,6 @@ void CS_ReleaseSink(CS_Sink sink, CS_Status* status) {
|
||||
return cs::ReleaseSink(sink, status);
|
||||
}
|
||||
|
||||
uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image,
|
||||
CS_Status* status) {
|
||||
auto mat = cv::cvarrToMat(image);
|
||||
return cs::GrabSinkFrame(sink, mat, status);
|
||||
}
|
||||
|
||||
char* CS_GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
llvm::SmallString<128> buf;
|
||||
auto str = cs::GetSinkError(sink, buf, status);
|
||||
if (*status != 0) return nullptr;
|
||||
return cs::ConvertToC(str);
|
||||
}
|
||||
|
||||
void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status) {
|
||||
return cs::SetSinkEnabled(sink, enabled, status);
|
||||
}
|
||||
|
||||
CS_Listener CS_AddSourceListener(void* data,
|
||||
void (*callback)(void* data, const char* name,
|
||||
CS_Source source, int event),
|
||||
|
||||
@@ -320,23 +320,10 @@ void ReleaseSource(CS_Source source, CS_Status* status) {
|
||||
if (data->refCount-- == 0) inst.Free(source);
|
||||
}
|
||||
|
||||
//
|
||||
// Sink Creation Functions
|
||||
//
|
||||
|
||||
CS_Sink CreateCvSink(llvm::StringRef name, CS_Status* status) {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
CS_Sink CreateCvSinkCallback(llvm::StringRef name,
|
||||
std::function<void(uint64_t time)> processFrame,
|
||||
CS_Status* status) {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
//
|
||||
// Sink Functions
|
||||
//
|
||||
|
||||
std::string GetSinkName(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data) {
|
||||
@@ -433,27 +420,6 @@ void ReleaseSink(CS_Sink sink, CS_Status* status) {
|
||||
if (data->refCount-- == 0) inst.Free(sink);
|
||||
}
|
||||
|
||||
//
|
||||
// OpenCV Sink Functions
|
||||
//
|
||||
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status) {
|
||||
return 0; // TODO
|
||||
}
|
||||
|
||||
std::string GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
return std::string{}; // TODO
|
||||
}
|
||||
|
||||
llvm::StringRef GetSinkError(CS_Sink sink, llvm::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
return llvm::StringRef{}; // TODO
|
||||
}
|
||||
|
||||
void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
//
|
||||
// Listener Functions
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user