diff --git a/wpilibc/athena/include/CameraServer.h b/wpilibc/athena/include/CameraServer.h index 317000e388..5dde767ebe 100644 --- a/wpilibc/athena/include/CameraServer.h +++ b/wpilibc/athena/include/CameraServer.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include @@ -44,8 +45,10 @@ class CameraServer : public ErrorBase { * If you also want to perform vision processing on the roboRIO, use * getVideo() to get access to the camera images. * - * This overload calls {@link #StartAutomaticCapture(int)} with device 0, - * creating a camera named "USB Camera 0". + * The first time this overload is called, it calls + * {@link #StartAutomaticCapture(int)} with device 0, creating a camera + * named "USB Camera 0". Subsequent calls increment the device number + * (e.g. 1, 2, etc). */ cs::UsbCamera StartAutomaticCapture(); @@ -241,6 +244,21 @@ class CameraServer : public ErrorBase { */ void RemoveServer(llvm::StringRef name); + /** + * Get server for the primary camera feed. + * + *

This is only valid to call after a camera feed has been added + * with StartAutomaticCapture() or AddServer(). + */ + cs::VideoSink GetServer(); + + /** + * Gets a server by name. + * + * @param name Server name + */ + cs::VideoSink GetServer(llvm::StringRef name); + /** * Adds an already created camera. * @@ -277,6 +295,7 @@ class CameraServer : public ErrorBase { static constexpr char const* kPublishName = "/CameraPublisher"; std::mutex m_mutex; + std::atomic m_defaultUsbDevice; std::string m_primarySourceName; llvm::StringMap m_sources; llvm::StringMap m_sinks; diff --git a/wpilibc/athena/src/CameraServer.cpp b/wpilibc/athena/src/CameraServer.cpp index 6abe89eafc..84921339a6 100644 --- a/wpilibc/athena/src/CameraServer.cpp +++ b/wpilibc/athena/src/CameraServer.cpp @@ -486,7 +486,7 @@ CameraServer::CameraServer() } cs::UsbCamera CameraServer::StartAutomaticCapture() { - return StartAutomaticCapture(0); + return StartAutomaticCapture(m_defaultUsbDevice++); } cs::UsbCamera CameraServer::StartAutomaticCapture(int dev) { @@ -659,6 +659,33 @@ void CameraServer::RemoveServer(llvm::StringRef name) { m_sinks.erase(name); } +cs::VideoSink CameraServer::GetServer() { + llvm::SmallString<64> name; + { + std::lock_guard lock(m_mutex); + if (m_primarySourceName.empty()) { + wpi_setWPIErrorWithContext(CameraServerError, "no camera available"); + return cs::VideoSink{}; + } + name = "serve_"; + name += m_primarySourceName; + } + return GetServer(name); +} + +cs::VideoSink CameraServer::GetServer(llvm::StringRef name) { + std::lock_guard lock(m_mutex); + auto it = m_sinks.find(name); + if (it == m_sinks.end()) { + llvm::SmallString<64> buf; + llvm::raw_svector_ostream err{buf}; + err << "could not find server " << name; + wpi_setWPIErrorWithContext(CameraServerError, err.str()); + return cs::VideoSink{}; + } + return it->second; +} + void CameraServer::AddCamera(const cs::VideoSource& camera) { std::string name = camera.GetName(); std::lock_guard lock(m_mutex); diff --git a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/CameraServer.java b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/CameraServer.java index 3dcb81c2ca..bb0be39c60 100644 --- a/wpilibj/src/athena/java/edu/wpi/first/wpilibj/CameraServer.java +++ b/wpilibj/src/athena/java/edu/wpi/first/wpilibj/CameraServer.java @@ -24,6 +24,7 @@ import edu.wpi.cscore.VideoSource; import edu.wpi.first.wpilibj.networktables.NetworkTable; import edu.wpi.first.wpilibj.networktables.NetworkTablesJNI; import edu.wpi.first.wpilibj.tables.ITable; +import java.util.concurrent.atomic.AtomicInteger; import java.util.ArrayList; import java.util.Hashtable; import java.util.regex.Matcher; @@ -56,6 +57,7 @@ public class CameraServer { return server; } + private AtomicInteger m_defaultUsbDevice; private String m_primarySourceName; private final Hashtable m_sources; private final Hashtable m_sinks; @@ -330,6 +332,7 @@ public class CameraServer { @SuppressWarnings({"JavadocMethod", "PMD.UnusedLocalVariable"}) private CameraServer() { + m_defaultUsbDevice = new AtomicInteger(); m_sources = new Hashtable(); m_sinks = new Hashtable(); m_tables = new Hashtable(); @@ -513,11 +516,13 @@ public class CameraServer { * If you also want to perform vision processing on the roboRIO, use * getVideo() to get access to the camera images. * - *

This overload calls {@link #startAutomaticCapture(int)} with device 0, - * creating a camera named "USB Camera 0". + *

The first time this overload is called, it calls + * {@link #startAutomaticCapture(int)} with device 0, creating a camera + * named "USB Camera 0". Subsequent calls increment the device number + * (e.g. 1, 2, etc). */ public UsbCamera startAutomaticCapture() { - return startAutomaticCapture(0); + return startAutomaticCapture(m_defaultUsbDevice.getAndIncrement()); } /** @@ -745,6 +750,32 @@ public class CameraServer { } } + /** + * Get server for the primary camera feed. + * + *

This is only valid to call after a camera feed has been added + * with startAutomaticCapture() or addServer(). + */ + public VideoSink getServer() { + synchronized (this) { + if (m_primarySourceName == null) { + throw new VideoException("no camera available"); + } + return getServer("serve_" + m_primarySourceName); + } + } + + /** + * Gets a server by name. + * + * @param name Server name + */ + public VideoSink getServer(String name) { + synchronized (this) { + return m_sinks.get(name); + } + } + /** * Adds an already created camera. *