mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-29 02:21:44 +00:00
Start implementation.
This commit is contained in:
14
src/Frame.cpp
Normal file
14
src/Frame.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "Frame.h"
|
||||
|
||||
#include "SourceImpl.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
void Frame::ReleaseFrame() { m_source->ReleaseFrame(m_data); }
|
||||
83
src/Frame.h
Normal file
83
src/Frame.h
Normal file
@@ -0,0 +1,83 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CAMERASERVER_FRAME_H_
|
||||
#define CAMERASERVER_FRAME_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
|
||||
#include "llvm/SmallVector.h"
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class SourceImpl;
|
||||
|
||||
class Frame {
|
||||
friend class SourceImpl;
|
||||
|
||||
struct Data {
|
||||
std::atomic_int refcount{0};
|
||||
std::chrono::system_clock::time_point timestamp;
|
||||
llvm::SmallVector<Image, 4> images;
|
||||
};
|
||||
|
||||
public:
|
||||
Frame(SourceImpl& source, Data* data) : m_source(&source), m_data(data) {
|
||||
if (m_data) ++(m_data->refcount);
|
||||
}
|
||||
|
||||
Frame(const Frame& frame) : m_source(frame.m_source), m_data(frame.m_data) {
|
||||
if (m_data) ++(m_data->refcount);
|
||||
}
|
||||
|
||||
Frame(Frame&& frame) : m_source(frame.m_source), m_data(frame.m_data) {
|
||||
frame.m_data = nullptr;
|
||||
}
|
||||
|
||||
~Frame() { DecRef(); }
|
||||
|
||||
Frame& operator=(const Frame& frame) {
|
||||
DecRef();
|
||||
m_source = frame.m_source;
|
||||
m_data = frame.m_data;
|
||||
if (m_data) ++(m_data->refcount);
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return m_data; }
|
||||
|
||||
std::size_t size(std::size_t channel) const {
|
||||
if (!m_data || channel >= m_data->images.size()) return 0;
|
||||
return m_data->images[channel].size();
|
||||
}
|
||||
|
||||
const char* data(std::size_t channel) const {
|
||||
if (!m_data || channel >= m_data->images.size()) return nullptr;
|
||||
return m_data->images[channel].data();
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point time() const {
|
||||
if (!m_data) return std::chrono::system_clock::time_point{};
|
||||
return m_data->timestamp;
|
||||
}
|
||||
|
||||
private:
|
||||
void DecRef() {
|
||||
if (m_data && --(m_data->refcount) == 0) ReleaseFrame();
|
||||
}
|
||||
void ReleaseFrame();
|
||||
|
||||
SourceImpl* m_source;
|
||||
Data* m_data;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CAMERASERVER_FRAME_H_
|
||||
13
src/Handle.cpp
Normal file
13
src/Handle.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "Handle.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
ATOMIC_STATIC_INIT(Sources)
|
||||
ATOMIC_STATIC_INIT(Sinks)
|
||||
107
src/Handle.h
Normal file
107
src/Handle.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CAMERASERVER_HANDLE_H_
|
||||
#define CAMERASERVER_HANDLE_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
#include "cameraserver_c.h"
|
||||
#include "UnlimitedHandleResource.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class SinkImpl;
|
||||
class SourceImpl;
|
||||
|
||||
// Handle data layout:
|
||||
// Bits 0-15: Handle index
|
||||
// Bits 16-23: Subindex (property only)
|
||||
// Bits 24-30: Type
|
||||
|
||||
class Handle {
|
||||
public:
|
||||
enum Type {
|
||||
kUndefined = 0,
|
||||
kProperty = 0x40,
|
||||
kSource,
|
||||
kSink,
|
||||
kListener
|
||||
};
|
||||
enum { kIndexMax = 0xffff };
|
||||
|
||||
Handle(CS_Handle handle) : m_handle(handle) {}
|
||||
operator CS_Handle() const { return m_handle; }
|
||||
|
||||
Handle(int index, Type type) {
|
||||
if (index < 0) {
|
||||
m_handle = 0;
|
||||
return;
|
||||
}
|
||||
m_handle = ((static_cast<int>(type) & 0x7f) << 24) | (index & 0xffff);
|
||||
}
|
||||
Handle(int index, int property, Type type) {
|
||||
if (index < 0 || property < 0) {
|
||||
m_handle = 0;
|
||||
return;
|
||||
}
|
||||
m_handle = ((static_cast<int>(type) & 0x7f) << 24) |
|
||||
((property & 0xff) << 16) | (index & 0xffff);
|
||||
}
|
||||
|
||||
int GetIndex() const { return static_cast<int>(m_handle) & 0xffff; }
|
||||
Type GetType() const {
|
||||
return static_cast<Type>((static_cast<int>(m_handle) >> 24) & 0xff);
|
||||
}
|
||||
bool IsType(Type type) const { return type == GetType(); }
|
||||
int GetTypedIndex(Type type) const { return IsType(type) ? GetIndex() : -1; }
|
||||
int GetSubIndex() const { return (static_cast<int>(m_handle) >> 16) & 0xff; }
|
||||
|
||||
private:
|
||||
CS_Handle m_handle;
|
||||
};
|
||||
|
||||
struct SourceData {
|
||||
enum Type {
|
||||
kUnknown = 0,
|
||||
kUSB,
|
||||
kHTTP,
|
||||
kCv
|
||||
};
|
||||
SourceData(Type type_, std::shared_ptr<SourceImpl> source_)
|
||||
: type{type_}, refCount{0}, source{source_} {}
|
||||
|
||||
Type type;
|
||||
std::atomic_int refCount;
|
||||
std::shared_ptr<SourceImpl> source;
|
||||
};
|
||||
|
||||
typedef StaticUnlimitedHandleResource<Handle, SourceData, Handle::kSource>
|
||||
Sources;
|
||||
|
||||
struct SinkData {
|
||||
enum Type {
|
||||
kUnknown = 0,
|
||||
kHTTP,
|
||||
kCv
|
||||
};
|
||||
explicit SinkData(Type type_, std::shared_ptr<SinkImpl> sink_)
|
||||
: type{type_}, refCount{0}, sourceHandle{0}, sink{sink_} {}
|
||||
|
||||
Type type;
|
||||
std::atomic_int refCount;
|
||||
std::atomic<CS_Source> sourceHandle;
|
||||
std::shared_ptr<SinkImpl> sink;
|
||||
};
|
||||
|
||||
typedef StaticUnlimitedHandleResource<Handle, SinkData, Handle::kSink> Sinks;
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CAMERASERVER_HANDLE_H_
|
||||
55
src/Image.h
Normal file
55
src/Image.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CAMERASERVER_IMAGE_H_
|
||||
#define CAMERASERVER_IMAGE_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Image {
|
||||
public:
|
||||
enum Type {
|
||||
kUnknown = 0,
|
||||
kJpeg
|
||||
};
|
||||
|
||||
Image() : m_data(nullptr), m_size(0), m_capacity(0) {}
|
||||
explicit Image(std::size_t capacity)
|
||||
: m_data(new char[capacity]), m_capacity(capacity) {}
|
||||
Image(Image&& image)
|
||||
: m_data(image.m_data),
|
||||
m_size(image.m_size),
|
||||
m_capacity(image.m_capacity) {
|
||||
image.m_data = nullptr;
|
||||
image.m_size = 0;
|
||||
image.m_capacity = 0;
|
||||
}
|
||||
~Image() { delete[] m_data; }
|
||||
Image(const Image&) = delete;
|
||||
Image& operator=(const Image&) = delete;
|
||||
|
||||
char* data() { return m_data; }
|
||||
const char* data() const { return m_data; }
|
||||
std::size_t size() const { return m_size; }
|
||||
std::size_t capacity() const { return m_capacity; }
|
||||
Type type() const { return m_type; }
|
||||
|
||||
void SetSize(std::size_t size) { m_size = size; }
|
||||
void SetType(Type type) { m_type = type; }
|
||||
|
||||
private:
|
||||
char* m_data;
|
||||
std::size_t m_size;
|
||||
std::size_t m_capacity;
|
||||
Type m_type = kUnknown;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CAMERASERVER_IMAGE_H_
|
||||
14
src/SinkImpl.cpp
Normal file
14
src/SinkImpl.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "SinkImpl.h"
|
||||
|
||||
#include "SourceImpl.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
SinkImpl::SinkImpl(llvm::StringRef name) : m_name{name} {}
|
||||
50
src/SinkImpl.h
Normal file
50
src/SinkImpl.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CAMERASERVER_SINKIMPL_H_
|
||||
#define CAMERASERVER_SINKIMPL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class Frame;
|
||||
class SourceImpl;
|
||||
|
||||
class SinkImpl {
|
||||
public:
|
||||
SinkImpl(llvm::StringRef name);
|
||||
virtual ~SinkImpl() = default;
|
||||
SinkImpl(const SinkImpl& queue) = delete;
|
||||
SinkImpl& operator=(const SinkImpl& queue) = delete;
|
||||
|
||||
llvm::StringRef GetName() const { return m_name; }
|
||||
virtual void GetDescription(llvm::SmallVectorImpl<char>& desc) const = 0;
|
||||
|
||||
void SetSource(std::shared_ptr<SourceImpl> source) {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_source = source;
|
||||
}
|
||||
|
||||
std::shared_ptr<SourceImpl> GetSource() const {
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_source;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
mutable std::mutex m_mutex;
|
||||
std::shared_ptr<SourceImpl> m_source;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CAMERASERVER_SINKIMPL_H_
|
||||
69
src/SourceImpl.cpp
Normal file
69
src/SourceImpl.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include "SourceImpl.h"
|
||||
|
||||
#include "llvm/STLExtras.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
SourceImpl::SourceImpl(llvm::StringRef name)
|
||||
: m_name{name}, m_frame{*this, nullptr} {}
|
||||
|
||||
SourceImpl::~SourceImpl() {
|
||||
// Wake up anyone who is waiting. This also clears the current frame,
|
||||
// which is good because its destructor will call back into the class.
|
||||
Wakeup();
|
||||
// Everything else can clean up itself.
|
||||
}
|
||||
|
||||
Frame SourceImpl::GetNextFrame() {
|
||||
std::unique_lock<std::mutex> lock{m_frameMutex};
|
||||
// TODO: handle spurious wakeup by comparing frame timestamps
|
||||
m_cv.wait(lock);
|
||||
return m_frame;
|
||||
}
|
||||
|
||||
void SourceImpl::Wakeup() {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_frameMutex};
|
||||
m_frame = Frame{*this, nullptr};
|
||||
}
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
void SourceImpl::StartFrame() {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
if (m_frameData) return;
|
||||
if (m_framesAvail.empty()) {
|
||||
m_frameData = llvm::make_unique<Frame::Data>();
|
||||
} else {
|
||||
m_frameData = std::move(m_framesAvail.back());
|
||||
m_framesAvail.pop_back();
|
||||
m_frameData->refcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Image& SourceImpl::AddImage(std::size_t channel, std::size_t size) {}
|
||||
|
||||
void SourceImpl::FinishFrame() {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
std::lock_guard<std::mutex> lock2{m_frameMutex};
|
||||
m_frame = Frame{*this, m_frameData.release()};
|
||||
}
|
||||
m_cv.notify_all();
|
||||
}
|
||||
|
||||
void SourceImpl::ReleaseFrame(Frame::Data* data) {
|
||||
std::lock_guard<std::mutex> lock{m_mutex};
|
||||
// Return the images to the pool
|
||||
for (auto&& image : data->images)
|
||||
m_imagesAvail.emplace_back(std::move(image));
|
||||
// Return the frame to the pool
|
||||
m_framesAvail.emplace_back(data);
|
||||
}
|
||||
99
src/SourceImpl.h
Normal file
99
src/SourceImpl.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CAMERASERVER_SOURCEIMPL_H_
|
||||
#define CAMERASERVER_SOURCEIMPL_H_
|
||||
|
||||
#include <condition_variable>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/StringRef.h"
|
||||
#include "cameraserver_c.h"
|
||||
#include "Frame.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
class SourceImpl {
|
||||
friend class Frame;
|
||||
|
||||
public:
|
||||
SourceImpl(llvm::StringRef name);
|
||||
virtual ~SourceImpl();
|
||||
SourceImpl(const SourceImpl& queue) = delete;
|
||||
SourceImpl& operator=(const SourceImpl& queue) = delete;
|
||||
|
||||
llvm::StringRef GetName() const { return m_name; }
|
||||
virtual void GetDescription(llvm::SmallVectorImpl<char>& desc) const = 0;
|
||||
int GetNumChannels() const { return m_numChannels; }
|
||||
bool IsConnected() const { return m_connected; }
|
||||
|
||||
// Gets the current frame (without waiting for a new one).
|
||||
Frame GetCurFrame();
|
||||
|
||||
// Blocking function that waits for the next frame and returns it.
|
||||
Frame GetNextFrame();
|
||||
|
||||
// Force a wakeup of all GetNextFrame() callers by sending an empty frame.
|
||||
void Wakeup();
|
||||
|
||||
// Property functions
|
||||
virtual int GetProperty(llvm::StringRef name) const = 0;
|
||||
virtual void EnumerateProperties(
|
||||
llvm::SmallVectorImpl<int>& properties) const = 0;
|
||||
virtual CS_PropertyType GetPropertyType(int property) const = 0;
|
||||
virtual void GetPropertyName(int property,
|
||||
llvm::SmallVectorImpl<char>& name) const = 0;
|
||||
virtual bool GetBooleanProperty(int property) const = 0;
|
||||
virtual void SetBooleanProperty(int property, bool value) = 0;
|
||||
virtual double GetDoubleProperty(int property) const = 0;
|
||||
virtual void SetDoubleProperty(int property, double value) = 0;
|
||||
virtual double GetPropertyMin(int property) const = 0;
|
||||
virtual double GetPropertyMax(int property) const = 0;
|
||||
virtual void GetStringProperty(int property,
|
||||
llvm::SmallVectorImpl<char>& value) const = 0;
|
||||
virtual void SetStringProperty(int property, llvm::StringRef value) = 0;
|
||||
virtual int GetEnumProperty(int property) const = 0;
|
||||
virtual void SetEnumProperty(int property, int value) = 0;
|
||||
virtual std::vector<std::string> GetEnumPropertyChoices(
|
||||
int property) const = 0;
|
||||
|
||||
protected:
|
||||
void StartFrame();
|
||||
Image& AddImage(std::size_t channel, std::size_t size);
|
||||
void FinishFrame();
|
||||
|
||||
std::atomic_int m_numChannels{0};
|
||||
std::atomic_bool m_connected{false};
|
||||
|
||||
private:
|
||||
void ReleaseFrame(Frame::Data* data);
|
||||
|
||||
std::string m_name;
|
||||
|
||||
std::mutex m_mutex;
|
||||
std::mutex m_frameMutex;
|
||||
std::condition_variable m_cv;
|
||||
|
||||
// Most recent complete frame (returned to callers of GetNextFrame)
|
||||
// Access protected by m_frameMutex.
|
||||
Frame m_frame;
|
||||
|
||||
// In-progress frame. Will be moved to m_frame when complete.
|
||||
std::unique_ptr<Frame::Data> m_frameData;
|
||||
|
||||
// Pools of frames and images to reduce malloc traffic.
|
||||
std::vector<std::unique_ptr<Frame::Data>> m_framesAvail;
|
||||
std::vector<Image> m_imagesAvail;
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CAMERASERVER_SOURCEIMPL_H_
|
||||
154
src/UnlimitedHandleResource.h
Normal file
154
src/UnlimitedHandleResource.h
Normal file
@@ -0,0 +1,154 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2016. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef CAMERASERVER_UNLIMITEDHANDLERESOURCE_H_
|
||||
#define CAMERASERVER_UNLIMITEDHANDLERESOURCE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "llvm/SmallVector.h"
|
||||
#include "support/atomic_static.h"
|
||||
|
||||
namespace cs {
|
||||
|
||||
// The UnlimitedHandleResource class is a way to track handles. This version
|
||||
// allows an unlimted number of handles that are allocated sequentially. When
|
||||
// possible, indices are reused to save memory usage and keep the array length
|
||||
// down.
|
||||
// However, automatic array management has not been implemented, but might be in
|
||||
// the future.
|
||||
// Because we have to loop through the allocator, we must use a global mutex.
|
||||
//
|
||||
// THandle needs to have the following attributes:
|
||||
// Type : enum or typedef
|
||||
// kIndexMax : static, constexpr, or enum value for the maximum index value
|
||||
// int GetTypedIndex() const : function that returns the index of the handle
|
||||
// THandle(int index, HandleType[int] type) : constructor for index and type
|
||||
//
|
||||
// @tparam THandle The Handle Type
|
||||
// @tparam TStruct The struct type held by this resource
|
||||
// @tparam typeValue The type value stored in the handle
|
||||
// @tparam TMutex The mutex type to use
|
||||
template <typename THandle, typename TStruct, int typeValue,
|
||||
typename TMutex = std::mutex>
|
||||
class UnlimitedHandleResource {
|
||||
public:
|
||||
UnlimitedHandleResource(const UnlimitedHandleResource&) = delete;
|
||||
UnlimitedHandleResource operator=(const UnlimitedHandleResource&) = delete;
|
||||
UnlimitedHandleResource() = default;
|
||||
|
||||
template <typename... Args>
|
||||
THandle Allocate(Args&&... args);
|
||||
THandle Allocate(std::shared_ptr<THandle> structure);
|
||||
|
||||
std::shared_ptr<TStruct> Get(THandle handle);
|
||||
|
||||
void Free(THandle handle);
|
||||
|
||||
template <typename T>
|
||||
void GetAll(llvm::SmallVectorImpl<T>& handles);
|
||||
|
||||
private:
|
||||
THandle MakeHandle(size_t i) {
|
||||
return THandle{static_cast<int>(i),
|
||||
static_cast<typename THandle::Type>(typeValue)};
|
||||
}
|
||||
std::vector<std::shared_ptr<TStruct>> m_structures;
|
||||
TMutex m_handleMutex;
|
||||
};
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
|
||||
template <typename... Args>
|
||||
THandle UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Allocate(
|
||||
Args&&... args) {
|
||||
std::lock_guard<TMutex> sync(m_handleMutex);
|
||||
size_t i;
|
||||
for (i = 0; i < m_structures.size(); i++) {
|
||||
if (m_structures[i] == nullptr) {
|
||||
m_structures[i] = std::make_shared<TStruct>(std::forward<Args>(args)...);
|
||||
return MakeHandle(i);
|
||||
}
|
||||
}
|
||||
if (i >= THandle::kIndexMax) return 0;
|
||||
|
||||
m_structures.emplace_back(
|
||||
std::make_shared<TStruct>(std::forward<Args>(args)...));
|
||||
return MakeHandle(i);
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
|
||||
THandle UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Allocate(
|
||||
std::shared_ptr<THandle> structure) {
|
||||
std::lock_guard<TMutex> sync(m_handleMutex);
|
||||
size_t i;
|
||||
for (i = 0; i < m_structures.size(); i++) {
|
||||
if (m_structures[i] == nullptr) {
|
||||
m_structures[i] = structure;
|
||||
return MakeHandle(i);
|
||||
}
|
||||
}
|
||||
if (i >= THandle::kIndexMax) return 0;
|
||||
|
||||
m_structures.push_back(structure);
|
||||
return MakeHandle(i);
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
|
||||
std::shared_ptr<TStruct> UnlimitedHandleResource<THandle, TStruct, typeValue,
|
||||
TMutex>::Get(THandle handle) {
|
||||
auto index =
|
||||
handle.GetTypedIndex(static_cast<typename THandle::Type>(typeValue));
|
||||
if (index < 0) return nullptr;
|
||||
std::lock_guard<TMutex> sync(m_handleMutex);
|
||||
if (index >= static_cast<int>(m_structures.size()))
|
||||
return nullptr;
|
||||
return m_structures[index];
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
|
||||
void UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Free(
|
||||
THandle handle) {
|
||||
auto index =
|
||||
handle.GetTypedIndex(static_cast<typename THandle::Type>(typeValue));
|
||||
if (index < 0) return;
|
||||
std::lock_guard<TMutex> sync(m_handleMutex);
|
||||
if (index >= static_cast<int>(m_structures.size())) return;
|
||||
m_structures[index].reset();
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
|
||||
template <typename T>
|
||||
void UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::GetAll(
|
||||
llvm::SmallVectorImpl<T>& handles) {
|
||||
std::lock_guard<TMutex> sync(m_handleMutex);
|
||||
size_t i;
|
||||
for (i = 0; i < m_structures.size(); i++) {
|
||||
if (m_structures[i] != nullptr) handles.push_back(MakeHandle(i));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename THandle, typename TStruct, int typeValue,
|
||||
typename TMutex = std::mutex>
|
||||
class StaticUnlimitedHandleResource
|
||||
: public UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex> {
|
||||
public:
|
||||
static StaticUnlimitedHandleResource& GetInstance() {
|
||||
ATOMIC_STATIC(StaticUnlimitedHandleResource, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
private:
|
||||
StaticUnlimitedHandleResource() {}
|
||||
|
||||
ATOMIC_STATIC_DECL(StaticUnlimitedHandleResource)
|
||||
};
|
||||
|
||||
} // namespace cs
|
||||
|
||||
#endif // CAMERASERVER_UNLIMITEDHANDLERESOURCE_H_
|
||||
@@ -7,10 +7,32 @@
|
||||
|
||||
#include "cameraserver_cpp.h"
|
||||
|
||||
#include <limits>
|
||||
#include "llvm/SmallString.h"
|
||||
|
||||
#include "SinkImpl.h"
|
||||
#include "SourceImpl.h"
|
||||
#include "Handle.h"
|
||||
|
||||
using namespace cs;
|
||||
|
||||
static std::shared_ptr<SourceImpl> GetPropertySource(CS_Property propertyHandle,
|
||||
int* propertyIndex,
|
||||
CS_Status* status) {
|
||||
Handle handle{propertyHandle};
|
||||
int i = handle.GetTypedIndex(Handle::kProperty);
|
||||
if (i < 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return nullptr;
|
||||
}
|
||||
auto data = Sources::GetInstance().Get(Handle{i, Handle::kSource});
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return nullptr;
|
||||
}
|
||||
*propertyIndex = handle.GetSubIndex();
|
||||
return data->source;
|
||||
}
|
||||
|
||||
namespace cs {
|
||||
|
||||
//
|
||||
@@ -18,67 +40,116 @@ namespace cs {
|
||||
//
|
||||
|
||||
CS_PropertyType GetPropertyType(CS_Property property, CS_Status* status) {
|
||||
return CS_PROP_NONE; // TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return CS_PROP_NONE;
|
||||
return source->GetPropertyType(propertyIndex);
|
||||
}
|
||||
|
||||
std::string GetPropertyName(CS_Property property, CS_Status* status) {
|
||||
return ""; // TODO
|
||||
llvm::SmallString<128> name;
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return std::string{};
|
||||
source->GetPropertyName(propertyIndex, name);
|
||||
return name.str();
|
||||
}
|
||||
|
||||
void GetPropertyName(CS_Property property, llvm::SmallVectorImpl<char>& name,
|
||||
CS_Status* status) {
|
||||
// TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return;
|
||||
source->GetPropertyName(propertyIndex, name);
|
||||
}
|
||||
|
||||
bool GetBooleanProperty(CS_Property property, CS_Status* status) {
|
||||
return false; // TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return false;
|
||||
return source->GetBooleanProperty(propertyIndex);
|
||||
}
|
||||
|
||||
void SetBooleanProperty(CS_Property property, bool value, CS_Status* status) {
|
||||
// TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return;
|
||||
source->SetBooleanProperty(propertyIndex, value);
|
||||
}
|
||||
|
||||
double GetDoubleProperty(CS_Property property, CS_Status* status) {
|
||||
return 0.0; // TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return false;
|
||||
return source->GetDoubleProperty(propertyIndex);
|
||||
}
|
||||
|
||||
void SetDoubleProperty(CS_Property property, double value, CS_Status* status) {
|
||||
// TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return;
|
||||
source->SetDoubleProperty(propertyIndex, value);
|
||||
}
|
||||
|
||||
double GetDoublePropertyMin(CS_Property property, CS_Status* status) {
|
||||
return 0.0; // TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return 0.0;
|
||||
return source->GetPropertyMin(propertyIndex);
|
||||
}
|
||||
|
||||
double GetDoublePropertyMax(CS_Property property, CS_Status* status) {
|
||||
return 0.0; // TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return 0.0;
|
||||
return source->GetPropertyMax(propertyIndex);
|
||||
}
|
||||
|
||||
std::string GetStringProperty(CS_Property property, CS_Status* status) {
|
||||
return ""; // TODO
|
||||
llvm::SmallString<128> value;
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return std::string{};
|
||||
source->GetStringProperty(propertyIndex, value);
|
||||
return value.str();
|
||||
}
|
||||
|
||||
void GetStringProperty(CS_Property property, llvm::SmallVectorImpl<char>& value,
|
||||
CS_Status* status) {
|
||||
// TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return;
|
||||
source->GetStringProperty(propertyIndex, value);
|
||||
}
|
||||
|
||||
void SetStringProperty(CS_Property property, llvm::StringRef value,
|
||||
CS_Status* status) {
|
||||
// TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return;
|
||||
source->SetStringProperty(propertyIndex, value);
|
||||
}
|
||||
|
||||
int GetEnumProperty(CS_Property property, CS_Status* status) {
|
||||
return 0; // TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return 0;
|
||||
return source->GetEnumProperty(propertyIndex);
|
||||
}
|
||||
|
||||
void SetEnumProperty(CS_Property property, int value, CS_Status* status) {
|
||||
// TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return;
|
||||
source->SetEnumProperty(propertyIndex, value);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetEnumPropertyChoices(CS_Property property,
|
||||
CS_Status* status) {
|
||||
return std::vector<std::string>{}; // TODO
|
||||
int propertyIndex;
|
||||
auto source = GetPropertySource(property, &propertyIndex, status);
|
||||
if (!source) return std::vector<std::string>{};
|
||||
return source->GetEnumPropertyChoices(propertyIndex);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -109,21 +180,44 @@ CS_Source CreateCvSource(llvm::StringRef name, int numChannels,
|
||||
//
|
||||
|
||||
std::string GetSourceName(CS_Source source, CS_Status* status) {
|
||||
return ""; // TODO
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
}
|
||||
return data->source->GetName();
|
||||
}
|
||||
|
||||
void GetSourceName(CS_Source sink, llvm::SmallVectorImpl<char>& name,
|
||||
void GetSourceName(CS_Source source, llvm::SmallVectorImpl<char>& name,
|
||||
CS_Status* status) {
|
||||
// TODO
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
auto str = data->source->GetName();
|
||||
name.append(str.begin(), str.end());
|
||||
}
|
||||
|
||||
std::string GetSourceDescription(CS_Source source, CS_Status* status) {
|
||||
return ""; // TODO
|
||||
llvm::SmallString<128> desc;
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
}
|
||||
data->source->GetDescription(desc);
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
void GetSourceDescription(CS_Source source, llvm::SmallVectorImpl<char>& desc,
|
||||
CS_Status* status) {
|
||||
// TODO
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
data->source->GetDescription(desc);
|
||||
}
|
||||
|
||||
uint64_t GetSourceLastFrameTime(CS_Source source, CS_Status* status) {
|
||||
@@ -131,16 +225,36 @@ uint64_t GetSourceLastFrameTime(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
int GetSourceNumChannels(CS_Source source, CS_Status* status) {
|
||||
return 0; // TODO
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
return data->source->GetNumChannels();
|
||||
}
|
||||
|
||||
bool IsSourceConnected(CS_Source source, CS_Status* status) {
|
||||
return false; // TODO
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return false;
|
||||
}
|
||||
return data->source->IsConnected();
|
||||
}
|
||||
|
||||
CS_Property GetSourceProperty(CS_Source source, llvm::StringRef name,
|
||||
CS_Status* status) {
|
||||
return 0; // TODO
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
int property = data->source->GetProperty(name);
|
||||
if (property < 0) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
return Handle{source, property, Handle::kProperty};
|
||||
}
|
||||
|
||||
void EnumerateSourceProperties(CS_Source source,
|
||||
@@ -150,11 +264,25 @@ void EnumerateSourceProperties(CS_Source source,
|
||||
}
|
||||
|
||||
CS_Source CopySource(CS_Source source, CS_Status* status) {
|
||||
return source; // TODO
|
||||
if (source == 0) return 0;
|
||||
auto data = Sources::GetInstance().Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
data->refCount++;
|
||||
return source;
|
||||
}
|
||||
|
||||
void ReleaseSource(CS_Source source, CS_Status* status) {
|
||||
// TODO
|
||||
if (source == 0) return;
|
||||
auto& inst = Sources::GetInstance();
|
||||
auto data = inst.Get(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
if (--(data->refCount) == 0) inst.Free(source);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -227,42 +355,100 @@ CS_Sink CreateCvSinkCallback(llvm::StringRef name,
|
||||
// Sink Functions
|
||||
//
|
||||
std::string GetSinkName(CS_Sink sink, CS_Status* status) {
|
||||
return ""; // TODO
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
}
|
||||
return data->sink->GetName();
|
||||
}
|
||||
|
||||
void GetSinkName(CS_Sink sink, llvm::SmallVectorImpl<char>& name,
|
||||
CS_Status* status) {
|
||||
// TODO
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
auto str = data->sink->GetName();
|
||||
name.append(str.begin(), str.end());
|
||||
}
|
||||
|
||||
std::string GetSinkDescription(CS_Sink sink, CS_Status* status) {
|
||||
return ""; // TODO
|
||||
llvm::SmallString<128> desc;
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return std::string{};
|
||||
}
|
||||
data->sink->GetDescription(desc);
|
||||
return desc.str();
|
||||
}
|
||||
|
||||
void GetSinkDescription(CS_Sink sink, llvm::SmallVectorImpl<char>& desc,
|
||||
CS_Status* status) {
|
||||
// TODO
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
data->sink->GetDescription(desc);
|
||||
}
|
||||
|
||||
void SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
|
||||
// TODO
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
auto sourceData = Sources::GetInstance().Get(source);
|
||||
if (!sourceData) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
data->sink->SetSource(sourceData->source);
|
||||
data->sourceHandle.store(source);
|
||||
}
|
||||
|
||||
CS_Source GetSinkSource(CS_Sink sink, CS_Status* status) {
|
||||
return 0; // TODO
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
return data->sourceHandle.load();
|
||||
}
|
||||
|
||||
CS_Property GetSinkSourceProperty(CS_Sink sink, llvm::StringRef name,
|
||||
CS_Status* status) {
|
||||
return 0; // TODO
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
return GetSourceProperty(data->sourceHandle.load(), name, status);
|
||||
}
|
||||
|
||||
CS_Sink CopySink(CS_Sink sink, CS_Status* status) {
|
||||
return sink; // TODO
|
||||
if (sink == 0) return 0;
|
||||
auto data = Sinks::GetInstance().Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
data->refCount++;
|
||||
return sink;
|
||||
}
|
||||
|
||||
void ReleaseSink(CS_Sink sink, CS_Status* status) {
|
||||
// TODO
|
||||
if (sink == 0) return;
|
||||
auto& inst = Sinks::GetInstance();
|
||||
auto data = inst.Get(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
if (--(data->refCount) == 0) inst.Free(sink);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -338,12 +524,12 @@ std::vector<USBCameraInfo> EnumerateUSBCameras(CS_Status* status) {
|
||||
|
||||
void EnumerateSourceHandles(llvm::SmallVectorImpl<CS_Source>& handles,
|
||||
CS_Status* status) {
|
||||
// TODO
|
||||
Sources::GetInstance().GetAll(handles);
|
||||
}
|
||||
|
||||
void EnumerateSinkHandles(llvm::SmallVectorImpl<CS_Sink>& handles,
|
||||
CS_Status* status) {
|
||||
// TODO
|
||||
Sinks::GetInstance().GetAll(handles);
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
Reference in New Issue
Block a user