mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-02 02:51:42 +00:00
Add raw sources and sinks to cscore (#1670)
In some cases, we don't want the cv requirement to get an image, for instance interop with other versions of opencv This enables getting a raw image, and handling conversions from the user side.
This commit is contained in:
committed by
Peter Johnson
parent
7de9477347
commit
fb1239a2ad
@@ -16,6 +16,7 @@
|
||||
#include <wpi/Twine.h>
|
||||
|
||||
#include "cscore.h"
|
||||
#include "cscore_cv.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2016-2019 FIRST. 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. */
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include "cscore.h"
|
||||
#include "cscore_cv.h"
|
||||
#include "vision/VisionPipeline.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2017-2019 FIRST. 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. */
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
#include "cscore.h"
|
||||
#include "cscore_cv.h"
|
||||
|
||||
int main() {
|
||||
cs::HttpCamera camera{"httpcam", "http://localhost:8081/?action=stream"};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2017-2019 FIRST. 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. */
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
#include "cscore.h"
|
||||
#include "cscore_cv.h"
|
||||
|
||||
int main() {
|
||||
cs::UsbCamera camera{"usbcam", 0};
|
||||
|
||||
96
cscore/java-examples/RawCVMatSink.java
Normal file
96
cscore/java-examples/RawCVMatSink.java
Normal file
@@ -0,0 +1,96 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.cscore;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
import edu.wpi.cscore.VideoMode.PixelFormat;
|
||||
import edu.wpi.cscore.raw.RawFrame;
|
||||
|
||||
public class RawCVMatSink extends ImageSink {
|
||||
RawFrame frame = new RawFrame();
|
||||
Mat tmpMat;
|
||||
ByteBuffer origByteBuffer;
|
||||
int width;
|
||||
int height;
|
||||
int pixelFormat;
|
||||
int bgrValue = PixelFormat.kBGR.getValue();
|
||||
|
||||
private int getCVFormat(PixelFormat pixelFormat) {
|
||||
int type = 0;
|
||||
switch (pixelFormat) {
|
||||
case kYUYV:
|
||||
case kRGB565:
|
||||
type = CvType.CV_8UC2;
|
||||
break;
|
||||
case kBGR:
|
||||
type = CvType.CV_8UC3;
|
||||
break;
|
||||
case kGray:
|
||||
case kMJPEG:
|
||||
default:
|
||||
type = CvType.CV_8UC1;
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images.
|
||||
* WaitForFrame() must be called on the created sink to get each new
|
||||
* image.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
*/
|
||||
public RawCVMatSink(String name) {
|
||||
super(CameraServerJNI.createRawSink(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after 0.225 seconds.
|
||||
* The provided image will have three 3-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message)
|
||||
*/
|
||||
public long grabFrame(Mat image) {
|
||||
return grabFrame(image, 0.225);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after timeout seconds.
|
||||
* The provided image will have three 3-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in 1 us increments.
|
||||
*/
|
||||
public long grabFrame(Mat image, double timeout) {
|
||||
frame.setWidth(0);
|
||||
frame.setHeight(0);
|
||||
frame.setPixelFormat(bgrValue);
|
||||
long rv = CameraServerJNI.grabSinkFrameTimeout(m_handle, frame, timeout);
|
||||
if (rv <= 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (frame.getDataByteBuffer() != origByteBuffer || width != frame.getWidth() || height != frame.getHeight() || pixelFormat != frame.getPixelFormat()) {
|
||||
origByteBuffer = frame.getDataByteBuffer();
|
||||
height = frame.getHeight();
|
||||
width = frame.getWidth();
|
||||
pixelFormat = frame.getPixelFormat();
|
||||
tmpMat = new Mat(frame.getHeight(), frame.getWidth(), getCVFormat(VideoMode.getPixelFormatFromInt(pixelFormat)), origByteBuffer);
|
||||
}
|
||||
tmpMat.copyTo(image);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
59
cscore/java-examples/RawCVMatSource.java
Normal file
59
cscore/java-examples/RawCVMatSource.java
Normal file
@@ -0,0 +1,59 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.cscore;
|
||||
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
import edu.wpi.cscore.VideoMode.PixelFormat;
|
||||
|
||||
public class RawCVMatSource extends ImageSource {
|
||||
/**
|
||||
* Create an OpenCV source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param mode Video mode being generated
|
||||
*/
|
||||
public RawCVMatSource(String name, VideoMode mode) {
|
||||
super(CameraServerJNI.createRawSource(name,
|
||||
mode.pixelFormat.getValue(),
|
||||
mode.width,
|
||||
mode.height,
|
||||
mode.fps));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an OpenCV source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param pixelFormat Pixel format
|
||||
* @param width width
|
||||
* @param height height
|
||||
* @param fps fps
|
||||
*/
|
||||
public RawCVMatSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
|
||||
super(CameraServerJNI.createRawSource(name, pixelFormat.getValue(), width, height, fps));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param image OpenCV image
|
||||
*/
|
||||
public void putFrame(Mat image) {
|
||||
int channels = image.channels();
|
||||
if (channels != 1 && channels != 3) {
|
||||
throw new VideoException("Unsupported Image Type");
|
||||
}
|
||||
int imgType = channels == 1 ? PixelFormat.kGray.getValue() : PixelFormat.kBGR.getValue();
|
||||
CameraServerJNI.putRawSourceFrame(m_handle, image.dataAddr(), image.width(), image.height(), imgType, (int)image.total() * channels);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2017-2019 FIRST. 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. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2017-2019 FIRST. 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. */
|
||||
|
||||
48
cscore/src/main/java/edu/wpi/cscore/CameraServerCvJNI.java
Normal file
48
cscore/src/main/java/edu/wpi/cscore/CameraServerCvJNI.java
Normal file
@@ -0,0 +1,48 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.cscore;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
|
||||
import edu.wpi.first.wpiutil.RuntimeLoader;
|
||||
|
||||
public class CameraServerCvJNI {
|
||||
static boolean cvLibraryLoaded = false;
|
||||
|
||||
static RuntimeLoader<Core> cvLoader = null;
|
||||
|
||||
static {
|
||||
String opencvName = Core.NATIVE_LIBRARY_NAME;
|
||||
if (!cvLibraryLoaded) {
|
||||
CameraServerJNI.forceLoad();
|
||||
try {
|
||||
cvLoader = new RuntimeLoader<>(opencvName, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
|
||||
cvLoader.loadLibraryHashed();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
cvLibraryLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void forceLoad() {}
|
||||
|
||||
public static native int createCvSource(String name, int pixelFormat, int width, int height, int fps);
|
||||
|
||||
public static native void putSourceFrame(int source, long imageNativeObj);
|
||||
|
||||
public static native int createCvSink(String name);
|
||||
//public static native int createCvSinkCallback(String name,
|
||||
// void (*processFrame)(long time));
|
||||
|
||||
public static native long grabSinkFrame(int sink, long imageNativeObj);
|
||||
public static native long grabSinkFrameTimeout(int sink, long imageNativeObj, double timeout);
|
||||
}
|
||||
@@ -8,18 +8,16 @@
|
||||
package edu.wpi.cscore;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.opencv.core.Core;
|
||||
|
||||
import edu.wpi.cscore.raw.RawFrame;
|
||||
import edu.wpi.first.wpiutil.RuntimeLoader;
|
||||
|
||||
public class CameraServerJNI {
|
||||
static boolean libraryLoaded = false;
|
||||
static boolean cvLibraryLoaded = false;
|
||||
|
||||
static RuntimeLoader<CameraServerJNI> loader = null;
|
||||
static RuntimeLoader<Core> cvLoader = null;
|
||||
|
||||
static {
|
||||
if (!libraryLoaded) {
|
||||
@@ -32,18 +30,6 @@ public class CameraServerJNI {
|
||||
}
|
||||
libraryLoaded = true;
|
||||
}
|
||||
|
||||
String opencvName = Core.NATIVE_LIBRARY_NAME;
|
||||
if (!cvLibraryLoaded) {
|
||||
try {
|
||||
cvLoader = new RuntimeLoader<>(opencvName, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
|
||||
cvLoader.loadLibraryHashed();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
cvLibraryLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void forceLoad() {}
|
||||
@@ -70,7 +56,7 @@ public class CameraServerJNI {
|
||||
public static native int createUsbCameraPath(String name, String path);
|
||||
public static native int createHttpCamera(String name, String url, int kind);
|
||||
public static native int createHttpCameraMulti(String name, String[] urls, int kind);
|
||||
public static native int createCvSource(String name, int pixelFormat, int width, int height, int fps);
|
||||
public static native int createRawSource(String name, int pixelFormat, int width, int height, int fps);
|
||||
|
||||
//
|
||||
// Source Functions
|
||||
@@ -122,9 +108,13 @@ public class CameraServerJNI {
|
||||
public static native String[] getHttpCameraUrls(int source);
|
||||
|
||||
//
|
||||
// OpenCV Source Functions
|
||||
// Image Source Functions
|
||||
//
|
||||
public static native void putSourceFrame(int source, long imageNativeObj);
|
||||
public static native void putRawSourceFrameBB(int source, ByteBuffer data, int width, int height, int pixelFormat, int totalData);
|
||||
public static native void putRawSourceFrame(int source, long data, int width, int height, int pixelFormat, int totalData);
|
||||
public static void putRawSourceFrame(int source, RawFrame raw) {
|
||||
putRawSourceFrame(source, raw.getDataPtr(), raw.getWidth(), raw.getHeight(), raw.getPixelFormat(), raw.getTotalData());
|
||||
}
|
||||
public static native void notifySourceError(int source, String msg);
|
||||
public static native void setSourceConnected(int source, boolean connected);
|
||||
public static native void setSourceDescription(int source, String description);
|
||||
@@ -135,9 +125,8 @@ public class CameraServerJNI {
|
||||
// Sink Creation Functions
|
||||
//
|
||||
public static native int createMjpegServer(String name, String listenAddress, int port);
|
||||
public static native int createCvSink(String name);
|
||||
//public static native int createCvSinkCallback(String name,
|
||||
// void (*processFrame)(long time));
|
||||
|
||||
public static native int createRawSink(String name);
|
||||
|
||||
//
|
||||
// Sink Functions
|
||||
@@ -162,11 +151,19 @@ public class CameraServerJNI {
|
||||
public static native int getMjpegServerPort(int sink);
|
||||
|
||||
//
|
||||
// OpenCV Sink Functions
|
||||
// Image Sink Functions
|
||||
//
|
||||
public static native void setSinkDescription(int sink, String description);
|
||||
public static native long grabSinkFrame(int sink, long imageNativeObj);
|
||||
public static native long grabSinkFrameTimeout(int sink, long imageNativeObj, double timeout);
|
||||
|
||||
private static native long grabRawSinkFrameImpl(int sink, RawFrame rawFrame, long rawFramePtr, ByteBuffer byteBuffer, int width, int height, int pixelFormat);
|
||||
private static native long grabRawSinkFrameTimeoutImpl(int sink, RawFrame rawFrame, long rawFramePtr, ByteBuffer byteBuffer, int width, int height, int pixelFormat, double timeout);
|
||||
|
||||
public static long grabSinkFrame(int sink, RawFrame rawFrame) {
|
||||
return grabRawSinkFrameImpl(sink, rawFrame, rawFrame.getFramePtr(), rawFrame.getDataByteBuffer(), rawFrame.getWidth(), rawFrame.getHeight(), rawFrame.getPixelFormat());
|
||||
}
|
||||
public static long grabSinkFrameTimeout(int sink, RawFrame rawFrame, double timeout) {
|
||||
return grabRawSinkFrameTimeoutImpl(sink, rawFrame, rawFrame.getFramePtr(), rawFrame.getDataByteBuffer(), rawFrame.getWidth(), rawFrame.getHeight(), rawFrame.getPixelFormat(), timeout);
|
||||
}
|
||||
public static native String getSinkError(int sink);
|
||||
public static native void setSinkEnabled(int sink, boolean enabled);
|
||||
|
||||
@@ -228,4 +225,8 @@ public class CameraServerJNI {
|
||||
public static native String getHostname();
|
||||
|
||||
public static native String[] getNetworkInterfaces();
|
||||
|
||||
public static native long allocateRawFrame();
|
||||
|
||||
public static native void freeRawFrame(long frame);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2016-2019 FIRST. 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. */
|
||||
@@ -11,8 +11,11 @@ import org.opencv.core.Mat;
|
||||
|
||||
/**
|
||||
* A sink for user code to accept video frames as OpenCV images.
|
||||
* These sinks require the WPILib OpenCV builds.
|
||||
* For an alternate OpenCV, see the documentation how to build your own
|
||||
* with RawSink.
|
||||
*/
|
||||
public class CvSink extends VideoSink {
|
||||
public class CvSink extends ImageSink {
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images.
|
||||
* WaitForFrame() must be called on the created sink to get each new
|
||||
@@ -21,7 +24,7 @@ public class CvSink extends VideoSink {
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
*/
|
||||
public CvSink(String name) {
|
||||
super(CameraServerJNI.createCvSink(name));
|
||||
super(CameraServerCvJNI.createCvSink(name));
|
||||
}
|
||||
|
||||
/// Create a sink for accepting OpenCV images in a separate thread.
|
||||
@@ -37,15 +40,6 @@ 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.
|
||||
* Times out (returning 0) after 0.225 seconds.
|
||||
@@ -67,7 +61,7 @@ public class CvSink extends VideoSink {
|
||||
* message); the frame time is in 1 us increments.
|
||||
*/
|
||||
public long grabFrame(Mat image, double timeout) {
|
||||
return CameraServerJNI.grabSinkFrameTimeout(m_handle, image.nativeObj, timeout);
|
||||
return CameraServerCvJNI.grabSinkFrameTimeout(m_handle, image.nativeObj, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,24 +72,6 @@ public class CvSink extends VideoSink {
|
||||
* message); the frame time is in 1 us increments.
|
||||
*/
|
||||
public long grabFrameNoTimeout(Mat image) {
|
||||
return CameraServerJNI.grabSinkFrame(m_handle, image.nativeObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error string. Call this if WaitForFrame() returns 0 to determine
|
||||
* what the error is.
|
||||
*/
|
||||
public String getError() {
|
||||
return CameraServerJNI.getSinkError(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable getting new frames.
|
||||
* Disabling will cause processFrame (for callback-based CvSinks) to not
|
||||
* be called and WaitForFrame() to not return. This can be used to save
|
||||
* processor resources when frames are not needed.
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
CameraServerJNI.setSinkEnabled(m_handle, enabled);
|
||||
return CameraServerCvJNI.grabSinkFrame(m_handle, image.nativeObj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2016-2019 FIRST. 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. */
|
||||
@@ -11,8 +11,11 @@ import org.opencv.core.Mat;
|
||||
|
||||
/**
|
||||
* A source that represents a video camera.
|
||||
* These sources require the WPILib OpenCV builds.
|
||||
* For an alternate OpenCV, see the documentation how to build your own
|
||||
* with RawSource.
|
||||
*/
|
||||
public class CvSource extends VideoSource {
|
||||
public class CvSource extends ImageSource {
|
||||
/**
|
||||
* Create an OpenCV source.
|
||||
*
|
||||
@@ -20,7 +23,7 @@ public class CvSource extends VideoSource {
|
||||
* @param mode Video mode being generated
|
||||
*/
|
||||
public CvSource(String name, VideoMode mode) {
|
||||
super(CameraServerJNI.createCvSource(name,
|
||||
super(CameraServerCvJNI.createCvSource(name,
|
||||
mode.pixelFormat.getValue(),
|
||||
mode.width,
|
||||
mode.height,
|
||||
@@ -37,7 +40,7 @@ public class CvSource extends VideoSource {
|
||||
* @param fps fps
|
||||
*/
|
||||
public CvSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
|
||||
super(CameraServerJNI.createCvSource(name, pixelFormat.getValue(), width, height, fps));
|
||||
super(CameraServerCvJNI.createCvSource(name, pixelFormat.getValue(), width, height, fps));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,154 +53,7 @@ public class CvSource extends VideoSource {
|
||||
* @param image OpenCV image
|
||||
*/
|
||||
public void putFrame(Mat image) {
|
||||
CameraServerJNI.putSourceFrame(m_handle, image.nativeObj);
|
||||
CameraServerCvJNI.putSourceFrame(m_handle, image.nativeObj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal sinks that an error has occurred. This should be called instead
|
||||
* of NotifyFrame when an error occurs.
|
||||
*/
|
||||
public void notifyError(String msg) {
|
||||
CameraServerJNI.notifySourceError(m_handle, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set source connection status. Defaults to true.
|
||||
*
|
||||
* @param connected True for connected, false for disconnected
|
||||
*/
|
||||
public void setConnected(boolean connected) {
|
||||
CameraServerJNI.setSourceConnected(m_handle, connected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set source description.
|
||||
*
|
||||
* @param description Description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
CameraServerJNI.setSourceDescription(m_handle, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a property.
|
||||
*
|
||||
* @param name Property name
|
||||
* @param kind Property kind
|
||||
* @param minimum Minimum value
|
||||
* @param maximum Maximum value
|
||||
* @param step Step value
|
||||
* @param defaultValue Default value
|
||||
* @param value Current value
|
||||
* @return Property
|
||||
*/
|
||||
public VideoProperty createProperty(String name,
|
||||
VideoProperty.Kind kind,
|
||||
int minimum,
|
||||
int maximum,
|
||||
int step,
|
||||
int defaultValue,
|
||||
int value) {
|
||||
return new VideoProperty(
|
||||
CameraServerJNI.createSourceProperty(m_handle,
|
||||
name,
|
||||
kind.getValue(),
|
||||
minimum,
|
||||
maximum,
|
||||
step,
|
||||
defaultValue,
|
||||
value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an integer property.
|
||||
*
|
||||
* @param name Property name
|
||||
* @param minimum Minimum value
|
||||
* @param maximum Maximum value
|
||||
* @param step Step value
|
||||
* @param defaultValue Default value
|
||||
* @param value Current value
|
||||
* @return Property
|
||||
*/
|
||||
public VideoProperty createIntegerProperty(String name,
|
||||
int minimum,
|
||||
int maximum,
|
||||
int step,
|
||||
int defaultValue,
|
||||
int value) {
|
||||
return new VideoProperty(
|
||||
CameraServerJNI.createSourceProperty(m_handle,
|
||||
name,
|
||||
VideoProperty.Kind.kInteger.getValue(),
|
||||
minimum,
|
||||
maximum,
|
||||
step,
|
||||
defaultValue,
|
||||
value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a boolean property.
|
||||
*
|
||||
* @param name Property name
|
||||
* @param defaultValue Default value
|
||||
* @param value Current value
|
||||
* @return Property
|
||||
*/
|
||||
public VideoProperty createBooleanProperty(String name, boolean defaultValue, boolean value) {
|
||||
return new VideoProperty(
|
||||
CameraServerJNI.createSourceProperty(m_handle,
|
||||
name,
|
||||
VideoProperty.Kind.kBoolean.getValue(),
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
defaultValue ? 1 : 0,
|
||||
value ? 1 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string property.
|
||||
*
|
||||
* @param name Property name
|
||||
* @param value Current value
|
||||
* @return Property
|
||||
*/
|
||||
public VideoProperty createStringProperty(String name, String value) {
|
||||
VideoProperty prop = new VideoProperty(
|
||||
CameraServerJNI.createSourceProperty(m_handle,
|
||||
name,
|
||||
VideoProperty.Kind.kString.getValue(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0));
|
||||
prop.setString(value);
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure enum property choices.
|
||||
*
|
||||
* @param property Property
|
||||
* @param choices Choices
|
||||
*/
|
||||
public void setEnumPropertyChoices(VideoProperty property, String[] choices) {
|
||||
CameraServerJNI.setSourceEnumPropertyChoices(m_handle, property.m_handle, choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure enum property choices.
|
||||
*
|
||||
* @param property Property
|
||||
* @param choices Choices
|
||||
* @deprecated Use {@code setEnumPropertyChoices} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("MethodName")
|
||||
public void SetEnumPropertyChoices(VideoProperty property, String[] choices) {
|
||||
setEnumPropertyChoices(property, choices);
|
||||
}
|
||||
}
|
||||
|
||||
41
cscore/src/main/java/edu/wpi/cscore/ImageSink.java
Normal file
41
cscore/src/main/java/edu/wpi/cscore/ImageSink.java
Normal file
@@ -0,0 +1,41 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.cscore;
|
||||
|
||||
public abstract class ImageSink extends VideoSink {
|
||||
protected ImageSink(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set sink description.
|
||||
*
|
||||
* @param description Description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
CameraServerJNI.setSinkDescription(m_handle, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get error string. Call this if WaitForFrame() returns 0 to determine
|
||||
* what the error is.
|
||||
*/
|
||||
public String getError() {
|
||||
return CameraServerJNI.getSinkError(m_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable getting new frames.
|
||||
* Disabling will cause processFrame (for callback-based CvSinks) to not
|
||||
* be called and WaitForFrame() to not return. This can be used to save
|
||||
* processor resources when frames are not needed.
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
CameraServerJNI.setSinkEnabled(m_handle, enabled);
|
||||
}
|
||||
}
|
||||
162
cscore/src/main/java/edu/wpi/cscore/ImageSource.java
Normal file
162
cscore/src/main/java/edu/wpi/cscore/ImageSource.java
Normal file
@@ -0,0 +1,162 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.cscore;
|
||||
|
||||
public abstract class ImageSource extends VideoSource {
|
||||
protected ImageSource(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal sinks that an error has occurred. This should be called instead
|
||||
* of NotifyFrame when an error occurs.
|
||||
*/
|
||||
public void notifyError(String msg) {
|
||||
CameraServerJNI.notifySourceError(m_handle, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set source connection status. Defaults to true.
|
||||
*
|
||||
* @param connected True for connected, false for disconnected
|
||||
*/
|
||||
public void setConnected(boolean connected) {
|
||||
CameraServerJNI.setSourceConnected(m_handle, connected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set source description.
|
||||
*
|
||||
* @param description Description
|
||||
*/
|
||||
public void setDescription(String description) {
|
||||
CameraServerJNI.setSourceDescription(m_handle, description);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a property.
|
||||
*
|
||||
* @param name Property name
|
||||
* @param kind Property kind
|
||||
* @param minimum Minimum value
|
||||
* @param maximum Maximum value
|
||||
* @param step Step value
|
||||
* @param defaultValue Default value
|
||||
* @param value Current value
|
||||
* @return Property
|
||||
*/
|
||||
public VideoProperty createProperty(String name,
|
||||
VideoProperty.Kind kind,
|
||||
int minimum,
|
||||
int maximum,
|
||||
int step,
|
||||
int defaultValue,
|
||||
int value) {
|
||||
return new VideoProperty(
|
||||
CameraServerJNI.createSourceProperty(m_handle,
|
||||
name,
|
||||
kind.getValue(),
|
||||
minimum,
|
||||
maximum,
|
||||
step,
|
||||
defaultValue,
|
||||
value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an integer property.
|
||||
*
|
||||
* @param name Property name
|
||||
* @param minimum Minimum value
|
||||
* @param maximum Maximum value
|
||||
* @param step Step value
|
||||
* @param defaultValue Default value
|
||||
* @param value Current value
|
||||
* @return Property
|
||||
*/
|
||||
public VideoProperty createIntegerProperty(String name,
|
||||
int minimum,
|
||||
int maximum,
|
||||
int step,
|
||||
int defaultValue,
|
||||
int value) {
|
||||
return new VideoProperty(
|
||||
CameraServerJNI.createSourceProperty(m_handle,
|
||||
name,
|
||||
VideoProperty.Kind.kInteger.getValue(),
|
||||
minimum,
|
||||
maximum,
|
||||
step,
|
||||
defaultValue,
|
||||
value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a boolean property.
|
||||
*
|
||||
* @param name Property name
|
||||
* @param defaultValue Default value
|
||||
* @param value Current value
|
||||
* @return Property
|
||||
*/
|
||||
public VideoProperty createBooleanProperty(String name, boolean defaultValue, boolean value) {
|
||||
return new VideoProperty(
|
||||
CameraServerJNI.createSourceProperty(m_handle,
|
||||
name,
|
||||
VideoProperty.Kind.kBoolean.getValue(),
|
||||
0,
|
||||
1,
|
||||
1,
|
||||
defaultValue ? 1 : 0,
|
||||
value ? 1 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a string property.
|
||||
*
|
||||
* @param name Property name
|
||||
* @param value Current value
|
||||
* @return Property
|
||||
*/
|
||||
public VideoProperty createStringProperty(String name, String value) {
|
||||
VideoProperty prop = new VideoProperty(
|
||||
CameraServerJNI.createSourceProperty(m_handle,
|
||||
name,
|
||||
VideoProperty.Kind.kString.getValue(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0));
|
||||
prop.setString(value);
|
||||
return prop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure enum property choices.
|
||||
*
|
||||
* @param property Property
|
||||
* @param choices Choices
|
||||
*/
|
||||
public void setEnumPropertyChoices(VideoProperty property, String[] choices) {
|
||||
CameraServerJNI.setSourceEnumPropertyChoices(m_handle, property.m_handle, choices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure enum property choices.
|
||||
*
|
||||
* @param property Property
|
||||
* @param choices Choices
|
||||
* @deprecated Use {@code setEnumPropertyChoices} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("MethodName")
|
||||
public void SetEnumPropertyChoices(VideoProperty property, String[] choices) {
|
||||
setEnumPropertyChoices(property, choices);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ package edu.wpi.cscore;
|
||||
*/
|
||||
public class VideoSink implements AutoCloseable {
|
||||
public enum Kind {
|
||||
kUnknown(0), kMjpeg(2), kCv(4);
|
||||
kUnknown(0), kMjpeg(2), kCv(4), kRaw(8);
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
private final int value;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2016-2019 FIRST. 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. */
|
||||
@@ -14,7 +14,7 @@ package edu.wpi.cscore;
|
||||
*/
|
||||
public class VideoSource implements AutoCloseable {
|
||||
public enum Kind {
|
||||
kUnknown(0), kUsb(1), kHttp(2), kCv(4);
|
||||
kUnknown(0), kUsb(1), kHttp(2), kCv(4), kRaw(8);
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
private final int value;
|
||||
|
||||
130
cscore/src/main/java/edu/wpi/cscore/raw/RawFrame.java
Normal file
130
cscore/src/main/java/edu/wpi/cscore/raw/RawFrame.java
Normal file
@@ -0,0 +1,130 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.cscore.raw;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import edu.wpi.cscore.CameraServerJNI;
|
||||
|
||||
/**
|
||||
* Class for storing raw frame data between image read call.
|
||||
*
|
||||
* <p>Data is reused for each frame read, rather then reallocating every frame.
|
||||
*/
|
||||
public class RawFrame implements AutoCloseable {
|
||||
private final long m_framePtr;
|
||||
private ByteBuffer m_dataByteBuffer;
|
||||
private long m_dataPtr;
|
||||
private int m_totalData;
|
||||
private int m_width;
|
||||
private int m_height;
|
||||
private int m_pixelFormat;
|
||||
|
||||
/**
|
||||
* Construct a new RawFrame.
|
||||
*/
|
||||
public RawFrame() {
|
||||
m_framePtr = CameraServerJNI.allocateRawFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the RawFrame, releasing native resources.
|
||||
* Any images currently using the data will be invalidated.
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
CameraServerJNI.freeRawFrame(m_framePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from JNI to set data in class.
|
||||
*/
|
||||
public void setData(ByteBuffer dataByteBuffer, long dataPtr, int totalData,
|
||||
int width, int height, int pixelFormat) {
|
||||
m_dataByteBuffer = dataByteBuffer;
|
||||
m_dataPtr = dataPtr;
|
||||
m_totalData = totalData;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_pixelFormat = pixelFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pointer to native representation of this frame.
|
||||
*/
|
||||
public long getFramePtr() {
|
||||
return m_framePtr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a ByteBuffer pointing to the frame data.
|
||||
* This ByteBuffer is backed by the frame directly. Its lifetime is controlled by
|
||||
* the frame. If a new frame gets read, it will overwrite the current one.
|
||||
*/
|
||||
public ByteBuffer getDataByteBuffer() {
|
||||
return m_dataByteBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a long (is a char* in native code) pointing to the frame data.
|
||||
* This pointer is backed by the frame directly. Its lifetime is controlled by
|
||||
* the frame. If a new frame gets read, it will overwrite the current one.
|
||||
*/
|
||||
public long getDataPtr() {
|
||||
return m_dataPtr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total length of the data stored in the frame.
|
||||
*/
|
||||
public int getTotalData() {
|
||||
return m_totalData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the frame.
|
||||
*/
|
||||
public int getWidth() {
|
||||
return m_width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the width of the frame.
|
||||
*/
|
||||
public void setWidth(int width) {
|
||||
this.m_width = width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the frame.
|
||||
*/
|
||||
public int getHeight() {
|
||||
return m_height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the height of the frame.
|
||||
*/
|
||||
public void setHeight(int height) {
|
||||
this.m_height = height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the PixelFormat of the frame.
|
||||
*/
|
||||
public int getPixelFormat() {
|
||||
return m_pixelFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the PixelFormat of the frame.
|
||||
*/
|
||||
public void setPixelFormat(int pixelFormat) {
|
||||
this.m_pixelFormat = pixelFormat;
|
||||
}
|
||||
}
|
||||
68
cscore/src/main/java/edu/wpi/cscore/raw/RawSink.java
Normal file
68
cscore/src/main/java/edu/wpi/cscore/raw/RawSink.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.cscore.raw;
|
||||
|
||||
import edu.wpi.cscore.CameraServerJNI;
|
||||
import edu.wpi.cscore.ImageSink;
|
||||
|
||||
/**
|
||||
* A sink for user code to accept video frames as raw bytes.
|
||||
*
|
||||
* <p>This is a complex API, most cases should use CvSink.
|
||||
*/
|
||||
public class RawSink extends ImageSink {
|
||||
/**
|
||||
* Create a sink for accepting raw images.
|
||||
*
|
||||
* <p>grabFrame() must be called on the created sink to get each new
|
||||
* image.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
*/
|
||||
public RawSink(String name) {
|
||||
super(CameraServerJNI.createRawSink(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after 0.225 seconds.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call getError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
protected long grabFrame(RawFrame frame) {
|
||||
return grabFrame(frame, 0.225);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after timeout seconds.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call getError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
protected long grabFrame(RawFrame frame, double timeout) {
|
||||
return CameraServerJNI.grabSinkFrameTimeout(m_handle, frame, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. May block forever.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call getError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
protected long grabFrameNoTimeout(RawFrame frame) {
|
||||
return CameraServerJNI.grabSinkFrame(m_handle, frame);
|
||||
}
|
||||
}
|
||||
85
cscore/src/main/java/edu/wpi/cscore/raw/RawSource.java
Normal file
85
cscore/src/main/java/edu/wpi/cscore/raw/RawSource.java
Normal file
@@ -0,0 +1,85 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.cscore.raw;
|
||||
|
||||
import edu.wpi.cscore.CameraServerJNI;
|
||||
import edu.wpi.cscore.ImageSource;
|
||||
import edu.wpi.cscore.VideoMode;
|
||||
|
||||
/**
|
||||
* A source for user code to provide video frames as raw bytes.
|
||||
*
|
||||
* <p>This is a complex API, most cases should use CvSource.
|
||||
*/
|
||||
public class RawSource extends ImageSource {
|
||||
/**
|
||||
* Create a raw frame source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param mode Video mode being generated
|
||||
*/
|
||||
public RawSource(String name, VideoMode mode) {
|
||||
super(CameraServerJNI.createRawSource(name,
|
||||
mode.pixelFormat.getValue(),
|
||||
mode.width, mode.height,
|
||||
mode.fps));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a raw frame source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param pixelFormat Pixel format
|
||||
* @param width width
|
||||
* @param height height
|
||||
* @param fps fps
|
||||
*/
|
||||
public RawSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
|
||||
super(CameraServerJNI.createRawSource(name,
|
||||
pixelFormat.getValue(),
|
||||
width, height,
|
||||
fps));
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a raw image and notify sinks.
|
||||
*
|
||||
* @param image raw frame image
|
||||
*/
|
||||
protected void putFrame(RawFrame image) {
|
||||
CameraServerJNI.putRawSourceFrame(m_handle, image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a raw image and notify sinks.
|
||||
*
|
||||
* @param data raw frame data pointer
|
||||
* @param width frame width
|
||||
* @param height frame height
|
||||
* @param pixelFormat pixel format
|
||||
* @param totalData length of data in total
|
||||
*/
|
||||
protected void putFrame(long data, int width, int height, int pixelFormat, int totalData) {
|
||||
CameraServerJNI.putRawSourceFrame(m_handle, data, width, height, pixelFormat, totalData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a raw image and notify sinks.
|
||||
*
|
||||
* @param data raw frame data pointer
|
||||
* @param width frame width
|
||||
* @param height frame height
|
||||
* @param pixelFormat pixel format
|
||||
* @param totalData length of data in total
|
||||
*/
|
||||
protected void putFrame(long data, int width, int height, VideoMode.PixelFormat pixelFormat,
|
||||
int totalData) {
|
||||
CameraServerJNI.putRawSourceFrame(m_handle, data, width, height, pixelFormat.getValue(),
|
||||
totalData);
|
||||
}
|
||||
}
|
||||
109
cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp
Normal file
109
cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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 "ConfigurableSourceImpl.h"
|
||||
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
ConfigurableSourceImpl::ConfigurableSourceImpl(const wpi::Twine& name,
|
||||
wpi::Logger& logger,
|
||||
Notifier& notifier,
|
||||
Telemetry& telemetry,
|
||||
const VideoMode& mode)
|
||||
: SourceImpl{name, logger, notifier, telemetry} {
|
||||
m_mode = mode;
|
||||
m_videoModes.push_back(m_mode);
|
||||
}
|
||||
|
||||
ConfigurableSourceImpl::~ConfigurableSourceImpl() {}
|
||||
|
||||
void ConfigurableSourceImpl::Start() {
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
m_notifier.NotifySourceVideoMode(*this, m_mode);
|
||||
}
|
||||
|
||||
bool ConfigurableSourceImpl::SetVideoMode(const VideoMode& mode,
|
||||
CS_Status* status) {
|
||||
{
|
||||
std::lock_guard<wpi::mutex> lock(m_mutex);
|
||||
m_mode = mode;
|
||||
m_videoModes[0] = mode;
|
||||
}
|
||||
m_notifier.NotifySourceVideoMode(*this, mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ConfigurableSourceImpl::NumSinksChanged() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
void ConfigurableSourceImpl::NumSinksEnabledChanged() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
void ConfigurableSourceImpl::NotifyError(const wpi::Twine& msg) {
|
||||
PutError(msg, wpi::Now());
|
||||
}
|
||||
|
||||
int ConfigurableSourceImpl::CreateProperty(const wpi::Twine& name,
|
||||
CS_PropertyKind kind, int minimum,
|
||||
int maximum, int step,
|
||||
int defaultValue, int value) {
|
||||
std::lock_guard<wpi::mutex> lock(m_mutex);
|
||||
int ndx = CreateOrUpdateProperty(name,
|
||||
[=] {
|
||||
return wpi::make_unique<PropertyImpl>(
|
||||
name, kind, minimum, maximum, step,
|
||||
defaultValue, value);
|
||||
},
|
||||
[&](PropertyImpl& prop) {
|
||||
// update all but value
|
||||
prop.propKind = kind;
|
||||
prop.minimum = minimum;
|
||||
prop.maximum = maximum;
|
||||
prop.step = step;
|
||||
prop.defaultValue = defaultValue;
|
||||
value = prop.value;
|
||||
});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name, ndx,
|
||||
kind, value, wpi::Twine{});
|
||||
return ndx;
|
||||
}
|
||||
|
||||
int ConfigurableSourceImpl::CreateProperty(
|
||||
const wpi::Twine& name, CS_PropertyKind kind, int minimum, int maximum,
|
||||
int step, int defaultValue, int value,
|
||||
std::function<void(CS_Property property)> onChange) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ConfigurableSourceImpl::SetEnumPropertyChoices(
|
||||
int property, wpi::ArrayRef<std::string> choices, CS_Status* status) {
|
||||
std::lock_guard<wpi::mutex> lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
*status = CS_INVALID_PROPERTY;
|
||||
return;
|
||||
}
|
||||
if (prop->propKind != CS_PROP_ENUM) {
|
||||
*status = CS_WRONG_PROPERTY_TYPE;
|
||||
return;
|
||||
}
|
||||
prop->enumChoices = choices;
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
prop->name, property, CS_PROP_ENUM,
|
||||
prop->value, wpi::Twine{});
|
||||
}
|
||||
56
cscore/src/main/native/cpp/ConfigurableSourceImpl.h
Normal file
56
cscore/src/main/native/cpp/ConfigurableSourceImpl.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2019 FIRST. 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 CSCORE_CONFIGURABLESOURCEIMPL_H_
|
||||
#define CSCORE_CONFIGURABLESOURCEIMPL_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/ArrayRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
|
||||
#include "SourceImpl.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class ConfigurableSourceImpl : public SourceImpl {
|
||||
protected:
|
||||
ConfigurableSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const VideoMode& mode);
|
||||
|
||||
public:
|
||||
~ConfigurableSourceImpl() override;
|
||||
|
||||
void Start() override;
|
||||
|
||||
bool SetVideoMode(const VideoMode& mode, CS_Status* status) override;
|
||||
|
||||
void NumSinksChanged() override;
|
||||
void NumSinksEnabledChanged() override;
|
||||
|
||||
// OpenCV-specific functions
|
||||
void NotifyError(const wpi::Twine& msg);
|
||||
int CreateProperty(const wpi::Twine& name, CS_PropertyKind kind, int minimum,
|
||||
int maximum, int step, int defaultValue, int value);
|
||||
int CreateProperty(const wpi::Twine& name, CS_PropertyKind kind, int minimum,
|
||||
int maximum, int step, int defaultValue, int value,
|
||||
std::function<void(CS_Property property)> onChange);
|
||||
void SetEnumPropertyChoices(int property, wpi::ArrayRef<std::string> choices,
|
||||
CS_Status* status);
|
||||
|
||||
private:
|
||||
std::atomic_bool m_connected{true};
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_CONFIGURABLESOURCEIMPL_H_
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2016-2019 FIRST. 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. */
|
||||
@@ -138,10 +138,12 @@ CS_Sink CreateCvSinkCallback(const wpi::Twine& name,
|
||||
inst.telemetry, processFrame));
|
||||
}
|
||||
|
||||
static constexpr unsigned SinkMask = CS_SINK_CV | CS_SINK_RAW;
|
||||
|
||||
void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
|
||||
CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
if (!data || (data->kind & SinkMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
@@ -169,7 +171,7 @@ uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
|
||||
|
||||
std::string GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
if (!data || (data->kind & SinkMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
}
|
||||
@@ -179,7 +181,7 @@ std::string GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
if (!data || (data->kind & SinkMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return wpi::StringRef{};
|
||||
}
|
||||
@@ -188,7 +190,7 @@ wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
|
||||
void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_CV) {
|
||||
if (!data || (data->kind & SinkMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2016-2019 FIRST. 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. */
|
||||
@@ -25,37 +25,10 @@ using namespace cs;
|
||||
CvSourceImpl::CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const VideoMode& mode)
|
||||
: SourceImpl{name, logger, notifier, telemetry} {
|
||||
m_mode = mode;
|
||||
m_videoModes.push_back(m_mode);
|
||||
}
|
||||
: ConfigurableSourceImpl{name, logger, notifier, telemetry, mode} {}
|
||||
|
||||
CvSourceImpl::~CvSourceImpl() {}
|
||||
|
||||
void CvSourceImpl::Start() {
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
|
||||
m_notifier.NotifySourceVideoMode(*this, m_mode);
|
||||
}
|
||||
|
||||
bool CvSourceImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) {
|
||||
{
|
||||
std::lock_guard<wpi::mutex> lock(m_mutex);
|
||||
m_mode = mode;
|
||||
m_videoModes[0] = mode;
|
||||
}
|
||||
m_notifier.NotifySourceVideoMode(*this, mode);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CvSourceImpl::NumSinksChanged() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
void CvSourceImpl::NumSinksEnabledChanged() {
|
||||
// ignore
|
||||
}
|
||||
|
||||
void CvSourceImpl::PutFrame(cv::Mat& image) {
|
||||
// We only support 8-bit images; convert if necessary.
|
||||
cv::Mat finalImage;
|
||||
@@ -89,61 +62,6 @@ void CvSourceImpl::PutFrame(cv::Mat& image) {
|
||||
SourceImpl::PutFrame(std::move(dest), wpi::Now());
|
||||
}
|
||||
|
||||
void CvSourceImpl::NotifyError(const wpi::Twine& msg) {
|
||||
PutError(msg, wpi::Now());
|
||||
}
|
||||
|
||||
int CvSourceImpl::CreateProperty(const wpi::Twine& name, CS_PropertyKind kind,
|
||||
int minimum, int maximum, int step,
|
||||
int defaultValue, int value) {
|
||||
std::lock_guard<wpi::mutex> lock(m_mutex);
|
||||
int ndx = CreateOrUpdateProperty(name,
|
||||
[=] {
|
||||
return wpi::make_unique<PropertyImpl>(
|
||||
name, kind, minimum, maximum, step,
|
||||
defaultValue, value);
|
||||
},
|
||||
[&](PropertyImpl& prop) {
|
||||
// update all but value
|
||||
prop.propKind = kind;
|
||||
prop.minimum = minimum;
|
||||
prop.maximum = maximum;
|
||||
prop.step = step;
|
||||
prop.defaultValue = defaultValue;
|
||||
value = prop.value;
|
||||
});
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name, ndx,
|
||||
kind, value, wpi::Twine{});
|
||||
return ndx;
|
||||
}
|
||||
|
||||
int CvSourceImpl::CreateProperty(
|
||||
const wpi::Twine& name, CS_PropertyKind kind, int minimum, int maximum,
|
||||
int step, int defaultValue, int value,
|
||||
std::function<void(CS_Property property)> onChange) {
|
||||
// TODO
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CvSourceImpl::SetEnumPropertyChoices(int property,
|
||||
wpi::ArrayRef<std::string> choices,
|
||||
CS_Status* status) {
|
||||
std::lock_guard<wpi::mutex> lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
*status = CS_INVALID_PROPERTY;
|
||||
return;
|
||||
}
|
||||
if (prop->propKind != CS_PROP_ENUM) {
|
||||
*status = CS_WRONG_PROPERTY_TYPE;
|
||||
return;
|
||||
}
|
||||
prop->enumChoices = choices;
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
prop->name, property, CS_PROP_ENUM,
|
||||
prop->value, wpi::Twine{});
|
||||
}
|
||||
|
||||
namespace cs {
|
||||
|
||||
CS_Source CreateCvSource(const wpi::Twine& name, const VideoMode& mode,
|
||||
@@ -163,10 +81,12 @@ void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status) {
|
||||
static_cast<CvSourceImpl&>(*data->source).PutFrame(image);
|
||||
}
|
||||
|
||||
static constexpr unsigned SourceMask = CS_SINK_CV | CS_SINK_RAW;
|
||||
|
||||
void NotifySourceError(CS_Source source, const wpi::Twine& msg,
|
||||
CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
if (!data || (data->kind & SourceMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
@@ -175,7 +95,7 @@ void NotifySourceError(CS_Source source, const wpi::Twine& msg,
|
||||
|
||||
void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
if (!data || (data->kind & SourceMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
@@ -185,7 +105,7 @@ void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) {
|
||||
void SetSourceDescription(CS_Source source, const wpi::Twine& description,
|
||||
CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
if (!data || (data->kind & SourceMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
@@ -197,7 +117,7 @@ CS_Property CreateSourceProperty(CS_Source source, const wpi::Twine& name,
|
||||
int step, int defaultValue, int value,
|
||||
CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
if (!data || (data->kind & SourceMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return -1;
|
||||
}
|
||||
@@ -212,7 +132,7 @@ CS_Property CreateSourcePropertyCallback(
|
||||
int maximum, int step, int defaultValue, int value,
|
||||
std::function<void(CS_Property property)> onChange, CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
if (!data || (data->kind & SourceMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return -1;
|
||||
}
|
||||
@@ -226,7 +146,7 @@ void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
|
||||
wpi::ArrayRef<std::string> choices,
|
||||
CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_CV) {
|
||||
if (!data || (data->kind & SourceMask) == 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2016-2019 FIRST. 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. */
|
||||
@@ -18,33 +18,19 @@
|
||||
#include <wpi/ArrayRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
|
||||
#include "ConfigurableSourceImpl.h"
|
||||
#include "SourceImpl.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class CvSourceImpl : public SourceImpl {
|
||||
class CvSourceImpl : public ConfigurableSourceImpl {
|
||||
public:
|
||||
CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry, const VideoMode& mode);
|
||||
~CvSourceImpl() override;
|
||||
|
||||
void Start() override;
|
||||
|
||||
bool SetVideoMode(const VideoMode& mode, CS_Status* status) override;
|
||||
|
||||
void NumSinksChanged() override;
|
||||
void NumSinksEnabledChanged() override;
|
||||
|
||||
// OpenCV-specific functions
|
||||
void PutFrame(cv::Mat& image);
|
||||
void NotifyError(const wpi::Twine& msg);
|
||||
int CreateProperty(const wpi::Twine& name, CS_PropertyKind kind, int minimum,
|
||||
int maximum, int step, int defaultValue, int value);
|
||||
int CreateProperty(const wpi::Twine& name, CS_PropertyKind kind, int minimum,
|
||||
int maximum, int step, int defaultValue, int value,
|
||||
std::function<void(CS_Property property)> onChange);
|
||||
void SetEnumPropertyChoices(int property, wpi::ArrayRef<std::string> choices,
|
||||
CS_Status* status);
|
||||
|
||||
private:
|
||||
std::atomic_bool m_connected{true};
|
||||
|
||||
199
cscore/src/main/native/cpp/RawSinkImpl.cpp
Normal file
199
cscore/src/main/native/cpp/RawSinkImpl.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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 "RawSinkImpl.h"
|
||||
|
||||
#include "Instance.h"
|
||||
#include "cscore.h"
|
||||
#include "cscore_raw.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
RawSinkImpl::RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry)
|
||||
: SinkImpl{name, logger, notifier, telemetry} {
|
||||
m_active = true;
|
||||
// m_thread = std::thread(&RawSinkImpl::ThreadMain, this);
|
||||
}
|
||||
|
||||
RawSinkImpl::RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
std::function<void(uint64_t time)> processFrame)
|
||||
: SinkImpl{name, logger, notifier, telemetry} {}
|
||||
|
||||
RawSinkImpl::~RawSinkImpl() { Stop(); }
|
||||
|
||||
void RawSinkImpl::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 RawSinkImpl::GrabFrame(CS_RawFrame& image) {
|
||||
SetEnabled(true);
|
||||
|
||||
auto source = GetSource();
|
||||
if (!source) {
|
||||
// Source disconnected; sleep for one second
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto frame = source->GetNextFrame(); // blocks
|
||||
if (!frame) {
|
||||
// Bad frame; sleep for 20 ms so we don't consume all processor time.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
return 0; // signal error
|
||||
}
|
||||
|
||||
return GrabFrameImpl(image, frame);
|
||||
}
|
||||
|
||||
uint64_t RawSinkImpl::GrabFrame(CS_RawFrame& image, double timeout) {
|
||||
SetEnabled(true);
|
||||
|
||||
auto source = GetSource();
|
||||
if (!source) {
|
||||
// Source disconnected; sleep for one second
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto frame = source->GetNextFrame(timeout); // blocks
|
||||
if (!frame) {
|
||||
// Bad frame; sleep for 20 ms so we don't consume all processor time.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
return 0; // signal error
|
||||
}
|
||||
|
||||
return GrabFrameImpl(image, frame);
|
||||
}
|
||||
|
||||
uint64_t RawSinkImpl::GrabFrameImpl(CS_RawFrame& rawFrame,
|
||||
Frame& incomingFrame) {
|
||||
Image* newImage = nullptr;
|
||||
|
||||
if (rawFrame.pixelFormat == CS_PixelFormat::CS_PIXFMT_UNKNOWN) {
|
||||
// Always get incoming image directly on unknown
|
||||
newImage = incomingFrame.GetExistingImage(0);
|
||||
} else {
|
||||
// Format is known, ask for it
|
||||
auto width = rawFrame.width;
|
||||
auto height = rawFrame.height;
|
||||
auto pixelFormat =
|
||||
static_cast<VideoMode::PixelFormat>(rawFrame.pixelFormat);
|
||||
if (width <= 0 || height <= 0) {
|
||||
width = incomingFrame.GetOriginalWidth();
|
||||
height = incomingFrame.GetOriginalHeight();
|
||||
}
|
||||
newImage = incomingFrame.GetImage(width, height, pixelFormat);
|
||||
}
|
||||
|
||||
if (!newImage) {
|
||||
// Shouldn't happen, but just in case...
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
return 0;
|
||||
}
|
||||
|
||||
CS_AllocateRawFrameData(&rawFrame, newImage->size());
|
||||
rawFrame.height = newImage->height;
|
||||
rawFrame.width = newImage->width;
|
||||
rawFrame.pixelFormat = newImage->pixelFormat;
|
||||
rawFrame.totalData = newImage->size();
|
||||
std::copy(newImage->data(), newImage->data() + rawFrame.totalData,
|
||||
rawFrame.data);
|
||||
|
||||
return incomingFrame.GetTime();
|
||||
}
|
||||
|
||||
// Send HTTP response and a stream of JPG-frames
|
||||
void RawSinkImpl::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;
|
||||
}
|
||||
SDEBUG4("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 CreateRawSink(const wpi::Twine& name, CS_Status* status) {
|
||||
auto& inst = Instance::GetInstance();
|
||||
return inst.CreateSink(CS_SINK_RAW,
|
||||
std::make_shared<RawSinkImpl>(
|
||||
name, inst.logger, inst.notifier, inst.telemetry));
|
||||
}
|
||||
|
||||
CS_Sink CreateRawSinkCallback(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame,
|
||||
CS_Status* status) {
|
||||
auto& inst = Instance::GetInstance();
|
||||
return inst.CreateSink(CS_SINK_RAW, std::make_shared<RawSinkImpl>(
|
||||
name, inst.logger, inst.notifier,
|
||||
inst.telemetry, processFrame));
|
||||
}
|
||||
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, CS_RawFrame& image, CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_RAW) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
return static_cast<RawSinkImpl&>(*data->sink).GrabFrame(image);
|
||||
}
|
||||
|
||||
uint64_t GrabSinkFrameTimeout(CS_Sink sink, CS_RawFrame& image, double timeout,
|
||||
CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data || data->kind != CS_SINK_RAW) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
return static_cast<RawSinkImpl&>(*data->sink).GrabFrame(image, timeout);
|
||||
}
|
||||
} // namespace cs
|
||||
|
||||
extern "C" {
|
||||
CS_Sink CS_CreateRawSink(const char* name, CS_Status* status) {
|
||||
return cs::CreateRawSink(name, status);
|
||||
}
|
||||
|
||||
CS_Sink CS_CreateRawSinkCallback(const char* name, void* data,
|
||||
void (*processFrame)(void* data,
|
||||
uint64_t time),
|
||||
CS_Status* status) {
|
||||
return cs::CreateRawSinkCallback(
|
||||
name, [=](uint64_t time) { processFrame(data, time); }, status);
|
||||
}
|
||||
|
||||
uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct CS_RawFrame* image,
|
||||
CS_Status* status) {
|
||||
return cs::GrabSinkFrame(sink, *image, status);
|
||||
}
|
||||
|
||||
uint64_t CS_GrabRawSinkFrameTimeout(CS_Sink sink, struct CS_RawFrame* image,
|
||||
double timeout, CS_Status* status) {
|
||||
return cs::GrabSinkFrameTimeout(sink, *image, timeout, status);
|
||||
}
|
||||
} // extern "C"
|
||||
52
cscore/src/main/native/cpp/RawSinkImpl.h
Normal file
52
cscore/src/main/native/cpp/RawSinkImpl.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2019 FIRST. 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 CSCORE_RAWSINKIMPL_H_
|
||||
#define CSCORE_RAWSINKIMPL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
#include <wpi/Twine.h>
|
||||
#include <wpi/condition_variable.h>
|
||||
|
||||
#include "Frame.h"
|
||||
#include "SinkImpl.h"
|
||||
#include "cscore_raw.h"
|
||||
|
||||
namespace cs {
|
||||
class SourceImpl;
|
||||
|
||||
class RawSinkImpl : public SinkImpl {
|
||||
public:
|
||||
RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry);
|
||||
RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry,
|
||||
std::function<void(uint64_t time)> processFrame);
|
||||
~RawSinkImpl() override;
|
||||
|
||||
void Stop();
|
||||
|
||||
uint64_t GrabFrame(CS_RawFrame& frame);
|
||||
uint64_t GrabFrame(CS_RawFrame& frame, double timeout);
|
||||
|
||||
private:
|
||||
void ThreadMain();
|
||||
|
||||
uint64_t GrabFrameImpl(CS_RawFrame& rawFrame, Frame& incomingFrame);
|
||||
|
||||
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 // CSCORE_RAWSINKIMPL_H_
|
||||
83
cscore/src/main/native/cpp/RawSourceImpl.cpp
Normal file
83
cscore/src/main/native/cpp/RawSourceImpl.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. 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 "RawSourceImpl.h"
|
||||
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "Handle.h"
|
||||
#include "Instance.h"
|
||||
#include "Log.h"
|
||||
#include "Notifier.h"
|
||||
#include "cscore_raw.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
RawSourceImpl::RawSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
Notifier& notifier, Telemetry& telemetry,
|
||||
const VideoMode& mode)
|
||||
: ConfigurableSourceImpl{name, logger, notifier, telemetry, mode} {}
|
||||
|
||||
RawSourceImpl::~RawSourceImpl() {}
|
||||
|
||||
void RawSourceImpl::PutFrame(const CS_RawFrame& image) {
|
||||
int type;
|
||||
switch (image.pixelFormat) {
|
||||
case VideoMode::kYUYV:
|
||||
case VideoMode::kRGB565:
|
||||
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};
|
||||
std::unique_ptr<Image> dest =
|
||||
AllocImage(static_cast<VideoMode::PixelFormat>(image.pixelFormat),
|
||||
image.width, image.height, image.totalData);
|
||||
finalImage.copyTo(dest->AsMat());
|
||||
|
||||
SourceImpl::PutFrame(std::move(dest), wpi::Now());
|
||||
}
|
||||
|
||||
namespace cs {
|
||||
CS_Source CreateRawSource(const wpi::Twine& name, const VideoMode& mode,
|
||||
CS_Status* status) {
|
||||
auto& inst = Instance::GetInstance();
|
||||
return inst.CreateSource(CS_SOURCE_RAW, std::make_shared<RawSourceImpl>(
|
||||
name, inst.logger, inst.notifier,
|
||||
inst.telemetry, mode));
|
||||
}
|
||||
|
||||
void PutSourceFrame(CS_Source source, const CS_RawFrame& image,
|
||||
CS_Status* status) {
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data || data->kind != CS_SOURCE_RAW) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
static_cast<RawSourceImpl&>(*data->source).PutFrame(image);
|
||||
}
|
||||
} // namespace cs
|
||||
|
||||
extern "C" {
|
||||
CS_Source CS_CreateRawSource(const char* name, const CS_VideoMode* mode,
|
||||
CS_Status* status) {
|
||||
return cs::CreateRawSource(name, static_cast<const cs::VideoMode&>(*mode),
|
||||
status);
|
||||
}
|
||||
|
||||
void CS_PutRawSourceFrame(CS_Source source, const struct CS_RawFrame* image,
|
||||
CS_Status* status) {
|
||||
return cs::PutSourceFrame(source, *image, status);
|
||||
}
|
||||
} // extern "C"
|
||||
41
cscore/src/main/native/cpp/RawSourceImpl.h
Normal file
41
cscore/src/main/native/cpp/RawSourceImpl.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2019 FIRST. 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 CSCORE_RAWSOURCEIMPL_H_
|
||||
#define CSCORE_RAWSOURCEIMPL_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <wpi/ArrayRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
|
||||
#include "ConfigurableSourceImpl.h"
|
||||
#include "SourceImpl.h"
|
||||
#include "cscore_raw.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class RawSourceImpl : public ConfigurableSourceImpl {
|
||||
public:
|
||||
RawSourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
|
||||
Telemetry& telemetry, const VideoMode& mode);
|
||||
~RawSourceImpl() override;
|
||||
|
||||
// Raw-specific functions
|
||||
void PutFrame(const CS_RawFrame& image);
|
||||
|
||||
private:
|
||||
std::atomic_bool m_connected{true};
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_RAWSOURCEIMPL_H_
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "c_util.h"
|
||||
#include "cscore_cpp.h"
|
||||
#include "cscore_raw.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -440,4 +441,23 @@ void CS_FreeNetworkInterfaces(char** interfaces, int count) {
|
||||
std::free(interfaces);
|
||||
}
|
||||
|
||||
void CS_AllocateRawFrameData(CS_RawFrame* frame, int requestedSize) {
|
||||
if (frame->dataLength >= requestedSize) return;
|
||||
if (frame->data) {
|
||||
frame->data =
|
||||
static_cast<char*>(wpi::safe_realloc(frame->data, requestedSize));
|
||||
} else {
|
||||
frame->data = static_cast<char*>(wpi::safe_malloc(requestedSize));
|
||||
}
|
||||
frame->dataLength = requestedSize;
|
||||
}
|
||||
|
||||
void CS_FreeRawFrameData(CS_RawFrame* frame) {
|
||||
if (frame->data) {
|
||||
std::free(frame->data);
|
||||
frame->data = nullptr;
|
||||
frame->dataLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -10,8 +10,14 @@
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
#include "cscore_cpp.h"
|
||||
#include "cscore_cv.h"
|
||||
#include "cscore_raw.h"
|
||||
#include "edu_wpi_cscore_CameraServerJNI.h"
|
||||
|
||||
namespace cv {
|
||||
class Mat;
|
||||
} // namespace cv
|
||||
|
||||
using namespace wpi::java;
|
||||
|
||||
//
|
||||
@@ -23,6 +29,7 @@ static JavaVM* jvm = nullptr;
|
||||
static JClass usbCameraInfoCls;
|
||||
static JClass videoModeCls;
|
||||
static JClass videoEventCls;
|
||||
static JClass rawFrameCls;
|
||||
static JException videoEx;
|
||||
static JException nullPointerEx;
|
||||
static JException unsupportedEx;
|
||||
@@ -32,7 +39,8 @@ static JNIEnv* listenerEnv = nullptr;
|
||||
static const JClassInit classes[] = {
|
||||
{"edu/wpi/cscore/UsbCameraInfo", &usbCameraInfoCls},
|
||||
{"edu/wpi/cscore/VideoMode", &videoModeCls},
|
||||
{"edu/wpi/cscore/VideoEvent", &videoEventCls}};
|
||||
{"edu/wpi/cscore/VideoEvent", &videoEventCls},
|
||||
{"edu/wpi/cscore/raw/RawFrame", &rawFrameCls}};
|
||||
|
||||
static const JExceptionInit exceptions[] = {
|
||||
{"edu/wpi/cscore/VideoException", &videoEx},
|
||||
@@ -506,12 +514,12 @@ Java_edu_wpi_cscore_CameraServerJNI_createHttpCameraMulti
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Class: edu_wpi_cscore_CameraServerCvJNI
|
||||
* Method: createCvSource
|
||||
* Signature: (Ljava/lang/String;IIII)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_createCvSource
|
||||
Java_edu_wpi_cscore_CameraServerCvJNI_createCvSource
|
||||
(JNIEnv* env, jclass, jstring name, jint pixelFormat, jint width, jint height,
|
||||
jint fps)
|
||||
{
|
||||
@@ -530,6 +538,31 @@ Java_edu_wpi_cscore_CameraServerJNI_createCvSource
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: createRawSource
|
||||
* Signature: (Ljava/lang/String;IIII)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_createRawSource
|
||||
(JNIEnv* env, jclass, jstring name, jint pixelFormat, jint width, jint height,
|
||||
jint fps)
|
||||
{
|
||||
if (!name) {
|
||||
nullPointerEx.Throw(env, "name cannot be null");
|
||||
return 0;
|
||||
}
|
||||
CS_Status status = 0;
|
||||
auto val = cs::CreateRawSource(
|
||||
JStringRef{env, name}.str(),
|
||||
cs::VideoMode{static_cast<cs::VideoMode::PixelFormat>(pixelFormat),
|
||||
static_cast<int>(width), static_cast<int>(height),
|
||||
static_cast<int>(fps)},
|
||||
&status);
|
||||
CheckStatus(env, status);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: getSourceKind
|
||||
@@ -1054,12 +1087,12 @@ Java_edu_wpi_cscore_CameraServerJNI_getHttpCameraUrls
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Class: edu_wpi_cscore_CameraServerCvJNI
|
||||
* Method: putSourceFrame
|
||||
* Signature: (IJ)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_putSourceFrame
|
||||
Java_edu_wpi_cscore_CameraServerCvJNI_putSourceFrame
|
||||
(JNIEnv* env, jclass, jint source, jlong imageNativeObj)
|
||||
{
|
||||
cv::Mat& image = *((cv::Mat*)imageNativeObj);
|
||||
@@ -1068,6 +1101,51 @@ Java_edu_wpi_cscore_CameraServerJNI_putSourceFrame
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
// int width, int height, int pixelFormat, int totalData
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: putRawSourceFrameBB
|
||||
* Signature: (ILjava/lang/Object;IIII)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_putRawSourceFrameBB
|
||||
(JNIEnv* env, jclass, jint source, jobject byteBuffer, jint width,
|
||||
jint height, jint pixelFormat, jint totalData)
|
||||
{
|
||||
CS_RawFrame rawFrame;
|
||||
rawFrame.data =
|
||||
reinterpret_cast<char*>(env->GetDirectBufferAddress(byteBuffer));
|
||||
rawFrame.totalData = totalData;
|
||||
rawFrame.pixelFormat = pixelFormat;
|
||||
rawFrame.width = width;
|
||||
rawFrame.height = height;
|
||||
CS_Status status = 0;
|
||||
cs::PutSourceFrame(source, rawFrame, &status);
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: putRawSourceFrame
|
||||
* Signature: (IJIIII)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_putRawSourceFrame
|
||||
(JNIEnv* env, jclass, jint source, jlong ptr, jint width, jint height,
|
||||
jint pixelFormat, jint totalData)
|
||||
{
|
||||
CS_RawFrame rawFrame;
|
||||
rawFrame.data = reinterpret_cast<char*>(static_cast<intptr_t>(ptr));
|
||||
rawFrame.totalData = totalData;
|
||||
rawFrame.pixelFormat = pixelFormat;
|
||||
rawFrame.width = width;
|
||||
rawFrame.height = height;
|
||||
CS_Status status = 0;
|
||||
cs::PutSourceFrame(source, rawFrame, &status);
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: notifySourceError
|
||||
@@ -1192,12 +1270,12 @@ Java_edu_wpi_cscore_CameraServerJNI_createMjpegServer
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Class: edu_wpi_cscore_CameraServerCvJNI
|
||||
* Method: createCvSink
|
||||
* Signature: (Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_createCvSink
|
||||
Java_edu_wpi_cscore_CameraServerCvJNI_createCvSink
|
||||
(JNIEnv* env, jclass, jstring name)
|
||||
{
|
||||
if (!name) {
|
||||
@@ -1210,6 +1288,25 @@ Java_edu_wpi_cscore_CameraServerJNI_createCvSink
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: createRawSink
|
||||
* Signature: (Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_createRawSink
|
||||
(JNIEnv* env, jclass, jstring name)
|
||||
{
|
||||
if (!name) {
|
||||
nullPointerEx.Throw(env, "name cannot be null");
|
||||
return 0;
|
||||
}
|
||||
CS_Status status = 0;
|
||||
auto val = cs::CreateRawSink(JStringRef{env, name}.str(), &status);
|
||||
CheckStatus(env, status);
|
||||
return val;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: getSinkKind
|
||||
@@ -1449,12 +1546,12 @@ Java_edu_wpi_cscore_CameraServerJNI_setSinkDescription
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Class: edu_wpi_cscore_CameraServerCvJNI
|
||||
* Method: grabSinkFrame
|
||||
* Signature: (IJ)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_grabSinkFrame
|
||||
Java_edu_wpi_cscore_CameraServerCvJNI_grabSinkFrame
|
||||
(JNIEnv* env, jclass, jint sink, jlong imageNativeObj)
|
||||
{
|
||||
cv::Mat& image = *((cv::Mat*)imageNativeObj);
|
||||
@@ -1465,12 +1562,12 @@ Java_edu_wpi_cscore_CameraServerJNI_grabSinkFrame
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Class: edu_wpi_cscore_CameraServerCvJNI
|
||||
* Method: grabSinkFrameTimeout
|
||||
* Signature: (IJD)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_grabSinkFrameTimeout
|
||||
Java_edu_wpi_cscore_CameraServerCvJNI_grabSinkFrameTimeout
|
||||
(JNIEnv* env, jclass, jint sink, jlong imageNativeObj, jdouble timeout)
|
||||
{
|
||||
cv::Mat& image = *((cv::Mat*)imageNativeObj);
|
||||
@@ -1480,6 +1577,75 @@ Java_edu_wpi_cscore_CameraServerJNI_grabSinkFrameTimeout
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void SetRawFrameData(JNIEnv* env, jobject rawFrameObj,
|
||||
jobject byteBuffer, bool didChangeDataPtr,
|
||||
const CS_RawFrame& frame) {
|
||||
static jmethodID setMethod =
|
||||
env->GetMethodID(rawFrameCls, "setData", "(Ljava/nio/ByteBuffer;JIIII)V");
|
||||
jlong framePtr = static_cast<jlong>(reinterpret_cast<intptr_t>(frame.data));
|
||||
|
||||
if (didChangeDataPtr) {
|
||||
byteBuffer = env->NewDirectByteBuffer(frame.data, frame.dataLength);
|
||||
}
|
||||
|
||||
env->CallVoidMethod(
|
||||
rawFrameObj, setMethod, byteBuffer, framePtr,
|
||||
static_cast<jint>(frame.totalData), static_cast<jint>(frame.width),
|
||||
static_cast<jint>(frame.height), static_cast<jint>(frame.pixelFormat));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: grabRawSinkFrameImpl
|
||||
* Signature: (ILjava/lang/Object;JLjava/lang/Object;III)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_grabRawSinkFrameImpl
|
||||
(JNIEnv* env, jclass, jint sink, jobject rawFrameObj, jlong rawFramePtr,
|
||||
jobject byteBuffer, jint width, jint height, jint pixelFormat)
|
||||
{
|
||||
CS_RawFrame* ptr =
|
||||
reinterpret_cast<CS_RawFrame*>(static_cast<intptr_t>(rawFramePtr));
|
||||
auto origDataPtr = ptr->data;
|
||||
ptr->width = width;
|
||||
ptr->height = height;
|
||||
ptr->pixelFormat = pixelFormat;
|
||||
CS_Status status = 0;
|
||||
auto rv = cs::GrabSinkFrame(static_cast<CS_Sink>(sink), *ptr, &status);
|
||||
if (!CheckStatus(env, status)) {
|
||||
return 0;
|
||||
}
|
||||
SetRawFrameData(env, rawFrameObj, byteBuffer, origDataPtr != ptr->data, *ptr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: grabRawSinkFrameTimeoutImpl
|
||||
* Signature: (ILjava/lang/Object;JLjava/lang/Object;IIID)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_grabRawSinkFrameTimeoutImpl
|
||||
(JNIEnv* env, jclass, jint sink, jobject rawFrameObj, jlong rawFramePtr,
|
||||
jobject byteBuffer, jint width, jint height, jint pixelFormat,
|
||||
jdouble timeout)
|
||||
{
|
||||
CS_RawFrame* ptr =
|
||||
reinterpret_cast<CS_RawFrame*>(static_cast<intptr_t>(rawFramePtr));
|
||||
auto origDataPtr = ptr->data;
|
||||
ptr->width = width;
|
||||
ptr->height = height;
|
||||
ptr->pixelFormat = pixelFormat;
|
||||
CS_Status status = 0;
|
||||
auto rv = cs::GrabSinkFrameTimeout(static_cast<CS_Sink>(sink), *ptr, timeout,
|
||||
&status);
|
||||
if (!CheckStatus(env, status)) {
|
||||
return 0;
|
||||
}
|
||||
SetRawFrameData(env, rawFrameObj, byteBuffer, origDataPtr != ptr->data, *ptr);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: getSinkError
|
||||
@@ -1781,4 +1947,32 @@ Java_edu_wpi_cscore_CameraServerJNI_setLogger
|
||||
minLevel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: allocateRawFrame
|
||||
* Signature: ()J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_allocateRawFrame
|
||||
(JNIEnv*, jclass)
|
||||
{
|
||||
cs::RawFrame* rawFrame = new cs::RawFrame{};
|
||||
intptr_t rawFrameIntPtr = reinterpret_cast<intptr_t>(rawFrame);
|
||||
return static_cast<jlong>(rawFrameIntPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_cscore_CameraServerJNI
|
||||
* Method: freeRawFrame
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_cscore_CameraServerJNI_freeRawFrame
|
||||
(JNIEnv*, jclass, jlong rawFrame)
|
||||
{
|
||||
cs::RawFrame* ptr =
|
||||
reinterpret_cast<cs::RawFrame*>(static_cast<intptr_t>(rawFrame));
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -20,8 +20,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct CvMat;
|
||||
|
||||
/**
|
||||
* @defgroup cscore_c_api cscore C API
|
||||
*
|
||||
@@ -128,7 +126,8 @@ enum CS_SourceKind {
|
||||
CS_SOURCE_UNKNOWN = 0,
|
||||
CS_SOURCE_USB = 1,
|
||||
CS_SOURCE_HTTP = 2,
|
||||
CS_SOURCE_CV = 4
|
||||
CS_SOURCE_CV = 4,
|
||||
CS_SOURCE_RAW = 8,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -144,7 +143,12 @@ enum CS_HttpCameraKind {
|
||||
/**
|
||||
* Sink kinds
|
||||
*/
|
||||
enum CS_SinkKind { CS_SINK_UNKNOWN = 0, CS_SINK_MJPEG = 2, CS_SINK_CV = 4 };
|
||||
enum CS_SinkKind {
|
||||
CS_SINK_UNKNOWN = 0,
|
||||
CS_SINK_MJPEG = 2,
|
||||
CS_SINK_CV = 4,
|
||||
CS_SINK_RAW = 8
|
||||
};
|
||||
|
||||
/**
|
||||
* Listener event kinds
|
||||
@@ -351,8 +355,6 @@ char** CS_GetHttpCameraUrls(CS_Source source, int* count, CS_Status* status);
|
||||
* @defgroup cscore_opencv_source_cfunc OpenCV Source Functions
|
||||
* @{
|
||||
*/
|
||||
void CS_PutSourceFrame(CS_Source source, struct CvMat* image,
|
||||
CS_Status* status);
|
||||
void CS_NotifySourceError(CS_Source source, const char* msg, CS_Status* status);
|
||||
void CS_SetSourceConnected(CS_Source source, CS_Bool connected,
|
||||
CS_Status* status);
|
||||
@@ -415,9 +417,6 @@ int CS_GetMjpegServerPort(CS_Sink sink, CS_Status* status);
|
||||
*/
|
||||
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);
|
||||
uint64_t CS_GrabSinkFrameTimeout(CS_Sink sink, struct CvMat* image,
|
||||
double timeout, CS_Status* status);
|
||||
char* CS_GetSinkError(CS_Sink sink, CS_Status* status);
|
||||
void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status);
|
||||
/** @} */
|
||||
|
||||
@@ -21,10 +21,6 @@
|
||||
|
||||
#include "cscore_c.h"
|
||||
|
||||
namespace cv {
|
||||
class Mat;
|
||||
} // namespace cv
|
||||
|
||||
namespace wpi {
|
||||
class json;
|
||||
} // namespace wpi
|
||||
@@ -286,7 +282,6 @@ std::vector<std::string> GetHttpCameraUrls(CS_Source source, CS_Status* status);
|
||||
* @defgroup cscore_opencv_source_func OpenCV Source Functions
|
||||
* @{
|
||||
*/
|
||||
void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status);
|
||||
void NotifySourceError(CS_Source source, const wpi::Twine& msg,
|
||||
CS_Status* status);
|
||||
void SetSourceConnected(CS_Source source, bool connected, CS_Status* status);
|
||||
@@ -312,6 +307,7 @@ CS_Sink CreateCvSink(const wpi::Twine& name, CS_Status* status);
|
||||
CS_Sink CreateCvSinkCallback(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame,
|
||||
CS_Status* status);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
@@ -356,9 +352,6 @@ int GetMjpegServerPort(CS_Sink sink, CS_Status* status);
|
||||
*/
|
||||
void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
|
||||
CS_Status* status);
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status);
|
||||
uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
|
||||
CS_Status* status);
|
||||
std::string GetSinkError(CS_Sink sink, CS_Status* status);
|
||||
wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
|
||||
CS_Status* status);
|
||||
@@ -429,18 +422,4 @@ std::vector<std::string> GetNetworkInterfaces();
|
||||
|
||||
} // namespace cs
|
||||
|
||||
/**
|
||||
* @defgroup cscore_cpp_opencv_special cscore C functions taking a cv::Mat*
|
||||
*
|
||||
* These are needed for specific interop implementations.
|
||||
* @{
|
||||
*/
|
||||
extern "C" {
|
||||
uint64_t CS_GrabSinkFrameCpp(CS_Sink sink, cv::Mat* image, CS_Status* status);
|
||||
uint64_t CS_GrabSinkFrameTimeoutCpp(CS_Sink sink, cv::Mat* image,
|
||||
double timeout, CS_Status* status);
|
||||
void CS_PutSourceFrameCpp(CS_Source source, cv::Mat* image, CS_Status* status);
|
||||
} // extern "C"
|
||||
/** @} */
|
||||
|
||||
#endif // CSCORE_CSCORE_CPP_H_
|
||||
|
||||
205
cscore/src/main/native/include/cscore_cv.h
Normal file
205
cscore/src/main/native/include/cscore_cv.h
Normal file
@@ -0,0 +1,205 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2019 FIRST. 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 CSCORE_CSCORE_CV_H_
|
||||
#define CSCORE_CSCORE_CV_H_
|
||||
|
||||
#include "cscore_c.h"
|
||||
|
||||
#ifdef CSCORE_CSCORE_RAW_CV_H_
|
||||
#error "Cannot include both cscore_cv.h and cscore_raw_cv.h in the same file"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "cscore_oo.h" // NOLINT(build/include_order)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" { // NOLINT(build/include_order)
|
||||
#endif
|
||||
|
||||
struct CvMat;
|
||||
|
||||
void CS_PutSourceFrame(CS_Source source, struct CvMat* image,
|
||||
CS_Status* status);
|
||||
|
||||
uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image, CS_Status* status);
|
||||
uint64_t CS_GrabSinkFrameTimeout(CS_Sink sink, struct CvMat* image,
|
||||
double timeout, CS_Status* status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "cscore_oo.h"
|
||||
|
||||
namespace cv {
|
||||
class Mat;
|
||||
} // namespace cv
|
||||
|
||||
namespace cs {
|
||||
|
||||
/**
|
||||
* @defgroup cscore_cpp_opencv_special cscore C functions taking a cv::Mat*
|
||||
*
|
||||
* These are needed for specific interop implementations.
|
||||
* @{
|
||||
*/
|
||||
extern "C" {
|
||||
uint64_t CS_GrabSinkFrameCpp(CS_Sink sink, cv::Mat* image, CS_Status* status);
|
||||
uint64_t CS_GrabSinkFrameTimeoutCpp(CS_Sink sink, cv::Mat* image,
|
||||
double timeout, CS_Status* status);
|
||||
void CS_PutSourceFrameCpp(CS_Source source, cv::Mat* image, CS_Status* status);
|
||||
} // extern "C"
|
||||
/** @} */
|
||||
|
||||
void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status);
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status);
|
||||
uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
|
||||
CS_Status* status);
|
||||
|
||||
/**
|
||||
* A source for user code to provide OpenCV images as video frames.
|
||||
* These sources require the WPILib OpenCV builds.
|
||||
* For an alternate OpenCV, include "cscore_raw_cv.h" instead, and
|
||||
* include your Mat header before that header.
|
||||
*/
|
||||
class CvSource : public ImageSource {
|
||||
public:
|
||||
CvSource() = default;
|
||||
|
||||
/**
|
||||
* Create an OpenCV source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param mode Video mode being generated
|
||||
*/
|
||||
CvSource(const wpi::Twine& name, const VideoMode& mode);
|
||||
|
||||
/**
|
||||
* Create an OpenCV source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param pixelFormat Pixel format
|
||||
* @param width width
|
||||
* @param height height
|
||||
* @param fps fps
|
||||
*/
|
||||
CvSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
|
||||
int width, int height, int fps);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param image OpenCV image
|
||||
*/
|
||||
void PutFrame(cv::Mat& image);
|
||||
};
|
||||
|
||||
/**
|
||||
* A sink for user code to accept video frames as OpenCV images.
|
||||
* These sinks require the WPILib OpenCV builds.
|
||||
* For an alternate OpenCV, include "cscore_raw_cv.h" instead, and
|
||||
* include your Mat header before that header.
|
||||
*/
|
||||
class CvSink : public ImageSink {
|
||||
public:
|
||||
CvSink() = default;
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images.
|
||||
*
|
||||
* <p>WaitForFrame() must be called on the created sink to get each new
|
||||
* image.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
*/
|
||||
explicit CvSink(const wpi::Twine& name);
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images in a separate thread.
|
||||
*
|
||||
* <p>A thread will be created that calls WaitForFrame() and calls the
|
||||
* processFrame() callback each time a new frame arrives.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param processFrame Frame processing function; will be called with a
|
||||
* time=0 if an error occurred. processFrame should call GetImage()
|
||||
* or GetError() as needed, but should not call (except in very
|
||||
* unusual circumstances) WaitForImage().
|
||||
*/
|
||||
CvSink(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame);
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after timeout seconds.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrame(cv::Mat& image, double timeout = 0.225) const;
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. May block forever.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrameNoTimeout(cv::Mat& image) const;
|
||||
};
|
||||
|
||||
inline CvSource::CvSource(const wpi::Twine& name, const VideoMode& mode) {
|
||||
m_handle = CreateCvSource(name, mode, &m_status);
|
||||
}
|
||||
|
||||
inline CvSource::CvSource(const wpi::Twine& name, VideoMode::PixelFormat format,
|
||||
int width, int height, int fps) {
|
||||
m_handle =
|
||||
CreateCvSource(name, VideoMode{format, width, height, fps}, &m_status);
|
||||
}
|
||||
|
||||
inline void CvSource::PutFrame(cv::Mat& image) {
|
||||
m_status = 0;
|
||||
PutSourceFrame(m_handle, image, &m_status);
|
||||
}
|
||||
|
||||
inline CvSink::CvSink(const wpi::Twine& name) {
|
||||
m_handle = CreateCvSink(name, &m_status);
|
||||
}
|
||||
|
||||
inline CvSink::CvSink(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame) {
|
||||
m_handle = CreateCvSinkCallback(name, processFrame, &m_status);
|
||||
}
|
||||
|
||||
inline uint64_t CvSink::GrabFrame(cv::Mat& image, double timeout) const {
|
||||
m_status = 0;
|
||||
return GrabSinkFrameTimeout(m_handle, image, timeout, &m_status);
|
||||
}
|
||||
|
||||
inline uint64_t CvSink::GrabFrameNoTimeout(cv::Mat& image) const {
|
||||
m_status = 0;
|
||||
return GrabSinkFrame(m_handle, image, &m_status);
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CSCORE_CSCORE_CV_H_
|
||||
@@ -28,7 +28,7 @@ namespace cs {
|
||||
*/
|
||||
|
||||
// Forward declarations so friend declarations work correctly
|
||||
class CvSource;
|
||||
class ImageSource;
|
||||
class VideoEvent;
|
||||
class VideoSink;
|
||||
class VideoSource;
|
||||
@@ -37,7 +37,7 @@ class VideoSource;
|
||||
* A source or sink property.
|
||||
*/
|
||||
class VideoProperty {
|
||||
friend class CvSource;
|
||||
friend class ImageSource;
|
||||
friend class VideoEvent;
|
||||
friend class VideoSink;
|
||||
friend class VideoSource;
|
||||
@@ -617,43 +617,13 @@ class AxisCamera : public HttpCamera {
|
||||
};
|
||||
|
||||
/**
|
||||
* A source for user code to provide OpenCV images as video frames.
|
||||
* A base class for single image providing sources.
|
||||
*/
|
||||
class CvSource : public VideoSource {
|
||||
class ImageSource : public VideoSource {
|
||||
protected:
|
||||
ImageSource() = default;
|
||||
|
||||
public:
|
||||
CvSource() = default;
|
||||
|
||||
/**
|
||||
* Create an OpenCV source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param mode Video mode being generated
|
||||
*/
|
||||
CvSource(const wpi::Twine& name, const VideoMode& mode);
|
||||
|
||||
/**
|
||||
* Create an OpenCV source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param pixelFormat Pixel format
|
||||
* @param width width
|
||||
* @param height height
|
||||
* @param fps fps
|
||||
*/
|
||||
CvSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
|
||||
int width, int height, int fps);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param image OpenCV image
|
||||
*/
|
||||
void PutFrame(cv::Mat& image);
|
||||
|
||||
/**
|
||||
* Signal sinks that an error has occurred. This should be called instead
|
||||
* of NotifyFrame when an error occurs.
|
||||
@@ -979,37 +949,13 @@ class MjpegServer : public VideoSink {
|
||||
};
|
||||
|
||||
/**
|
||||
* A sink for user code to accept video frames as OpenCV images.
|
||||
* A base class for single image reading sinks.
|
||||
*/
|
||||
class CvSink : public VideoSink {
|
||||
class ImageSink : public VideoSink {
|
||||
protected:
|
||||
ImageSink() = default;
|
||||
|
||||
public:
|
||||
CvSink() = default;
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images.
|
||||
*
|
||||
* <p>WaitForFrame() must be called on the created sink to get each new
|
||||
* image.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
*/
|
||||
explicit CvSink(const wpi::Twine& name);
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images in a separate thread.
|
||||
*
|
||||
* <p>A thread will be created that calls WaitForFrame() and calls the
|
||||
* processFrame() callback each time a new frame arrives.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param processFrame Frame processing function; will be called with a
|
||||
* time=0 if an error occurred. processFrame should call GetImage()
|
||||
* or GetError() as needed, but should not call (except in very
|
||||
* unusual circumstances) WaitForImage().
|
||||
*/
|
||||
CvSink(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame);
|
||||
|
||||
/**
|
||||
* Set sink description.
|
||||
*
|
||||
@@ -1017,27 +963,6 @@ class CvSink : public VideoSink {
|
||||
*/
|
||||
void SetDescription(const wpi::Twine& description);
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after timeout seconds.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrame(cv::Mat& image, double timeout = 0.225) const;
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. May block forever.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrameNoTimeout(cv::Mat& image) const;
|
||||
|
||||
/**
|
||||
* Get error string. Call this if WaitForFrame() returns 0 to determine
|
||||
* what the error is.
|
||||
|
||||
@@ -378,37 +378,22 @@ inline AxisCamera::AxisCamera(const wpi::Twine& name,
|
||||
std::initializer_list<T> hosts)
|
||||
: HttpCamera(name, HostToUrl(hosts), kAxis) {}
|
||||
|
||||
inline CvSource::CvSource(const wpi::Twine& name, const VideoMode& mode) {
|
||||
m_handle = CreateCvSource(name, mode, &m_status);
|
||||
}
|
||||
|
||||
inline CvSource::CvSource(const wpi::Twine& name, VideoMode::PixelFormat format,
|
||||
int width, int height, int fps) {
|
||||
m_handle =
|
||||
CreateCvSource(name, VideoMode{format, width, height, fps}, &m_status);
|
||||
}
|
||||
|
||||
inline void CvSource::PutFrame(cv::Mat& image) {
|
||||
m_status = 0;
|
||||
PutSourceFrame(m_handle, image, &m_status);
|
||||
}
|
||||
|
||||
inline void CvSource::NotifyError(const wpi::Twine& msg) {
|
||||
inline void ImageSource::NotifyError(const wpi::Twine& msg) {
|
||||
m_status = 0;
|
||||
NotifySourceError(m_handle, msg, &m_status);
|
||||
}
|
||||
|
||||
inline void CvSource::SetConnected(bool connected) {
|
||||
inline void ImageSource::SetConnected(bool connected) {
|
||||
m_status = 0;
|
||||
SetSourceConnected(m_handle, connected, &m_status);
|
||||
}
|
||||
|
||||
inline void CvSource::SetDescription(const wpi::Twine& description) {
|
||||
inline void ImageSource::SetDescription(const wpi::Twine& description) {
|
||||
m_status = 0;
|
||||
SetSourceDescription(m_handle, description, &m_status);
|
||||
}
|
||||
|
||||
inline VideoProperty CvSource::CreateProperty(const wpi::Twine& name,
|
||||
inline VideoProperty ImageSource::CreateProperty(const wpi::Twine& name,
|
||||
VideoProperty::Kind kind,
|
||||
int minimum, int maximum,
|
||||
int step, int defaultValue,
|
||||
@@ -419,7 +404,7 @@ inline VideoProperty CvSource::CreateProperty(const wpi::Twine& name,
|
||||
minimum, maximum, step, defaultValue, value, &m_status)};
|
||||
}
|
||||
|
||||
inline VideoProperty CvSource::CreateIntegerProperty(const wpi::Twine& name,
|
||||
inline VideoProperty ImageSource::CreateIntegerProperty(const wpi::Twine& name,
|
||||
int minimum, int maximum,
|
||||
int step, int defaultValue,
|
||||
int value) {
|
||||
@@ -429,7 +414,7 @@ inline VideoProperty CvSource::CreateIntegerProperty(const wpi::Twine& name,
|
||||
minimum, maximum, step, defaultValue, value, &m_status)};
|
||||
}
|
||||
|
||||
inline VideoProperty CvSource::CreateBooleanProperty(const wpi::Twine& name,
|
||||
inline VideoProperty ImageSource::CreateBooleanProperty(const wpi::Twine& name,
|
||||
bool defaultValue,
|
||||
bool value) {
|
||||
m_status = 0;
|
||||
@@ -438,7 +423,7 @@ inline VideoProperty CvSource::CreateBooleanProperty(const wpi::Twine& name,
|
||||
0, 1, 1, defaultValue ? 1 : 0, value ? 1 : 0, &m_status)};
|
||||
}
|
||||
|
||||
inline VideoProperty CvSource::CreateStringProperty(const wpi::Twine& name,
|
||||
inline VideoProperty ImageSource::CreateStringProperty(const wpi::Twine& name,
|
||||
const wpi::Twine& value) {
|
||||
m_status = 0;
|
||||
auto prop = VideoProperty{CreateSourceProperty(
|
||||
@@ -449,14 +434,14 @@ inline VideoProperty CvSource::CreateStringProperty(const wpi::Twine& name,
|
||||
}
|
||||
|
||||
|
||||
inline void CvSource::SetEnumPropertyChoices(
|
||||
inline void ImageSource::SetEnumPropertyChoices(
|
||||
const VideoProperty& property, wpi::ArrayRef<std::string> choices) {
|
||||
m_status = 0;
|
||||
SetSourceEnumPropertyChoices(m_handle, property.m_handle, choices, &m_status);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void CvSource::SetEnumPropertyChoices(const VideoProperty& property,
|
||||
inline void ImageSource::SetEnumPropertyChoices(const VideoProperty& property,
|
||||
std::initializer_list<T> choices) {
|
||||
std::vector<std::string> vec;
|
||||
vec.reserve(choices.size());
|
||||
@@ -575,36 +560,17 @@ inline void MjpegServer::SetDefaultCompression(int quality) {
|
||||
quality, &m_status);
|
||||
}
|
||||
|
||||
inline CvSink::CvSink(const wpi::Twine& name) {
|
||||
m_handle = CreateCvSink(name, &m_status);
|
||||
}
|
||||
|
||||
inline CvSink::CvSink(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame) {
|
||||
m_handle = CreateCvSinkCallback(name, processFrame, &m_status);
|
||||
}
|
||||
|
||||
inline void CvSink::SetDescription(const wpi::Twine& description) {
|
||||
inline void ImageSink::SetDescription(const wpi::Twine& description) {
|
||||
m_status = 0;
|
||||
SetSinkDescription(m_handle, description, &m_status);
|
||||
}
|
||||
|
||||
inline uint64_t CvSink::GrabFrame(cv::Mat& image, double timeout) const {
|
||||
m_status = 0;
|
||||
return GrabSinkFrameTimeout(m_handle, image, timeout, &m_status);
|
||||
}
|
||||
|
||||
inline uint64_t CvSink::GrabFrameNoTimeout(cv::Mat& image) const {
|
||||
m_status = 0;
|
||||
return GrabSinkFrame(m_handle, image, &m_status);
|
||||
}
|
||||
|
||||
inline std::string CvSink::GetError() const {
|
||||
inline std::string ImageSink::GetError() const {
|
||||
m_status = 0;
|
||||
return GetSinkError(m_handle, &m_status);
|
||||
}
|
||||
|
||||
inline void CvSink::SetEnabled(bool enabled) {
|
||||
inline void ImageSink::SetEnabled(bool enabled) {
|
||||
m_status = 0;
|
||||
SetSinkEnabled(m_handle, enabled, &m_status);
|
||||
}
|
||||
|
||||
234
cscore/src/main/native/include/cscore_raw.h
Normal file
234
cscore/src/main/native/include/cscore_raw.h
Normal file
@@ -0,0 +1,234 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2019 FIRST. 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 CSCORE_CSCORE_RAW_H_
|
||||
#define CSCORE_CSCORE_RAW_H_
|
||||
|
||||
#include "cscore_c.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include "cscore_oo.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Raw Frame
|
||||
*/
|
||||
typedef struct CS_RawFrame {
|
||||
char* data;
|
||||
int dataLength;
|
||||
int pixelFormat;
|
||||
int width;
|
||||
int height;
|
||||
int totalData;
|
||||
} CS_RawFrame;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup cscore_raw_cfunc Raw Image Functions
|
||||
* @{
|
||||
*/
|
||||
void CS_AllocateRawFrameData(CS_RawFrame* frame, int requestedSize);
|
||||
void CS_FreeRawFrameData(CS_RawFrame* frame);
|
||||
|
||||
uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct CS_RawFrame* rawImage,
|
||||
CS_Status* status);
|
||||
uint64_t CS_GrabRawSinkFrameTimeout(CS_Sink sink, struct CS_RawFrame* rawImage,
|
||||
double timeout, CS_Status* status);
|
||||
|
||||
CS_Sink CS_CreateRawSink(const char* name, CS_Status* status);
|
||||
|
||||
CS_Sink CS_CreateRawSinkCallback(const char* name, void* data,
|
||||
void (*processFrame)(void* data,
|
||||
uint64_t time),
|
||||
CS_Status* status);
|
||||
|
||||
void CS_PutRawSourceFrame(CS_Source source, const struct CS_RawFrame* image,
|
||||
CS_Status* status);
|
||||
|
||||
CS_Source CS_CreateRawSource(const char* name, const CS_VideoMode* mode,
|
||||
CS_Status* status);
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace cs {
|
||||
|
||||
struct RawFrame : public CS_RawFrame {
|
||||
RawFrame() {
|
||||
data = nullptr;
|
||||
dataLength = 0;
|
||||
pixelFormat = CS_PIXFMT_UNKNOWN;
|
||||
width = 0;
|
||||
height = 0;
|
||||
totalData = 0;
|
||||
}
|
||||
|
||||
~RawFrame() { CS_FreeRawFrameData(this); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @defgroup cscore_raw_func Raw Image Functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
CS_Source CreateRawSource(const wpi::Twine& name, const VideoMode& mode,
|
||||
CS_Status* status);
|
||||
|
||||
CS_Sink CreateRawSink(const wpi::Twine& name, CS_Status* status);
|
||||
CS_Sink CreateRawSinkCallback(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame,
|
||||
CS_Status* status);
|
||||
|
||||
void PutSourceFrame(CS_Source source, const CS_RawFrame& image,
|
||||
CS_Status* status);
|
||||
uint64_t GrabSinkFrame(CS_Sink sink, CS_RawFrame& image, CS_Status* status);
|
||||
uint64_t GrabSinkFrameTimeout(CS_Sink sink, CS_RawFrame& image, double timeout,
|
||||
CS_Status* status);
|
||||
|
||||
/**
|
||||
* A source for user code to provide video frames as raw bytes.
|
||||
*
|
||||
* This is a complex API, most cases should use CvSource.
|
||||
*/
|
||||
class RawSource : public ImageSource {
|
||||
public:
|
||||
RawSource() = default;
|
||||
|
||||
/**
|
||||
* Create a raw frame source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param mode Video mode being generated
|
||||
*/
|
||||
RawSource(const wpi::Twine& name, const VideoMode& mode);
|
||||
|
||||
/**
|
||||
* Create a raw frame source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param pixelFormat Pixel format
|
||||
* @param width width
|
||||
* @param height height
|
||||
* @param fps fps
|
||||
*/
|
||||
RawSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
|
||||
int width, int height, int fps);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Put a raw image and notify sinks.
|
||||
*
|
||||
* @param image raw frame image
|
||||
*/
|
||||
void PutFrame(RawFrame& image);
|
||||
};
|
||||
|
||||
/**
|
||||
* A sink for user code to accept video frames as raw bytes.
|
||||
*
|
||||
* This is a complex API, most cases should use CvSource.
|
||||
*/
|
||||
class RawSink : public ImageSink {
|
||||
public:
|
||||
RawSink() = default;
|
||||
|
||||
/**
|
||||
* Create a sink for accepting raw images.
|
||||
*
|
||||
* <p>GrabFrame() must be called on the created sink to get each new
|
||||
* image.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
*/
|
||||
explicit RawSink(const wpi::Twine& name);
|
||||
|
||||
/**
|
||||
* Create a sink for accepting raws images in a separate thread.
|
||||
*
|
||||
* <p>A thread will be created that calls WaitForFrame() and calls the
|
||||
* processFrame() callback each time a new frame arrives.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param processFrame Frame processing function; will be called with a
|
||||
* time=0 if an error occurred. processFrame should call GetImage()
|
||||
* or GetError() as needed, but should not call (except in very
|
||||
* unusual circumstances) WaitForImage().
|
||||
*/
|
||||
RawSink(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after timeout seconds.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrame(RawFrame& image, double timeout = 0.225) const;
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. May block forever.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrameNoTimeout(RawFrame& image) const;
|
||||
};
|
||||
|
||||
inline RawSource::RawSource(const wpi::Twine& name, const VideoMode& mode) {
|
||||
m_handle = CreateRawSource(name, mode, &m_status);
|
||||
}
|
||||
|
||||
inline RawSource::RawSource(const wpi::Twine& name,
|
||||
VideoMode::PixelFormat format, int width,
|
||||
int height, int fps) {
|
||||
m_handle =
|
||||
CreateRawSource(name, VideoMode{format, width, height, fps}, &m_status);
|
||||
}
|
||||
|
||||
inline void RawSource::PutFrame(RawFrame& image) {
|
||||
m_status = 0;
|
||||
PutSourceFrame(m_handle, image, &m_status);
|
||||
}
|
||||
|
||||
inline RawSink::RawSink(const wpi::Twine& name) {
|
||||
m_handle = CreateRawSink(name, &m_status);
|
||||
}
|
||||
|
||||
inline RawSink::RawSink(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame) {
|
||||
m_handle = CreateRawSinkCallback(name, processFrame, &m_status);
|
||||
}
|
||||
|
||||
inline uint64_t RawSink::GrabFrame(RawFrame& image, double timeout) const {
|
||||
m_status = 0;
|
||||
return GrabSinkFrameTimeout(m_handle, image, timeout, &m_status);
|
||||
}
|
||||
|
||||
inline uint64_t RawSink::GrabFrameNoTimeout(RawFrame& image) const {
|
||||
m_status = 0;
|
||||
return GrabSinkFrame(m_handle, image, &m_status);
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CSCORE_CSCORE_RAW_H_
|
||||
218
cscore/src/main/native/include/cscore_raw_cv.h
Normal file
218
cscore/src/main/native/include/cscore_raw_cv.h
Normal file
@@ -0,0 +1,218 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2015-2019 FIRST. 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 CSCORE_CSCORE_RAW_CV_H_
|
||||
#define CSCORE_CSCORE_RAW_CV_H_
|
||||
|
||||
#ifdef CSCORE_CSCORE_CV_H_
|
||||
#error "Cannot include both cscore_cv.h and cscore_raw_cv.h in the same file"
|
||||
#endif
|
||||
|
||||
#include "cscore_raw.h"
|
||||
|
||||
namespace cs {
|
||||
/**
|
||||
* A source for using the raw frame API to provide opencv images.
|
||||
*
|
||||
* If you are using the WPILib OpenCV builds, do not use this, and
|
||||
* instead include "cscore_cv.h" to get a more performant version.
|
||||
*
|
||||
* This is not dependent on any opencv binary ABI, and can be used
|
||||
* with versions of OpenCV that are not 3. If using OpenCV 3, use
|
||||
* CvSource.
|
||||
*/
|
||||
class RawCvSource : public RawSource {
|
||||
public:
|
||||
RawCvSource() = default;
|
||||
|
||||
/**
|
||||
* Create a Raw OpenCV source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param mode Video mode being generated
|
||||
*/
|
||||
RawCvSource(const wpi::Twine& name, const VideoMode& mode);
|
||||
|
||||
/**
|
||||
* Create a Raw OpenCV source.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param pixelFormat Pixel format
|
||||
* @param width width
|
||||
* @param height height
|
||||
* @param fps fps
|
||||
*/
|
||||
RawCvSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
|
||||
int width, int height, int fps);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param image OpenCV image
|
||||
*/
|
||||
void PutFrame(cv::Mat& image);
|
||||
|
||||
private:
|
||||
RawFrame rawFrame;
|
||||
};
|
||||
|
||||
/**
|
||||
* A sink for user code to accept raw video frames as OpenCV images.
|
||||
*
|
||||
* If you are using the WPILib OpenCV builds, do not use this, and
|
||||
* instead include "cscore_cv.h" to get a more performant version.
|
||||
*
|
||||
* This is not dependent on any opencv binary ABI, and can be used
|
||||
* with versions of OpenCV that are not 3. If using OpenCV 3, use
|
||||
* CvSink.
|
||||
*/
|
||||
class RawCvSink : public RawSink {
|
||||
public:
|
||||
RawCvSink() = default;
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images.
|
||||
*
|
||||
* <p>WaitForFrame() must be called on the created sink to get each new
|
||||
* image.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
*/
|
||||
explicit RawCvSink(const wpi::Twine& name);
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images in a separate thread.
|
||||
*
|
||||
* <p>A thread will be created that calls WaitForFrame() and calls the
|
||||
* processFrame() callback each time a new frame arrives.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param processFrame Frame processing function; will be called with a
|
||||
* time=0 if an error occurred. processFrame should call GetImage()
|
||||
* or GetError() as needed, but should not call (except in very
|
||||
* unusual circumstances) WaitForImage().
|
||||
*/
|
||||
RawCvSink(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame);
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after timeout seconds.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrame(cv::Mat& image, double timeout = 0.225);
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. May block forever.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrameNoTimeout(cv::Mat& image);
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image.
|
||||
* Times out (returning 0) after timeout seconds.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrameDirect(cv::Mat& image, double timeout = 0.225);
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. May block forever.
|
||||
* The provided image will have three 8-bit channels stored in BGR order.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in the same time base as wpi::Now(),
|
||||
* and is in 1 us increments.
|
||||
*/
|
||||
uint64_t GrabFrameNoTimeoutDirect(cv::Mat& image);
|
||||
|
||||
private:
|
||||
RawFrame rawFrame;
|
||||
};
|
||||
|
||||
inline RawCvSource::RawCvSource(const wpi::Twine& name, const VideoMode& mode)
|
||||
: RawSource{name, mode} {}
|
||||
|
||||
inline RawCvSource::RawCvSource(const wpi::Twine& name,
|
||||
VideoMode::PixelFormat format, int width,
|
||||
int height, int fps)
|
||||
: RawSource{name, format, width, height, fps} {}
|
||||
|
||||
inline void RawCvSource::PutFrame(cv::Mat& image) {
|
||||
m_status = 0;
|
||||
rawFrame.data = reinterpret_cast<char*>(image.data);
|
||||
rawFrame.width = image.cols;
|
||||
rawFrame.height = image.rows;
|
||||
rawFrame.totalData = image.total() * image.channels;
|
||||
rawFrame.pixelFormat = image.channels == 3 ? CS_PIXFMT_BGR : CS_PIXFMT_GRAY;
|
||||
PutSourceFrame(m_handle, rawFrame, &m_status);
|
||||
}
|
||||
|
||||
inline RawCvSink::RawCvSink(const wpi::Twine& name) : RawSink{name} {}
|
||||
|
||||
inline RawCvSink::RawCvSink(const wpi::Twine& name,
|
||||
std::function<void(uint64_t time)> processFrame)
|
||||
: RawSink{name, processFrame} {}
|
||||
|
||||
inline uint64_t RawCvSink::GrabFrame(cv::Mat& image, double timeout) {
|
||||
cv::Mat tmpMat;
|
||||
auto retVal = GrabFrameDirect(tmpMat);
|
||||
if (retVal <= 0) {
|
||||
return retVal;
|
||||
}
|
||||
tmpMat.copyTo(image);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
inline uint64_t RawCvSink::GrabFrameNoTimeout(cv::Mat& image) {
|
||||
cv::Mat tmpMat;
|
||||
auto retVal = GrabFrameNoTimeoutDirect(tmpMat);
|
||||
if (retVal <= 0) {
|
||||
return retVal;
|
||||
}
|
||||
tmpMat.copyTo(image);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
inline uint64_t RawCvSink::GrabFrameDirect(cv::Mat& image, double timeout) {
|
||||
rawFrame.height = 0;
|
||||
rawFrame.width = 0;
|
||||
rawFrame.pixelFormat = CS_PixelFormat::CS_PIXFMT_BGR;
|
||||
m_status = RawSink::GrabFrame(rawFrame, timeout);
|
||||
if (m_status <= 0) return m_status;
|
||||
image = cv::Mat{rawFrame.height, rawFrame.width, CV_8UC3, rawFrame.data};
|
||||
return m_status;
|
||||
}
|
||||
|
||||
inline uint64_t RawCvSink::GrabFrameNoTimeoutDirect(cv::Mat& image) {
|
||||
rawFrame.height = 0;
|
||||
rawFrame.width = 0;
|
||||
rawFrame.pixelFormat = CS_PixelFormat::CS_PIXFMT_BGR;
|
||||
m_status = RawSink::GrabFrameNoTimeout(rawFrame);
|
||||
if (m_status <= 0) return m_status;
|
||||
image = cv::Mat{rawFrame.height, rawFrame.width, CV_8UC3, rawFrame.data};
|
||||
return m_status;
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CSCORE_CSCORE_RAW_CV_H_
|
||||
Reference in New Issue
Block a user