Use std::string_view and fmtlib across all libraries (#3402)

- Twine, StringRef, Format, and NativeFormatting have been removed
- Logging now uses fmtlib style formatting
- Nearly all uses of wpi::outs/errs have been replaced with fmt::print() or
std::puts()/std::fputs() (for unformatted strings).
- A wpi/fmt/raw_ostream.h header has been added to enable
fmt::print() with wpi::raw_ostream
This commit is contained in:
Peter Johnson
2021-06-06 16:13:58 -07:00
committed by GitHub
parent 4f1cecb8e7
commit b2c3b2dd8e
441 changed files with 5061 additions and 9749 deletions

View File

@@ -13,7 +13,7 @@
using namespace cs;
ConfigurableSourceImpl::ConfigurableSourceImpl(const wpi::Twine& name,
ConfigurableSourceImpl::ConfigurableSourceImpl(std::string_view name,
wpi::Logger& logger,
Notifier& notifier,
Telemetry& telemetry,
@@ -50,11 +50,11 @@ void ConfigurableSourceImpl::NumSinksEnabledChanged() {
// ignore
}
void ConfigurableSourceImpl::NotifyError(const wpi::Twine& msg) {
void ConfigurableSourceImpl::NotifyError(std::string_view msg) {
PutError(msg, wpi::Now());
}
int ConfigurableSourceImpl::CreateProperty(const wpi::Twine& name,
int ConfigurableSourceImpl::CreateProperty(std::string_view name,
CS_PropertyKind kind, int minimum,
int maximum, int step,
int defaultValue, int value) {
@@ -75,12 +75,12 @@ int ConfigurableSourceImpl::CreateProperty(const wpi::Twine& name,
value = prop.value;
});
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name, ndx,
kind, value, wpi::Twine{});
kind, value, {});
return ndx;
}
int ConfigurableSourceImpl::CreateProperty(
const wpi::Twine& name, CS_PropertyKind kind, int minimum, int maximum,
std::string_view name, CS_PropertyKind kind, int minimum, int maximum,
int step, int defaultValue, int value,
std::function<void(CS_Property property)> onChange) {
// TODO
@@ -102,5 +102,5 @@ void ConfigurableSourceImpl::SetEnumPropertyChoices(
prop->enumChoices = choices;
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
prop->name, property, CS_PROP_ENUM,
prop->value, wpi::Twine{});
prop->value, {});
}

View File

@@ -9,10 +9,10 @@
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <wpi/ArrayRef.h>
#include <wpi/Twine.h>
#include "SourceImpl.h"
@@ -20,7 +20,7 @@ namespace cs {
class ConfigurableSourceImpl : public SourceImpl {
protected:
ConfigurableSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
ConfigurableSourceImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
const VideoMode& mode);
@@ -35,10 +35,10 @@ class ConfigurableSourceImpl : public SourceImpl {
void NumSinksEnabledChanged() override;
// OpenCV-specific functions
void NotifyError(const wpi::Twine& msg);
int CreateProperty(const wpi::Twine& name, CS_PropertyKind kind, int minimum,
void NotifyError(std::string_view msg);
int CreateProperty(std::string_view 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 CreateProperty(std::string_view 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,

View File

@@ -18,14 +18,14 @@
using namespace cs;
CvSinkImpl::CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
CvSinkImpl::CvSinkImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry)
: SinkImpl{name, logger, notifier, telemetry} {
m_active = true;
// m_thread = std::thread(&CvSinkImpl::ThreadMain, this);
}
CvSinkImpl::CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
CvSinkImpl::CvSinkImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
std::function<void(uint64_t time)> processFrame)
: SinkImpl{name, logger, notifier, telemetry} {}
@@ -110,7 +110,7 @@ void CvSinkImpl::ThreadMain() {
std::this_thread::sleep_for(std::chrono::seconds(1));
continue;
}
SDEBUG4("waiting for frame");
SDEBUG4("{}", "waiting for frame");
Frame frame = source->GetNextFrame(); // blocks
if (!m_active) {
break;
@@ -127,14 +127,14 @@ void CvSinkImpl::ThreadMain() {
namespace cs {
CS_Sink CreateCvSink(const wpi::Twine& name, CS_Status* status) {
CS_Sink CreateCvSink(std::string_view name, CS_Status* status) {
auto& inst = Instance::GetInstance();
return inst.CreateSink(
CS_SINK_CV, std::make_shared<CvSinkImpl>(name, inst.logger, inst.notifier,
inst.telemetry));
}
CS_Sink CreateCvSinkCallback(const wpi::Twine& name,
CS_Sink CreateCvSinkCallback(std::string_view name,
std::function<void(uint64_t time)> processFrame,
CS_Status* status) {
auto& inst = Instance::GetInstance();
@@ -145,7 +145,7 @@ CS_Sink CreateCvSinkCallback(const wpi::Twine& name,
static constexpr unsigned SinkMask = CS_SINK_CV | CS_SINK_RAW;
void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
void SetSinkDescription(CS_Sink sink, std::string_view description,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data || (data->kind & SinkMask) == 0) {
@@ -183,12 +183,12 @@ std::string GetSinkError(CS_Sink sink, CS_Status* status) {
return static_cast<CvSinkImpl&>(*data->sink).GetError();
}
wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
std::string_view GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data || (data->kind & SinkMask) == 0) {
*status = CS_INVALID_HANDLE;
return wpi::StringRef{};
return {};
}
return static_cast<CvSinkImpl&>(*data->sink).GetError(buf);
}

View File

@@ -9,10 +9,10 @@
#include <atomic>
#include <functional>
#include <string_view>
#include <thread>
#include <opencv2/core/core.hpp>
#include <wpi/Twine.h>
#include <wpi/condition_variable.h>
#include "Frame.h"
@@ -24,9 +24,9 @@ class SourceImpl;
class CvSinkImpl : public SinkImpl {
public:
CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
CvSinkImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry);
CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
CvSinkImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry,
std::function<void(uint64_t time)> processFrame);
~CvSinkImpl() override;

View File

@@ -19,7 +19,7 @@
using namespace cs;
CvSourceImpl::CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
CvSourceImpl::CvSourceImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
const VideoMode& mode)
: ConfigurableSourceImpl{name, logger, notifier, telemetry, mode} {}
@@ -53,8 +53,7 @@ void CvSourceImpl::PutFrame(cv::Mat& image) {
cv::cvtColor(finalImage, dest->AsMat(), cv::COLOR_BGRA2BGR);
break;
default:
SERROR("PutFrame: " << image.channels()
<< "-channel images not supported");
SERROR("PutFrame: {}-channel images not supported", image.channels());
return;
}
SourceImpl::PutFrame(std::move(dest), wpi::Now());
@@ -62,7 +61,7 @@ void CvSourceImpl::PutFrame(cv::Mat& image) {
namespace cs {
CS_Source CreateCvSource(const wpi::Twine& name, const VideoMode& mode,
CS_Source CreateCvSource(std::string_view name, const VideoMode& mode,
CS_Status* status) {
auto& inst = Instance::GetInstance();
return inst.CreateSource(CS_SOURCE_CV, std::make_shared<CvSourceImpl>(
@@ -81,7 +80,7 @@ void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status) {
static constexpr unsigned SourceMask = CS_SINK_CV | CS_SINK_RAW;
void NotifySourceError(CS_Source source, const wpi::Twine& msg,
void NotifySourceError(CS_Source source, std::string_view msg,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
if (!data || (data->kind & SourceMask) == 0) {
@@ -100,7 +99,7 @@ void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) {
static_cast<CvSourceImpl&>(*data->source).SetConnected(connected);
}
void SetSourceDescription(CS_Source source, const wpi::Twine& description,
void SetSourceDescription(CS_Source source, std::string_view description,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
if (!data || (data->kind & SourceMask) == 0) {
@@ -110,7 +109,7 @@ void SetSourceDescription(CS_Source source, const wpi::Twine& description,
static_cast<CvSourceImpl&>(*data->source).SetDescription(description);
}
CS_Property CreateSourceProperty(CS_Source source, const wpi::Twine& name,
CS_Property CreateSourceProperty(CS_Source source, std::string_view name,
CS_PropertyKind kind, int minimum, int maximum,
int step, int defaultValue, int value,
CS_Status* status) {
@@ -126,7 +125,7 @@ CS_Property CreateSourceProperty(CS_Source source, const wpi::Twine& name,
}
CS_Property CreateSourcePropertyCallback(
CS_Source source, const wpi::Twine& name, CS_PropertyKind kind, int minimum,
CS_Source source, std::string_view name, CS_PropertyKind kind, int minimum,
int maximum, int step, int defaultValue, int value,
std::function<void(CS_Property property)> onChange, CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);

View File

@@ -9,11 +9,11 @@
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <opencv2/core/core.hpp>
#include <wpi/ArrayRef.h>
#include <wpi/Twine.h>
#include "ConfigurableSourceImpl.h"
#include "SourceImpl.h"
@@ -22,7 +22,7 @@ namespace cs {
class CvSourceImpl : public ConfigurableSourceImpl {
public:
CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
CvSourceImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry, const VideoMode& mode);
~CvSourceImpl() override;

View File

@@ -16,10 +16,10 @@
using namespace cs;
Frame::Frame(SourceImpl& source, const wpi::Twine& error, Time time)
Frame::Frame(SourceImpl& source, std::string_view error, Time time)
: m_impl{source.AllocFrameImpl().release()} {
m_impl->refcount = 1;
m_impl->error = error.str();
m_impl->error = error;
m_impl->time = time;
}
@@ -522,10 +522,8 @@ Image* Frame::GetImageImpl(int width, int height,
}
WPI_DEBUG4(Instance::GetInstance().logger,
"converting image from " << cur->width << "x" << cur->height
<< " type " << cur->pixelFormat << " to "
<< width << "x" << height << " type "
<< pixelFormat);
"converting image from {}x{} type {} to {}x{} type {}", cur->width,
cur->height, cur->pixelFormat, width, height, pixelFormat);
// If the source image is a JPEG, we need to decode it before we can do
// anything else with it. Note that if the destination format is JPEG, we

View File

@@ -8,11 +8,11 @@
#include <atomic>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <wpi/SmallVector.h>
#include <wpi/Twine.h>
#include <wpi/mutex.h>
#include "Image.h"
@@ -44,7 +44,7 @@ class Frame {
public:
Frame() noexcept = default;
Frame(SourceImpl& source, const wpi::Twine& error, Time time);
Frame(SourceImpl& source, std::string_view error, Time time);
Frame(SourceImpl& source, std::unique_ptr<Image> image, Time time);
@@ -72,7 +72,7 @@ class Frame {
Time GetTime() const { return m_impl ? m_impl->time : 0; }
wpi::StringRef GetError() const {
std::string_view GetError() const {
if (!m_impl) {
return {};
}

View File

@@ -5,6 +5,7 @@
#include "HttpCameraImpl.h"
#include <wpi/MemAlloc.h>
#include <wpi/StringExtras.h>
#include <wpi/TCPConnector.h>
#include <wpi/timestamp.h>
@@ -18,7 +19,7 @@
using namespace cs;
HttpCameraImpl::HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind,
HttpCameraImpl::HttpCameraImpl(std::string_view name, CS_HttpCameraKind kind,
wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry)
: SourceImpl{name, logger, notifier, telemetry}, m_kind{kind} {}
@@ -84,7 +85,7 @@ void HttpCameraImpl::MonitorThreadMain() {
// (this will result in an error at the read point, and ultimately
// a reconnect attempt)
if (m_streamConn && m_frameCount == 0) {
SWARNING("Monitor detected stream hung, disconnecting");
SWARNING("{}", "Monitor detected stream hung, disconnecting");
m_streamConn->stream->close();
}
@@ -92,7 +93,7 @@ void HttpCameraImpl::MonitorThreadMain() {
m_frameCount = 0;
}
SDEBUG("Monitor Thread exiting");
SDEBUG("{}", "Monitor Thread exiting");
}
void HttpCameraImpl::StreamThreadMain() {
@@ -132,14 +133,14 @@ void HttpCameraImpl::StreamThreadMain() {
SetConnected(true);
// stream
DeviceStream(conn->is, boundary);
DeviceStream(conn->is, boundary.str());
{
std::unique_lock lock(m_mutex);
m_streamConn = nullptr;
}
}
SDEBUG("Camera Thread exiting");
SDEBUG("{}", "Camera Thread exiting");
SetConnected(false);
}
@@ -150,7 +151,7 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
{
std::scoped_lock lock(m_mutex);
if (m_locations.empty()) {
SERROR("locations array is empty!?");
SERROR("{}", "locations array is empty!?");
std::this_thread::sleep_for(std::chrono::seconds(1));
return nullptr;
}
@@ -181,19 +182,17 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
std::string warn;
if (!conn->Handshake(req, &warn)) {
SWARNING(GetName() << ": " << warn);
SWARNING("{}", warn);
std::scoped_lock lock(m_mutex);
m_streamConn = nullptr;
return nullptr;
}
// Parse Content-Type header to get the boundary
wpi::StringRef mediaType, contentType;
std::tie(mediaType, contentType) = conn->contentType.str().split(';');
mediaType = mediaType.trim();
auto [mediaType, contentType] = wpi::split(conn->contentType.str(), ';');
mediaType = wpi::trim(mediaType);
if (mediaType != "multipart/x-mixed-replace") {
SWARNING("\"" << req.host << "\": unrecognized Content-Type \"" << mediaType
<< "\"");
SWARNING("\"{}\": unrecognized Content-Type \"{}\"", req.host, mediaType);
std::scoped_lock lock(m_mutex);
m_streamConn = nullptr;
return nullptr;
@@ -202,14 +201,13 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
// media parameters
boundary.clear();
while (!contentType.empty()) {
wpi::StringRef keyvalue;
std::tie(keyvalue, contentType) = contentType.split(';');
contentType = contentType.ltrim();
wpi::StringRef key, value;
std::tie(key, value) = keyvalue.split('=');
if (key.trim() == "boundary") {
value = value.trim().trim('"'); // value may be quoted
if (value.startswith("--")) {
std::string_view keyvalue;
std::tie(keyvalue, contentType) = wpi::split(contentType, ';');
contentType = wpi::ltrim(contentType);
auto [key, value] = wpi::split(keyvalue, '=');
if (wpi::trim(key) == "boundary") {
value = wpi::trim(wpi::trim(value), '"'); // value may be quoted
if (wpi::starts_with(value, "--")) {
value = value.substr(2);
}
boundary.append(value.begin(), value.end());
@@ -217,8 +215,7 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
}
if (boundary.empty()) {
SWARNING("\"" << req.host
<< "\": empty multi-part boundary or no Content-Type");
SWARNING("\"{}\": empty multi-part boundary or no Content-Type", req.host);
std::scoped_lock lock(m_mutex);
m_streamConn = nullptr;
return nullptr;
@@ -228,7 +225,7 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
}
void HttpCameraImpl::DeviceStream(wpi::raw_istream& is,
wpi::StringRef boundary) {
std::string_view boundary) {
// Stored here so we reuse it from frame to frame
std::string imageBuf;
@@ -275,28 +272,29 @@ bool HttpCameraImpl::DeviceStreamFrame(wpi::raw_istream& is,
wpi::SmallString<64> contentTypeBuf;
wpi::SmallString<64> contentLengthBuf;
if (!ParseHttpHeaders(is, &contentTypeBuf, &contentLengthBuf)) {
SWARNING("disconnected during headers");
SWARNING("{}", "disconnected during headers");
PutError("disconnected during headers", wpi::Now());
return false;
}
// Check the content type (if present)
if (!contentTypeBuf.str().empty() &&
!contentTypeBuf.str().startswith("image/jpeg")) {
wpi::SmallString<64> errBuf;
wpi::raw_svector_ostream errMsg{errBuf};
errMsg << "received unknown Content-Type \"" << contentTypeBuf << "\"";
SWARNING(errMsg.str());
PutError(errMsg.str(), wpi::Now());
!wpi::starts_with(contentTypeBuf, "image/jpeg")) {
auto errMsg =
fmt::format("received unknown Content-Type \"{}\"", contentTypeBuf);
SWARNING("{}", errMsg);
PutError(errMsg, wpi::Now());
return false;
}
unsigned int contentLength = 0;
if (contentLengthBuf.str().getAsInteger(10, contentLength)) {
if (auto v = wpi::parse_integer<unsigned int>(contentLengthBuf, 10)) {
contentLength = v.value();
} else {
// Ugh, no Content-Length? Read the blocks of the JPEG file.
int width, height;
if (!ReadJpeg(is, imageBuf, &width, &height)) {
SWARNING("did not receive a JPEG image");
SWARNING("{}", "did not receive a JPEG image");
PutError("did not receive a JPEG image", wpi::Now());
return false;
}
@@ -315,7 +313,7 @@ bool HttpCameraImpl::DeviceStreamFrame(wpi::raw_istream& is,
}
int width, height;
if (!GetJpegSize(image->str(), &width, &height)) {
SWARNING("did not receive a JPEG image");
SWARNING("{}", "did not receive a JPEG image");
PutError("did not receive a JPEG image", wpi::Now());
return false;
}
@@ -345,7 +343,7 @@ void HttpCameraImpl::SettingsThreadMain() {
DeviceSendSettings(req);
}
SDEBUG("Settings Thread exiting");
SDEBUG("{}", "Settings Thread exiting");
}
void HttpCameraImpl::DeviceSendSettings(wpi::HttpRequest& req) {
@@ -369,7 +367,7 @@ void HttpCameraImpl::DeviceSendSettings(wpi::HttpRequest& req) {
// Just need a handshake as settings are sent via GET parameters
std::string warn;
if (!conn->Handshake(req, &warn)) {
SWARNING(GetName() << ": " << warn);
SWARNING("{}", warn);
}
conn->stream->close();
@@ -388,7 +386,7 @@ bool HttpCameraImpl::SetUrls(wpi::ArrayRef<std::string> urls,
std::string errorMsg;
locations.emplace_back(url, &error, &errorMsg);
if (error) {
SERROR(GetName() << ": " << errorMsg);
SERROR("{}", errorMsg);
*status = CS_BAD_URL;
return false;
}
@@ -410,8 +408,8 @@ std::vector<std::string> HttpCameraImpl::GetUrls() const {
return urls;
}
void HttpCameraImpl::CreateProperty(const wpi::Twine& name,
const wpi::Twine& httpParam,
void HttpCameraImpl::CreateProperty(std::string_view name,
std::string_view httpParam,
bool viaSettings, CS_PropertyKind kind,
int minimum, int maximum, int step,
int defaultValue, int value) const {
@@ -421,13 +419,12 @@ void HttpCameraImpl::CreateProperty(const wpi::Twine& name,
value));
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name,
m_propertyData.size() + 1, kind, value,
wpi::Twine{});
m_propertyData.size() + 1, kind, value, {});
}
template <typename T>
void HttpCameraImpl::CreateEnumProperty(
const wpi::Twine& name, const wpi::Twine& httpParam, bool viaSettings,
std::string_view name, std::string_view httpParam, bool viaSettings,
int defaultValue, int value, std::initializer_list<T> choices) const {
std::scoped_lock lock(m_mutex);
m_propertyData.emplace_back(std::make_unique<PropertyData>(
@@ -442,14 +439,14 @@ void HttpCameraImpl::CreateEnumProperty(
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name,
m_propertyData.size() + 1, CS_PROP_ENUM,
value, wpi::Twine{});
value, {});
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
name, m_propertyData.size() + 1, CS_PROP_ENUM,
value, wpi::Twine{});
value, {});
}
std::unique_ptr<PropertyImpl> HttpCameraImpl::CreateEmptyProperty(
const wpi::Twine& name) const {
std::string_view name) const {
return std::make_unique<PropertyData>(name);
}
@@ -474,7 +471,7 @@ void HttpCameraImpl::SetProperty(int property, int value, CS_Status* status) {
// TODO
}
void HttpCameraImpl::SetStringProperty(int property, const wpi::Twine& value,
void HttpCameraImpl::SetStringProperty(int property, std::string_view value,
CS_Status* status) {
// TODO
}
@@ -560,7 +557,7 @@ bool AxisCameraImpl::CacheProperties(CS_Status* status) const {
namespace cs {
CS_Source CreateHttpCamera(const wpi::Twine& name, const wpi::Twine& url,
CS_Source CreateHttpCamera(std::string_view name, std::string_view url,
CS_HttpCameraKind kind, CS_Status* status) {
auto& inst = Instance::GetInstance();
std::shared_ptr<HttpCameraImpl> source;
@@ -574,13 +571,13 @@ CS_Source CreateHttpCamera(const wpi::Twine& name, const wpi::Twine& url,
inst.notifier, inst.telemetry);
break;
}
if (!source->SetUrls(url.str(), status)) {
if (!source->SetUrls(std::string{url}, status)) {
return 0;
}
return inst.CreateSource(CS_SOURCE_HTTP, source);
}
CS_Source CreateHttpCamera(const wpi::Twine& name,
CS_Source CreateHttpCamera(std::string_view name,
wpi::ArrayRef<std::string> urls,
CS_HttpCameraKind kind, CS_Status* status) {
auto& inst = Instance::GetInstance();

View File

@@ -10,13 +10,13 @@
#include <initializer_list>
#include <memory>
#include <string>
#include <string_view>
#include <thread>
#include <vector>
#include <wpi/HttpUtil.h>
#include <wpi/SmallString.h>
#include <wpi/StringMap.h>
#include <wpi/Twine.h>
#include <wpi/condition_variable.h>
#include <wpi/raw_istream.h>
@@ -27,7 +27,7 @@ namespace cs {
class HttpCameraImpl : public SourceImpl {
public:
HttpCameraImpl(const wpi::Twine& name, CS_HttpCameraKind kind,
HttpCameraImpl(std::string_view name, CS_HttpCameraKind kind,
wpi::Logger& logger, Notifier& notifier, Telemetry& telemetry);
~HttpCameraImpl() override;
@@ -35,7 +35,7 @@ class HttpCameraImpl : public SourceImpl {
// Property functions
void SetProperty(int property, int value, CS_Status* status) override;
void SetStringProperty(int property, const wpi::Twine& value,
void SetStringProperty(int property, std::string_view value,
CS_Status* status) override;
// Standard common camera properties
@@ -61,13 +61,13 @@ class HttpCameraImpl : public SourceImpl {
class PropertyData : public PropertyImpl {
public:
PropertyData() = default;
explicit PropertyData(const wpi::Twine& name_) : PropertyImpl{name_} {}
PropertyData(const wpi::Twine& name_, const wpi::Twine& httpParam_,
explicit PropertyData(std::string_view name_) : PropertyImpl{name_} {}
PropertyData(std::string_view name_, std::string_view httpParam_,
bool viaSettings_, CS_PropertyKind kind_, int minimum_,
int maximum_, int step_, int defaultValue_, int value_)
: PropertyImpl(name_, kind_, step_, defaultValue_, value_),
viaSettings(viaSettings_),
httpParam(httpParam_.str()) {
httpParam(httpParam_) {
hasMinimum = true;
minimum = minimum_;
hasMaximum = true;
@@ -81,16 +81,16 @@ class HttpCameraImpl : public SourceImpl {
protected:
std::unique_ptr<PropertyImpl> CreateEmptyProperty(
const wpi::Twine& name) const override;
std::string_view name) const override;
bool CacheProperties(CS_Status* status) const override;
void CreateProperty(const wpi::Twine& name, const wpi::Twine& httpParam,
void CreateProperty(std::string_view name, std::string_view httpParam,
bool viaSettings, CS_PropertyKind kind, int minimum,
int maximum, int step, int defaultValue, int value) const;
template <typename T>
void CreateEnumProperty(const wpi::Twine& name, const wpi::Twine& httpParam,
void CreateEnumProperty(std::string_view name, std::string_view httpParam,
bool viaSettings, int defaultValue, int value,
std::initializer_list<T> choices) const;
@@ -101,7 +101,7 @@ class HttpCameraImpl : public SourceImpl {
// Functions used by StreamThreadMain()
wpi::HttpConnection* DeviceStreamConnect(
wpi::SmallVectorImpl<char>& boundary);
void DeviceStream(wpi::raw_istream& is, wpi::StringRef boundary);
void DeviceStream(wpi::raw_istream& is, std::string_view boundary);
bool DeviceStreamFrame(wpi::raw_istream& is, std::string& imageBuf);
// The camera settings thread
@@ -146,12 +146,12 @@ class HttpCameraImpl : public SourceImpl {
class AxisCameraImpl : public HttpCameraImpl {
public:
AxisCameraImpl(const wpi::Twine& name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry)
AxisCameraImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry)
: HttpCameraImpl{name, CS_HTTP_AXIS, logger, notifier, telemetry} {}
#if 0
void SetProperty(int property, int value, CS_Status* status) override;
void SetStringProperty(int property, const wpi::Twine& value,
void SetStringProperty(int property, std::string_view value,
CS_Status* status) override;
#endif
protected:

View File

@@ -5,10 +5,10 @@
#ifndef CSCORE_IMAGE_H_
#define CSCORE_IMAGE_H_
#include <string_view>
#include <vector>
#include <opencv2/core/core.hpp>
#include <wpi/StringRef.h>
#include "cscore_cpp.h"
#include "default_init_allocator.h"
@@ -34,8 +34,8 @@ class Image {
Image& operator=(const Image&) = delete;
// Getters
operator wpi::StringRef() const { return str(); } // NOLINT
wpi::StringRef str() const { return wpi::StringRef(data(), size()); }
operator std::string_view() const { return str(); } // NOLINT
std::string_view str() const { return {data(), size()}; }
size_t capacity() const { return m_data.capacity(); }
const char* data() const {
return reinterpret_cast<const char*>(m_data.data());

View File

@@ -4,36 +4,32 @@
#include "Instance.h"
#include <wpi/SmallString.h>
#include <wpi/StringRef.h>
#include <string_view>
#include <fmt/format.h>
#include <wpi/fs.h>
#include <wpi/raw_ostream.h>
using namespace cs;
static void def_log_func(unsigned int level, const char* file,
unsigned int line, const char* msg) {
wpi::SmallString<128> buf;
wpi::raw_svector_ostream oss(buf);
if (level == 20) {
oss << "CS: " << msg << '\n';
wpi::errs() << oss.str();
fmt::print(stderr, "CS: {}\n", msg);
return;
}
wpi::StringRef levelmsg;
std::string_view levelmsg;
if (level >= 50) {
levelmsg = "CRITICAL: ";
levelmsg = "CRITICAL";
} else if (level >= 40) {
levelmsg = "ERROR: ";
levelmsg = "ERROR";
} else if (level >= 30) {
levelmsg = "WARNING: ";
levelmsg = "WARNING";
} else {
return;
}
oss << "CS: " << levelmsg << msg << " (" << fs::path{file}.filename().string()
<< ':' << line << ")\n";
wpi::errs() << oss.str();
fmt::print(stderr, "CS: {}: {} ({}:{})\n", levelmsg, msg,
fs::path{file}.filename().string(), line);
}
Instance::Instance()

View File

@@ -46,20 +46,20 @@ static const unsigned char dhtData[] = {
0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};
bool IsJpeg(wpi::StringRef data) {
bool IsJpeg(std::string_view data) {
if (data.size() < 11) {
return false;
}
// Check for valid SOI
auto bytes = data.bytes_begin();
auto bytes = reinterpret_cast<const unsigned char*>(data.data());
if (bytes[0] != 0xff || bytes[1] != 0xd8) {
return false;
}
return true;
}
bool GetJpegSize(wpi::StringRef data, int* width, int* height) {
bool GetJpegSize(std::string_view data, int* width, int* height) {
if (!IsJpeg(data)) {
return false;
}
@@ -69,7 +69,7 @@ bool GetJpegSize(wpi::StringRef data, int* width, int* height) {
if (data.size() < 4) {
return false; // EOF
}
auto bytes = data.bytes_begin();
auto bytes = reinterpret_cast<const unsigned char*>(data.data());
if (bytes[0] != 0xff) {
return false; // not a tag
}
@@ -94,7 +94,7 @@ bool GetJpegSize(wpi::StringRef data, int* width, int* height) {
}
bool JpegNeedsDHT(const char* data, size_t* size, size_t* locSOF) {
wpi::StringRef sdata(data, *size);
std::string_view sdata(data, *size);
if (!IsJpeg(sdata)) {
return false;
}
@@ -107,7 +107,7 @@ bool JpegNeedsDHT(const char* data, size_t* size, size_t* locSOF) {
if (sdata.size() < 4) {
return false; // EOF
}
auto bytes = sdata.bytes_begin();
auto bytes = reinterpret_cast<const unsigned char*>(sdata.data());
if (bytes[0] != 0xff) {
return false; // not a tag
}
@@ -132,9 +132,8 @@ bool JpegNeedsDHT(const char* data, size_t* size, size_t* locSOF) {
return false;
}
wpi::StringRef JpegGetDHT() {
return wpi::StringRef(reinterpret_cast<const char*>(dhtData),
sizeof(dhtData));
std::string_view JpegGetDHT() {
return {reinterpret_cast<const char*>(dhtData), sizeof(dhtData)};
}
static inline void ReadInto(wpi::raw_istream& is, std::string& buf,

View File

@@ -6,8 +6,7 @@
#define CSCORE_JPEGUTIL_H_
#include <string>
#include <wpi/StringRef.h>
#include <string_view>
namespace wpi {
class raw_istream;
@@ -15,13 +14,13 @@ class raw_istream;
namespace cs {
bool IsJpeg(wpi::StringRef data);
bool IsJpeg(std::string_view data);
bool GetJpegSize(wpi::StringRef data, int* width, int* height);
bool GetJpegSize(std::string_view data, int* width, int* height);
bool JpegNeedsDHT(const char* data, size_t* size, size_t* locSOF);
wpi::StringRef JpegGetDHT();
std::string_view JpegGetDHT();
bool ReadJpeg(wpi::raw_istream& is, std::string& buf, int* width, int* height);

View File

@@ -0,0 +1,15 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
#include "Log.h"
void cs::NamedLogV(wpi::Logger& logger, unsigned int level, const char* file,
unsigned int line, std::string_view name,
fmt::string_view format, fmt::format_args args) {
fmt::memory_buffer out;
fmt::format_to(out, "{}: ", name);
fmt::vformat_to(out, format, args);
out.push_back('\0');
logger.DoLog(level, file, line, out.data());
}

View File

@@ -5,29 +5,71 @@
#ifndef CSCORE_LOG_H_
#define CSCORE_LOG_H_
#include <string_view>
#include <wpi/Logger.h>
#define LOG(level, x) WPI_LOG(m_logger, level, x)
namespace cs {
void NamedLogV(wpi::Logger& logger, unsigned int level, const char* file,
unsigned int line, std::string_view name,
fmt::string_view format, fmt::format_args args);
template <typename S, typename... Args>
inline void NamedLog(wpi::Logger& logger, unsigned int level, const char* file,
unsigned int line, std::string_view name, const S& format,
Args&&... args) {
if (logger.HasLogger() && level >= logger.min_level()) {
NamedLogV(logger, level, file, line, name, format,
fmt::make_args_checked<Args...>(format, args...));
}
}
} // namespace cs
#define LOG(level, format, ...) WPI_LOG(m_logger, level, format, __VA_ARGS__)
#undef ERROR
#define ERROR(x) WPI_ERROR(m_logger, x)
#define WARNING(x) WPI_WARNING(m_logger, x)
#define INFO(x) WPI_INFO(m_logger, x)
#define ERROR(format, ...) WPI_ERROR(m_logger, format, __VA_ARGS__)
#define WARNING(format, ...) WPI_WARNING(m_logger, format, __VA_ARGS__)
#define INFO(format, ...) WPI_INFO(m_logger, format, __VA_ARGS__)
#define DEBUG0(x) WPI_DEBUG(m_logger, x)
#define DEBUG1(x) WPI_DEBUG1(m_logger, x)
#define DEBUG2(x) WPI_DEBUG2(m_logger, x)
#define DEBUG3(x) WPI_DEBUG3(m_logger, x)
#define DEBUG4(x) WPI_DEBUG4(m_logger, x)
#define DEBUG0(format, ...) WPI_DEBUG(m_logger, format, __VA_ARGS__)
#define DEBUG1(format, ...) WPI_DEBUG1(m_logger, format, __VA_ARGS__)
#define DEBUG2(format, ...) WPI_DEBUG2(m_logger, format, __VA_ARGS__)
#define DEBUG3(format, ...) WPI_DEBUG3(m_logger, format, __VA_ARGS__)
#define DEBUG4(format, ...) WPI_DEBUG4(m_logger, format, __VA_ARGS__)
#define SERROR(x) ERROR(GetName() << ": " << x)
#define SWARNING(x) WARNING(GetName() << ": " << x)
#define SINFO(x) INFO(GetName() << ": " << x)
#define SLOG(level, format, ...) \
NamedLog(m_logger, level, __FILE__, __LINE__, GetName(), FMT_STRING(format), \
__VA_ARGS__)
#define SDEBUG(x) DEBUG0(GetName() << ": " << x)
#define SDEBUG1(x) DEBUG1(GetName() << ": " << x)
#define SDEBUG2(x) DEBUG2(GetName() << ": " << x)
#define SDEBUG3(x) DEBUG3(GetName() << ": " << x)
#define SDEBUG4(x) DEBUG4(GetName() << ": " << x)
#define SERROR(format, ...) SLOG(::wpi::WPI_LOG_ERROR, format, __VA_ARGS__)
#define SWARNING(format, ...) SLOG(::wpi::WPI_LOG_WARNING, format, __VA_ARGS__)
#define SINFO(format, ...) SLOG(::wpi::WPI_LOG_INFO, format, __VA_ARGS__)
#ifdef NDEBUG
#define SDEBUG(format, ...) \
do { \
} while (0)
#define SDEBUG1(format, ...) \
do { \
} while (0)
#define SDEBUG2(format, ...) \
do { \
} while (0)
#define SDEBUG3(format, ...) \
do { \
} while (0)
#define SDEBUG4(format, ...) \
do { \
} while (0)
#else
#define SDEBUG(format, ...) SLOG(::wpi::WPI_LOG_DEBUG, format, __VA_ARGS__)
#define SDEBUG1(format, ...) SLOG(::wpi::WPI_LOG_DEBUG1, format, __VA_ARGS__)
#define SDEBUG2(format, ...) SLOG(::wpi::WPI_LOG_DEBUG2, format, __VA_ARGS__)
#define SDEBUG3(format, ...) SLOG(::wpi::WPI_LOG_DEBUG3, format, __VA_ARGS__)
#define SDEBUG4(format, ...) SLOG(::wpi::WPI_LOG_DEBUG4, format, __VA_ARGS__)
#endif
#endif // CSCORE_LOG_H_

View File

@@ -6,9 +6,12 @@
#include <chrono>
#include <fmt/format.h>
#include <wpi/HttpUtil.h>
#include <wpi/SmallString.h>
#include <wpi/StringExtras.h>
#include <wpi/TCPAcceptor.h>
#include <wpi/fmt/raw_ostream.h>
#include <wpi/raw_socket_istream.h>
#include <wpi/raw_socket_ostream.h>
@@ -72,13 +75,13 @@ static const char* endRootPage = "</div></body></html>";
class MjpegServerImpl::ConnThread : public wpi::SafeThread {
public:
explicit ConnThread(const wpi::Twine& name, wpi::Logger& logger)
: m_name(name.str()), m_logger(logger) {}
explicit ConnThread(std::string_view name, wpi::Logger& logger)
: m_name(name), m_logger(logger) {}
void Main() override;
bool ProcessCommand(wpi::raw_ostream& os, SourceImpl& source,
wpi::StringRef parameters, bool respond);
std::string_view parameters, bool respond);
void SendJSON(wpi::raw_ostream& os, SourceImpl& source, bool header);
void SendHTMLHeadTitle(wpi::raw_ostream& os) const;
void SendHTML(wpi::raw_ostream& os, SourceImpl& source, bool header);
@@ -99,7 +102,7 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread {
std::string m_name;
wpi::Logger& m_logger;
wpi::StringRef GetName() { return m_name; }
std::string_view GetName() { return m_name; }
std::shared_ptr<SourceImpl> GetSource() {
std::scoped_lock lock(m_mutex);
@@ -130,10 +133,9 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread {
// Using cached pictures would lead to showing old/outdated pictures.
// Many browsers seem to ignore, or at least not always obey, those headers.
static void SendHeader(wpi::raw_ostream& os, int code,
const wpi::Twine& codeText,
const wpi::Twine& contentType,
const wpi::Twine& extra = wpi::Twine{}) {
os << "HTTP/1.0 " << code << ' ' << codeText << "\r\n";
std::string_view codeText, std::string_view contentType,
std::string_view extra = {}) {
fmt::print(os, "HTTP/1.0 {} {}\r\n", code, codeText);
os << "Connection: close\r\n"
"Server: CameraServer/1.0\r\n"
"Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, "
@@ -142,10 +144,8 @@ static void SendHeader(wpi::raw_ostream& os, int code,
"Expires: Mon, 3 Jan 2000 12:34:56 GMT\r\n";
os << "Content-Type: " << contentType << "\r\n";
os << "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Methods: *\r\n";
wpi::SmallString<128> extraBuf;
wpi::StringRef extraStr = extra.toStringRef(extraBuf);
if (!extraStr.empty()) {
os << extraStr << "\r\n";
if (!extra.empty()) {
os << extra << "\r\n";
}
os << "\r\n"; // header ends with a blank line
}
@@ -154,8 +154,8 @@ static void SendHeader(wpi::raw_ostream& os, int code,
// @param code HTTP error code (e.g. 404)
// @param message Additional message text
static void SendError(wpi::raw_ostream& os, int code,
const wpi::Twine& message) {
wpi::StringRef codeText, extra, baseMessage;
std::string_view message) {
std::string_view codeText, extra, baseMessage;
switch (code) {
case 401:
codeText = "Unauthorized";
@@ -195,66 +195,61 @@ static void SendError(wpi::raw_ostream& os, int code,
// Perform a command specified by HTTP GET parameters.
bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
SourceImpl& source,
wpi::StringRef parameters,
std::string_view parameters,
bool respond) {
wpi::SmallString<256> responseBuf;
wpi::raw_svector_ostream response{responseBuf};
// command format: param1=value1&param2=value2...
while (!parameters.empty()) {
// split out next param and value
wpi::StringRef rawParam, rawValue;
std::tie(rawParam, parameters) = parameters.split('&');
std::string_view rawParam, rawValue;
std::tie(rawParam, parameters) = wpi::split(parameters, '&');
if (rawParam.empty()) {
continue; // ignore "&&"
}
std::tie(rawParam, rawValue) = rawParam.split('=');
std::tie(rawParam, rawValue) = wpi::split(rawParam, '=');
if (rawParam.empty() || rawValue.empty()) {
continue; // ignore "param="
}
SDEBUG4("HTTP parameter \"" << rawParam << "\" value \"" << rawValue
<< "\"");
SDEBUG4("HTTP parameter \"{}\" value \"{}\"", rawParam, rawValue);
// unescape param
bool error = false;
wpi::SmallString<64> paramBuf;
wpi::StringRef param = wpi::UnescapeURI(rawParam, paramBuf, &error);
std::string_view param = wpi::UnescapeURI(rawParam, paramBuf, &error);
if (error) {
wpi::SmallString<128> error;
wpi::raw_svector_ostream oss{error};
oss << "could not unescape parameter \"" << rawParam << "\"";
SendError(os, 500, error.str());
SDEBUG(error.str());
auto estr = fmt::format("could not unescape parameter \"{}\"", rawParam);
SendError(os, 500, estr);
SDEBUG("{}", estr);
return false;
}
// unescape value
wpi::SmallString<64> valueBuf;
wpi::StringRef value = wpi::UnescapeURI(rawValue, valueBuf, &error);
std::string_view value = wpi::UnescapeURI(rawValue, valueBuf, &error);
if (error) {
wpi::SmallString<128> error;
wpi::raw_svector_ostream oss{error};
oss << "could not unescape value \"" << rawValue << "\"";
SendError(os, 500, error.str());
SDEBUG(error.str());
auto estr = fmt::format("could not unescape value \"{}\"", rawValue);
SendError(os, 500, estr);
SDEBUG("{}", estr);
return false;
}
// Handle resolution, compression, and FPS. These are handled locally
// rather than passed to the source.
if (param == "resolution") {
wpi::StringRef widthStr, heightStr;
std::tie(widthStr, heightStr) = value.split('x');
int width, height;
if (widthStr.getAsInteger(10, width)) {
auto [widthStr, heightStr] = wpi::split(value, 'x');
int width = wpi::parse_integer<int>(widthStr, 10).value_or(-1);
int height = wpi::parse_integer<int>(heightStr, 10).value_or(-1);
if (width < 0) {
response << param << ": \"width is not an integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" width \"" << widthStr
<< "\" is not an integer");
SWARNING("HTTP parameter \"{}\" width \"{}\" is not an integer", param,
widthStr);
continue;
}
if (heightStr.getAsInteger(10, height)) {
if (height < 0) {
response << param << ": \"height is not an integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" height \"" << heightStr
<< "\" is not an integer");
SWARNING("HTTP parameter \"{}\" height \"{}\" is not an integer", param,
heightStr);
continue;
}
m_width = width;
@@ -264,29 +259,25 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
}
if (param == "fps") {
int fps;
if (value.getAsInteger(10, fps)) {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" value \"" << value
<< "\" is not an integer");
continue;
} else {
m_fps = fps;
if (auto v = wpi::parse_integer<int>(value, 10)) {
m_fps = v.value();
response << param << ": \"ok\"\r\n";
} else {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"{}\" value \"{}\" is not an integer", param,
value);
}
continue;
}
if (param == "compression") {
int compression;
if (value.getAsInteger(10, compression)) {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" value \"" << value
<< "\" is not an integer");
continue;
} else {
m_compression = compression;
if (auto v = wpi::parse_integer<int>(value, 10)) {
m_compression = v.value();
response << param << ": \"ok\"\r\n";
} else {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"{}\" value \"{}\" is not an integer", param,
value);
}
continue;
}
@@ -300,7 +291,7 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
auto prop = source.GetPropertyIndex(param);
if (!prop) {
response << param << ": \"ignored\"\r\n";
SWARNING("ignoring HTTP parameter \"" << param << "\"");
SWARNING("ignoring HTTP parameter \"{}\"", param);
continue;
}
@@ -310,21 +301,20 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
case CS_PROP_BOOLEAN:
case CS_PROP_INTEGER:
case CS_PROP_ENUM: {
int val = 0;
if (value.getAsInteger(10, val)) {
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"" << param << "\" value \"" << value
<< "\" is not an integer");
if (auto v = wpi::parse_integer<int>(value, 10)) {
fmt::print(response, "{}: {}\r\n", param, v.value());
SDEBUG4("HTTP parameter \"{}\" value {}", param, value);
source.SetProperty(prop, v.value(), &status);
} else {
response << param << ": " << val << "\r\n";
SDEBUG4("HTTP parameter \"" << param << "\" value " << value);
source.SetProperty(prop, val, &status);
response << param << ": \"invalid integer\"\r\n";
SWARNING("HTTP parameter \"{}\" value \"{}\" is not an integer",
param, value);
}
break;
}
case CS_PROP_STRING: {
response << param << ": \"ok\"\r\n";
SDEBUG4("HTTP parameter \"" << param << "\" value \"" << value << "\"");
SDEBUG4("HTTP parameter \"{}\" value \"{}\"", param, value);
source.SetStringProperty(prop, value, &status);
break;
}
@@ -362,17 +352,17 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
for (auto prop : source.EnumerateProperties(properties_vec, &status)) {
wpi::SmallString<128> name_buf;
auto name = source.GetPropertyName(prop, name_buf, &status);
if (name.startswith("raw_")) {
if (wpi::starts_with(name, "raw_")) {
continue;
}
auto kind = source.GetPropertyKind(prop);
os << "<p />"
<< "<label for=\"" << name << "\">" << name << "</label>\n";
fmt::print(os, "<p /><label for=\"{0}\">{0}</label>\n", name);
switch (kind) {
case CS_PROP_BOOLEAN:
os << "<input id=\"" << name
<< "\" type=\"checkbox\" onclick=\"update('" << name
<< "', this.checked ? 1 : 0)\" ";
fmt::print(os,
"<input id=\"{0}\" type=\"checkbox\" "
"onclick=\"update('{0}', this.checked ? 1 : 0)\" ",
name);
if (source.GetProperty(prop, &status) != 0) {
os << "checked />\n";
} else {
@@ -384,12 +374,13 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
auto min = source.GetPropertyMin(prop, &status);
auto max = source.GetPropertyMax(prop, &status);
auto step = source.GetPropertyStep(prop, &status);
os << "<input type=\"range\" min=\"" << min << "\" max=\"" << max
<< "\" value=\"" << valI << "\" id=\"" << name << "\" step=\""
<< step << "\" oninput=\"updateInt('#" << name << "op', '" << name
<< "', value)\" />\n";
os << "<output for=\"" << name << "\" id=\"" << name << "op\">" << valI
<< "</output>\n";
fmt::print(os,
"<input type=\"range\" min=\"{1}\" max=\"{2}\" "
"value=\"{3}\" id=\"{0}\" step=\"{4}\" "
"oninput=\"updateInt('#{0}op', '{0}', value)\" />\n",
name, min, max, valI, step);
fmt::print(os, "<output for=\"{0}\" id=\"{0}op\">{1}</output>\n", name,
valI);
break;
}
case CS_PROP_ENUM: {
@@ -404,26 +395,30 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
// replace any non-printable characters in name with spaces
wpi::SmallString<128> ch_name;
for (char ch : *choice) {
ch_name.push_back(std::isprint(ch) ? ch : ' ');
ch_name.push_back(wpi::isPrint(ch) ? ch : ' ');
}
os << "<input id=\"" << name << j << "\" type=\"radio\" name=\""
<< name << "\" value=\"" << ch_name << "\" onclick=\"update('"
<< name << "', " << j << ")\"";
fmt::print(os,
"<input id=\"{0}{1}\" type=\"radio\" name=\"{0}\" "
"value=\"{2}\" onclick=\"update('{0}', {1})\"",
name, j, ch_name);
if (j == valE) {
os << " checked";
}
os << " /><label for=\"" << name << j << "\">" << ch_name
<< "</label>\n";
fmt::print(os, " /><label for=\"{}{}\">{}</label>\n", name, j,
ch_name);
}
break;
}
case CS_PROP_STRING: {
wpi::SmallString<128> strval_buf;
os << "<input type=\"text\" id=\"" << name << "box\" name=\"" << name
<< "\" value=\""
<< source.GetStringProperty(prop, strval_buf, &status) << "\" />\n";
os << "<input type=\"button\" value =\"Submit\" onclick=\"update('"
<< name << "', " << name << "box.value)\" />\n";
fmt::print(os,
"<input type=\"text\" id=\"{0}box\" name=\"{0}\" "
"value=\"{1}\" />\n",
name, source.GetStringProperty(prop, strval_buf, &status));
fmt::print(os,
"<input type=\"button\" value =\"Submit\" "
"onclick=\"update('{0}', {0}box.value)\" />\n",
name);
break;
}
default:
@@ -469,10 +464,8 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
os << "unknown";
break;
}
os << "</td><td>" << mode.width;
os << "</td><td>" << mode.height;
os << "</td><td>" << mode.fps;
os << "</td></tr>";
fmt::print(os, "</td><td>{}</td><td>{}</td><td>{}</td></tr>", mode.width,
mode.height, mode.fps);
}
os << "</table>\n";
os << endRootPage << "\r\n";
@@ -500,20 +493,21 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
wpi::SmallString<128> name_buf;
auto name = source.GetPropertyName(prop, name_buf, &status);
auto kind = source.GetPropertyKind(prop);
os << "\n\"name\": \"" << name << '"';
os << ",\n\"id\": \"" << prop << '"';
os << ",\n\"type\": \"" << kind << '"';
os << ",\n\"min\": \"" << source.GetPropertyMin(prop, &status) << '"';
os << ",\n\"max\": \"" << source.GetPropertyMax(prop, &status) << '"';
os << ",\n\"step\": \"" << source.GetPropertyStep(prop, &status) << '"';
os << ",\n\"default\": \"" << source.GetPropertyDefault(prop, &status)
<< '"';
fmt::print(os, "\n\"name\": \"{}\"", name);
fmt::print(os, ",\n\"id\": \"{}\"", prop);
fmt::print(os, ",\n\"type\": \"{}\"", kind);
fmt::print(os, ",\n\"min\": \"{}\"", source.GetPropertyMin(prop, &status));
fmt::print(os, ",\n\"max\": \"{}\"", source.GetPropertyMax(prop, &status));
fmt::print(os, ",\n\"step\": \"{}\"",
source.GetPropertyStep(prop, &status));
fmt::print(os, ",\n\"default\": \"{}\"",
source.GetPropertyDefault(prop, &status));
os << ",\n\"value\": \"";
switch (kind) {
case CS_PROP_BOOLEAN:
case CS_PROP_INTEGER:
case CS_PROP_ENUM:
os << source.GetProperty(prop, &status);
fmt::print(os, "{}", source.GetProperty(prop, &status));
break;
case CS_PROP_STRING: {
wpi::SmallString<128> strval_buf;
@@ -543,7 +537,7 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
for (char ch : *choice) {
ch_name.push_back(std::isprint(ch) ? ch : ' ');
}
os << '"' << j << "\": \"" << ch_name << '"';
fmt::print(os, "\"{}\": \"{}\"", j, ch_name);
}
os << "}\n";
}
@@ -579,29 +573,26 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
os << "unknown";
break;
}
os << "\",\n\"width\": \"" << mode.width << '"';
os << ",\n\"height\": \"" << mode.height << '"';
os << ",\n\"fps\": \"" << mode.fps << '"';
fmt::print(os, "\",\n\"width\": \"{}\"", mode.width);
fmt::print(os, ",\n\"height\": \"{}\"", mode.height);
fmt::print(os, ",\n\"fps\": \"{}\"", mode.fps);
os << '}';
}
os << "\n]\n}\n";
os.flush();
}
MjpegServerImpl::MjpegServerImpl(const wpi::Twine& name, wpi::Logger& logger,
MjpegServerImpl::MjpegServerImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
const wpi::Twine& listenAddress, int port,
std::string_view listenAddress, int port,
std::unique_ptr<wpi::NetworkAcceptor> acceptor)
: SinkImpl{name, logger, notifier, telemetry},
m_listenAddress(listenAddress.str()),
m_listenAddress(listenAddress),
m_port(port),
m_acceptor{std::move(acceptor)} {
m_active = true;
wpi::SmallString<128> descBuf;
wpi::raw_svector_ostream desc{descBuf};
desc << "HTTP Server on port " << port;
SetDescription(desc.str());
SetDescription(fmt::format("HTTP Server on port {}", port));
// Create properties
m_widthProp = CreateProperty("width", [] {
@@ -659,7 +650,7 @@ void MjpegServerImpl::Stop() {
// Send HTTP response and a stream of JPG-frames
void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
if (m_noStreaming) {
SERROR("Too many simultaneous client streams");
SERROR("{}", "Too many simultaneous client streams");
SendError(os, 503, "Too many simultaneous streams");
return;
}
@@ -672,7 +663,7 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
SendHeader(oss, 200, "OK", "multipart/x-mixed-replace;boundary=" BOUNDARY);
os << oss.str();
SDEBUG("Headers send, sending stream now");
SDEBUG("{}", "Headers send, sending stream now");
Frame::Time lastFrameTime = 0;
Frame::Time timePerFrame = 0;
@@ -694,7 +685,7 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
continue;
}
SDEBUG4("waiting for frame");
SDEBUG4("{}", "waiting for frame");
Frame frame = source->GetNextFrame(0.225); // blocks
if (!m_active) {
break;
@@ -757,7 +748,7 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
continue;
}
SDEBUG4("sending frame size=" << size << " addDHT=" << addDHT);
SDEBUG4("sending frame size={} addDHT={}", size, addDHT);
// print the individual mimetype and the length
// sending the content-length fixes random stream disruption observed
@@ -766,18 +757,18 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
double timestamp = lastFrameTime / 1000000.0;
header.clear();
oss << "\r\n--" BOUNDARY "\r\n"
<< "Content-Type: image/jpeg\r\n"
<< "Content-Length: " << size << "\r\n"
<< "X-Timestamp: " << timestamp << "\r\n"
<< "\r\n";
<< "Content-Type: image/jpeg\r\n";
fmt::print(oss, "Content-Length: {}\r\n", size);
fmt::print(oss, "X-Timestamp: {}\r\n", timestamp);
oss << "\r\n";
os << oss.str();
if (addDHT) {
// Insert DHT data immediately before SOF
os << wpi::StringRef(data, locSOF);
os << std::string_view(data, locSOF);
os << JpegGetDHT();
os << wpi::StringRef(data + locSOF, image->size() - locSOF);
os << std::string_view(data + locSOF, image->size() - locSOF);
} else {
os << wpi::StringRef(data, size);
os << std::string_view(data, size);
}
// os.flush();
}
@@ -790,48 +781,50 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
// Read the request string from the stream
wpi::SmallString<128> reqBuf;
wpi::StringRef req = is.getline(reqBuf, 4096);
std::string_view req = is.getline(reqBuf, 4096);
if (is.has_error()) {
SDEBUG("error getting request string");
SDEBUG("{}", "error getting request string");
return;
}
enum { kCommand, kStream, kGetSettings, kGetSourceConfig, kRootPage } kind;
wpi::StringRef parameters;
std::string_view parameters;
size_t pos;
SDEBUG("HTTP request: '" << req << "'\n");
SDEBUG("HTTP request: '{}'\n", req);
// Determine request kind. Most of these are for mjpgstreamer
// compatibility, others are for Axis camera compatibility.
if ((pos = req.find("POST /stream")) != wpi::StringRef::npos) {
if ((pos = req.find("POST /stream")) != std::string_view::npos) {
kind = kStream;
parameters = req.substr(req.find('?', pos + 12)).substr(1);
} else if ((pos = req.find("GET /?action=stream")) != wpi::StringRef::npos) {
} else if ((pos = req.find("GET /?action=stream")) !=
std::string_view::npos) {
kind = kStream;
parameters = req.substr(req.find('&', pos + 19)).substr(1);
} else if ((pos = req.find("GET /stream.mjpg")) != wpi::StringRef::npos) {
} else if ((pos = req.find("GET /stream.mjpg")) != std::string_view::npos) {
kind = kStream;
parameters = req.substr(req.find('?', pos + 16)).substr(1);
} else if (req.find("GET /settings") != wpi::StringRef::npos &&
req.find(".json") != wpi::StringRef::npos) {
} else if (req.find("GET /settings") != std::string_view::npos &&
req.find(".json") != std::string_view::npos) {
kind = kGetSettings;
} else if (req.find("GET /config") != wpi::StringRef::npos &&
req.find(".json") != wpi::StringRef::npos) {
} else if (req.find("GET /config") != std::string_view::npos &&
req.find(".json") != std::string_view::npos) {
kind = kGetSourceConfig;
} else if (req.find("GET /input") != wpi::StringRef::npos &&
req.find(".json") != wpi::StringRef::npos) {
} else if (req.find("GET /input") != std::string_view::npos &&
req.find(".json") != std::string_view::npos) {
kind = kGetSettings;
} else if (req.find("GET /output") != wpi::StringRef::npos &&
req.find(".json") != wpi::StringRef::npos) {
} else if (req.find("GET /output") != std::string_view::npos &&
req.find(".json") != std::string_view::npos) {
kind = kGetSettings;
} else if ((pos = req.find("GET /?action=command")) != wpi::StringRef::npos) {
} else if ((pos = req.find("GET /?action=command")) !=
std::string_view::npos) {
kind = kCommand;
parameters = req.substr(req.find('&', pos + 20)).substr(1);
} else if (req.find("GET / ") != wpi::StringRef::npos || req == "GET /\n") {
} else if (req.find("GET / ") != std::string_view::npos || req == "GET /\n") {
kind = kRootPage;
} else {
SDEBUG("HTTP request resource not found");
SDEBUG("{}", "HTTP request resource not found");
SendError(os, 404, "Resource not found");
return;
}
@@ -841,13 +834,13 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
"-=&1234567890%./");
parameters = parameters.substr(0, pos);
SDEBUG("command parameters: \"" << parameters << "\"");
SDEBUG("command parameters: \"{}\"", parameters);
// Read the rest of the HTTP request.
// The end of the request is marked by a single, empty line
wpi::SmallString<128> lineBuf;
for (;;) {
if (is.getline(lineBuf, 4096).startswith("\n")) {
if (wpi::starts_with(is.getline(lineBuf, 4096), "\n")) {
break;
}
if (is.has_error()) {
@@ -859,7 +852,7 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
switch (kind) {
case kStream:
if (auto source = GetSource()) {
SDEBUG("request for stream " << source->GetName());
SDEBUG("request for stream {}", source->GetName());
if (!ProcessCommand(os, *source, parameters, false)) {
return;
}
@@ -873,11 +866,11 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
SendHeader(os, 200, "OK", "text/plain");
os << "Ignored due to no connected source."
<< "\r\n";
SDEBUG("Ignored due to no connected source.");
SDEBUG("{}", "Ignored due to no connected source.");
}
break;
case kGetSettings:
SDEBUG("request for JSON file");
SDEBUG("{}", "request for JSON file");
if (auto source = GetSource()) {
SendJSON(os, *source, true);
} else {
@@ -885,7 +878,7 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
}
break;
case kGetSourceConfig:
SDEBUG("request for JSON file");
SDEBUG("{}", "request for JSON file");
if (auto source = GetSource()) {
SendHeader(os, 200, "OK", "application/json");
CS_Status status = CS_OK;
@@ -896,7 +889,7 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
}
break;
case kRootPage:
SDEBUG("request for root page");
SDEBUG("{}", "request for root page");
SendHeader(os, 200, "OK", "text/html");
if (auto source = GetSource()) {
SendHTML(os, *source, false);
@@ -907,7 +900,7 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
break;
}
SDEBUG("leaving HTTP client thread");
SDEBUG("{}", "leaving HTTP client thread");
}
// worker thread for clients that connected to this server
@@ -934,7 +927,7 @@ void MjpegServerImpl::ServerThreadMain() {
return;
}
SDEBUG("waiting for clients to connect");
SDEBUG("{}", "waiting for clients to connect");
while (m_active) {
auto stream = m_acceptor->accept();
if (!stream) {
@@ -945,7 +938,7 @@ void MjpegServerImpl::ServerThreadMain() {
return;
}
SDEBUG("client connection from " << stream->getPeerIP());
SDEBUG("client connection from {}", stream->getPeerIP());
auto source = GetSource();
@@ -984,7 +977,7 @@ void MjpegServerImpl::ServerThreadMain() {
thr->m_cond.notify_one();
}
SDEBUG("leaving server thread");
SDEBUG("{}", "leaving server thread");
}
void MjpegServerImpl::SetSourceImpl(std::shared_ptr<SourceImpl> source) {
@@ -1007,19 +1000,15 @@ void MjpegServerImpl::SetSourceImpl(std::shared_ptr<SourceImpl> source) {
namespace cs {
CS_Sink CreateMjpegServer(const wpi::Twine& name,
const wpi::Twine& listenAddress, int port,
CS_Status* status) {
CS_Sink CreateMjpegServer(std::string_view name, std::string_view listenAddress,
int port, CS_Status* status) {
auto& inst = Instance::GetInstance();
wpi::SmallString<128> listenAddressBuf;
return inst.CreateSink(
CS_SINK_MJPEG,
std::make_shared<MjpegServerImpl>(
name, inst.logger, inst.notifier, inst.telemetry, listenAddress, port,
std::unique_ptr<wpi::NetworkAcceptor>(new wpi::TCPAcceptor(
port,
listenAddress.toNullTerminatedStringRef(listenAddressBuf).data(),
inst.logger))));
std::unique_ptr<wpi::NetworkAcceptor>(
new wpi::TCPAcceptor(port, listenAddress, inst.logger))));
}
std::string GetMjpegServerListenAddress(CS_Sink sink, CS_Status* status) {

View File

@@ -8,6 +8,7 @@
#include <atomic>
#include <memory>
#include <string>
#include <string_view>
#include <thread>
#include <vector>
@@ -15,7 +16,6 @@
#include <wpi/NetworkStream.h>
#include <wpi/SafeThread.h>
#include <wpi/SmallVector.h>
#include <wpi/Twine.h>
#include <wpi/raw_istream.h>
#include <wpi/raw_ostream.h>
#include <wpi/raw_socket_ostream.h>
@@ -28,9 +28,9 @@ class SourceImpl;
class MjpegServerImpl : public SinkImpl {
public:
MjpegServerImpl(const wpi::Twine& name, wpi::Logger& logger,
MjpegServerImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
const wpi::Twine& listenAddress, int port,
std::string_view listenAddress, int port,
std::unique_ptr<wpi::NetworkAcceptor> acceptor);
~MjpegServerImpl() override;

View File

@@ -32,7 +32,7 @@ unsigned int Notifier::AddPolled(unsigned int pollerUid, int eventMask) {
return DoAdd(pollerUid, eventMask);
}
void Notifier::NotifySource(const wpi::Twine& name, CS_Source source,
void Notifier::NotifySource(std::string_view name, CS_Source source,
CS_EventKind kind) {
Send(UINT_MAX, name, source, static_cast<RawEvent::Kind>(kind));
}
@@ -49,9 +49,9 @@ void Notifier::NotifySourceVideoMode(const SourceImpl& source,
}
void Notifier::NotifySourceProperty(const SourceImpl& source, CS_EventKind kind,
const wpi::Twine& propertyName,
int property, CS_PropertyKind propertyKind,
int value, const wpi::Twine& valueStr) {
std::string_view propertyName, int property,
CS_PropertyKind propertyKind, int value,
std::string_view valueStr) {
auto handleData = Instance::GetInstance().FindSource(source);
Send(UINT_MAX, propertyName, handleData.first,
static_cast<RawEvent::Kind>(kind),
@@ -59,7 +59,7 @@ void Notifier::NotifySourceProperty(const SourceImpl& source, CS_EventKind kind,
value, valueStr);
}
void Notifier::NotifySink(const wpi::Twine& name, CS_Sink sink,
void Notifier::NotifySink(std::string_view name, CS_Sink sink,
CS_EventKind kind) {
Send(UINT_MAX, name, sink, static_cast<RawEvent::Kind>(kind));
}
@@ -69,7 +69,7 @@ void Notifier::NotifySink(const SinkImpl& sink, CS_EventKind kind) {
NotifySink(sink.GetName(), handleData.first, kind);
}
void Notifier::NotifySinkSourceChanged(const wpi::Twine& name, CS_Sink sink,
void Notifier::NotifySinkSourceChanged(std::string_view name, CS_Sink sink,
CS_Source source) {
RawEvent event{name, sink, RawEvent::kSinkSourceChanged};
event.sourceHandle = source;
@@ -77,9 +77,9 @@ void Notifier::NotifySinkSourceChanged(const wpi::Twine& name, CS_Sink sink,
}
void Notifier::NotifySinkProperty(const SinkImpl& sink, CS_EventKind kind,
const wpi::Twine& propertyName, int property,
std::string_view propertyName, int property,
CS_PropertyKind propertyKind, int value,
const wpi::Twine& valueStr) {
std::string_view valueStr) {
auto handleData = Instance::GetInstance().FindSink(sink);
Send(UINT_MAX, propertyName, handleData.first,
static_cast<RawEvent::Kind>(kind),

View File

@@ -65,22 +65,21 @@ class Notifier : public wpi::CallbackManager<Notifier, impl::NotifierThread> {
unsigned int AddPolled(unsigned int pollerUid, int eventMask);
// Notification events
void NotifySource(const wpi::Twine& name, CS_Source source,
CS_EventKind kind);
void NotifySource(std::string_view name, CS_Source source, CS_EventKind kind);
void NotifySource(const SourceImpl& source, CS_EventKind kind);
void NotifySourceVideoMode(const SourceImpl& source, const VideoMode& mode);
void NotifySourceProperty(const SourceImpl& source, CS_EventKind kind,
const wpi::Twine& propertyName, int property,
std::string_view propertyName, int property,
CS_PropertyKind propertyKind, int value,
const wpi::Twine& valueStr);
void NotifySink(const wpi::Twine& name, CS_Sink sink, CS_EventKind kind);
std::string_view valueStr);
void NotifySink(std::string_view name, CS_Sink sink, CS_EventKind kind);
void NotifySink(const SinkImpl& sink, CS_EventKind kind);
void NotifySinkSourceChanged(const wpi::Twine& name, CS_Sink sink,
void NotifySinkSourceChanged(std::string_view name, CS_Sink sink,
CS_Source source);
void NotifySinkProperty(const SinkImpl& sink, CS_EventKind kind,
const wpi::Twine& propertyName, int property,
std::string_view propertyName, int property,
CS_PropertyKind propertyKind, int value,
const wpi::Twine& valueStr);
std::string_view valueStr);
void NotifyNetworkInterfacesChanged();
void NotifyTelemetryUpdated();
void NotifyUsbCamerasChanged();

View File

@@ -11,15 +11,14 @@
using namespace cs;
int PropertyContainer::GetPropertyIndex(const wpi::Twine& name) const {
int PropertyContainer::GetPropertyIndex(std::string_view name) const {
// We can't fail, so instead we create a new index if caching fails.
CS_Status status = 0;
if (!m_properties_cached) {
CacheProperties(&status);
}
std::scoped_lock lock(m_mutex);
wpi::SmallVector<char, 64> nameBuf;
int& ndx = m_properties[name.toStringRef(nameBuf)];
int& ndx = m_properties[name];
if (ndx == 0) {
// create a new index
ndx = m_propertyData.size() + 1;
@@ -55,7 +54,7 @@ CS_PropertyKind PropertyContainer::GetPropertyKind(int property) const {
return prop->propKind;
}
wpi::StringRef PropertyContainer::GetPropertyName(
std::string_view PropertyContainer::GetPropertyName(
int property, wpi::SmallVectorImpl<char>& buf, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) {
return {};
@@ -108,7 +107,7 @@ void PropertyContainer::SetProperty(int property, int value,
return;
}
UpdatePropertyValue(property, false, value, wpi::Twine{});
UpdatePropertyValue(property, false, value, {});
}
int PropertyContainer::GetPropertyMin(int property, CS_Status* status) const {
@@ -164,7 +163,7 @@ int PropertyContainer::GetPropertyDefault(int property,
return prop->defaultValue;
}
wpi::StringRef PropertyContainer::GetStringProperty(
std::string_view PropertyContainer::GetStringProperty(
int property, wpi::SmallVectorImpl<char>& buf, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) {
return {};
@@ -181,10 +180,10 @@ wpi::StringRef PropertyContainer::GetStringProperty(
}
buf.clear();
buf.append(prop->valueStr.begin(), prop->valueStr.end());
return wpi::StringRef(buf.data(), buf.size());
return {buf.data(), buf.size()};
}
void PropertyContainer::SetStringProperty(int property, const wpi::Twine& value,
void PropertyContainer::SetStringProperty(int property, std::string_view value,
CS_Status* status) {
std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
@@ -225,7 +224,7 @@ std::vector<std::string> PropertyContainer::GetEnumPropertyChoices(
}
std::unique_ptr<PropertyImpl> PropertyContainer::CreateEmptyProperty(
const wpi::Twine& name) const {
std::string_view name) const {
return std::make_unique<PropertyImpl>(name);
}
@@ -237,16 +236,15 @@ bool PropertyContainer::CacheProperties(CS_Status* status) const {
bool PropertyContainer::SetPropertiesJson(const wpi::json& config,
wpi::Logger& logger,
wpi::StringRef logName,
std::string_view logName,
CS_Status* status) {
for (auto&& prop : config) {
std::string name;
try {
name = prop.at("name").get<std::string>();
} catch (const wpi::json::exception& e) {
WPI_WARNING(logger,
logName << ": SetConfigJson: could not read property name: "
<< e.what());
WPI_WARNING(logger, "{}: SetConfigJson: could not read property name: {}",
logName, e.what());
continue;
}
int n = GetPropertyIndex(name);
@@ -254,24 +252,24 @@ bool PropertyContainer::SetPropertiesJson(const wpi::json& config,
auto& v = prop.at("value");
if (v.is_string()) {
std::string val = v.get<std::string>();
WPI_INFO(logger, logName << ": SetConfigJson: setting property '"
<< name << "' to '" << val << '\'');
WPI_INFO(logger, "{}: SetConfigJson: setting property '{}' to '{}'",
logName, name, val);
SetStringProperty(n, val, status);
} else if (v.is_boolean()) {
bool val = v.get<bool>();
WPI_INFO(logger, logName << ": SetConfigJson: setting property '"
<< name << "' to " << val);
WPI_INFO(logger, "{}: SetConfigJson: setting property '{}' to {}",
logName, name, val);
SetProperty(n, val, status);
} else {
int val = v.get<int>();
WPI_INFO(logger, logName << ": SetConfigJson: setting property '"
<< name << "' to " << val);
WPI_INFO(logger, "{}: SetConfigJson: setting property '{}' to {}",
logName, name, val);
SetProperty(n, val, status);
}
} catch (const wpi::json::exception& e) {
WPI_WARNING(logger,
logName << ": SetConfigJson: could not read property value: "
<< e.what());
"{}: SetConfigJson: could not read property value: {}",
logName, e.what());
continue;
}
}

View File

@@ -9,13 +9,11 @@
#include <cstddef>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <wpi/ArrayRef.h>
#include <wpi/SmallVector.h>
#include <wpi/StringMap.h>
#include <wpi/StringRef.h>
#include <wpi/Twine.h>
#include <wpi/mutex.h>
#include "PropertyImpl.h"
@@ -23,6 +21,8 @@
namespace wpi {
class Logger;
template <typename T>
class SmallVectorImpl;
class json;
} // namespace wpi
@@ -32,28 +32,29 @@ class PropertyContainer {
public:
virtual ~PropertyContainer() = default;
int GetPropertyIndex(const wpi::Twine& name) const;
int GetPropertyIndex(std::string_view name) const;
wpi::ArrayRef<int> EnumerateProperties(wpi::SmallVectorImpl<int>& vec,
CS_Status* status) const;
CS_PropertyKind GetPropertyKind(int property) const;
wpi::StringRef GetPropertyName(int property, wpi::SmallVectorImpl<char>& buf,
CS_Status* status) const;
std::string_view GetPropertyName(int property,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) const;
int GetProperty(int property, CS_Status* status) const;
virtual void SetProperty(int property, int value, CS_Status* status);
int GetPropertyMin(int property, CS_Status* status) const;
int GetPropertyMax(int property, CS_Status* status) const;
int GetPropertyStep(int property, CS_Status* status) const;
int GetPropertyDefault(int property, CS_Status* status) const;
wpi::StringRef GetStringProperty(int property,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) const;
virtual void SetStringProperty(int property, const wpi::Twine& value,
std::string_view GetStringProperty(int property,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) const;
virtual void SetStringProperty(int property, std::string_view value,
CS_Status* status);
std::vector<std::string> GetEnumPropertyChoices(int property,
CS_Status* status) const;
bool SetPropertiesJson(const wpi::json& config, wpi::Logger& logger,
wpi::StringRef logName, CS_Status* status);
std::string_view logName, CS_Status* status);
wpi::json GetPropertiesJsonObject(CS_Status* status);
protected:
@@ -76,10 +77,9 @@ class PropertyContainer {
// @tparam NewFunc functor that returns a std::unique_ptr<PropertyImpl>
// @tparam UpdateFunc functor that takes a PropertyImpl&.
template <typename NewFunc, typename UpdateFunc>
int CreateOrUpdateProperty(const wpi::Twine& name, NewFunc newFunc,
int CreateOrUpdateProperty(std::string_view name, NewFunc newFunc,
UpdateFunc updateFunc) {
wpi::SmallVector<char, 64> nameBuf;
int& ndx = m_properties[name.toStringRef(nameBuf)];
int& ndx = m_properties[name];
if (ndx == 0) {
// create a new index
ndx = m_propertyData.size() + 1;
@@ -91,7 +91,7 @@ class PropertyContainer {
return ndx;
}
template <typename NewFunc>
int CreateProperty(const wpi::Twine& name, NewFunc newFunc) {
int CreateProperty(std::string_view name, NewFunc newFunc) {
return CreateOrUpdateProperty(name, newFunc, [](PropertyImpl&) {});
}
@@ -100,7 +100,7 @@ class PropertyContainer {
// Note: called with m_mutex held.
// The default implementation simply creates a PropertyImpl object.
virtual std::unique_ptr<PropertyImpl> CreateEmptyProperty(
const wpi::Twine& name) const;
std::string_view name) const;
// Cache properties. Implementations must return false and set status to
// CS_SOURCE_IS_DISCONNECTED if not possible to cache.
@@ -111,7 +111,7 @@ class PropertyContainer {
// Update property value; must be called with m_mutex held.
virtual void UpdatePropertyValue(int property, bool setString, int value,
const wpi::Twine& valueStr) = 0;
std::string_view valueStr) = 0;
// Whether CacheProperties() has been successful at least once (and thus
// should not be called again)

View File

@@ -6,18 +6,18 @@
using namespace cs;
PropertyImpl::PropertyImpl(const wpi::Twine& name_) : name{name_.str()} {}
PropertyImpl::PropertyImpl(const wpi::Twine& name_, CS_PropertyKind kind_,
PropertyImpl::PropertyImpl(std::string_view name_) : name{name_} {}
PropertyImpl::PropertyImpl(std::string_view name_, CS_PropertyKind kind_,
int step_, int defaultValue_, int value_)
: name{name_.str()},
: name{name_},
propKind{kind_},
step{step_},
defaultValue{defaultValue_},
value{value_} {}
PropertyImpl::PropertyImpl(const wpi::Twine& name_, CS_PropertyKind kind_,
PropertyImpl::PropertyImpl(std::string_view name_, CS_PropertyKind kind_,
int minimum_, int maximum_, int step_,
int defaultValue_, int value_)
: name{name_.str()},
: name{name_},
propKind{kind_},
hasMinimum{true},
hasMaximum{true},
@@ -43,11 +43,10 @@ void PropertyImpl::SetValue(int v) {
}
}
void PropertyImpl::SetValue(const wpi::Twine& v) {
void PropertyImpl::SetValue(std::string_view v) {
bool valueChanged = false;
std::string vStr = v.str();
if (valueStr != vStr) {
valueStr = vStr;
if (valueStr != v) {
valueStr = v;
valueChanged = true;
}
bool wasValueSet = valueSet;

View File

@@ -6,11 +6,10 @@
#define CSCORE_PROPERTYIMPL_H_
#include <string>
#include <string_view>
#include <vector>
#include <wpi/Signal.h>
#include <wpi/StringRef.h>
#include <wpi/Twine.h>
#include "cscore_c.h"
@@ -20,17 +19,17 @@ namespace cs {
class PropertyImpl {
public:
PropertyImpl() = default;
explicit PropertyImpl(const wpi::Twine& name_);
PropertyImpl(const wpi::Twine& name_, CS_PropertyKind kind_, int step_,
explicit PropertyImpl(std::string_view name_);
PropertyImpl(std::string_view name_, CS_PropertyKind kind_, int step_,
int defaultValue_, int value_);
PropertyImpl(const wpi::Twine& name_, CS_PropertyKind kind_, int minimum_,
PropertyImpl(std::string_view name_, CS_PropertyKind kind_, int minimum_,
int maximum_, int step_, int defaultValue_, int value_);
virtual ~PropertyImpl() = default;
PropertyImpl(const PropertyImpl& oth) = delete;
PropertyImpl& operator=(const PropertyImpl& oth) = delete;
void SetValue(int v);
void SetValue(const wpi::Twine& v);
void SetValue(std::string_view v);
void SetDefaultValue(int v);
std::string name;

View File

@@ -10,14 +10,14 @@
using namespace cs;
RawSinkImpl::RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
RawSinkImpl::RawSinkImpl(std::string_view 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,
RawSinkImpl::RawSinkImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
std::function<void(uint64_t time)> processFrame)
: SinkImpl{name, logger, notifier, telemetry} {}
@@ -127,7 +127,7 @@ void RawSinkImpl::ThreadMain() {
std::this_thread::sleep_for(std::chrono::seconds(1));
continue;
}
SDEBUG4("waiting for frame");
SDEBUG4("{}", "waiting for frame");
Frame frame = source->GetNextFrame(); // blocks
if (!m_active) {
break;
@@ -143,14 +143,14 @@ void RawSinkImpl::ThreadMain() {
}
namespace cs {
CS_Sink CreateRawSink(const wpi::Twine& name, CS_Status* status) {
CS_Sink CreateRawSink(std::string_view 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,
CS_Sink CreateRawSinkCallback(std::string_view name,
std::function<void(uint64_t time)> processFrame,
CS_Status* status) {
auto& inst = Instance::GetInstance();

View File

@@ -9,9 +9,9 @@
#include <atomic>
#include <functional>
#include <string_view>
#include <thread>
#include <wpi/Twine.h>
#include <wpi/condition_variable.h>
#include "Frame.h"
@@ -23,9 +23,9 @@ class SourceImpl;
class RawSinkImpl : public SinkImpl {
public:
RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
RawSinkImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry);
RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
RawSinkImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry,
std::function<void(uint64_t time)> processFrame);
~RawSinkImpl() override;

View File

@@ -14,7 +14,7 @@
using namespace cs;
RawSourceImpl::RawSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
RawSourceImpl::RawSourceImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
const VideoMode& mode)
: ConfigurableSourceImpl{name, logger, notifier, telemetry, mode} {}
@@ -47,7 +47,7 @@ void RawSourceImpl::PutFrame(const CS_RawFrame& image) {
}
namespace cs {
CS_Source CreateRawSource(const wpi::Twine& name, const VideoMode& mode,
CS_Source CreateRawSource(std::string_view name, const VideoMode& mode,
CS_Status* status) {
auto& inst = Instance::GetInstance();
return inst.CreateSource(CS_SOURCE_RAW, std::make_shared<RawSourceImpl>(

View File

@@ -9,10 +9,10 @@
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <wpi/ArrayRef.h>
#include <wpi/Twine.h>
#include "ConfigurableSourceImpl.h"
#include "SourceImpl.h"
@@ -22,7 +22,7 @@ namespace cs {
class RawSourceImpl : public ConfigurableSourceImpl {
public:
RawSourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
RawSourceImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry, const VideoMode& mode);
~RawSourceImpl() override;

View File

@@ -12,12 +12,12 @@
using namespace cs;
SinkImpl::SinkImpl(const wpi::Twine& name, wpi::Logger& logger,
SinkImpl::SinkImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry)
: m_logger(logger),
m_notifier(notifier),
m_telemetry(telemetry),
m_name{name.str()} {}
m_name{name} {}
SinkImpl::~SinkImpl() {
if (m_source) {
@@ -28,15 +28,16 @@ SinkImpl::~SinkImpl() {
}
}
void SinkImpl::SetDescription(const wpi::Twine& description) {
void SinkImpl::SetDescription(std::string_view description) {
std::scoped_lock lock(m_mutex);
m_description = description.str();
m_description = description;
}
wpi::StringRef SinkImpl::GetDescription(wpi::SmallVectorImpl<char>& buf) const {
std::string_view SinkImpl::GetDescription(
wpi::SmallVectorImpl<char>& buf) const {
std::scoped_lock lock(m_mutex);
buf.append(m_description.begin(), m_description.end());
return wpi::StringRef{buf.data(), buf.size()};
return {buf.data(), buf.size()};
}
void SinkImpl::Enable() {
@@ -106,28 +107,27 @@ std::string SinkImpl::GetError() const {
if (!m_source) {
return "no source connected";
}
return m_source->GetCurFrame().GetError();
return std::string{m_source->GetCurFrame().GetError()};
}
wpi::StringRef SinkImpl::GetError(wpi::SmallVectorImpl<char>& buf) const {
std::string_view SinkImpl::GetError(wpi::SmallVectorImpl<char>& buf) const {
std::scoped_lock lock(m_mutex);
if (!m_source) {
return "no source connected";
}
// Make a copy as it's shared data
wpi::StringRef error = m_source->GetCurFrame().GetError();
std::string_view error = m_source->GetCurFrame().GetError();
buf.clear();
buf.append(error.data(), error.data() + error.size());
return wpi::StringRef{buf.data(), buf.size()};
return {buf.data(), buf.size()};
}
bool SinkImpl::SetConfigJson(wpi::StringRef config, CS_Status* status) {
bool SinkImpl::SetConfigJson(std::string_view config, CS_Status* status) {
wpi::json j;
try {
j = wpi::json::parse(config);
} catch (const wpi::json::parse_error& e) {
SWARNING("SetConfigJson: parse error at byte " << e.byte << ": "
<< e.what());
SWARNING("SetConfigJson: parse error at byte {}: {}", e.byte, e.what());
*status = CS_PROPERTY_WRITE_FAILED;
return false;
}
@@ -169,12 +169,12 @@ void SinkImpl::NotifyPropertyCreated(int propIndex, PropertyImpl& prop) {
if (prop.propKind == CS_PROP_ENUM) {
m_notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CHOICES_UPDATED,
prop.name, propIndex, prop.propKind,
prop.value, wpi::Twine{});
prop.value, {});
}
}
void SinkImpl::UpdatePropertyValue(int property, bool setString, int value,
const wpi::Twine& valueStr) {
std::string_view valueStr) {
auto prop = GetProperty(property);
if (!prop) {
return;

View File

@@ -7,10 +7,9 @@
#include <memory>
#include <string>
#include <string_view>
#include <wpi/Logger.h>
#include <wpi/StringRef.h>
#include <wpi/Twine.h>
#include <wpi/mutex.h>
#include "SourceImpl.h"
@@ -27,16 +26,16 @@ class Telemetry;
class SinkImpl : public PropertyContainer {
public:
explicit SinkImpl(const wpi::Twine& name, wpi::Logger& logger,
explicit SinkImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry);
~SinkImpl() override;
SinkImpl(const SinkImpl& queue) = delete;
SinkImpl& operator=(const SinkImpl& queue) = delete;
wpi::StringRef GetName() const { return m_name; }
std::string_view GetName() const { return m_name; }
void SetDescription(const wpi::Twine& description);
wpi::StringRef GetDescription(wpi::SmallVectorImpl<char>& buf) const;
void SetDescription(std::string_view description);
std::string_view GetDescription(wpi::SmallVectorImpl<char>& buf) const;
void Enable();
void Disable();
@@ -50,9 +49,9 @@ class SinkImpl : public PropertyContainer {
}
std::string GetError() const;
wpi::StringRef GetError(wpi::SmallVectorImpl<char>& buf) const;
std::string_view GetError(wpi::SmallVectorImpl<char>& buf) const;
bool SetConfigJson(wpi::StringRef config, CS_Status* status);
bool SetConfigJson(std::string_view config, CS_Status* status);
virtual bool SetConfigJson(const wpi::json& config, CS_Status* status);
std::string GetConfigJson(CS_Status* status);
virtual wpi::json GetConfigJsonObject(CS_Status* status);
@@ -61,7 +60,7 @@ class SinkImpl : public PropertyContainer {
// PropertyContainer implementation
void NotifyPropertyCreated(int propIndex, PropertyImpl& prop) override;
void UpdatePropertyValue(int property, bool setString, int value,
const wpi::Twine& valueStr) override;
std::string_view valueStr) override;
virtual void SetSourceImpl(std::shared_ptr<SourceImpl> source);

View File

@@ -8,6 +8,7 @@
#include <cstring>
#include <memory>
#include <wpi/StringExtras.h>
#include <wpi/json.h>
#include <wpi/timestamp.h>
@@ -19,13 +20,13 @@ using namespace cs;
static constexpr size_t kMaxImagesAvail = 32;
SourceImpl::SourceImpl(const wpi::Twine& name, wpi::Logger& logger,
SourceImpl::SourceImpl(std::string_view name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry)
: m_logger(logger),
m_notifier(notifier),
m_telemetry(telemetry),
m_name{name.str()} {
m_frame = Frame{*this, wpi::StringRef{}, 0};
m_name{name} {
m_frame = Frame{*this, std::string_view{}, 0};
}
SourceImpl::~SourceImpl() {
@@ -41,16 +42,16 @@ SourceImpl::~SourceImpl() {
// Everything else can clean up itself.
}
void SourceImpl::SetDescription(const wpi::Twine& description) {
void SourceImpl::SetDescription(std::string_view description) {
std::scoped_lock lock(m_mutex);
m_description = description.str();
m_description = description;
}
wpi::StringRef SourceImpl::GetDescription(
std::string_view SourceImpl::GetDescription(
wpi::SmallVectorImpl<char>& buf) const {
std::scoped_lock lock(m_mutex);
buf.append(m_description.begin(), m_description.end());
return wpi::StringRef{buf.data(), buf.size()};
return {buf.data(), buf.size()};
}
void SourceImpl::SetConnected(bool connected) {
@@ -93,7 +94,7 @@ Frame SourceImpl::GetNextFrame(double timeout) {
void SourceImpl::Wakeup() {
{
std::scoped_lock lock{m_frameMutex};
m_frame = Frame{*this, wpi::StringRef{}, 0};
m_frame = Frame{*this, std::string_view{}, 0};
}
m_frameCv.notify_all();
}
@@ -168,13 +169,12 @@ bool SourceImpl::SetFPS(int fps, CS_Status* status) {
return SetVideoMode(mode, status);
}
bool SourceImpl::SetConfigJson(wpi::StringRef config, CS_Status* status) {
bool SourceImpl::SetConfigJson(std::string_view config, CS_Status* status) {
wpi::json j;
try {
j = wpi::json::parse(config);
} catch (const wpi::json::parse_error& e) {
SWARNING("SetConfigJson: parse error at byte " << e.byte << ": "
<< e.what());
SWARNING("SetConfigJson: parse error at byte {}: {}", e.byte, e.what());
*status = CS_PROPERTY_WRITE_FAILED;
return false;
}
@@ -188,23 +188,22 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
if (config.count("pixel format") != 0) {
try {
auto str = config.at("pixel format").get<std::string>();
wpi::StringRef s(str);
if (s.equals_lower("mjpeg")) {
if (wpi::equals_lower(str, "mjpeg")) {
mode.pixelFormat = cs::VideoMode::kMJPEG;
} else if (s.equals_lower("yuyv")) {
} else if (wpi::equals_lower(str, "yuyv")) {
mode.pixelFormat = cs::VideoMode::kYUYV;
} else if (s.equals_lower("rgb565")) {
} else if (wpi::equals_lower(str, "rgb565")) {
mode.pixelFormat = cs::VideoMode::kRGB565;
} else if (s.equals_lower("bgr")) {
} else if (wpi::equals_lower(str, "bgr")) {
mode.pixelFormat = cs::VideoMode::kBGR;
} else if (s.equals_lower("gray")) {
} else if (wpi::equals_lower(str, "gray")) {
mode.pixelFormat = cs::VideoMode::kGray;
} else {
SWARNING("SetConfigJson: could not understand pixel format value '"
<< str << '\'');
SWARNING("SetConfigJson: could not understand pixel format value '{}'",
str);
}
} catch (const wpi::json::exception& e) {
SWARNING("SetConfigJson: could not read pixel format: " << e.what());
SWARNING("SetConfigJson: could not read pixel format: {}", e.what());
}
}
@@ -213,7 +212,7 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
try {
mode.width = config.at("width").get<unsigned int>();
} catch (const wpi::json::exception& e) {
SWARNING("SetConfigJson: could not read width: " << e.what());
SWARNING("SetConfigJson: could not read width: {}", e.what());
}
}
@@ -222,7 +221,7 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
try {
mode.height = config.at("height").get<unsigned int>();
} catch (const wpi::json::exception& e) {
SWARNING("SetConfigJson: could not read height: " << e.what());
SWARNING("SetConfigJson: could not read height: {}", e.what());
}
}
@@ -231,30 +230,31 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
try {
mode.fps = config.at("fps").get<unsigned int>();
} catch (const wpi::json::exception& e) {
SWARNING("SetConfigJson: could not read fps: " << e.what());
SWARNING("SetConfigJson: could not read fps: {}", e.what());
}
}
// if all of video mode is set, use SetVideoMode, otherwise piecemeal it
if (mode.pixelFormat != VideoMode::kUnknown && mode.width != 0 &&
mode.height != 0 && mode.fps != 0) {
SINFO("SetConfigJson: setting video mode to pixelFormat "
<< mode.pixelFormat << ", width " << mode.width << ", height "
<< mode.height << ", fps " << mode.fps);
SINFO(
"SetConfigJson: setting video mode to pixelFormat {}, width {}, height "
"{}, fps {}",
mode.pixelFormat, mode.width, mode.height, mode.fps);
SetVideoMode(mode, status);
} else {
if (mode.pixelFormat != cs::VideoMode::kUnknown) {
SINFO("SetConfigJson: setting pixelFormat " << mode.pixelFormat);
SINFO("SetConfigJson: setting pixelFormat {}", mode.pixelFormat);
SetPixelFormat(static_cast<cs::VideoMode::PixelFormat>(mode.pixelFormat),
status);
}
if (mode.width != 0 && mode.height != 0) {
SINFO("SetConfigJson: setting width " << mode.width << ", height "
<< mode.height);
SINFO("SetConfigJson: setting width {}, height {}", mode.width,
mode.height);
SetResolution(mode.width, mode.height, status);
}
if (mode.fps != 0) {
SINFO("SetConfigJson: setting fps " << mode.fps);
SINFO("SetConfigJson: setting fps {}", mode.fps);
SetFPS(mode.fps, status);
}
}
@@ -263,10 +263,10 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
if (config.count("brightness") != 0) {
try {
int val = config.at("brightness").get<int>();
SINFO("SetConfigJson: setting brightness to " << val);
SINFO("SetConfigJson: setting brightness to {}", val);
SetBrightness(val, status);
} catch (const wpi::json::exception& e) {
SWARNING("SetConfigJson: could not read brightness: " << e.what());
SWARNING("SetConfigJson: could not read brightness: {}", e.what());
}
}
@@ -276,24 +276,24 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
auto& setting = config.at("white balance");
if (setting.is_string()) {
auto str = setting.get<std::string>();
wpi::StringRef s(str);
if (s.equals_lower("auto")) {
SINFO("SetConfigJson: setting white balance to auto");
if (wpi::equals_lower(str, "auto")) {
SINFO("SetConfigJson: setting white balance to {}", "auto");
SetWhiteBalanceAuto(status);
} else if (s.equals_lower("hold")) {
SINFO("SetConfigJson: setting white balance to hold current");
} else if (wpi::equals_lower(str, "hold")) {
SINFO("SetConfigJson: setting white balance to {}", "hold current");
SetWhiteBalanceHoldCurrent(status);
} else {
SWARNING("SetConfigJson: could not understand white balance value '"
<< str << '\'');
SWARNING(
"SetConfigJson: could not understand white balance value '{}'",
str);
}
} else {
int val = setting.get<int>();
SINFO("SetConfigJson: setting white balance to " << val);
SINFO("SetConfigJson: setting white balance to {}", val);
SetWhiteBalanceManual(val, status);
}
} catch (const wpi::json::exception& e) {
SWARNING("SetConfigJson: could not read white balance: " << e.what());
SWARNING("SetConfigJson: could not read white balance: {}", e.what());
}
}
@@ -303,24 +303,23 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
auto& setting = config.at("exposure");
if (setting.is_string()) {
auto str = setting.get<std::string>();
wpi::StringRef s(str);
if (s.equals_lower("auto")) {
SINFO("SetConfigJson: setting exposure to auto");
if (wpi::equals_lower(str, "auto")) {
SINFO("SetConfigJson: setting exposure to {}", "auto");
SetExposureAuto(status);
} else if (s.equals_lower("hold")) {
SINFO("SetConfigJson: setting exposure to hold current");
} else if (wpi::equals_lower(str, "hold")) {
SINFO("SetConfigJson: setting exposure to {}", "hold current");
SetExposureHoldCurrent(status);
} else {
SWARNING("SetConfigJson: could not understand exposure value '"
<< str << '\'');
SWARNING("SetConfigJson: could not understand exposure value '{}'",
str);
}
} else {
int val = setting.get<int>();
SINFO("SetConfigJson: setting exposure to " << val);
SINFO("SetConfigJson: setting exposure to {}", val);
SetExposureManual(val, status);
}
} catch (const wpi::json::exception& e) {
SWARNING("SetConfigJson: could not read exposure: " << e.what());
SWARNING("SetConfigJson: could not read exposure: {}", e.what());
}
}
@@ -344,7 +343,7 @@ wpi::json SourceImpl::GetConfigJsonObject(CS_Status* status) {
wpi::json j;
// pixel format
wpi::StringRef pixelFormat;
std::string_view pixelFormat;
switch (m_mode.pixelFormat) {
case VideoMode::kMJPEG:
pixelFormat = "mjpeg";
@@ -440,14 +439,12 @@ std::unique_ptr<Image> SourceImpl::AllocImage(
}
void SourceImpl::PutFrame(VideoMode::PixelFormat pixelFormat, int width,
int height, wpi::StringRef data, Frame::Time time) {
int height, std::string_view data, Frame::Time time) {
auto image = AllocImage(pixelFormat, width, height, data.size());
// Copy in image data
SDEBUG4("Copying data to "
<< reinterpret_cast<const void*>(image->data()) << " from "
<< reinterpret_cast<const void*>(data.data()) << " (" << data.size()
<< " bytes)");
SDEBUG4("Copying data to {} from {} ({} bytes)", fmt::ptr(image->data()),
fmt::ptr(data.data()), data.size());
std::memcpy(image->data(), data.data(), data.size());
PutFrame(std::move(image), time);
@@ -468,7 +465,7 @@ void SourceImpl::PutFrame(std::unique_ptr<Image> image, Frame::Time time) {
m_frameCv.notify_all();
}
void SourceImpl::PutError(const wpi::Twine& msg, Frame::Time time) {
void SourceImpl::PutError(std::string_view msg, Frame::Time time) {
// Update frame
{
std::scoped_lock lock{m_frameMutex};
@@ -487,12 +484,12 @@ void SourceImpl::NotifyPropertyCreated(int propIndex, PropertyImpl& prop) {
if (prop.propKind == CS_PROP_ENUM) {
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
prop.name, propIndex, prop.propKind,
prop.value, wpi::Twine{});
prop.value, {});
}
}
void SourceImpl::UpdatePropertyValue(int property, bool setString, int value,
const wpi::Twine& valueStr) {
std::string_view valueStr) {
auto prop = GetProperty(property);
if (!prop) {
return;

View File

@@ -9,12 +9,11 @@
#include <cstddef>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <wpi/ArrayRef.h>
#include <wpi/Logger.h>
#include <wpi/StringRef.h>
#include <wpi/Twine.h>
#include <wpi/condition_variable.h>
#include <wpi/mutex.h>
@@ -37,7 +36,7 @@ class SourceImpl : public PropertyContainer {
friend class Frame;
public:
SourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
SourceImpl(std::string_view name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry);
~SourceImpl() override;
SourceImpl(const SourceImpl& oth) = delete;
@@ -45,10 +44,10 @@ class SourceImpl : public PropertyContainer {
virtual void Start() = 0;
wpi::StringRef GetName() const { return m_name; }
std::string_view GetName() const { return m_name; }
void SetDescription(const wpi::Twine& description);
wpi::StringRef GetDescription(wpi::SmallVectorImpl<char>& buf) const;
void SetDescription(std::string_view description);
std::string_view GetDescription(wpi::SmallVectorImpl<char>& buf) const;
void SetConnectionStrategy(CS_ConnectionStrategy strategy) {
m_strategy = static_cast<int>(strategy);
@@ -128,7 +127,7 @@ class SourceImpl : public PropertyContainer {
virtual bool SetResolution(int width, int height, CS_Status* status);
virtual bool SetFPS(int fps, CS_Status* status);
bool SetConfigJson(wpi::StringRef config, CS_Status* status);
bool SetConfigJson(std::string_view config, CS_Status* status);
virtual bool SetConfigJson(const wpi::json& config, CS_Status* status);
std::string GetConfigJson(CS_Status* status);
virtual wpi::json GetConfigJsonObject(CS_Status* status);
@@ -141,12 +140,12 @@ class SourceImpl : public PropertyContainer {
protected:
void NotifyPropertyCreated(int propIndex, PropertyImpl& prop) override;
void UpdatePropertyValue(int property, bool setString, int value,
const wpi::Twine& valueStr) override;
std::string_view valueStr) override;
void PutFrame(VideoMode::PixelFormat pixelFormat, int width, int height,
wpi::StringRef data, Frame::Time time);
std::string_view data, Frame::Time time);
void PutFrame(std::unique_ptr<Image> image, Frame::Time time);
void PutError(const wpi::Twine& msg, Frame::Time time);
void PutError(std::string_view msg, Frame::Time time);
// Notification functions for corresponding atomics
virtual void NumSinksChanged() = 0;

View File

@@ -7,13 +7,13 @@
#include <cstdlib>
#include <cstring>
#include <string_view>
#include <wpi/MemAlloc.h>
#include <wpi/StringRef.h>
namespace cs {
inline char* ConvertToC(wpi::StringRef in) {
inline char* ConvertToC(std::string_view in) {
char* out = static_cast<char*>(wpi::safe_malloc(in.size() + 1));
std::memmove(out, in.data(), in.size());
out[in.size()] = '\0';

View File

@@ -70,12 +70,12 @@ std::string GetPropertyName(CS_Property property, CS_Status* status) {
if (!container) {
return {};
}
return container->GetPropertyName(propertyIndex, buf, status);
return std::string{container->GetPropertyName(propertyIndex, buf, status)};
}
wpi::StringRef GetPropertyName(CS_Property property,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
std::string_view GetPropertyName(CS_Property property,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
int propertyIndex;
auto container = GetPropertyContainer(property, &propertyIndex, status);
if (!container) {
@@ -145,12 +145,12 @@ std::string GetStringProperty(CS_Property property, CS_Status* status) {
if (!container) {
return {};
}
return container->GetStringProperty(propertyIndex, buf, status);
return std::string{container->GetStringProperty(propertyIndex, buf, status)};
}
wpi::StringRef GetStringProperty(CS_Property property,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
std::string_view GetStringProperty(CS_Property property,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
int propertyIndex;
auto container = GetPropertyContainer(property, &propertyIndex, status);
if (!container) {
@@ -159,7 +159,7 @@ wpi::StringRef GetStringProperty(CS_Property property,
return container->GetStringProperty(propertyIndex, buf, status);
}
void SetStringProperty(CS_Property property, const wpi::Twine& value,
void SetStringProperty(CS_Property property, std::string_view value,
CS_Status* status) {
int propertyIndex;
auto container = GetPropertyContainer(property, &propertyIndex, status);
@@ -196,17 +196,18 @@ std::string GetSourceName(CS_Source source, CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
if (!data) {
*status = CS_INVALID_HANDLE;
return std::string{};
return {};
}
return data->source->GetName();
return std::string{data->source->GetName()};
}
wpi::StringRef GetSourceName(CS_Source source, wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
std::string_view GetSourceName(CS_Source source,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
if (!data) {
*status = CS_INVALID_HANDLE;
return wpi::StringRef{};
return {};
}
return data->source->GetName();
}
@@ -215,19 +216,19 @@ std::string GetSourceDescription(CS_Source source, CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
if (!data) {
*status = CS_INVALID_HANDLE;
return std::string{};
return {};
}
wpi::SmallString<128> buf;
return data->source->GetDescription(buf);
return std::string{data->source->GetDescription(buf)};
}
wpi::StringRef GetSourceDescription(CS_Source source,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
std::string_view GetSourceDescription(CS_Source source,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
if (!data) {
*status = CS_INVALID_HANDLE;
return wpi::StringRef{};
return {};
}
return data->source->GetDescription(buf);
}
@@ -270,7 +271,7 @@ bool IsSourceEnabled(CS_Source source, CS_Status* status) {
return data->source->IsEnabled();
}
CS_Property GetSourceProperty(CS_Source source, const wpi::Twine& name,
CS_Property GetSourceProperty(CS_Source source, std::string_view name,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
if (!data) {
@@ -349,7 +350,7 @@ bool SetSourceFPS(CS_Source source, int fps, CS_Status* status) {
return data->source->SetFPS(fps, status);
}
bool SetSourceConfigJson(CS_Source source, wpi::StringRef config,
bool SetSourceConfigJson(CS_Source source, std::string_view config,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
if (!data) {
@@ -531,17 +532,17 @@ std::string GetSinkName(CS_Sink sink, CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
*status = CS_INVALID_HANDLE;
return std::string{};
return {};
}
return data->sink->GetName();
return std::string{data->sink->GetName()};
}
wpi::StringRef GetSinkName(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
std::string_view GetSinkName(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
*status = CS_INVALID_HANDLE;
return wpi::StringRef{};
return {};
}
return data->sink->GetName();
}
@@ -550,23 +551,24 @@ std::string GetSinkDescription(CS_Sink sink, CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
*status = CS_INVALID_HANDLE;
return std::string{};
return {};
}
wpi::SmallString<128> buf;
return data->sink->GetDescription(buf);
return std::string{data->sink->GetDescription(buf)};
}
wpi::StringRef GetSinkDescription(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
std::string_view GetSinkDescription(CS_Sink sink,
wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
*status = CS_INVALID_HANDLE;
return wpi::StringRef{};
return {};
}
return data->sink->GetDescription(buf);
}
CS_Property GetSinkProperty(CS_Sink sink, const wpi::Twine& name,
CS_Property GetSinkProperty(CS_Sink sink, std::string_view name,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
@@ -596,7 +598,8 @@ wpi::ArrayRef<CS_Property> EnumerateSinkProperties(
return vec;
}
bool SetSinkConfigJson(CS_Sink sink, wpi::StringRef config, CS_Status* status) {
bool SetSinkConfigJson(CS_Sink sink, std::string_view config,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
*status = CS_INVALID_HANDLE;
@@ -663,7 +666,7 @@ CS_Source GetSinkSource(CS_Sink sink, CS_Status* status) {
return data->sourceHandle.load();
}
CS_Property GetSinkSourceProperty(CS_Sink sink, const wpi::Twine& name,
CS_Property GetSinkSourceProperty(CS_Sink sink, std::string_view name,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {

View File

@@ -4,6 +4,7 @@
#include "cscore_oo.h"
#include <fmt/format.h>
#include <wpi/json.h>
using namespace cs;
@@ -82,3 +83,7 @@ std::vector<VideoSink> VideoSink::EnumerateSinks() {
}
return sinks;
}
std::string AxisCamera::HostToUrl(std::string_view host) {
return fmt::format("http://{}/mjpg/video.mjpg", host);
}

View File

@@ -4,10 +4,10 @@
#include <exception>
#include <fmt/format.h>
#include <opencv2/core/core.hpp>
#include <wpi/SmallString.h>
#include <wpi/jni_util.h>
#include <wpi/raw_ostream.h>
#include "cscore_cpp.h"
#include "cscore_cv.h"
@@ -197,7 +197,8 @@ static void ReportError(JNIEnv* env, CS_Status status) {
if (status == CS_OK) {
return;
}
wpi::SmallString<64> msg;
std::string_view msg;
std::string msgBuf;
switch (status) {
case CS_PROPERTY_WRITE_FAILED:
msg = "property write failed";
@@ -230,8 +231,8 @@ static void ReportError(JNIEnv* env, CS_Status status) {
msg = "telemetry not enabled";
break;
default: {
wpi::raw_svector_ostream oss{msg};
oss << "unknown error code=" << status;
msgBuf = fmt::format("unknown error code={}", status);
msg = msgBuf;
break;
}
}
@@ -577,7 +578,7 @@ Java_edu_wpi_first_cscore_CameraServerJNI_createHttpCameraMulti
// TODO
return 0;
}
vec.push_back(JStringRef{env, elem}.str());
vec.emplace_back(JStringRef{env, elem}.str());
}
CS_Status status = 0;
auto val =
@@ -1172,7 +1173,7 @@ Java_edu_wpi_first_cscore_CameraServerJNI_setHttpCameraUrls
// TODO
return;
}
vec.push_back(JStringRef{env, elem}.str());
vec.emplace_back(JStringRef{env, elem}.str());
}
CS_Status status = 0;
cs::SetHttpCameraUrls(source, vec, &status);
@@ -1353,7 +1354,7 @@ Java_edu_wpi_first_cscore_CameraServerJNI_setSourceEnumPropertyChoices
// TODO
return;
}
vec.push_back(JStringRef{env, elem}.str());
vec.emplace_back(JStringRef{env, elem}.str());
}
CS_Status status = 0;
cs::SetSourceEnumPropertyChoices(source, property, vec, &status);