Skip to content

Commit

Permalink
cscore: Add config json to VideoSink (#1543)
Browse files Browse the repository at this point in the history
Same format as VideoSource.

Refactor properties json handling into PropertyContainer.
  • Loading branch information
PeterJohnson committed Jan 12, 2019
1 parent 1349dd4 commit 05d6660
Show file tree
Hide file tree
Showing 15 changed files with 317 additions and 54 deletions.
2 changes: 2 additions & 0 deletions cscore/src/main/java/edu/wpi/cscore/CameraServerJNI.java
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ public static void forceLoad() {}
public static native String getSinkDescription(int sink);
public static native int getSinkProperty(int sink, String name);
public static native int[] enumerateSinkProperties(int sink);
public static native boolean setSinkConfigJson(int sink, String config);
public static native String getSinkConfigJson(int sink);
public static native void setSinkSource(int sink, int source);
public static native int getSinkSourceProperty(int sink, String name);
public static native int getSinkSource(int sink);
Expand Down
32 changes: 32 additions & 0 deletions cscore/src/main/java/edu/wpi/cscore/VideoSink.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,38 @@ public VideoProperty[] enumerateProperties() {
return rv;
}

/**
* Set properties from a JSON configuration string.
*
* <p>The format of the JSON input is:
*
* <pre>
* {
* "properties": [
* {
* "name": property name
* "value": property value
* }
* ]
* }
* </pre>
*
* @param config configuration
* @return True if set successfully
*/
public boolean setConfigJson(String config) {
return CameraServerJNI.setSinkConfigJson(m_handle, config);
}

/**
* Get a JSON configuration string.
*
* @return JSON configuration string
*/
public String getConfigJson() {
return CameraServerJNI.getSinkConfigJson(m_handle);
}

/**
* Configure which source should provide frames to this sink. Each sink
* can accept frames from only a single source, but a single source can
Expand Down
76 changes: 76 additions & 0 deletions cscore/src/main/native/cpp/PropertyContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@

#include "PropertyContainer.h"

#include <wpi/Logger.h>
#include <wpi/SmallString.h>
#include <wpi/SmallVector.h>
#include <wpi/json.h>

using namespace cs;

int PropertyContainer::GetPropertyIndex(const wpi::Twine& name) const {
Expand Down Expand Up @@ -204,3 +209,74 @@ bool PropertyContainer::CacheProperties(CS_Status* status) const {
m_properties_cached = true;
return true;
}

bool PropertyContainer::SetPropertiesJson(const wpi::json& config,
wpi::Logger& logger,
wpi::StringRef 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());
continue;
}
int n = GetPropertyIndex(name);
try {
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 << '\'');
SetStringProperty(n, val, status);
} else if (v.is_boolean()) {
bool val = v.get<bool>();
WPI_INFO(logger, logName << ": SetConfigJson: setting property '"
<< name << "' to " << val);
SetProperty(n, val, status);
} else {
int val = v.get<int>();
WPI_INFO(logger, logName << ": SetConfigJson: setting property '"
<< name << "' to " << val);
SetProperty(n, val, status);
}
} catch (const wpi::json::exception& e) {
WPI_WARNING(logger,
logName << ": SetConfigJson: could not read property value: "
<< e.what());
continue;
}
}

return true;
}

wpi::json PropertyContainer::GetPropertiesJsonObject(CS_Status* status) {
wpi::json j;
wpi::SmallVector<int, 32> propVec;
for (int p : EnumerateProperties(propVec, status)) {
wpi::json prop;
wpi::SmallString<128> strBuf;
prop.emplace("name", GetPropertyName(p, strBuf, status));
switch (GetPropertyKind(p)) {
case CS_PROP_BOOLEAN:
prop.emplace("value", static_cast<bool>(GetProperty(p, status)));
break;
case CS_PROP_INTEGER:
case CS_PROP_ENUM:
prop.emplace("value", GetProperty(p, status));
break;
case CS_PROP_STRING:
prop.emplace("value", GetStringProperty(p, strBuf, status));
break;
default:
continue;
}
j.emplace_back(prop);
}

return j;
}
9 changes: 9 additions & 0 deletions cscore/src/main/native/cpp/PropertyContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
#include "PropertyImpl.h"
#include "cscore_cpp.h"

namespace wpi {
class Logger;
class json;
} // namespace wpi

namespace cs {

class PropertyContainer {
Expand All @@ -50,6 +55,10 @@ class PropertyContainer {
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);
wpi::json GetPropertiesJsonObject(CS_Status* status);

protected:
// Get a property; must be called with m_mutex held.
PropertyImpl* GetProperty(int property) {
Expand Down
39 changes: 39 additions & 0 deletions cscore/src/main/native/cpp/SinkImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include "SinkImpl.h"

#include <wpi/json.h>

#include "Instance.h"
#include "Notifier.h"
#include "SourceImpl.h"
Expand Down Expand Up @@ -102,6 +104,43 @@ wpi::StringRef SinkImpl::GetError(wpi::SmallVectorImpl<char>& buf) const {
return wpi::StringRef{buf.data(), buf.size()};
}

bool SinkImpl::SetConfigJson(wpi::StringRef 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());
*status = CS_PROPERTY_WRITE_FAILED;
return false;
}
return SetConfigJson(j, status);
}

bool SinkImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
if (config.count("properties") != 0)
SetPropertiesJson(config.at("properties"), m_logger, GetName(), status);

return true;
}

std::string SinkImpl::GetConfigJson(CS_Status* status) {
std::string rv;
wpi::raw_string_ostream os(rv);
GetConfigJsonObject(status).dump(os, 4);
os.flush();
return rv;
}

wpi::json SinkImpl::GetConfigJsonObject(CS_Status* status) {
wpi::json j;

wpi::json props = GetPropertiesJsonObject(status);
if (props.is_array()) j.emplace("properties", props);

return j;
}

void SinkImpl::NotifyPropertyCreated(int propIndex, PropertyImpl& prop) {
m_notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CREATED, prop.name,
propIndex, prop.propKind, prop.value,
Expand Down
9 changes: 9 additions & 0 deletions cscore/src/main/native/cpp/SinkImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

#include "SourceImpl.h"

namespace wpi {
class json;
} // namespace wpi

namespace cs {

class Frame;
Expand Down Expand Up @@ -51,6 +55,11 @@ class SinkImpl : public PropertyContainer {
std::string GetError() const;
wpi::StringRef GetError(wpi::SmallVectorImpl<char>& buf) const;

bool SetConfigJson(wpi::StringRef 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);

protected:
// PropertyContainer implementation
void NotifyPropertyCreated(int propIndex, PropertyImpl& prop) override;
Expand Down
57 changes: 3 additions & 54 deletions cscore/src/main/native/cpp/SourceImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -319,38 +319,8 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
}

// properties
if (config.count("properties") != 0) {
for (auto&& prop : config.at("properties")) {
std::string name;
try {
name = prop.at("name").get<std::string>();
} catch (const wpi::json::exception& e) {
SWARNING("SetConfigJson: could not read property name: " << e.what());
continue;
}
int n = GetPropertyIndex(name);
try {
auto& v = prop.at("value");
if (v.is_string()) {
std::string val = v.get<std::string>();
SINFO("SetConfigJson: setting property '" << name << "' to '" << val
<< '\'');
SetStringProperty(n, val, status);
} else if (v.is_boolean()) {
bool val = v.get<bool>();
SINFO("SetConfigJson: setting property '" << name << "' to " << val);
SetProperty(n, val, status);
} else {
int val = v.get<int>();
SINFO("SetConfigJson: setting property '" << name << "' to " << val);
SetProperty(n, val, status);
}
} catch (const wpi::json::exception& e) {
SWARNING("SetConfigJson: could not read property value: " << e.what());
continue;
}
}
}
if (config.count("properties") != 0)
SetPropertiesJson(config.at("properties"), m_logger, GetName(), status);

return true;
}
Expand Down Expand Up @@ -401,28 +371,7 @@ wpi::json SourceImpl::GetConfigJsonObject(CS_Status* status) {
// TODO: output brightness, white balance, and exposure?

// properties
wpi::json props;
wpi::SmallVector<int, 32> propVec;
for (int p : EnumerateProperties(propVec, status)) {
wpi::json prop;
wpi::SmallString<128> strBuf;
prop.emplace("name", GetPropertyName(p, strBuf, status));
switch (GetPropertyKind(p)) {
case CS_PROP_BOOLEAN:
prop.emplace("value", static_cast<bool>(GetProperty(p, status)));
break;
case CS_PROP_INTEGER:
case CS_PROP_ENUM:
prop.emplace("value", GetProperty(p, status));
break;
case CS_PROP_STRING:
prop.emplace("value", GetStringProperty(p, strBuf, status));
break;
default:
continue;
}
props.emplace_back(prop);
}
wpi::json props = GetPropertiesJsonObject(status);
if (props.is_array()) j.emplace("properties", props);

return j;
Expand Down
9 changes: 9 additions & 0 deletions cscore/src/main/native/cpp/cscore_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,15 @@ CS_Property* CS_EnumerateSinkProperties(CS_Sink sink, int* count,
return out;
}

CS_Bool CS_SetSinkConfigJson(CS_Sink sink, const char* config,
CS_Status* status) {
return cs::SetSinkConfigJson(sink, config, status);
}

char* CS_GetSinkConfigJson(CS_Sink sink, CS_Status* status) {
return cs::ConvertToC(cs::GetSinkConfigJson(sink, status));
}

void CS_SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
return cs::SetSinkSource(sink, source, status);
}
Expand Down
37 changes: 37 additions & 0 deletions cscore/src/main/native/cpp/cscore_cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,43 @@ wpi::ArrayRef<CS_Property> EnumerateSinkProperties(
return vec;
}

bool SetSinkConfigJson(CS_Sink sink, wpi::StringRef config, CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
*status = CS_INVALID_HANDLE;
return false;
}
return data->sink->SetConfigJson(config, status);
}

bool SetSinkConfigJson(CS_Sink sink, const wpi::json& config,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
*status = CS_INVALID_HANDLE;
return false;
}
return data->sink->SetConfigJson(config, status);
}

std::string GetSinkConfigJson(CS_Sink sink, CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
*status = CS_INVALID_HANDLE;
return std::string{};
}
return data->sink->GetConfigJson(status);
}

wpi::json GetSinkConfigJsonObject(CS_Sink sink, CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
*status = CS_INVALID_HANDLE;
return wpi::json{};
}
return data->sink->GetConfigJsonObject(status);
}

void SetSinkSource(CS_Sink sink, CS_Source source, CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
if (!data) {
Expand Down
5 changes: 5 additions & 0 deletions cscore/src/main/native/cpp/cscore_oo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ wpi::json VideoSource::GetConfigJsonObject() const {
return GetSourceConfigJsonObject(m_handle, &m_status);
}

wpi::json VideoSink::GetConfigJsonObject() const {
m_status = 0;
return GetSinkConfigJsonObject(m_handle, &m_status);
}

std::vector<VideoProperty> VideoSource::EnumerateProperties() const {
wpi::SmallVector<CS_Property, 32> handles_buf;
CS_Status status = 0;
Expand Down

0 comments on commit 05d6660

Please sign in to comment.