diff --git a/include/cscore_c.h b/include/cscore_c.h index aadb2b642a..4169c9bed4 100644 --- a/include/cscore_c.h +++ b/include/cscore_c.h @@ -85,6 +85,25 @@ enum CS_PropertyType { CS_PROP_ENUM = 8 }; +// +// Source types +// +enum CS_SourceType { + CS_SOURCE_UNKNOWN = 0, + CS_SOURCE_USB = 1, + CS_SOURCE_HTTP = 2, + CS_SOURCE_CV = 4 +}; + +// +// Sink types +// +enum CS_SinkType { + CS_SINK_UNKNOWN = 0, + CS_SINK_MJPEG = 2, + CS_SINK_CV = 4 +}; + // // Listener event types // @@ -160,6 +179,7 @@ CS_Source CS_CreateCvSource(const char* name, const CS_VideoMode* mode, // // Source Functions // +CS_SourceType CS_GetSourceType(CS_Source source, CS_Status* status); char* CS_GetSourceName(CS_Source source, CS_Status* status); char* CS_GetSourceDescription(CS_Source source, CS_Status* status); uint64_t CS_GetSourceLastFrameTime(CS_Source source, CS_Status* status); @@ -184,6 +204,8 @@ CS_Bool CS_SetSourceResolution(CS_Source source, int width, int height, CS_Bool CS_SetSourceFPS(CS_Source source, int fps, CS_Status* status); CS_VideoMode* CS_EnumerateSourceVideoModes(CS_Source source, int* count, CS_Status* status); +CS_Sink* CS_EnumerateSourceSinks(CS_Source source, int* count, + CS_Status* status); CS_Source CS_CopySource(CS_Source source, CS_Status* status); void CS_ReleaseSource(CS_Source source, CS_Status* status); @@ -218,6 +240,7 @@ CS_Sink CS_CreateCvSinkCallback(const char* name, void* data, // // Sink Functions // +CS_SinkType CS_GetSinkType(CS_Sink sink, CS_Status* status); char* CS_GetSinkName(CS_Sink sink, CS_Status* status); char* CS_GetSinkDescription(CS_Sink sink, CS_Status* status); void CS_SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status); diff --git a/include/cscore_cpp.h b/include/cscore_cpp.h index 5d7f18d078..ded67268c9 100644 --- a/include/cscore_cpp.h +++ b/include/cscore_cpp.h @@ -165,6 +165,7 @@ CS_Source CreateCvSource(llvm::StringRef name, const VideoMode& mode, // // Source Functions // +CS_SourceType GetSourceType(CS_Source source, CS_Status* status); std::string GetSourceName(CS_Source source, CS_Status* status); llvm::StringRef GetSourceName(CS_Source source, llvm::SmallVectorImpl& buf, @@ -190,6 +191,8 @@ bool SetSourceResolution(CS_Source source, int width, int height, bool SetSourceFPS(CS_Source source, int fps, CS_Status* status); std::vector EnumerateSourceVideoModes(CS_Source source, CS_Status* status); +llvm::ArrayRef EnumerateSourceSinks( + CS_Source source, llvm::SmallVectorImpl& vec, CS_Status* status); CS_Source CopySource(CS_Source source, CS_Status* status); void ReleaseSource(CS_Source source, CS_Status* status); @@ -223,6 +226,7 @@ CS_Sink CreateCvSinkCallback(llvm::StringRef name, // // Sink Functions // +CS_SinkType GetSinkType(CS_Sink sink, CS_Status* status); std::string GetSinkName(CS_Sink sink, CS_Status* status); llvm::StringRef GetSinkName(CS_Sink sink, llvm::SmallVectorImpl& buf, CS_Status* status); diff --git a/include/cscore_oo.h b/include/cscore_oo.h index a526e3833b..9109c52b32 100644 --- a/include/cscore_oo.h +++ b/include/cscore_oo.h @@ -83,6 +83,13 @@ class VideoSource { friend class VideoSink; public: + enum Type { + kUnknown = CS_SOURCE_UNKNOWN, + kUSB = CS_SOURCE_USB, + kHTTP = CS_SOURCE_HTTP, + kCv = CS_SOURCE_CV + }; + VideoSource() noexcept : m_handle(0) {} VideoSource(const VideoSource& source); VideoSource(VideoSource&& other) noexcept; @@ -99,6 +106,9 @@ class VideoSource { bool operator!=(const VideoSource& other) const { return !(*this == other); } + /// Get the type of the source. + Type GetType() const; + /// Get the name of the source. The name is an arbitrary identifier /// provided when the source is created, and should be unique. std::string GetName() const; @@ -158,6 +168,10 @@ class VideoSource { CS_Status GetLastStatus() const { return m_status; } + /// Enumerate all sinks connected to this source. + /// @return Vector of sinks. + std::vector EnumerateSinks(); + /// Enumerate all existing sources. /// @return Vector of sources. static std::vector EnumerateSources(); @@ -260,8 +274,15 @@ class CvSource : public VideoSource { /// A sink for video that accepts a sequence of frames. class VideoSink { friend class VideoEvent; + friend class VideoSource; public: + enum Type { + kUnknown = CS_SINK_UNKNOWN, + kMJPEG = CS_SINK_MJPEG, + kCv = CS_SINK_CV + }; + VideoSink() noexcept : m_handle(0) {} VideoSink(const VideoSink& sink); VideoSink(VideoSink&& sink) noexcept; @@ -278,6 +299,9 @@ class VideoSink { bool operator!=(const VideoSink& other) const { return !(*this == other); } + /// Get the type of the sink. + Type GetType() const; + /// Get the name of the sink. The name is an arbitrary identifier /// provided when the sink is created, and should be unique. std::string GetName() const; diff --git a/include/cscore_oo.inl b/include/cscore_oo.inl index 9d448e9100..b3c52e125a 100644 --- a/include/cscore_oo.inl +++ b/include/cscore_oo.inl @@ -93,6 +93,11 @@ inline VideoSource::~VideoSource() { if (m_handle != 0) ReleaseSource(m_handle, &m_status); } +inline VideoSource::Type VideoSource::GetType() const { + m_status = 0; + return static_cast(GetSourceType(m_handle, &m_status)); +} + inline std::string VideoSource::GetName() const { m_status = 0; return GetSourceName(m_handle, &m_status); @@ -236,6 +241,11 @@ inline VideoSink::~VideoSink() { if (m_handle != 0) ReleaseSink(m_handle, &m_status); } +inline VideoSink::Type VideoSink::GetType() const { + m_status = 0; + return static_cast(GetSinkType(m_handle, &m_status)); +} + inline std::string VideoSink::GetName() const { m_status = 0; return GetSinkName(m_handle, &m_status); diff --git a/java/lib/CameraServerJNI.cpp b/java/lib/CameraServerJNI.cpp index 01951488b6..e9065ef906 100644 --- a/java/lib/CameraServerJNI.cpp +++ b/java/lib/CameraServerJNI.cpp @@ -398,6 +398,20 @@ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_createCvSource return val; } +/* + * Class: edu_wpi_cscore_CameraServerJNI + * Method: getSourceType + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSourceType + (JNIEnv *env, jclass, jint source) +{ + CS_Status status = 0; + auto val = cs::GetSourceType(source, &status); + CheckStatus(env, status); + return val; +} + /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSourceName @@ -582,6 +596,21 @@ JNIEXPORT jobjectArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_enumerateSour return jarr; } +/* + * Class: edu_wpi_cscore_CameraServerJNI + * Method: enumerateSourceSinks + * Signature: (I)[I + */ +JNIEXPORT jintArray JNICALL Java_edu_wpi_cscore_CameraServerJNI_enumerateSourceSinks + (JNIEnv *env, jclass, jint source) +{ + CS_Status status = 0; + llvm::SmallVector buf; + auto arr = cs::EnumerateSourceSinks(source, buf, &status); + if (!CheckStatus(env, status)) return nullptr; + return MakeJIntArray(env, arr); +} + /* * Class: edu_wpi_cscore_CameraServerJNI * Method: copySource @@ -732,6 +761,20 @@ JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_createCvSink return val; } +/* + * Class: edu_wpi_cscore_CameraServerJNI + * Method: getSinkType + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_edu_wpi_cscore_CameraServerJNI_getSinkType + (JNIEnv *env, jclass, jint sink) +{ + CS_Status status = 0; + auto val = cs::GetSinkType(sink, &status); + CheckStatus(env, status); + return val; +} + /* * Class: edu_wpi_cscore_CameraServerJNI * Method: getSinkName diff --git a/java/src/edu/wpi/cscore/CameraServerJNI.java b/java/src/edu/wpi/cscore/CameraServerJNI.java index 26cce88f8c..1a717506f2 100644 --- a/java/src/edu/wpi/cscore/CameraServerJNI.java +++ b/java/src/edu/wpi/cscore/CameraServerJNI.java @@ -110,6 +110,7 @@ public class CameraServerJNI { // // Source Functions // + public static native int getSourceType(int source); public static native String getSourceName(int source); public static native String getSourceDescription(int source); public static native long getSourceLastFrameTime(int source); @@ -122,6 +123,7 @@ public class CameraServerJNI { public static native boolean setSourceResolution(int source, int width, int height); public static native boolean setSourceFPS(int source, int fps); public static native VideoMode[] enumerateSourceVideoModes(int source); + public static native int[] enumerateSourceSinks(int source); public static native int copySource(int source); public static native void releaseSource(int source); @@ -146,6 +148,7 @@ public class CameraServerJNI { // // Sink Functions // + public static native int getSinkType(int sink); public static native String getSinkName(int sink); public static native String getSinkDescription(int sink); public static native void setSinkSource(int sink, int source); diff --git a/java/src/edu/wpi/cscore/VideoSink.java b/java/src/edu/wpi/cscore/VideoSink.java index e7f001c59d..e9d3c698d3 100644 --- a/java/src/edu/wpi/cscore/VideoSink.java +++ b/java/src/edu/wpi/cscore/VideoSink.java @@ -11,6 +11,20 @@ package edu.wpi.cscore; /// consist of multiple images (e.g. from a stereo or depth camera); these /// are called channels. public class VideoSink { + public enum Type { + kUnknown(0), kMJPEG(2), kCv(4); + private int value; + + private Type(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + static final Type[] m_typeValues = Type.values(); + protected VideoSink(int handle) { m_handle = handle; } @@ -42,6 +56,11 @@ public class VideoSink { return m_handle; } + /// Get the type of the sink. + public Type getType() { + return m_typeValues[CameraServerJNI.getSinkType(m_handle)]; + } + /// Get the name of the sink. The name is an arbitrary identifier /// provided when the sink is created, and should be unique. public String getName() { diff --git a/java/src/edu/wpi/cscore/VideoSource.java b/java/src/edu/wpi/cscore/VideoSource.java index e7210b2ab1..9bcb166f83 100644 --- a/java/src/edu/wpi/cscore/VideoSource.java +++ b/java/src/edu/wpi/cscore/VideoSource.java @@ -11,6 +11,20 @@ package edu.wpi.cscore; /// consist of multiple images (e.g. from a stereo or depth camera); these /// are called channels. public class VideoSource { + public enum Type { + kUnknown(0), kUSB(1), kHTTP(2), kCv(4); + private int value; + + private Type(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + static final Type[] m_typeValues = Type.values(); + protected VideoSource(int handle) { m_handle = handle; } @@ -42,6 +56,11 @@ public class VideoSource { return m_handle; } + /// Get the type of the source. + public Type getType() { + return m_typeValues[CameraServerJNI.getSourceType(m_handle)]; + } + /// Get the name of the source. The name is an arbitrary identifier /// provided when the source is created, and should be unique. public String getName() { @@ -129,6 +148,17 @@ public class VideoSource { return CameraServerJNI.enumerateSourceVideoModes(m_handle); } + /// Enumerate all sinks connected to this source. + /// @return Vector of sinks. + public VideoSink[] enumerateSinks() { + int[] handles = CameraServerJNI.enumerateSourceSinks(m_handle); + VideoSink[] rv = new VideoSink[handles.length]; + for (int i=0; i(name); - return Sinks::GetInstance().Allocate(SinkData::kCv, sink); + return Sinks::GetInstance().Allocate(CS_SINK_CV, sink); } CS_Sink CreateCvSinkCallback(llvm::StringRef name, std::function processFrame, CS_Status* status) { auto sink = std::make_shared(name, processFrame); - return Sinks::GetInstance().Allocate(SinkData::kCv, sink); + return Sinks::GetInstance().Allocate(CS_SINK_CV, sink); } void SetSinkDescription(CS_Sink sink, llvm::StringRef description, CS_Status* status) { auto data = Sinks::GetInstance().Get(sink); - if (!data || data->type != SinkData::kCv) { + if (!data || data->type != CS_SINK_CV) { *status = CS_INVALID_HANDLE; return; } @@ -119,7 +119,7 @@ void SetSinkDescription(CS_Sink sink, llvm::StringRef description, uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status) { auto data = Sinks::GetInstance().Get(sink); - if (!data || data->type != SinkData::kCv) { + if (!data || data->type != CS_SINK_CV) { *status = CS_INVALID_HANDLE; return 0; } @@ -128,7 +128,7 @@ uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status) { std::string GetSinkError(CS_Sink sink, CS_Status* status) { auto data = Sinks::GetInstance().Get(sink); - if (!data || data->type != SinkData::kCv) { + if (!data || data->type != CS_SINK_CV) { *status = CS_INVALID_HANDLE; return std::string{}; } @@ -138,7 +138,7 @@ std::string GetSinkError(CS_Sink sink, CS_Status* status) { llvm::StringRef GetSinkError(CS_Sink sink, llvm::SmallVectorImpl& buf, CS_Status* status) { auto data = Sinks::GetInstance().Get(sink); - if (!data || data->type != SinkData::kCv) { + if (!data || data->type != CS_SINK_CV) { *status = CS_INVALID_HANDLE; return llvm::StringRef{}; } @@ -147,7 +147,7 @@ llvm::StringRef GetSinkError(CS_Sink sink, llvm::SmallVectorImpl& buf, void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) { auto data = Sinks::GetInstance().Get(sink); - if (!data || data->type != SinkData::kCv) { + if (!data || data->type != CS_SINK_CV) { *status = CS_INVALID_HANDLE; return; } diff --git a/src/CvSourceImpl.cpp b/src/CvSourceImpl.cpp index 80b4577f08..5832ceae06 100644 --- a/src/CvSourceImpl.cpp +++ b/src/CvSourceImpl.cpp @@ -157,12 +157,12 @@ namespace cs { CS_Source CreateCvSource(llvm::StringRef name, const VideoMode& mode, CS_Status* status) { auto source = std::make_shared(name, mode); - return Sources::GetInstance().Allocate(SourceData::kCv, source); + return Sources::GetInstance().Allocate(CS_SOURCE_CV, source); } void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status) { auto data = Sources::GetInstance().Get(source); - if (!data || data->type != SourceData::kCv) { + if (!data || data->type != CS_SOURCE_CV) { *status = CS_INVALID_HANDLE; return; } @@ -172,7 +172,7 @@ void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status) { void NotifySourceError(CS_Source source, llvm::StringRef msg, CS_Status* status) { auto data = Sources::GetInstance().Get(source); - if (!data || data->type != SourceData::kCv) { + if (!data || data->type != CS_SOURCE_CV) { *status = CS_INVALID_HANDLE; return; } @@ -181,7 +181,7 @@ void NotifySourceError(CS_Source source, llvm::StringRef msg, void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) { auto data = Sources::GetInstance().Get(source); - if (!data || data->type != SourceData::kCv) { + if (!data || data->type != CS_SOURCE_CV) { *status = CS_INVALID_HANDLE; return; } @@ -191,7 +191,7 @@ void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) { void SetSourceDescription(CS_Source source, llvm::StringRef description, CS_Status* status) { auto data = Sources::GetInstance().Get(source); - if (!data || data->type != SourceData::kCv) { + if (!data || data->type != CS_SOURCE_CV) { *status = CS_INVALID_HANDLE; return; } @@ -203,7 +203,7 @@ CS_Property CreateSourceProperty(CS_Source source, llvm::StringRef name, int step, int defaultValue, int value, CS_Status* status) { auto data = Sources::GetInstance().Get(source); - if (!data || data->type != SourceData::kCv) { + if (!data || data->type != CS_SOURCE_CV) { *status = CS_INVALID_HANDLE; return -1; } @@ -216,7 +216,7 @@ CS_Property CreateSourcePropertyCallback( int maximum, int step, int defaultValue, int value, std::function onChange, CS_Status* status) { auto data = Sources::GetInstance().Get(source); - if (!data || data->type != SourceData::kCv) { + if (!data || data->type != CS_SOURCE_CV) { *status = CS_INVALID_HANDLE; return -1; } @@ -229,7 +229,7 @@ void SetSourceEnumPropertyChoices(CS_Source source, CS_Property property, llvm::ArrayRef choices, CS_Status* status) { auto data = Sources::GetInstance().Get(source); - if (!data || data->type != SourceData::kCv) { + if (!data || data->type != CS_SOURCE_CV) { *status = CS_INVALID_HANDLE; return; } diff --git a/src/Handle.h b/src/Handle.h index d34d975f36..fe50b8af2b 100644 --- a/src/Handle.h +++ b/src/Handle.h @@ -71,16 +71,10 @@ class Handle { }; struct SourceData { - enum Type { - kUnknown = 0, - kUSB, - kHTTP, - kCv - }; - SourceData(Type type_, std::shared_ptr source_) + SourceData(CS_SourceType type_, std::shared_ptr source_) : type{type_}, refCount{0}, source{source_} {} - Type type; + CS_SourceType type; std::atomic_int refCount; std::shared_ptr source; }; @@ -89,15 +83,10 @@ typedef StaticUnlimitedHandleResource Sources; struct SinkData { - enum Type { - kUnknown = 0, - kHTTP, - kCv - }; - explicit SinkData(Type type_, std::shared_ptr sink_) + explicit SinkData(CS_SinkType type_, std::shared_ptr sink_) : type{type_}, refCount{0}, sourceHandle{0}, sink{sink_} {} - Type type; + CS_SinkType type; std::atomic_int refCount; std::atomic sourceHandle; std::shared_ptr sink; diff --git a/src/MJPEGServerImpl.cpp b/src/MJPEGServerImpl.cpp index c75f0d5b4b..426d45b5a2 100644 --- a/src/MJPEGServerImpl.cpp +++ b/src/MJPEGServerImpl.cpp @@ -696,7 +696,7 @@ CS_Sink CreateMJPEGServer(llvm::StringRef name, llvm::StringRef listenAddress, name, desc.str(), std::unique_ptr( new wpi::TCPAcceptor(port, str.c_str(), Logger::GetInstance()))); - return Sinks::GetInstance().Allocate(SinkData::kHTTP, sink); + return Sinks::GetInstance().Allocate(CS_SINK_MJPEG, sink); } } // namespace cs diff --git a/src/USBCameraImpl.cpp b/src/USBCameraImpl.cpp index 17ba0e750b..63f76f3a29 100644 --- a/src/USBCameraImpl.cpp +++ b/src/USBCameraImpl.cpp @@ -1360,7 +1360,7 @@ CS_Source CreateUSBCameraDev(llvm::StringRef name, int dev, CS_Status* status) { CS_Source CreateUSBCameraPath(llvm::StringRef name, llvm::StringRef path, CS_Status* status) { auto source = std::make_shared(name, path); - return Sources::GetInstance().Allocate(SourceData::kUSB, source); + return Sources::GetInstance().Allocate(CS_SOURCE_USB, source); } std::vector EnumerateUSBCameras(CS_Status* status) { diff --git a/src/UnlimitedHandleResource.h b/src/UnlimitedHandleResource.h index f2807e1364..90cf35aa2c 100644 --- a/src/UnlimitedHandleResource.h +++ b/src/UnlimitedHandleResource.h @@ -55,6 +55,10 @@ class UnlimitedHandleResource { template llvm::ArrayRef GetAll(llvm::SmallVectorImpl& vec); + // @param func functor with (THandle, const TStruct&) parameters + template + void ForEach(F func); + private: THandle MakeHandle(size_t i) { return THandle{static_cast(i), @@ -128,12 +132,19 @@ template llvm::ArrayRef UnlimitedHandleResource::GetAll( llvm::SmallVectorImpl& vec) { + ForEach([&](THandle handle, const TStruct& data) { vec.push_back(handle); }); + return vec; +} + +template +template +void UnlimitedHandleResource::ForEach( + F func) { std::lock_guard sync(m_handleMutex); size_t i; for (i = 0; i < m_structures.size(); i++) { - if (m_structures[i] != nullptr) vec.push_back(MakeHandle(i)); + if (m_structures[i] != nullptr) func(MakeHandle(i), *(m_structures[i])); } - return vec; } template buf; auto str = cs::GetSourceName(source, buf, status); @@ -168,6 +172,17 @@ CS_VideoMode* CS_EnumerateSourceVideoModes(CS_Source source, int* count, return out; } +CS_Sink* CS_EnumerateSourceSinks(CS_Source source, int* count, + CS_Status* status) { + llvm::SmallVector buf; + auto handles = cs::EnumerateSourceSinks(source, buf, status); + CS_Sink* sinks = + static_cast(std::malloc(handles.size() * sizeof(CS_Sink))); + *count = handles.size(); + std::copy(handles.begin(), handles.end(), sinks); + return sinks; +} + CS_Source CS_CopySource(CS_Source source, CS_Status* status) { return cs::CopySource(source, status); } @@ -176,6 +191,10 @@ void CS_ReleaseSource(CS_Source source, CS_Status* status) { return cs::ReleaseSource(source, status); } +CS_SinkType CS_GetSinkType(CS_Sink sink, CS_Status* status) { + return cs::GetSinkType(sink, status); +} + char* CS_GetSinkName(CS_Sink sink, CS_Status* status) { llvm::SmallString<128> buf; auto str = cs::GetSinkName(sink, buf, status); diff --git a/src/cscore_cpp.cpp b/src/cscore_cpp.cpp index d889fd3029..754fff8de8 100644 --- a/src/cscore_cpp.cpp +++ b/src/cscore_cpp.cpp @@ -152,6 +152,15 @@ CS_Source CreateHTTPCamera(llvm::StringRef name, llvm::StringRef url, // Source Functions // +CS_SourceType GetSourceType(CS_Source source, CS_Status* status) { + auto data = Sources::GetInstance().Get(source); + if (!data) { + *status = CS_INVALID_HANDLE; + return CS_SOURCE_UNKNOWN; + } + return data->type; +} + std::string GetSourceName(CS_Source source, CS_Status* status) { auto data = Sources::GetInstance().Get(source); if (!data) { @@ -299,6 +308,20 @@ std::vector EnumerateSourceVideoModes(CS_Source source, return data->source->EnumerateVideoModes(status); } +llvm::ArrayRef EnumerateSourceSinks( + CS_Source source, llvm::SmallVectorImpl& vec, CS_Status* status) { + auto data = Sources::GetInstance().Get(source); + if (!data) { + *status = CS_INVALID_HANDLE; + return llvm::ArrayRef{}; + } + vec.clear(); + Sinks::GetInstance().ForEach([&](CS_Sink sinkHandle, const SinkData& data) { + if (source == data.sourceHandle.load()) vec.push_back(sinkHandle); + }); + return vec; +} + CS_Source CopySource(CS_Source source, CS_Status* status) { if (source == 0) return 0; auto data = Sources::GetInstance().Get(source); @@ -325,6 +348,15 @@ void ReleaseSource(CS_Source source, CS_Status* status) { // Sink Functions // +CS_SinkType GetSinkType(CS_Sink sink, CS_Status* status) { + auto data = Sinks::GetInstance().Get(sink); + if (!data) { + *status = CS_INVALID_HANDLE; + return CS_SINK_UNKNOWN; + } + return data->type; +} + std::string GetSinkName(CS_Sink sink, CS_Status* status) { auto data = Sinks::GetInstance().Get(sink); if (!data) { diff --git a/src/cscore_oo.cpp b/src/cscore_oo.cpp index 4aac76ccf1..655f81c2e9 100644 --- a/src/cscore_oo.cpp +++ b/src/cscore_oo.cpp @@ -21,6 +21,18 @@ std::vector VideoSource::EnumerateProperties() const { return properties; } +std::vector VideoSource::EnumerateSinks() { + llvm::SmallVector handles_buf; + CS_Status status = 0; + auto handles = EnumerateSourceSinks(m_handle, handles_buf, &status); + + std::vector sinks; + sinks.reserve(handles.size()); + for (int handle : handles) + sinks.emplace_back(VideoSink{handle}); + return sinks; +} + std::vector VideoSource::EnumerateSources() { llvm::SmallVector handles_buf; CS_Status status = 0;