mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-02 02:51:42 +00:00
Add braces to C++ single-line loops and conditionals (NFC) (#2973)
This makes code easier to read and more consistent between C++ and Java. Also update clang-format settings to always add a line break (even if no braces are used).
This commit is contained in:
@@ -30,16 +30,22 @@ CvSinkImpl::CvSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
std::function<void(uint64_t time)> processFrame)
|
||||
: SinkImpl{name, logger, notifier, telemetry} {}
|
||||
|
||||
CvSinkImpl::~CvSinkImpl() { Stop(); }
|
||||
CvSinkImpl::~CvSinkImpl() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void CvSinkImpl::Stop() {
|
||||
m_active = false;
|
||||
|
||||
// wake up any waiters by forcing an empty frame to be sent
|
||||
if (auto source = GetSource()) source->Wakeup();
|
||||
if (auto source = GetSource()) {
|
||||
source->Wakeup();
|
||||
}
|
||||
|
||||
// join thread
|
||||
if (m_thread.joinable()) m_thread.join();
|
||||
if (m_thread.joinable()) {
|
||||
m_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t CvSinkImpl::GrabFrame(cv::Mat& image) {
|
||||
@@ -106,7 +112,9 @@ void CvSinkImpl::ThreadMain() {
|
||||
}
|
||||
SDEBUG4("waiting for frame");
|
||||
Frame frame = source->GetNextFrame(); // blocks
|
||||
if (!m_active) break;
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
if (!frame) {
|
||||
// Bad frame; sleep for 10 ms so we don't consume all processor time.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
@@ -240,7 +248,9 @@ uint64_t CS_GrabSinkFrameTimeoutCpp(CS_Sink sink, cv::Mat* image,
|
||||
char* CS_GetSinkError(CS_Sink sink, CS_Status* status) {
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSinkError(sink, buf, status);
|
||||
if (*status != 0) return nullptr;
|
||||
if (*status != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return cs::ConvertToC(str);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,10 +29,11 @@ CvSourceImpl::~CvSourceImpl() {}
|
||||
void CvSourceImpl::PutFrame(cv::Mat& image) {
|
||||
// We only support 8-bit images; convert if necessary.
|
||||
cv::Mat finalImage;
|
||||
if (image.depth() == CV_8U)
|
||||
if (image.depth() == CV_8U) {
|
||||
finalImage = image;
|
||||
else
|
||||
} else {
|
||||
image.convertTo(finalImage, CV_8U);
|
||||
}
|
||||
|
||||
std::unique_ptr<Image> dest;
|
||||
switch (image.channels()) {
|
||||
@@ -224,7 +225,9 @@ void CS_SetSourceEnumPropertyChoices(CS_Source source, CS_Property property,
|
||||
CS_Status* status) {
|
||||
wpi::SmallVector<std::string, 8> vec;
|
||||
vec.reserve(count);
|
||||
for (int i = 0; i < count; ++i) vec.push_back(choices[i]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
vec.push_back(choices[i]);
|
||||
}
|
||||
return cs::SetSourceEnumPropertyChoices(source, property, vec, status);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,22 +32,31 @@ Frame::Frame(SourceImpl& source, std::unique_ptr<Image> image, Time time)
|
||||
}
|
||||
|
||||
Image* Frame::GetNearestImage(int width, int height) const {
|
||||
if (!m_impl) return nullptr;
|
||||
if (!m_impl) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
Image* found = nullptr;
|
||||
|
||||
// Ideally we want the smallest image at least width/height in size
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->IsLarger(width, height) && (!found || (i->IsSmaller(*found))))
|
||||
if (i->IsLarger(width, height) && (!found || (i->IsSmaller(*found)))) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
if (found) return found;
|
||||
|
||||
// Find the largest image (will be less than width/height)
|
||||
for (auto i : m_impl->images) {
|
||||
if (!found || (i->IsLarger(*found))) found = i;
|
||||
if (!found || (i->IsLarger(*found))) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
if (found) return found;
|
||||
|
||||
// Shouldn't reach this, but just in case...
|
||||
return m_impl->images.empty() ? nullptr : m_impl->images[0];
|
||||
@@ -56,7 +65,9 @@ Image* Frame::GetNearestImage(int width, int height) const {
|
||||
Image* Frame::GetNearestImage(int width, int height,
|
||||
VideoMode::PixelFormat pixelFormat,
|
||||
int jpegQuality) const {
|
||||
if (!m_impl) return nullptr;
|
||||
if (!m_impl) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
Image* found = nullptr;
|
||||
|
||||
@@ -71,19 +82,25 @@ Image* Frame::GetNearestImage(int width, int height,
|
||||
// 1) Same width, height, pixelFormat, and (possibly) JPEG quality
|
||||
// (e.g. exactly what we want)
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->Is(width, height, pixelFormat, jpegQuality)) return i;
|
||||
if (i->Is(width, height, pixelFormat, jpegQuality)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Same width, height, different (but non-JPEG) pixelFormat (color conv)
|
||||
// 2a) If we want JPEG output, prefer BGR over other pixel formats
|
||||
if (pixelFormat == VideoMode::kMJPEG) {
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->Is(width, height, VideoMode::kBGR)) return i;
|
||||
if (i->Is(width, height, VideoMode::kBGR)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->Is(width, height) && i->pixelFormat != VideoMode::kMJPEG) return i;
|
||||
if (i->Is(width, height) && i->pixelFormat != VideoMode::kMJPEG) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Different width, height, same pixelFormat (only if non-JPEG) (resample)
|
||||
@@ -91,17 +108,23 @@ Image* Frame::GetNearestImage(int width, int height,
|
||||
// 3a) Smallest image at least width/height in size
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->IsLarger(width, height) && i->pixelFormat == pixelFormat &&
|
||||
(!found || (i->IsSmaller(*found))))
|
||||
(!found || (i->IsSmaller(*found)))) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
if (found) return found;
|
||||
|
||||
// 3b) Largest image (less than width/height)
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->pixelFormat == pixelFormat && (!found || (i->IsLarger(*found))))
|
||||
if (i->pixelFormat == pixelFormat && (!found || (i->IsLarger(*found)))) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
if (found) return found;
|
||||
}
|
||||
|
||||
// 4) Different width, height, different (but non-JPEG) pixelFormat
|
||||
@@ -109,18 +132,24 @@ Image* Frame::GetNearestImage(int width, int height,
|
||||
// 4a) Smallest image at least width/height in size
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->IsLarger(width, height) && i->pixelFormat != VideoMode::kMJPEG &&
|
||||
(!found || (i->IsSmaller(*found))))
|
||||
(!found || (i->IsSmaller(*found)))) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
if (found) return found;
|
||||
|
||||
// 4b) Largest image (less than width/height)
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->pixelFormat != VideoMode::kMJPEG &&
|
||||
(!found || (i->IsLarger(*found))))
|
||||
(!found || (i->IsLarger(*found)))) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
if (found) return found;
|
||||
|
||||
// 5) Same width, height, JPEG pixelFormat (decompression). As there may be
|
||||
// multiple JPEG images, find the highest quality one.
|
||||
@@ -130,27 +159,37 @@ Image* Frame::GetNearestImage(int width, int height,
|
||||
found = i;
|
||||
// consider one without a quality setting to be the highest quality
|
||||
// (e.g. directly from the camera)
|
||||
if (i->jpegQuality == -1) break;
|
||||
if (i->jpegQuality == -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) return found;
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
|
||||
// 6) Different width, height, JPEG pixelFormat (decompression)
|
||||
// 6a) Smallest image at least width/height in size
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->IsLarger(width, height) && i->pixelFormat == VideoMode::kMJPEG &&
|
||||
(!found || (i->IsSmaller(*found))))
|
||||
(!found || (i->IsSmaller(*found)))) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
if (found) return found;
|
||||
|
||||
// 6b) Largest image (less than width/height)
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->pixelFormat != VideoMode::kMJPEG &&
|
||||
(!found || (i->IsLarger(*found))))
|
||||
(!found || (i->IsLarger(*found)))) {
|
||||
found = i;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
return found;
|
||||
}
|
||||
if (found) return found;
|
||||
|
||||
// Shouldn't reach this, but just in case...
|
||||
return m_impl->images.empty() ? nullptr : m_impl->images[0];
|
||||
@@ -158,9 +197,10 @@ Image* Frame::GetNearestImage(int width, int height,
|
||||
|
||||
Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
|
||||
int requiredJpegQuality, int defaultJpegQuality) {
|
||||
if (!image ||
|
||||
image->Is(image->width, image->height, pixelFormat, requiredJpegQuality))
|
||||
if (!image || image->Is(image->width, image->height, pixelFormat,
|
||||
requiredJpegQuality)) {
|
||||
return image;
|
||||
}
|
||||
Image* cur = image;
|
||||
|
||||
// If the source image is a JPEG, we need to decode it before we can do
|
||||
@@ -169,7 +209,9 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
|
||||
// would have returned above).
|
||||
if (cur->pixelFormat == VideoMode::kMJPEG) {
|
||||
cur = ConvertMJPEGToBGR(cur);
|
||||
if (pixelFormat == VideoMode::kBGR) return cur;
|
||||
if (pixelFormat == VideoMode::kBGR) {
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
|
||||
// Color convert
|
||||
@@ -179,17 +221,19 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
|
||||
if (cur->pixelFormat == VideoMode::kYUYV) {
|
||||
// Check to see if BGR version already exists...
|
||||
if (Image* newImage =
|
||||
GetExistingImage(cur->width, cur->height, VideoMode::kBGR))
|
||||
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
|
||||
cur = newImage;
|
||||
else
|
||||
} else {
|
||||
cur = ConvertYUYVToBGR(cur);
|
||||
}
|
||||
} else if (cur->pixelFormat == VideoMode::kGray) {
|
||||
// Check to see if BGR version already exists...
|
||||
if (Image* newImage =
|
||||
GetExistingImage(cur->width, cur->height, VideoMode::kBGR))
|
||||
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
|
||||
cur = newImage;
|
||||
else
|
||||
} else {
|
||||
cur = ConvertGrayToBGR(cur);
|
||||
}
|
||||
}
|
||||
return ConvertBGRToRGB565(cur);
|
||||
case VideoMode::kGray:
|
||||
@@ -197,17 +241,19 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
|
||||
if (cur->pixelFormat == VideoMode::kYUYV) {
|
||||
// Check to see if BGR version already exists...
|
||||
if (Image* newImage =
|
||||
GetExistingImage(cur->width, cur->height, VideoMode::kBGR))
|
||||
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
|
||||
cur = newImage;
|
||||
else
|
||||
} else {
|
||||
cur = ConvertYUYVToBGR(cur);
|
||||
}
|
||||
} else if (cur->pixelFormat == VideoMode::kRGB565) {
|
||||
// Check to see if BGR version already exists...
|
||||
if (Image* newImage =
|
||||
GetExistingImage(cur->width, cur->height, VideoMode::kBGR))
|
||||
GetExistingImage(cur->width, cur->height, VideoMode::kBGR)) {
|
||||
cur = newImage;
|
||||
else
|
||||
} else {
|
||||
cur = ConvertRGB565ToBGR(cur);
|
||||
}
|
||||
}
|
||||
return ConvertBGRToGray(cur);
|
||||
case VideoMode::kBGR:
|
||||
@@ -217,10 +263,11 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
|
||||
} else if (cur->pixelFormat == VideoMode::kRGB565) {
|
||||
cur = ConvertRGB565ToBGR(cur);
|
||||
} else if (cur->pixelFormat == VideoMode::kGray) {
|
||||
if (pixelFormat == VideoMode::kBGR)
|
||||
if (pixelFormat == VideoMode::kBGR) {
|
||||
return ConvertGrayToBGR(cur);
|
||||
else
|
||||
} else {
|
||||
return ConvertGrayToMJPEG(cur, defaultJpegQuality);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VideoMode::kYUYV:
|
||||
@@ -229,14 +276,17 @@ Image* Frame::ConvertImpl(Image* image, VideoMode::PixelFormat pixelFormat,
|
||||
}
|
||||
|
||||
// Compress if destination is JPEG
|
||||
if (pixelFormat == VideoMode::kMJPEG)
|
||||
if (pixelFormat == VideoMode::kMJPEG) {
|
||||
cur = ConvertBGRToMJPEG(cur, defaultJpegQuality);
|
||||
}
|
||||
|
||||
return cur;
|
||||
}
|
||||
|
||||
Image* Frame::ConvertMJPEGToBGR(Image* image) {
|
||||
if (!image || image->pixelFormat != VideoMode::kMJPEG) return nullptr;
|
||||
if (!image || image->pixelFormat != VideoMode::kMJPEG) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate an BGR image
|
||||
auto newImage =
|
||||
@@ -257,7 +307,9 @@ Image* Frame::ConvertMJPEGToBGR(Image* image) {
|
||||
}
|
||||
|
||||
Image* Frame::ConvertMJPEGToGray(Image* image) {
|
||||
if (!image || image->pixelFormat != VideoMode::kMJPEG) return nullptr;
|
||||
if (!image || image->pixelFormat != VideoMode::kMJPEG) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate an grayscale image
|
||||
auto newImage =
|
||||
@@ -278,7 +330,9 @@ Image* Frame::ConvertMJPEGToGray(Image* image) {
|
||||
}
|
||||
|
||||
Image* Frame::ConvertYUYVToBGR(Image* image) {
|
||||
if (!image || image->pixelFormat != VideoMode::kYUYV) return nullptr;
|
||||
if (!image || image->pixelFormat != VideoMode::kYUYV) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate a BGR image
|
||||
auto newImage =
|
||||
@@ -298,7 +352,9 @@ Image* Frame::ConvertYUYVToBGR(Image* image) {
|
||||
}
|
||||
|
||||
Image* Frame::ConvertBGRToRGB565(Image* image) {
|
||||
if (!image || image->pixelFormat != VideoMode::kBGR) return nullptr;
|
||||
if (!image || image->pixelFormat != VideoMode::kBGR) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate a RGB565 image
|
||||
auto newImage =
|
||||
@@ -318,7 +374,9 @@ Image* Frame::ConvertBGRToRGB565(Image* image) {
|
||||
}
|
||||
|
||||
Image* Frame::ConvertRGB565ToBGR(Image* image) {
|
||||
if (!image || image->pixelFormat != VideoMode::kRGB565) return nullptr;
|
||||
if (!image || image->pixelFormat != VideoMode::kRGB565) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate a BGR image
|
||||
auto newImage =
|
||||
@@ -338,7 +396,9 @@ Image* Frame::ConvertRGB565ToBGR(Image* image) {
|
||||
}
|
||||
|
||||
Image* Frame::ConvertBGRToGray(Image* image) {
|
||||
if (!image || image->pixelFormat != VideoMode::kBGR) return nullptr;
|
||||
if (!image || image->pixelFormat != VideoMode::kBGR) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate a Grayscale image
|
||||
auto newImage =
|
||||
@@ -358,7 +418,9 @@ Image* Frame::ConvertBGRToGray(Image* image) {
|
||||
}
|
||||
|
||||
Image* Frame::ConvertGrayToBGR(Image* image) {
|
||||
if (!image || image->pixelFormat != VideoMode::kGray) return nullptr;
|
||||
if (!image || image->pixelFormat != VideoMode::kGray) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate a BGR image
|
||||
auto newImage =
|
||||
@@ -378,8 +440,12 @@ Image* Frame::ConvertGrayToBGR(Image* image) {
|
||||
}
|
||||
|
||||
Image* Frame::ConvertBGRToMJPEG(Image* image, int quality) {
|
||||
if (!image || image->pixelFormat != VideoMode::kBGR) return nullptr;
|
||||
if (!m_impl) return nullptr;
|
||||
if (!image || image->pixelFormat != VideoMode::kBGR) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!m_impl) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
|
||||
// Allocate a JPEG image. We don't actually know what the resulting size
|
||||
@@ -409,8 +475,12 @@ Image* Frame::ConvertBGRToMJPEG(Image* image, int quality) {
|
||||
}
|
||||
|
||||
Image* Frame::ConvertGrayToMJPEG(Image* image, int quality) {
|
||||
if (!image || image->pixelFormat != VideoMode::kGray) return nullptr;
|
||||
if (!m_impl) return nullptr;
|
||||
if (!image || image->pixelFormat != VideoMode::kGray) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!m_impl) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
|
||||
// Allocate a JPEG image. We don't actually know what the resulting size
|
||||
@@ -442,11 +512,14 @@ Image* Frame::ConvertGrayToMJPEG(Image* image, int quality) {
|
||||
Image* Frame::GetImageImpl(int width, int height,
|
||||
VideoMode::PixelFormat pixelFormat,
|
||||
int requiredJpegQuality, int defaultJpegQuality) {
|
||||
if (!m_impl) return nullptr;
|
||||
if (!m_impl) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
Image* cur = GetNearestImage(width, height, pixelFormat, requiredJpegQuality);
|
||||
if (!cur || cur->Is(width, height, pixelFormat, requiredJpegQuality))
|
||||
if (!cur || cur->Is(width, height, pixelFormat, requiredJpegQuality)) {
|
||||
return cur;
|
||||
}
|
||||
|
||||
WPI_DEBUG4(Instance::GetInstance().logger,
|
||||
"converting image from " << cur->width << "x" << cur->height
|
||||
@@ -458,7 +531,9 @@ Image* Frame::GetImageImpl(int width, int height,
|
||||
// anything else with it. Note that if the destination format is JPEG, we
|
||||
// still need to do this (unless the width/height/compression were the same,
|
||||
// in which case we already returned the existing JPEG above).
|
||||
if (cur->pixelFormat == VideoMode::kMJPEG) cur = ConvertMJPEGToBGR(cur);
|
||||
if (cur->pixelFormat == VideoMode::kMJPEG) {
|
||||
cur = ConvertMJPEGToBGR(cur);
|
||||
}
|
||||
|
||||
// Resize
|
||||
if (!cur->Is(width, height)) {
|
||||
@@ -482,14 +557,17 @@ Image* Frame::GetImageImpl(int width, int height,
|
||||
|
||||
bool Frame::GetCv(cv::Mat& image, int width, int height) {
|
||||
Image* rawImage = GetImage(width, height, VideoMode::kBGR);
|
||||
if (!rawImage) return false;
|
||||
if (!rawImage) {
|
||||
return false;
|
||||
}
|
||||
rawImage->AsMat().copyTo(image);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Frame::ReleaseFrame() {
|
||||
for (auto image : m_impl->images)
|
||||
for (auto image : m_impl->images) {
|
||||
m_impl->source.ReleaseImage(std::unique_ptr<Image>(image));
|
||||
}
|
||||
m_impl->images.clear();
|
||||
m_impl->source.ReleaseFrameImpl(std::unique_ptr<Impl>(m_impl));
|
||||
m_impl = nullptr;
|
||||
|
||||
@@ -49,7 +49,9 @@ class Frame {
|
||||
Frame(SourceImpl& source, std::unique_ptr<Image> image, Time time);
|
||||
|
||||
Frame(const Frame& frame) noexcept : m_impl{frame.m_impl} {
|
||||
if (m_impl) ++m_impl->refcount;
|
||||
if (m_impl) {
|
||||
++m_impl->refcount;
|
||||
}
|
||||
}
|
||||
|
||||
Frame(Frame&& other) noexcept : Frame() { swap(*this, other); }
|
||||
@@ -71,60 +73,90 @@ class Frame {
|
||||
Time GetTime() const { return m_impl ? m_impl->time : 0; }
|
||||
|
||||
wpi::StringRef GetError() const {
|
||||
if (!m_impl) return wpi::StringRef{};
|
||||
if (!m_impl) {
|
||||
return {};
|
||||
}
|
||||
return m_impl->error;
|
||||
}
|
||||
|
||||
int GetOriginalWidth() const {
|
||||
if (!m_impl) return 0;
|
||||
if (!m_impl) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
if (m_impl->images.empty()) return 0;
|
||||
if (m_impl->images.empty()) {
|
||||
return 0;
|
||||
}
|
||||
return m_impl->images[0]->width;
|
||||
}
|
||||
|
||||
int GetOriginalHeight() const {
|
||||
if (!m_impl) return 0;
|
||||
if (!m_impl) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
if (m_impl->images.empty()) return 0;
|
||||
if (m_impl->images.empty()) {
|
||||
return 0;
|
||||
}
|
||||
return m_impl->images[0]->height;
|
||||
}
|
||||
|
||||
int GetOriginalPixelFormat() const {
|
||||
if (!m_impl) return 0;
|
||||
if (!m_impl) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
if (m_impl->images.empty()) return 0;
|
||||
if (m_impl->images.empty()) {
|
||||
return 0;
|
||||
}
|
||||
return m_impl->images[0]->pixelFormat;
|
||||
}
|
||||
|
||||
int GetOriginalJpegQuality() const {
|
||||
if (!m_impl) return 0;
|
||||
if (!m_impl) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
if (m_impl->images.empty()) return 0;
|
||||
if (m_impl->images.empty()) {
|
||||
return 0;
|
||||
}
|
||||
return m_impl->images[0]->jpegQuality;
|
||||
}
|
||||
|
||||
Image* GetExistingImage(size_t i = 0) const {
|
||||
if (!m_impl) return nullptr;
|
||||
if (!m_impl) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
if (i >= m_impl->images.size()) return nullptr;
|
||||
if (i >= m_impl->images.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_impl->images[i];
|
||||
}
|
||||
|
||||
Image* GetExistingImage(int width, int height) const {
|
||||
if (!m_impl) return nullptr;
|
||||
if (!m_impl) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->Is(width, height)) return i;
|
||||
if (i->Is(width, height)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Image* GetExistingImage(int width, int height,
|
||||
VideoMode::PixelFormat pixelFormat) const {
|
||||
if (!m_impl) return nullptr;
|
||||
if (!m_impl) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->Is(width, height, pixelFormat)) return i;
|
||||
if (i->Is(width, height, pixelFormat)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -132,10 +164,14 @@ class Frame {
|
||||
Image* GetExistingImage(int width, int height,
|
||||
VideoMode::PixelFormat pixelFormat,
|
||||
int jpegQuality) const {
|
||||
if (!m_impl) return nullptr;
|
||||
if (!m_impl) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock lock(m_impl->mutex);
|
||||
for (auto i : m_impl->images) {
|
||||
if (i->Is(width, height, pixelFormat, jpegQuality)) return i;
|
||||
if (i->Is(width, height, pixelFormat, jpegQuality)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@@ -146,7 +182,9 @@ class Frame {
|
||||
int jpegQuality = -1) const;
|
||||
|
||||
Image* Convert(Image* image, VideoMode::PixelFormat pixelFormat) {
|
||||
if (pixelFormat == VideoMode::kMJPEG) return nullptr;
|
||||
if (pixelFormat == VideoMode::kMJPEG) {
|
||||
return nullptr;
|
||||
}
|
||||
return ConvertImpl(image, pixelFormat, -1, 80);
|
||||
}
|
||||
Image* ConvertToMJPEG(Image* image, int requiredQuality,
|
||||
@@ -165,7 +203,9 @@ class Frame {
|
||||
Image* ConvertGrayToMJPEG(Image* image, int quality);
|
||||
|
||||
Image* GetImage(int width, int height, VideoMode::PixelFormat pixelFormat) {
|
||||
if (pixelFormat == VideoMode::kMJPEG) return nullptr;
|
||||
if (pixelFormat == VideoMode::kMJPEG) {
|
||||
return nullptr;
|
||||
}
|
||||
return GetImageImpl(width, height, pixelFormat, -1, 80);
|
||||
}
|
||||
Image* GetImageMJPEG(int width, int height, int requiredQuality,
|
||||
@@ -185,7 +225,9 @@ class Frame {
|
||||
Image* GetImageImpl(int width, int height, VideoMode::PixelFormat pixelFormat,
|
||||
int requiredJpegQuality, int defaultJpegQuality);
|
||||
void DecRef() {
|
||||
if (m_impl && --(m_impl->refcount) == 0) ReleaseFrame();
|
||||
if (m_impl && --(m_impl->refcount) == 0) {
|
||||
ReleaseFrame();
|
||||
}
|
||||
}
|
||||
void ReleaseFrame();
|
||||
|
||||
|
||||
@@ -30,26 +30,36 @@ HttpCameraImpl::~HttpCameraImpl() {
|
||||
m_monitorCond.notify_one();
|
||||
|
||||
// join monitor thread
|
||||
if (m_monitorThread.joinable()) m_monitorThread.join();
|
||||
if (m_monitorThread.joinable()) {
|
||||
m_monitorThread.join();
|
||||
}
|
||||
|
||||
// Close file if it's open
|
||||
{
|
||||
std::scoped_lock lock(m_mutex);
|
||||
if (m_streamConn) m_streamConn->stream->close();
|
||||
if (m_settingsConn) m_settingsConn->stream->close();
|
||||
if (m_streamConn) {
|
||||
m_streamConn->stream->close();
|
||||
}
|
||||
if (m_settingsConn) {
|
||||
m_settingsConn->stream->close();
|
||||
}
|
||||
}
|
||||
|
||||
// force wakeup of camera thread in case it's waiting on cv
|
||||
m_sinkEnabledCond.notify_one();
|
||||
|
||||
// join camera thread
|
||||
if (m_streamThread.joinable()) m_streamThread.join();
|
||||
if (m_streamThread.joinable()) {
|
||||
m_streamThread.join();
|
||||
}
|
||||
|
||||
// force wakeup of settings thread
|
||||
m_settingsCond.notify_one();
|
||||
|
||||
// join settings thread
|
||||
if (m_settingsThread.joinable()) m_settingsThread.join();
|
||||
if (m_settingsThread.joinable()) {
|
||||
m_settingsThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpCameraImpl::Start() {
|
||||
@@ -66,7 +76,9 @@ void HttpCameraImpl::MonitorThreadMain() {
|
||||
m_monitorCond.wait_for(lock, std::chrono::seconds(1),
|
||||
[=] { return !m_active; });
|
||||
|
||||
if (!m_active) break;
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
|
||||
// check to see if we got any frames, and close the stream if not
|
||||
// (this will result in an error at the read point, and ultimately
|
||||
@@ -93,20 +105,28 @@ void HttpCameraImpl::StreamThreadMain() {
|
||||
// disconnect if not enabled
|
||||
if (!IsEnabled()) {
|
||||
std::unique_lock lock(m_mutex);
|
||||
if (m_streamConn) m_streamConn->stream->close();
|
||||
if (m_streamConn) {
|
||||
m_streamConn->stream->close();
|
||||
}
|
||||
// Wait for enable
|
||||
m_sinkEnabledCond.wait(lock, [=] { return !m_active || IsEnabled(); });
|
||||
if (!m_active) return;
|
||||
if (!m_active) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// connect
|
||||
wpi::SmallString<64> boundary;
|
||||
wpi::HttpConnection* conn = DeviceStreamConnect(boundary);
|
||||
|
||||
if (!m_active) break;
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
|
||||
// keep retrying
|
||||
if (!conn) continue;
|
||||
if (!conn) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// update connected since we're actually connected
|
||||
SetConnected(true);
|
||||
@@ -134,7 +154,9 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
return nullptr;
|
||||
}
|
||||
if (m_nextLocation >= m_locations.size()) m_nextLocation = 0;
|
||||
if (m_nextLocation >= m_locations.size()) {
|
||||
m_nextLocation = 0;
|
||||
}
|
||||
req = wpi::HttpRequest{m_locations[m_nextLocation++], m_streamSettings};
|
||||
m_streamSettingsUpdated = false;
|
||||
}
|
||||
@@ -143,7 +165,9 @@ wpi::HttpConnection* HttpCameraImpl::DeviceStreamConnect(
|
||||
auto stream =
|
||||
wpi::TCPConnector::connect(req.host.c_str(), req.port, m_logger, 1);
|
||||
|
||||
if (!m_active || !stream) return nullptr;
|
||||
if (!m_active || !stream) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto connPtr = std::make_unique<wpi::HttpConnection>(std::move(stream), 1);
|
||||
wpi::HttpConnection* conn = connPtr.get();
|
||||
@@ -215,24 +239,33 @@ void HttpCameraImpl::DeviceStream(wpi::raw_istream& is,
|
||||
// streaming loop
|
||||
while (m_active && !is.has_error() && IsEnabled() && numErrors < 3 &&
|
||||
!m_streamSettingsUpdated) {
|
||||
if (!FindMultipartBoundary(is, boundary, nullptr)) break;
|
||||
if (!FindMultipartBoundary(is, boundary, nullptr)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Read the next two characters after the boundary (normally \r\n)
|
||||
// Handle just \n for LabVIEW however
|
||||
char eol[2];
|
||||
is.read(eol, 1);
|
||||
if (!m_active || is.has_error()) break;
|
||||
if (!m_active || is.has_error()) {
|
||||
break;
|
||||
}
|
||||
if (eol[0] != '\n') {
|
||||
is.read(eol + 1, 1);
|
||||
if (!m_active || is.has_error()) break;
|
||||
if (!m_active || is.has_error()) {
|
||||
break;
|
||||
}
|
||||
// End-of-stream is indicated with trailing --
|
||||
if (eol[0] == '-' && eol[1] == '-') break;
|
||||
if (eol[0] == '-' && eol[1] == '-') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!DeviceStreamFrame(is, imageBuf))
|
||||
if (!DeviceStreamFrame(is, imageBuf)) {
|
||||
++numErrors;
|
||||
else
|
||||
} else {
|
||||
numErrors = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +310,9 @@ bool HttpCameraImpl::DeviceStreamFrame(wpi::raw_istream& is,
|
||||
// the data directly into it.
|
||||
auto image = AllocImage(VideoMode::PixelFormat::kMJPEG, 0, 0, contentLength);
|
||||
is.read(image->data(), contentLength);
|
||||
if (!m_active || is.has_error()) return false;
|
||||
if (!m_active || is.has_error()) {
|
||||
return false;
|
||||
}
|
||||
int width, height;
|
||||
if (!GetJpegSize(image->str(), &width, &height)) {
|
||||
SWARNING("did not receive a JPEG image");
|
||||
@@ -299,7 +334,9 @@ void HttpCameraImpl::SettingsThreadMain() {
|
||||
m_settingsCond.wait(lock, [=] {
|
||||
return !m_active || (m_prefLocation != -1 && !m_settings.empty());
|
||||
});
|
||||
if (!m_active) break;
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Build the request
|
||||
req = wpi::HttpRequest{m_locations[m_prefLocation], m_settings};
|
||||
@@ -316,7 +353,9 @@ void HttpCameraImpl::DeviceSendSettings(wpi::HttpRequest& req) {
|
||||
auto stream =
|
||||
wpi::TCPConnector::connect(req.host.c_str(), req.port, m_logger, 1);
|
||||
|
||||
if (!m_active || !stream) return;
|
||||
if (!m_active || !stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto connPtr = std::make_unique<wpi::HttpConnection>(std::move(stream), 1);
|
||||
wpi::HttpConnection* conn = connPtr.get();
|
||||
@@ -329,7 +368,9 @@ 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);
|
||||
if (!conn->Handshake(req, &warn)) {
|
||||
SWARNING(GetName() << ": " << warn);
|
||||
}
|
||||
|
||||
conn->stream->close();
|
||||
}
|
||||
@@ -363,7 +404,9 @@ bool HttpCameraImpl::SetUrls(wpi::ArrayRef<std::string> urls,
|
||||
std::vector<std::string> HttpCameraImpl::GetUrls() const {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
std::vector<std::string> urls;
|
||||
for (const auto& loc : m_locations) urls.push_back(loc.url);
|
||||
for (const auto& loc : m_locations) {
|
||||
urls.push_back(loc.url);
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
@@ -393,7 +436,9 @@ void HttpCameraImpl::CreateEnumProperty(
|
||||
|
||||
auto& enumChoices = m_propertyData.back()->enumChoices;
|
||||
enumChoices.clear();
|
||||
for (const auto& choice : choices) enumChoices.emplace_back(choice);
|
||||
for (const auto& choice : choices) {
|
||||
enumChoices.emplace_back(choice);
|
||||
}
|
||||
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name,
|
||||
m_propertyData.size() + 1, CS_PROP_ENUM,
|
||||
@@ -468,7 +513,9 @@ void HttpCameraImpl::SetExposureManual(int value, CS_Status* status) {
|
||||
}
|
||||
|
||||
bool HttpCameraImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) {
|
||||
if (mode.pixelFormat != VideoMode::kMJPEG) return false;
|
||||
if (mode.pixelFormat != VideoMode::kMJPEG) {
|
||||
return false;
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_mode = mode;
|
||||
m_streamSettingsUpdated = true;
|
||||
@@ -527,7 +574,9 @@ CS_Source CreateHttpCamera(const wpi::Twine& name, const wpi::Twine& url,
|
||||
inst.notifier, inst.telemetry);
|
||||
break;
|
||||
}
|
||||
if (!source->SetUrls(url.str(), status)) return 0;
|
||||
if (!source->SetUrls(url.str(), status)) {
|
||||
return 0;
|
||||
}
|
||||
return inst.CreateSource(CS_SOURCE_HTTP, source);
|
||||
}
|
||||
|
||||
@@ -541,7 +590,9 @@ CS_Source CreateHttpCamera(const wpi::Twine& name,
|
||||
}
|
||||
auto source = std::make_shared<HttpCameraImpl>(name, kind, inst.logger,
|
||||
inst.notifier, inst.telemetry);
|
||||
if (!source->SetUrls(urls, status)) return 0;
|
||||
if (!source->SetUrls(urls, status)) {
|
||||
return 0;
|
||||
}
|
||||
return inst.CreateSource(CS_SOURCE_HTTP, source);
|
||||
}
|
||||
|
||||
@@ -592,7 +643,9 @@ CS_Source CS_CreateHttpCameraMulti(const char* name, const char** urls,
|
||||
CS_Status* status) {
|
||||
wpi::SmallVector<std::string, 4> vec;
|
||||
vec.reserve(count);
|
||||
for (int i = 0; i < count; ++i) vec.push_back(urls[i]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
vec.push_back(urls[i]);
|
||||
}
|
||||
return cs::CreateHttpCamera(name, vec, kind, status);
|
||||
}
|
||||
|
||||
@@ -604,7 +657,9 @@ void CS_SetHttpCameraUrls(CS_Source source, const char** urls, int count,
|
||||
CS_Status* status) {
|
||||
wpi::SmallVector<std::string, 4> vec;
|
||||
vec.reserve(count);
|
||||
for (int i = 0; i < count; ++i) vec.push_back(urls[i]);
|
||||
for (int i = 0; i < count; ++i) {
|
||||
vec.push_back(urls[i]);
|
||||
}
|
||||
cs::SetHttpCameraUrls(source, vec, status);
|
||||
}
|
||||
|
||||
@@ -613,13 +668,19 @@ char** CS_GetHttpCameraUrls(CS_Source source, int* count, CS_Status* status) {
|
||||
char** out =
|
||||
static_cast<char**>(wpi::safe_malloc(urls.size() * sizeof(char*)));
|
||||
*count = urls.size();
|
||||
for (size_t i = 0; i < urls.size(); ++i) out[i] = cs::ConvertToC(urls[i]);
|
||||
for (size_t i = 0; i < urls.size(); ++i) {
|
||||
out[i] = cs::ConvertToC(urls[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void CS_FreeHttpCameraUrls(char** urls, int count) {
|
||||
if (!urls) return;
|
||||
for (int i = 0; i < count; ++i) std::free(urls[i]);
|
||||
if (!urls) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
std::free(urls[i]);
|
||||
}
|
||||
std::free(urls);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,14 +22,15 @@ static void def_log_func(unsigned int level, const char* file,
|
||||
}
|
||||
|
||||
wpi::StringRef levelmsg;
|
||||
if (level >= 50)
|
||||
if (level >= 50) {
|
||||
levelmsg = "CRITICAL: ";
|
||||
else if (level >= 40)
|
||||
} else if (level >= 40) {
|
||||
levelmsg = "ERROR: ";
|
||||
else if (level >= 30)
|
||||
} else if (level >= 30) {
|
||||
levelmsg = "WARNING: ";
|
||||
else
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
oss << "CS: " << levelmsg << msg << " (" << wpi::sys::path::filename(file)
|
||||
<< ':' << line << ")\n";
|
||||
wpi::errs() << oss.str();
|
||||
@@ -55,7 +56,9 @@ void Instance::Shutdown() {
|
||||
notifier.Stop();
|
||||
}
|
||||
|
||||
void Instance::SetDefaultLogger() { logger.SetLogger(def_log_func); }
|
||||
void Instance::SetDefaultLogger() {
|
||||
logger.SetLogger(def_log_func);
|
||||
}
|
||||
|
||||
std::pair<CS_Source, std::shared_ptr<SourceData>> Instance::FindSource(
|
||||
const SourceImpl& source) {
|
||||
@@ -84,11 +87,13 @@ CS_Sink Instance::CreateSink(CS_SinkKind kind, std::shared_ptr<SinkImpl> sink) {
|
||||
}
|
||||
|
||||
void Instance::DestroySource(CS_Source handle) {
|
||||
if (auto data = m_sources.Free(handle))
|
||||
if (auto data = m_sources.Free(handle)) {
|
||||
notifier.NotifySource(data->source->GetName(), handle, CS_SOURCE_DESTROYED);
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::DestroySink(CS_Sink handle) {
|
||||
if (auto data = m_sinks.Free(handle))
|
||||
if (auto data = m_sinks.Free(handle)) {
|
||||
notifier.NotifySink(data->sink->GetName(), handle, CS_SINK_DESTROYED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,9 @@ class Instance {
|
||||
CS_Source source, wpi::SmallVectorImpl<CS_Sink>& vec) {
|
||||
vec.clear();
|
||||
m_sinks.ForEach([&](CS_Sink sinkHandle, const SinkData& data) {
|
||||
if (source == data.sourceHandle.load()) vec.push_back(sinkHandle);
|
||||
if (source == data.sourceHandle.load()) {
|
||||
vec.push_back(sinkHandle);
|
||||
}
|
||||
});
|
||||
return vec;
|
||||
}
|
||||
|
||||
@@ -47,28 +47,44 @@ static const unsigned char dhtData[] = {
|
||||
0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa};
|
||||
|
||||
bool IsJpeg(wpi::StringRef data) {
|
||||
if (data.size() < 11) return false;
|
||||
if (data.size() < 11) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for valid SOI
|
||||
auto bytes = data.bytes_begin();
|
||||
if (bytes[0] != 0xff || bytes[1] != 0xd8) return false;
|
||||
if (bytes[0] != 0xff || bytes[1] != 0xd8) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetJpegSize(wpi::StringRef data, int* width, int* height) {
|
||||
if (!IsJpeg(data)) return false;
|
||||
if (!IsJpeg(data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data = data.substr(2); // Get to the first block
|
||||
auto bytes = data.bytes_begin();
|
||||
for (;;) {
|
||||
if (data.size() < 4) return false; // EOF
|
||||
if (data.size() < 4) {
|
||||
return false; // EOF
|
||||
}
|
||||
bytes = data.bytes_begin();
|
||||
if (bytes[0] != 0xff) return false; // not a tag
|
||||
if (bytes[1] == 0xd9) return false; // EOI without finding SOF?
|
||||
if (bytes[1] == 0xda) return false; // SOS without finding SOF?
|
||||
if (bytes[0] != 0xff) {
|
||||
return false; // not a tag
|
||||
}
|
||||
if (bytes[1] == 0xd9) {
|
||||
return false; // EOI without finding SOF?
|
||||
}
|
||||
if (bytes[1] == 0xda) {
|
||||
return false; // SOS without finding SOF?
|
||||
}
|
||||
if (bytes[1] == 0xc0) {
|
||||
// SOF contains the file size
|
||||
if (data.size() < 9) return false;
|
||||
if (data.size() < 9) {
|
||||
return false;
|
||||
}
|
||||
*height = bytes[5] * 256 + bytes[6];
|
||||
*width = bytes[7] * 256 + bytes[8];
|
||||
return true;
|
||||
@@ -80,7 +96,9 @@ 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);
|
||||
if (!IsJpeg(sdata)) return false;
|
||||
if (!IsJpeg(sdata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*locSOF = *size;
|
||||
|
||||
@@ -88,12 +106,22 @@ bool JpegNeedsDHT(const char* data, size_t* size, size_t* locSOF) {
|
||||
sdata = sdata.substr(2); // Get to the first block
|
||||
auto bytes = sdata.bytes_begin();
|
||||
for (;;) {
|
||||
if (sdata.size() < 4) return false; // EOF
|
||||
if (sdata.size() < 4) {
|
||||
return false; // EOF
|
||||
}
|
||||
bytes = sdata.bytes_begin();
|
||||
if (bytes[0] != 0xff) return false; // not a tag
|
||||
if (bytes[1] == 0xda) break; // SOS
|
||||
if (bytes[1] == 0xc4) return false; // DHT
|
||||
if (bytes[1] == 0xc0) *locSOF = sdata.data() - data; // SOF
|
||||
if (bytes[0] != 0xff) {
|
||||
return false; // not a tag
|
||||
}
|
||||
if (bytes[1] == 0xda) {
|
||||
break; // SOS
|
||||
}
|
||||
if (bytes[1] == 0xc4) {
|
||||
return false; // DHT
|
||||
}
|
||||
if (bytes[1] == 0xc0) {
|
||||
*locSOF = sdata.data() - data; // SOF
|
||||
}
|
||||
// Go to the next block
|
||||
sdata = sdata.substr(bytes[2] * 256 + bytes[3] + 2);
|
||||
}
|
||||
@@ -126,18 +154,26 @@ bool ReadJpeg(wpi::raw_istream& is, std::string& buf, int* width, int* height) {
|
||||
// read SOI and first marker
|
||||
buf.resize(4);
|
||||
is.read(&(*buf.begin()), 4);
|
||||
if (is.has_error()) return false;
|
||||
if (is.has_error()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for valid SOI
|
||||
auto bytes = reinterpret_cast<const unsigned char*>(buf.data());
|
||||
if (bytes[0] != 0xff || bytes[1] != 0xd8) return false;
|
||||
if (bytes[0] != 0xff || bytes[1] != 0xd8) {
|
||||
return false;
|
||||
}
|
||||
size_t pos = 2; // point to first marker
|
||||
for (;;) {
|
||||
bytes = reinterpret_cast<const unsigned char*>(buf.data() + pos);
|
||||
if (bytes[0] != 0xff) return false; // not a marker
|
||||
if (bytes[0] != 0xff) {
|
||||
return false; // not a marker
|
||||
}
|
||||
unsigned char marker = bytes[1];
|
||||
|
||||
if (marker == 0xd9) return true; // EOI, we're done
|
||||
if (marker == 0xd9) {
|
||||
return true; // EOI, we're done
|
||||
}
|
||||
|
||||
if (marker == 0xda) {
|
||||
// SOS: need to keep reading until we reach a normal marker.
|
||||
@@ -147,12 +183,15 @@ bool ReadJpeg(wpi::raw_istream& is, std::string& buf, int* width, int* height) {
|
||||
bool maybeMarker = false;
|
||||
for (;;) {
|
||||
ReadInto(is, buf, 1);
|
||||
if (is.has_error()) return false;
|
||||
if (is.has_error()) {
|
||||
return false;
|
||||
}
|
||||
bytes = reinterpret_cast<const unsigned char*>(buf.data() + pos);
|
||||
if (maybeMarker) {
|
||||
if (bytes[0] != 0x00 && bytes[0] != 0xff &&
|
||||
(bytes[0] < 0xd0 || bytes[0] > 0xd7))
|
||||
(bytes[0] < 0xd0 || bytes[0] > 0xd7)) {
|
||||
break;
|
||||
}
|
||||
maybeMarker = false;
|
||||
} else if (bytes[0] == 0xff) {
|
||||
maybeMarker = true;
|
||||
@@ -165,7 +204,9 @@ bool ReadJpeg(wpi::raw_istream& is, std::string& buf, int* width, int* height) {
|
||||
|
||||
// A normal block. Read the length
|
||||
ReadInto(is, buf, 2); // read length
|
||||
if (is.has_error()) return false;
|
||||
if (is.has_error()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Point to length
|
||||
pos += 2;
|
||||
@@ -174,7 +215,9 @@ bool ReadJpeg(wpi::raw_istream& is, std::string& buf, int* width, int* height) {
|
||||
// Read the block and the next marker
|
||||
size_t blockLength = bytes[0] * 256 + bytes[1];
|
||||
ReadInto(is, buf, blockLength);
|
||||
if (is.has_error()) return false;
|
||||
if (is.has_error()) {
|
||||
return false;
|
||||
}
|
||||
bytes = reinterpret_cast<const unsigned char*>(buf.data() + pos);
|
||||
|
||||
// Special block processing
|
||||
|
||||
@@ -108,13 +108,17 @@ class MjpegServerImpl::ConnThread : public wpi::SafeThread {
|
||||
|
||||
void StartStream() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
if (m_source) m_source->EnableSink();
|
||||
if (m_source) {
|
||||
m_source->EnableSink();
|
||||
}
|
||||
m_streaming = true;
|
||||
}
|
||||
|
||||
void StopStream() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
if (m_source) m_source->DisableSink();
|
||||
if (m_source) {
|
||||
m_source->DisableSink();
|
||||
}
|
||||
m_streaming = false;
|
||||
}
|
||||
};
|
||||
@@ -140,7 +144,9 @@ static void SendHeader(wpi::raw_ostream& os, int code,
|
||||
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 (!extraStr.empty()) {
|
||||
os << extraStr << "\r\n";
|
||||
}
|
||||
os << "\r\n"; // header ends with a blank line
|
||||
}
|
||||
|
||||
@@ -198,9 +204,13 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
|
||||
// split out next param and value
|
||||
wpi::StringRef rawParam, rawValue;
|
||||
std::tie(rawParam, parameters) = parameters.split('&');
|
||||
if (rawParam.empty()) continue; // ignore "&&"
|
||||
if (rawParam.empty()) {
|
||||
continue; // ignore "&&"
|
||||
}
|
||||
std::tie(rawParam, rawValue) = rawParam.split('=');
|
||||
if (rawParam.empty() || rawValue.empty()) continue; // ignore "param="
|
||||
if (rawParam.empty() || rawValue.empty()) {
|
||||
continue; // ignore "param="
|
||||
}
|
||||
SDEBUG4("HTTP parameter \"" << rawParam << "\" value \"" << rawValue
|
||||
<< "\"");
|
||||
|
||||
@@ -282,7 +292,9 @@ bool MjpegServerImpl::ConnThread::ProcessCommand(wpi::raw_ostream& os,
|
||||
}
|
||||
|
||||
// ignore name parameter
|
||||
if (param == "name") continue;
|
||||
if (param == "name") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// try to assign parameter
|
||||
auto prop = source.GetPropertyIndex(param);
|
||||
@@ -339,7 +351,9 @@ void MjpegServerImpl::ConnThread::SendHTMLHeadTitle(
|
||||
// Send the root html file with controls for all the settable properties.
|
||||
void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
|
||||
SourceImpl& source, bool header) {
|
||||
if (header) SendHeader(os, 200, "OK", "text/html");
|
||||
if (header) {
|
||||
SendHeader(os, 200, "OK", "text/html");
|
||||
}
|
||||
|
||||
SendHTMLHeadTitle(os);
|
||||
os << startRootPage;
|
||||
@@ -348,7 +362,9 @@ 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_")) continue;
|
||||
if (name.startswith("raw_")) {
|
||||
continue;
|
||||
}
|
||||
auto kind = source.GetPropertyKind(prop);
|
||||
os << "<p />"
|
||||
<< "<label for=\"" << name << "\">" << name << "</label>\n";
|
||||
@@ -357,10 +373,11 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
|
||||
os << "<input id=\"" << name
|
||||
<< "\" type=\"checkbox\" onclick=\"update('" << name
|
||||
<< "', this.checked ? 1 : 0)\" ";
|
||||
if (source.GetProperty(prop, &status) != 0)
|
||||
if (source.GetProperty(prop, &status) != 0) {
|
||||
os << "checked />\n";
|
||||
else
|
||||
} else {
|
||||
os << " />\n";
|
||||
}
|
||||
break;
|
||||
case CS_PROP_INTEGER: {
|
||||
auto valI = source.GetProperty(prop, &status);
|
||||
@@ -381,11 +398,14 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
|
||||
int j = 0;
|
||||
for (auto choice = choices.begin(), end = choices.end(); choice != end;
|
||||
++j, ++choice) {
|
||||
if (choice->empty()) continue; // skip empty choices
|
||||
if (choice->empty()) {
|
||||
continue; // skip empty choices
|
||||
}
|
||||
// replace any non-printable characters in name with spaces
|
||||
wpi::SmallString<128> ch_name;
|
||||
for (char ch : *choice)
|
||||
for (char ch : *choice) {
|
||||
ch_name.push_back(std::isprint(ch) ? ch : ' ');
|
||||
}
|
||||
os << "<input id=\"" << name << j << "\" type=\"radio\" name=\""
|
||||
<< name << "\" value=\"" << ch_name << "\" onclick=\"update('"
|
||||
<< name << "', " << j << ")\"";
|
||||
@@ -416,8 +436,9 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
|
||||
&status);
|
||||
if (status == CS_OK) {
|
||||
os << "<p>USB device path: " << info.path << '\n';
|
||||
for (auto&& path : info.otherPaths)
|
||||
for (auto&& path : info.otherPaths) {
|
||||
os << "<p>Alternate device path: " << path << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
os << "<p>Supported Video Modes:</p>\n";
|
||||
@@ -461,17 +482,20 @@ void MjpegServerImpl::ConnThread::SendHTML(wpi::raw_ostream& os,
|
||||
// Send a JSON file which is contains information about the source parameters.
|
||||
void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
|
||||
SourceImpl& source, bool header) {
|
||||
if (header) SendHeader(os, 200, "OK", "application/json");
|
||||
if (header) {
|
||||
SendHeader(os, 200, "OK", "application/json");
|
||||
}
|
||||
|
||||
os << "{\n\"controls\": [\n";
|
||||
wpi::SmallVector<int, 32> properties_vec;
|
||||
bool first = true;
|
||||
CS_Status status = 0;
|
||||
for (auto prop : source.EnumerateProperties(properties_vec, &status)) {
|
||||
if (first)
|
||||
if (first) {
|
||||
first = false;
|
||||
else
|
||||
} else {
|
||||
os << ",\n";
|
||||
}
|
||||
os << '{';
|
||||
wpi::SmallString<128> name_buf;
|
||||
auto name = source.GetPropertyName(prop, name_buf, &status);
|
||||
@@ -511,10 +535,14 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
|
||||
int j = 0;
|
||||
for (auto choice = choices.begin(), end = choices.end(); choice != end;
|
||||
++j, ++choice) {
|
||||
if (j != 0) os << ", ";
|
||||
if (j != 0) {
|
||||
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 : ' ');
|
||||
for (char ch : *choice) {
|
||||
ch_name.push_back(std::isprint(ch) ? ch : ' ');
|
||||
}
|
||||
os << '"' << j << "\": \"" << ch_name << '"';
|
||||
}
|
||||
os << "}\n";
|
||||
@@ -524,10 +552,11 @@ void MjpegServerImpl::ConnThread::SendJSON(wpi::raw_ostream& os,
|
||||
os << "\n],\n\"modes\": [\n";
|
||||
first = true;
|
||||
for (auto mode : source.EnumerateVideoModes(&status)) {
|
||||
if (first)
|
||||
if (first) {
|
||||
first = false;
|
||||
else
|
||||
} else {
|
||||
os << ",\n";
|
||||
}
|
||||
os << '{';
|
||||
os << "\n\"pixelFormat\": \"";
|
||||
switch (mode.pixelFormat) {
|
||||
@@ -596,7 +625,9 @@ MjpegServerImpl::MjpegServerImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
m_serverThread = std::thread(&MjpegServerImpl::ServerThreadMain, this);
|
||||
}
|
||||
|
||||
MjpegServerImpl::~MjpegServerImpl() { Stop(); }
|
||||
MjpegServerImpl::~MjpegServerImpl() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void MjpegServerImpl::Stop() {
|
||||
m_active = false;
|
||||
@@ -605,18 +636,24 @@ void MjpegServerImpl::Stop() {
|
||||
m_acceptor->shutdown();
|
||||
|
||||
// join server thread
|
||||
if (m_serverThread.joinable()) m_serverThread.join();
|
||||
if (m_serverThread.joinable()) {
|
||||
m_serverThread.join();
|
||||
}
|
||||
|
||||
// close streams
|
||||
for (auto& connThread : m_connThreads) {
|
||||
if (auto thr = connThread.GetThread()) {
|
||||
if (thr->m_stream) thr->m_stream->close();
|
||||
if (thr->m_stream) {
|
||||
thr->m_stream->close();
|
||||
}
|
||||
}
|
||||
connThread.Stop();
|
||||
}
|
||||
|
||||
// wake up connection threads by forcing an empty frame to be sent
|
||||
if (auto source = GetSource()) source->Wakeup();
|
||||
if (auto source = GetSource()) {
|
||||
source->Wakeup();
|
||||
}
|
||||
}
|
||||
|
||||
// Send HTTP response and a stream of JPG-frames
|
||||
@@ -639,10 +676,14 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
|
||||
|
||||
Frame::Time lastFrameTime = 0;
|
||||
Frame::Time timePerFrame = 0;
|
||||
if (m_fps != 0) timePerFrame = 1000000.0 / m_fps;
|
||||
if (m_fps != 0) {
|
||||
timePerFrame = 1000000.0 / m_fps;
|
||||
}
|
||||
Frame::Time averageFrameTime = 0;
|
||||
Frame::Time averagePeriod = 1000000; // 1 second window
|
||||
if (averagePeriod < timePerFrame) averagePeriod = timePerFrame * 10;
|
||||
if (averagePeriod < timePerFrame) {
|
||||
averagePeriod = timePerFrame * 10;
|
||||
}
|
||||
|
||||
StartStream();
|
||||
while (m_active && !os.has_error()) {
|
||||
@@ -655,7 +696,9 @@ void MjpegServerImpl::ConnThread::SendStream(wpi::raw_socket_ostream& os) {
|
||||
}
|
||||
SDEBUG4("waiting for frame");
|
||||
Frame frame = source->GetNextFrame(0.225); // blocks
|
||||
if (!m_active) break;
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
if (!frame) {
|
||||
// Bad frame; sleep for 20 ms so we don't consume all processor time.
|
||||
os << "\r\n"; // Keep connection alive
|
||||
@@ -804,8 +847,12 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
|
||||
// The end of the request is marked by a single, empty line
|
||||
wpi::SmallString<128> lineBuf;
|
||||
for (;;) {
|
||||
if (is.getline(lineBuf, 4096).startswith("\n")) break;
|
||||
if (is.has_error()) return;
|
||||
if (is.getline(lineBuf, 4096).startswith("\n")) {
|
||||
break;
|
||||
}
|
||||
if (is.has_error()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Send response
|
||||
@@ -813,7 +860,9 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
|
||||
case kStream:
|
||||
if (auto source = GetSource()) {
|
||||
SDEBUG("request for stream " << source->GetName());
|
||||
if (!ProcessCommand(os, *source, parameters, false)) return;
|
||||
if (!ProcessCommand(os, *source, parameters, false)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
SendStream(os);
|
||||
break;
|
||||
@@ -829,10 +878,11 @@ void MjpegServerImpl::ConnThread::ProcessRequest() {
|
||||
break;
|
||||
case kGetSettings:
|
||||
SDEBUG("request for JSON file");
|
||||
if (auto source = GetSource())
|
||||
if (auto source = GetSource()) {
|
||||
SendJSON(os, *source, true);
|
||||
else
|
||||
} else {
|
||||
SendError(os, 404, "Resource not found");
|
||||
}
|
||||
break;
|
||||
case kGetSourceConfig:
|
||||
SDEBUG("request for JSON file");
|
||||
@@ -866,7 +916,9 @@ void MjpegServerImpl::ConnThread::Main() {
|
||||
while (m_active) {
|
||||
while (!m_stream) {
|
||||
m_cond.wait(lock);
|
||||
if (!m_active) return;
|
||||
if (!m_active) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
ProcessRequest();
|
||||
@@ -889,7 +941,9 @@ void MjpegServerImpl::ServerThreadMain() {
|
||||
m_active = false;
|
||||
return;
|
||||
}
|
||||
if (!m_active) return;
|
||||
if (!m_active) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDEBUG("client connection from " << stream->getPeerIP());
|
||||
|
||||
@@ -939,9 +993,13 @@ void MjpegServerImpl::SetSourceImpl(std::shared_ptr<SourceImpl> source) {
|
||||
if (auto thr = connThread.GetThread()) {
|
||||
if (thr->m_source != source) {
|
||||
bool streaming = thr->m_streaming;
|
||||
if (thr->m_source && streaming) thr->m_source->DisableSink();
|
||||
if (thr->m_source && streaming) {
|
||||
thr->m_source->DisableSink();
|
||||
}
|
||||
thr->m_source = source;
|
||||
if (source && streaming) thr->m_source->EnableSink();
|
||||
if (source && streaming) {
|
||||
thr->m_source->EnableSink();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,9 @@ class UidVector {
|
||||
// one. The element is added to the freelist for later reuse.
|
||||
void erase(unsigned int uid) {
|
||||
--uid;
|
||||
if (uid >= m_vector.size() || !m_vector[uid]) return;
|
||||
if (uid >= m_vector.size() || !m_vector[uid]) {
|
||||
return;
|
||||
}
|
||||
m_free.push_back(uid);
|
||||
m_vector[uid] = T();
|
||||
}
|
||||
@@ -88,35 +90,53 @@ class Notifier::Thread : public wpi::SafeThread {
|
||||
std::function<void()> m_on_exit;
|
||||
};
|
||||
|
||||
Notifier::Notifier() { s_destroyed = false; }
|
||||
Notifier::Notifier() {
|
||||
s_destroyed = false;
|
||||
}
|
||||
|
||||
Notifier::~Notifier() { s_destroyed = true; }
|
||||
Notifier::~Notifier() {
|
||||
s_destroyed = true;
|
||||
}
|
||||
|
||||
void Notifier::Start() { m_owner.Start(m_on_start, m_on_exit); }
|
||||
void Notifier::Start() {
|
||||
m_owner.Start(m_on_start, m_on_exit);
|
||||
}
|
||||
|
||||
void Notifier::Stop() { m_owner.Stop(); }
|
||||
void Notifier::Stop() {
|
||||
m_owner.Stop();
|
||||
}
|
||||
|
||||
void Notifier::Thread::Main() {
|
||||
if (m_on_start) m_on_start();
|
||||
if (m_on_start) {
|
||||
m_on_start();
|
||||
}
|
||||
|
||||
std::unique_lock lock(m_mutex);
|
||||
while (m_active) {
|
||||
while (m_notifications.empty()) {
|
||||
m_cond.wait(lock);
|
||||
if (!m_active) goto done;
|
||||
if (!m_active) {
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
while (!m_notifications.empty()) {
|
||||
if (!m_active) goto done;
|
||||
if (!m_active) {
|
||||
goto done;
|
||||
}
|
||||
auto item = std::move(m_notifications.front());
|
||||
m_notifications.pop();
|
||||
|
||||
// Use index because iterator might get invalidated.
|
||||
for (size_t i = 0; i < m_listeners.size(); ++i) {
|
||||
if (!m_listeners[i]) continue; // removed
|
||||
if (!m_listeners[i]) {
|
||||
continue; // removed
|
||||
}
|
||||
|
||||
// Event type must be within requested set for this listener.
|
||||
if ((item.kind & m_listeners[i].eventMask) == 0) continue;
|
||||
if ((item.kind & m_listeners[i].eventMask) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// make a copy of the callback so we can safely release the mutex
|
||||
auto callback = m_listeners[i].callback;
|
||||
@@ -130,7 +150,9 @@ void Notifier::Thread::Main() {
|
||||
}
|
||||
|
||||
done:
|
||||
if (m_on_exit) m_on_exit();
|
||||
if (m_on_exit) {
|
||||
m_on_exit();
|
||||
}
|
||||
}
|
||||
|
||||
int Notifier::AddListener(std::function<void(const RawEvent& event)> callback,
|
||||
@@ -142,14 +164,18 @@ int Notifier::AddListener(std::function<void(const RawEvent& event)> callback,
|
||||
|
||||
void Notifier::RemoveListener(int uid) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
thr->m_listeners.erase(uid);
|
||||
}
|
||||
|
||||
void Notifier::NotifySource(const wpi::Twine& name, CS_Source source,
|
||||
CS_EventKind kind) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
thr->m_notifications.emplace(name, source, static_cast<RawEvent::Kind>(kind));
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
@@ -162,7 +188,9 @@ void Notifier::NotifySource(const SourceImpl& source, CS_EventKind kind) {
|
||||
void Notifier::NotifySourceVideoMode(const SourceImpl& source,
|
||||
const VideoMode& mode) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
|
||||
@@ -175,7 +203,9 @@ void Notifier::NotifySourceProperty(const SourceImpl& source, CS_EventKind kind,
|
||||
int property, CS_PropertyKind propertyKind,
|
||||
int value, const wpi::Twine& valueStr) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
|
||||
@@ -189,7 +219,9 @@ void Notifier::NotifySourceProperty(const SourceImpl& source, CS_EventKind kind,
|
||||
void Notifier::NotifySink(const wpi::Twine& name, CS_Sink sink,
|
||||
CS_EventKind kind) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
|
||||
thr->m_notifications.emplace(name, sink, static_cast<RawEvent::Kind>(kind));
|
||||
thr->m_cond.notify_one();
|
||||
@@ -203,7 +235,9 @@ void Notifier::NotifySink(const SinkImpl& sink, CS_EventKind kind) {
|
||||
void Notifier::NotifySinkSourceChanged(const wpi::Twine& name, CS_Sink sink,
|
||||
CS_Source source) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
|
||||
RawEvent event{name, sink, RawEvent::kSinkSourceChanged};
|
||||
event.sourceHandle = source;
|
||||
@@ -217,7 +251,9 @@ void Notifier::NotifySinkProperty(const SinkImpl& sink, CS_EventKind kind,
|
||||
CS_PropertyKind propertyKind, int value,
|
||||
const wpi::Twine& valueStr) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto handleData = Instance::GetInstance().FindSink(sink);
|
||||
|
||||
@@ -230,7 +266,9 @@ void Notifier::NotifySinkProperty(const SinkImpl& sink, CS_EventKind kind,
|
||||
|
||||
void Notifier::NotifyNetworkInterfacesChanged() {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
|
||||
thr->m_notifications.emplace(RawEvent::kNetworkInterfacesChanged);
|
||||
thr->m_cond.notify_one();
|
||||
@@ -238,7 +276,9 @@ void Notifier::NotifyNetworkInterfacesChanged() {
|
||||
|
||||
void Notifier::NotifyTelemetryUpdated() {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
|
||||
thr->m_notifications.emplace(RawEvent::kTelemetryUpdated);
|
||||
thr->m_cond.notify_one();
|
||||
|
||||
@@ -14,7 +14,9 @@ using namespace cs;
|
||||
int PropertyContainer::GetPropertyIndex(const wpi::Twine& 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);
|
||||
if (!m_properties_cached) {
|
||||
CacheProperties(&status);
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
wpi::SmallVector<char, 64> nameBuf;
|
||||
int& ndx = m_properties[name.toStringRef(nameBuf)];
|
||||
@@ -28,39 +30,50 @@ int PropertyContainer::GetPropertyIndex(const wpi::Twine& name) const {
|
||||
|
||||
wpi::ArrayRef<int> PropertyContainer::EnumerateProperties(
|
||||
wpi::SmallVectorImpl<int>& vec, CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status))
|
||||
return wpi::ArrayRef<int>{};
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return {};
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
for (int i = 0; i < static_cast<int>(m_propertyData.size()); ++i) {
|
||||
if (m_propertyData[i]) vec.push_back(i + 1);
|
||||
if (m_propertyData[i]) {
|
||||
vec.push_back(i + 1);
|
||||
}
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
CS_PropertyKind PropertyContainer::GetPropertyKind(int property) const {
|
||||
CS_Status status = 0;
|
||||
if (!m_properties_cached && !CacheProperties(&status)) return CS_PROP_NONE;
|
||||
if (!m_properties_cached && !CacheProperties(&status)) {
|
||||
return CS_PROP_NONE;
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) return CS_PROP_NONE;
|
||||
if (!prop) {
|
||||
return CS_PROP_NONE;
|
||||
}
|
||||
return prop->propKind;
|
||||
}
|
||||
|
||||
wpi::StringRef PropertyContainer::GetPropertyName(
|
||||
int property, wpi::SmallVectorImpl<char>& buf, CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status)) return wpi::StringRef{};
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return {};
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
*status = CS_INVALID_PROPERTY;
|
||||
return wpi::StringRef{};
|
||||
return {};
|
||||
}
|
||||
// safe to not copy because we never modify it after caching
|
||||
return prop->name;
|
||||
}
|
||||
|
||||
int PropertyContainer::GetProperty(int property, CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status)) return 0;
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
@@ -85,7 +98,9 @@ void PropertyContainer::SetProperty(int property, int value,
|
||||
}
|
||||
|
||||
// Guess it's integer if we've set before get
|
||||
if (prop->propKind == CS_PROP_NONE) prop->propKind = CS_PROP_INTEGER;
|
||||
if (prop->propKind == CS_PROP_NONE) {
|
||||
prop->propKind = CS_PROP_INTEGER;
|
||||
}
|
||||
|
||||
if ((prop->propKind & (CS_PROP_BOOLEAN | CS_PROP_INTEGER | CS_PROP_ENUM)) ==
|
||||
0) {
|
||||
@@ -97,7 +112,9 @@ void PropertyContainer::SetProperty(int property, int value,
|
||||
}
|
||||
|
||||
int PropertyContainer::GetPropertyMin(int property, CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status)) return 0;
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
@@ -108,7 +125,9 @@ int PropertyContainer::GetPropertyMin(int property, CS_Status* status) const {
|
||||
}
|
||||
|
||||
int PropertyContainer::GetPropertyMax(int property, CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status)) return 0;
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
@@ -119,7 +138,9 @@ int PropertyContainer::GetPropertyMax(int property, CS_Status* status) const {
|
||||
}
|
||||
|
||||
int PropertyContainer::GetPropertyStep(int property, CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status)) return 0;
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
@@ -131,7 +152,9 @@ int PropertyContainer::GetPropertyStep(int property, CS_Status* status) const {
|
||||
|
||||
int PropertyContainer::GetPropertyDefault(int property,
|
||||
CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status)) return 0;
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return 0;
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
@@ -143,16 +166,18 @@ int PropertyContainer::GetPropertyDefault(int property,
|
||||
|
||||
wpi::StringRef PropertyContainer::GetStringProperty(
|
||||
int property, wpi::SmallVectorImpl<char>& buf, CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status)) return wpi::StringRef{};
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return {};
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
*status = CS_INVALID_PROPERTY;
|
||||
return wpi::StringRef{};
|
||||
return {};
|
||||
}
|
||||
if (prop->propKind != CS_PROP_STRING) {
|
||||
*status = CS_WRONG_PROPERTY_TYPE;
|
||||
return wpi::StringRef{};
|
||||
return {};
|
||||
}
|
||||
buf.clear();
|
||||
buf.append(prop->valueStr.begin(), prop->valueStr.end());
|
||||
@@ -169,7 +194,9 @@ void PropertyContainer::SetStringProperty(int property, const wpi::Twine& value,
|
||||
}
|
||||
|
||||
// Guess it's string if we've set before get
|
||||
if (prop->propKind == CS_PROP_NONE) prop->propKind = CS_PROP_STRING;
|
||||
if (prop->propKind == CS_PROP_NONE) {
|
||||
prop->propKind = CS_PROP_STRING;
|
||||
}
|
||||
|
||||
if (prop->propKind != CS_PROP_STRING) {
|
||||
*status = CS_WRONG_PROPERTY_TYPE;
|
||||
@@ -181,17 +208,18 @@ void PropertyContainer::SetStringProperty(int property, const wpi::Twine& value,
|
||||
|
||||
std::vector<std::string> PropertyContainer::GetEnumPropertyChoices(
|
||||
int property, CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status))
|
||||
return std::vector<std::string>{};
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return {};
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) {
|
||||
*status = CS_INVALID_PROPERTY;
|
||||
return std::vector<std::string>{};
|
||||
return {};
|
||||
}
|
||||
if (prop->propKind != CS_PROP_ENUM) {
|
||||
*status = CS_WRONG_PROPERTY_TYPE;
|
||||
return std::vector<std::string>{};
|
||||
return {};
|
||||
}
|
||||
return prop->enumChoices;
|
||||
}
|
||||
|
||||
@@ -59,13 +59,17 @@ class PropertyContainer {
|
||||
protected:
|
||||
// Get a property; must be called with m_mutex held.
|
||||
PropertyImpl* GetProperty(int property) {
|
||||
if (property <= 0 || static_cast<size_t>(property) > m_propertyData.size())
|
||||
if (property <= 0 ||
|
||||
static_cast<size_t>(property) > m_propertyData.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_propertyData[property - 1].get();
|
||||
}
|
||||
const PropertyImpl* GetProperty(int property) const {
|
||||
if (property <= 0 || static_cast<size_t>(property) > m_propertyData.size())
|
||||
if (property <= 0 ||
|
||||
static_cast<size_t>(property) > m_propertyData.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_propertyData[property - 1].get();
|
||||
}
|
||||
// Create or update a property; must be called with m_mutex held.
|
||||
|
||||
@@ -29,15 +29,18 @@ PropertyImpl::PropertyImpl(const wpi::Twine& name_, CS_PropertyKind kind_,
|
||||
|
||||
void PropertyImpl::SetValue(int v) {
|
||||
int oldValue = value;
|
||||
if (hasMinimum && v < minimum)
|
||||
if (hasMinimum && v < minimum) {
|
||||
value = minimum;
|
||||
else if (hasMaximum && v > maximum)
|
||||
} else if (hasMaximum && v > maximum) {
|
||||
value = maximum;
|
||||
else
|
||||
} else {
|
||||
value = v;
|
||||
}
|
||||
bool wasValueSet = valueSet;
|
||||
valueSet = true;
|
||||
if (!wasValueSet || value != oldValue) changed();
|
||||
if (!wasValueSet || value != oldValue) {
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyImpl::SetValue(const wpi::Twine& v) {
|
||||
@@ -49,14 +52,17 @@ void PropertyImpl::SetValue(const wpi::Twine& v) {
|
||||
}
|
||||
bool wasValueSet = valueSet;
|
||||
valueSet = true;
|
||||
if (!wasValueSet || valueChanged) changed();
|
||||
if (!wasValueSet || valueChanged) {
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
void PropertyImpl::SetDefaultValue(int v) {
|
||||
if (hasMinimum && v < minimum)
|
||||
if (hasMinimum && v < minimum) {
|
||||
defaultValue = minimum;
|
||||
else if (hasMaximum && v > maximum)
|
||||
} else if (hasMaximum && v > maximum) {
|
||||
defaultValue = maximum;
|
||||
else
|
||||
} else {
|
||||
defaultValue = v;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,22 @@ RawSinkImpl::RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
std::function<void(uint64_t time)> processFrame)
|
||||
: SinkImpl{name, logger, notifier, telemetry} {}
|
||||
|
||||
RawSinkImpl::~RawSinkImpl() { Stop(); }
|
||||
RawSinkImpl::~RawSinkImpl() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void RawSinkImpl::Stop() {
|
||||
m_active = false;
|
||||
|
||||
// wake up any waiters by forcing an empty frame to be sent
|
||||
if (auto source = GetSource()) source->Wakeup();
|
||||
if (auto source = GetSource()) {
|
||||
source->Wakeup();
|
||||
}
|
||||
|
||||
// join thread
|
||||
if (m_thread.joinable()) m_thread.join();
|
||||
if (m_thread.joinable()) {
|
||||
m_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t RawSinkImpl::GrabFrame(CS_RawFrame& image) {
|
||||
@@ -123,7 +129,9 @@ void RawSinkImpl::ThreadMain() {
|
||||
}
|
||||
SDEBUG4("waiting for frame");
|
||||
Frame frame = source->GetNextFrame(); // blocks
|
||||
if (!m_active) break;
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
if (!frame) {
|
||||
// Bad frame; sleep for 10 ms so we don't consume all processor time.
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
@@ -21,7 +21,9 @@ SinkImpl::SinkImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
|
||||
SinkImpl::~SinkImpl() {
|
||||
if (m_source) {
|
||||
if (m_enabledCount > 0) m_source->DisableSink();
|
||||
if (m_enabledCount > 0) {
|
||||
m_source->DisableSink();
|
||||
}
|
||||
m_source->RemoveSink();
|
||||
}
|
||||
}
|
||||
@@ -41,7 +43,9 @@ void SinkImpl::Enable() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
++m_enabledCount;
|
||||
if (m_enabledCount == 1) {
|
||||
if (m_source) m_source->EnableSink();
|
||||
if (m_source) {
|
||||
m_source->EnableSink();
|
||||
}
|
||||
m_notifier.NotifySink(*this, CS_SINK_ENABLED);
|
||||
}
|
||||
}
|
||||
@@ -50,7 +54,9 @@ void SinkImpl::Disable() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
--m_enabledCount;
|
||||
if (m_enabledCount == 0) {
|
||||
if (m_source) m_source->DisableSink();
|
||||
if (m_source) {
|
||||
m_source->DisableSink();
|
||||
}
|
||||
m_notifier.NotifySink(*this, CS_SINK_DISABLED);
|
||||
}
|
||||
}
|
||||
@@ -58,11 +64,15 @@ void SinkImpl::Disable() {
|
||||
void SinkImpl::SetEnabled(bool enabled) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
if (enabled && m_enabledCount == 0) {
|
||||
if (m_source) m_source->EnableSink();
|
||||
if (m_source) {
|
||||
m_source->EnableSink();
|
||||
}
|
||||
m_enabledCount = 1;
|
||||
m_notifier.NotifySink(*this, CS_SINK_ENABLED);
|
||||
} else if (!enabled && m_enabledCount > 0) {
|
||||
if (m_source) m_source->DisableSink();
|
||||
if (m_source) {
|
||||
m_source->DisableSink();
|
||||
}
|
||||
m_enabledCount = 0;
|
||||
m_notifier.NotifySink(*this, CS_SINK_DISABLED);
|
||||
}
|
||||
@@ -71,15 +81,21 @@ void SinkImpl::SetEnabled(bool enabled) {
|
||||
void SinkImpl::SetSource(std::shared_ptr<SourceImpl> source) {
|
||||
{
|
||||
std::scoped_lock lock(m_mutex);
|
||||
if (m_source == source) return;
|
||||
if (m_source == source) {
|
||||
return;
|
||||
}
|
||||
if (m_source) {
|
||||
if (m_enabledCount > 0) m_source->DisableSink();
|
||||
if (m_enabledCount > 0) {
|
||||
m_source->DisableSink();
|
||||
}
|
||||
m_source->RemoveSink();
|
||||
}
|
||||
m_source = source;
|
||||
if (m_source) {
|
||||
m_source->AddSink();
|
||||
if (m_enabledCount > 0) m_source->EnableSink();
|
||||
if (m_enabledCount > 0) {
|
||||
m_source->EnableSink();
|
||||
}
|
||||
}
|
||||
}
|
||||
SetSourceImpl(source);
|
||||
@@ -87,13 +103,17 @@ void SinkImpl::SetSource(std::shared_ptr<SourceImpl> source) {
|
||||
|
||||
std::string SinkImpl::GetError() const {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
if (!m_source) return "no source connected";
|
||||
if (!m_source) {
|
||||
return "no source connected";
|
||||
}
|
||||
return m_source->GetCurFrame().GetError();
|
||||
}
|
||||
|
||||
wpi::StringRef SinkImpl::GetError(wpi::SmallVectorImpl<char>& buf) const {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
if (!m_source) return "no source connected";
|
||||
if (!m_source) {
|
||||
return "no source connected";
|
||||
}
|
||||
// Make a copy as it's shared data
|
||||
wpi::StringRef error = m_source->GetCurFrame().GetError();
|
||||
buf.clear();
|
||||
@@ -115,8 +135,9 @@ bool SinkImpl::SetConfigJson(wpi::StringRef config, CS_Status* status) {
|
||||
}
|
||||
|
||||
bool SinkImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
|
||||
if (config.count("properties") != 0)
|
||||
if (config.count("properties") != 0) {
|
||||
SetPropertiesJson(config.at("properties"), m_logger, GetName(), status);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -133,7 +154,9 @@ wpi::json SinkImpl::GetConfigJsonObject(CS_Status* status) {
|
||||
wpi::json j;
|
||||
|
||||
wpi::json props = GetPropertiesJsonObject(status);
|
||||
if (props.is_array()) j.emplace("properties", props);
|
||||
if (props.is_array()) {
|
||||
j.emplace("properties", props);
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
@@ -143,21 +166,25 @@ void SinkImpl::NotifyPropertyCreated(int propIndex, PropertyImpl& prop) {
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
// also notify choices updated event for enum types
|
||||
if (prop.propKind == CS_PROP_ENUM)
|
||||
if (prop.propKind == CS_PROP_ENUM) {
|
||||
m_notifier.NotifySinkProperty(*this, CS_SINK_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind,
|
||||
prop.value, wpi::Twine{});
|
||||
}
|
||||
}
|
||||
|
||||
void SinkImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
const wpi::Twine& valueStr) {
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) return;
|
||||
if (!prop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (setString)
|
||||
if (setString) {
|
||||
prop->SetValue(valueStr);
|
||||
else
|
||||
} else {
|
||||
prop->SetValue(value);
|
||||
}
|
||||
|
||||
// Only notify updates after we've notified created
|
||||
if (m_properties_cached) {
|
||||
|
||||
@@ -54,10 +54,11 @@ wpi::StringRef SourceImpl::GetDescription(
|
||||
|
||||
void SourceImpl::SetConnected(bool connected) {
|
||||
bool wasConnected = m_connected.exchange(connected);
|
||||
if (wasConnected && !connected)
|
||||
if (wasConnected && !connected) {
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_DISCONNECTED);
|
||||
else if (!wasConnected && connected)
|
||||
} else if (!wasConnected && connected) {
|
||||
m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t SourceImpl::GetCurFrameTime() {
|
||||
@@ -130,7 +131,9 @@ void SourceImpl::SetExposureManual(int value, CS_Status* status) {
|
||||
}
|
||||
|
||||
VideoMode SourceImpl::GetVideoMode(CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status)) return VideoMode{};
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return {};
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
return m_mode;
|
||||
}
|
||||
@@ -138,14 +141,18 @@ VideoMode SourceImpl::GetVideoMode(CS_Status* status) const {
|
||||
bool SourceImpl::SetPixelFormat(VideoMode::PixelFormat pixelFormat,
|
||||
CS_Status* status) {
|
||||
auto mode = GetVideoMode(status);
|
||||
if (!mode) return false;
|
||||
if (!mode) {
|
||||
return false;
|
||||
}
|
||||
mode.pixelFormat = pixelFormat;
|
||||
return SetVideoMode(mode, status);
|
||||
}
|
||||
|
||||
bool SourceImpl::SetResolution(int width, int height, CS_Status* status) {
|
||||
auto mode = GetVideoMode(status);
|
||||
if (!mode) return false;
|
||||
if (!mode) {
|
||||
return false;
|
||||
}
|
||||
mode.width = width;
|
||||
mode.height = height;
|
||||
return SetVideoMode(mode, status);
|
||||
@@ -153,7 +160,9 @@ bool SourceImpl::SetResolution(int width, int height, CS_Status* status) {
|
||||
|
||||
bool SourceImpl::SetFPS(int fps, CS_Status* status) {
|
||||
auto mode = GetVideoMode(status);
|
||||
if (!mode) return false;
|
||||
if (!mode) {
|
||||
return false;
|
||||
}
|
||||
mode.fps = fps;
|
||||
return SetVideoMode(mode, status);
|
||||
}
|
||||
@@ -315,8 +324,9 @@ bool SourceImpl::SetConfigJson(const wpi::json& config, CS_Status* status) {
|
||||
}
|
||||
|
||||
// properties
|
||||
if (config.count("properties") != 0)
|
||||
if (config.count("properties") != 0) {
|
||||
SetPropertiesJson(config.at("properties"), m_logger, GetName(), status);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -353,30 +363,41 @@ wpi::json SourceImpl::GetConfigJsonObject(CS_Status* status) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!pixelFormat.empty()) j.emplace("pixel format", pixelFormat);
|
||||
if (!pixelFormat.empty()) {
|
||||
j.emplace("pixel format", pixelFormat);
|
||||
}
|
||||
|
||||
// width
|
||||
if (m_mode.width != 0) j.emplace("width", m_mode.width);
|
||||
if (m_mode.width != 0) {
|
||||
j.emplace("width", m_mode.width);
|
||||
}
|
||||
|
||||
// height
|
||||
if (m_mode.height != 0) j.emplace("height", m_mode.height);
|
||||
if (m_mode.height != 0) {
|
||||
j.emplace("height", m_mode.height);
|
||||
}
|
||||
|
||||
// fps
|
||||
if (m_mode.fps != 0) j.emplace("fps", m_mode.fps);
|
||||
if (m_mode.fps != 0) {
|
||||
j.emplace("fps", m_mode.fps);
|
||||
}
|
||||
|
||||
// TODO: output brightness, white balance, and exposure?
|
||||
|
||||
// properties
|
||||
wpi::json props = GetPropertiesJsonObject(status);
|
||||
if (props.is_array()) j.emplace("properties", props);
|
||||
if (props.is_array()) {
|
||||
j.emplace("properties", props);
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
std::vector<VideoMode> SourceImpl::EnumerateVideoModes(
|
||||
CS_Status* status) const {
|
||||
if (!m_properties_cached && !CacheProperties(status))
|
||||
return std::vector<VideoMode>{};
|
||||
if (!m_properties_cached && !CacheProperties(status)) {
|
||||
return {};
|
||||
}
|
||||
std::scoped_lock lock(m_mutex);
|
||||
return m_videoModes;
|
||||
}
|
||||
@@ -401,10 +422,11 @@ std::unique_ptr<Image> SourceImpl::AllocImage(
|
||||
}
|
||||
|
||||
// if nothing found, allocate a new buffer
|
||||
if (found < 0)
|
||||
if (found < 0) {
|
||||
image.reset(new Image{size});
|
||||
else
|
||||
} else {
|
||||
image = std::move(m_imagesAvail[found]);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize image
|
||||
@@ -461,21 +483,25 @@ void SourceImpl::NotifyPropertyCreated(int propIndex, PropertyImpl& prop) {
|
||||
propIndex, prop.propKind, prop.value,
|
||||
prop.valueStr);
|
||||
// also notify choices updated event for enum types
|
||||
if (prop.propKind == CS_PROP_ENUM)
|
||||
if (prop.propKind == CS_PROP_ENUM) {
|
||||
m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
|
||||
prop.name, propIndex, prop.propKind,
|
||||
prop.value, wpi::Twine{});
|
||||
}
|
||||
}
|
||||
|
||||
void SourceImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
const wpi::Twine& valueStr) {
|
||||
auto prop = GetProperty(property);
|
||||
if (!prop) return;
|
||||
if (!prop) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (setString)
|
||||
if (setString) {
|
||||
prop->SetValue(valueStr);
|
||||
else
|
||||
} else {
|
||||
prop->SetValue(value);
|
||||
}
|
||||
|
||||
// Only notify updates after we've notified created
|
||||
if (m_properties_cached) {
|
||||
@@ -487,7 +513,9 @@ void SourceImpl::UpdatePropertyValue(int property, bool setString, int value,
|
||||
|
||||
void SourceImpl::ReleaseImage(std::unique_ptr<Image> image) {
|
||||
std::scoped_lock lock{m_poolMutex};
|
||||
if (m_destroyFrames) return;
|
||||
if (m_destroyFrames) {
|
||||
return;
|
||||
}
|
||||
// Return the frame to the pool. First try to find an empty slot, otherwise
|
||||
// add it to the end.
|
||||
auto it = std::find(m_imagesAvail.begin(), m_imagesAvail.end(), nullptr);
|
||||
@@ -501,7 +529,9 @@ void SourceImpl::ReleaseImage(std::unique_ptr<Image> image) {
|
||||
[](const std::unique_ptr<Image>& a, const std::unique_ptr<Image>& b) {
|
||||
return a->capacity() < b->capacity();
|
||||
});
|
||||
if ((*it2)->capacity() < image->capacity()) *it2 = std::move(image);
|
||||
if ((*it2)->capacity() < image->capacity()) {
|
||||
*it2 = std::move(image);
|
||||
}
|
||||
} else {
|
||||
m_imagesAvail.emplace_back(std::move(image));
|
||||
}
|
||||
@@ -510,7 +540,9 @@ void SourceImpl::ReleaseImage(std::unique_ptr<Image> image) {
|
||||
std::unique_ptr<Frame::Impl> SourceImpl::AllocFrameImpl() {
|
||||
std::scoped_lock lock{m_poolMutex};
|
||||
|
||||
if (m_framesAvail.empty()) return std::make_unique<Frame::Impl>(*this);
|
||||
if (m_framesAvail.empty()) {
|
||||
return std::make_unique<Frame::Impl>(*this);
|
||||
}
|
||||
|
||||
auto impl = std::move(m_framesAvail.back());
|
||||
m_framesAvail.pop_back();
|
||||
@@ -519,6 +551,8 @@ std::unique_ptr<Frame::Impl> SourceImpl::AllocFrameImpl() {
|
||||
|
||||
void SourceImpl::ReleaseFrameImpl(std::unique_ptr<Frame::Impl> impl) {
|
||||
std::scoped_lock lock{m_poolMutex};
|
||||
if (m_destroyFrames) return;
|
||||
if (m_destroyFrames) {
|
||||
return;
|
||||
}
|
||||
m_framesAvail.push_back(std::move(impl));
|
||||
}
|
||||
|
||||
@@ -45,22 +45,31 @@ int64_t Telemetry::Thread::GetValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
|
||||
Telemetry::~Telemetry() {}
|
||||
|
||||
void Telemetry::Start() { m_owner.Start(m_notifier); }
|
||||
void Telemetry::Start() {
|
||||
m_owner.Start(m_notifier);
|
||||
}
|
||||
|
||||
void Telemetry::Stop() { m_owner.Stop(); }
|
||||
void Telemetry::Stop() {
|
||||
m_owner.Stop();
|
||||
}
|
||||
|
||||
void Telemetry::Thread::Main() {
|
||||
std::unique_lock lock(m_mutex);
|
||||
auto prevTime = std::chrono::steady_clock::now();
|
||||
while (m_active) {
|
||||
double period = m_period;
|
||||
if (period == 0) period = 1000.0;
|
||||
if (period == 0) {
|
||||
period = 1000.0;
|
||||
}
|
||||
auto timeoutTime = prevTime + std::chrono::duration<double>(period);
|
||||
while (m_active && !m_updated) {
|
||||
if (m_cond.wait_until(lock, timeoutTime) == std::cv_status::timeout)
|
||||
if (m_cond.wait_until(lock, timeoutTime) == std::cv_status::timeout) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
if (!m_active) break;
|
||||
if (m_updated) {
|
||||
m_updated = false;
|
||||
continue;
|
||||
@@ -80,8 +89,12 @@ void Telemetry::Thread::Main() {
|
||||
|
||||
void Telemetry::SetPeriod(double seconds) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (thr->m_period == seconds) return; // no change
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
if (thr->m_period == seconds) {
|
||||
return; // no change
|
||||
}
|
||||
thr->m_period = seconds;
|
||||
thr->m_updated = true;
|
||||
thr->m_cond.notify_one();
|
||||
@@ -89,7 +102,9 @@ void Telemetry::SetPeriod(double seconds) {
|
||||
|
||||
double Telemetry::GetElapsedTime() {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return 0;
|
||||
if (!thr) {
|
||||
return 0;
|
||||
}
|
||||
return thr->m_elapsed;
|
||||
}
|
||||
|
||||
@@ -110,13 +125,17 @@ double Telemetry::GetAverageValue(CS_Handle handle, CS_TelemetryKind kind,
|
||||
*status = CS_TELEMETRY_NOT_ENABLED;
|
||||
return 0;
|
||||
}
|
||||
if (thr->m_elapsed == 0) return 0.0;
|
||||
if (thr->m_elapsed == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
return thr->GetValue(handle, kind, status) / thr->m_elapsed;
|
||||
}
|
||||
|
||||
void Telemetry::RecordSourceBytes(const SourceImpl& source, int quantity) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
thr->m_current[std::make_pair(Handle{handleData.first, Handle::kSource},
|
||||
static_cast<int>(CS_SOURCE_BYTES_RECEIVED))] +=
|
||||
@@ -125,7 +144,9 @@ void Telemetry::RecordSourceBytes(const SourceImpl& source, int quantity) {
|
||||
|
||||
void Telemetry::RecordSourceFrames(const SourceImpl& source, int quantity) {
|
||||
auto thr = m_owner.GetThread();
|
||||
if (!thr) return;
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
auto handleData = Instance::GetInstance().FindSource(source);
|
||||
thr->m_current[std::make_pair(Handle{handleData.first, Handle::kSource},
|
||||
static_cast<int>(CS_SOURCE_FRAMES_RECEIVED))] +=
|
||||
|
||||
@@ -87,7 +87,9 @@ THandle UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Allocate(
|
||||
return MakeHandle(i);
|
||||
}
|
||||
}
|
||||
if (i >= THandle::kIndexMax) return 0;
|
||||
if (i >= THandle::kIndexMax) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_structures.emplace_back(
|
||||
std::make_shared<TStruct>(std::forward<Args>(args)...));
|
||||
@@ -105,7 +107,9 @@ THandle UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Allocate(
|
||||
return MakeHandle(i);
|
||||
}
|
||||
}
|
||||
if (i >= THandle::kIndexMax) return 0;
|
||||
if (i >= THandle::kIndexMax) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m_structures.push_back(structure);
|
||||
return MakeHandle(i);
|
||||
@@ -117,9 +121,13 @@ UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Get(
|
||||
THandle handle) {
|
||||
auto index =
|
||||
handle.GetTypedIndex(static_cast<typename THandle::Type>(typeValue));
|
||||
if (index < 0) return nullptr;
|
||||
if (index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock sync(m_handleMutex);
|
||||
if (index >= static_cast<int>(m_structures.size())) return nullptr;
|
||||
if (index >= static_cast<int>(m_structures.size())) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_structures[index];
|
||||
}
|
||||
|
||||
@@ -129,9 +137,13 @@ UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Free(
|
||||
THandle handle) {
|
||||
auto index =
|
||||
handle.GetTypedIndex(static_cast<typename THandle::Type>(typeValue));
|
||||
if (index < 0) return nullptr;
|
||||
if (index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
std::scoped_lock sync(m_handleMutex);
|
||||
if (index >= static_cast<int>(m_structures.size())) return nullptr;
|
||||
if (index >= static_cast<int>(m_structures.size())) {
|
||||
return nullptr;
|
||||
}
|
||||
auto rv = std::move(m_structures[index]);
|
||||
m_structures[index].reset();
|
||||
return rv;
|
||||
@@ -161,7 +173,9 @@ inline void
|
||||
UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::ForEach(F func) {
|
||||
std::scoped_lock sync(m_handleMutex);
|
||||
for (size_t i = 0; i < m_structures.size(); i++) {
|
||||
if (m_structures[i] != nullptr) func(MakeHandle(i), *(m_structures[i]));
|
||||
if (m_structures[i] != nullptr) {
|
||||
func(MakeHandle(i), *(m_structures[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,8 +186,9 @@ UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::FindIf(F func) {
|
||||
std::scoped_lock sync(m_handleMutex);
|
||||
for (size_t i = 0; i < m_structures.size(); i++) {
|
||||
auto& structure = m_structures[i];
|
||||
if (structure != nullptr && func(*structure))
|
||||
if (structure != nullptr && func(*structure)) {
|
||||
return std::make_pair(MakeHandle(i), structure);
|
||||
}
|
||||
}
|
||||
return std::make_pair(0, nullptr);
|
||||
}
|
||||
|
||||
@@ -16,8 +16,9 @@ static void ConvertToC(CS_UsbCameraInfo* out, const UsbCameraInfo& in) {
|
||||
out->otherPaths = static_cast<char**>(
|
||||
wpi::safe_malloc(in.otherPaths.size() * sizeof(char*)));
|
||||
out->otherPathsCount = in.otherPaths.size();
|
||||
for (size_t i = 0; i < in.otherPaths.size(); ++i)
|
||||
for (size_t i = 0; i < in.otherPaths.size(); ++i) {
|
||||
out->otherPaths[i] = cs::ConvertToC(in.otherPaths[i]);
|
||||
}
|
||||
out->vendorId = in.vendorId;
|
||||
out->productId = in.productId;
|
||||
}
|
||||
@@ -25,8 +26,9 @@ static void ConvertToC(CS_UsbCameraInfo* out, const UsbCameraInfo& in) {
|
||||
static void FreeUsbCameraInfo(CS_UsbCameraInfo* info) {
|
||||
std::free(info->path);
|
||||
std::free(info->name);
|
||||
for (int i = 0; i < info->otherPathsCount; ++i)
|
||||
for (int i = 0; i < info->otherPathsCount; ++i) {
|
||||
std::free(info->otherPaths[i]);
|
||||
}
|
||||
std::free(info->otherPaths);
|
||||
}
|
||||
|
||||
@@ -52,7 +54,9 @@ char* CS_GetUsbCameraPath(CS_Source source, CS_Status* status) {
|
||||
|
||||
CS_UsbCameraInfo* CS_GetUsbCameraInfo(CS_Source source, CS_Status* status) {
|
||||
auto info = cs::GetUsbCameraInfo(source, status);
|
||||
if (*status != CS_OK) return nullptr;
|
||||
if (*status != CS_OK) {
|
||||
return nullptr;
|
||||
}
|
||||
CS_UsbCameraInfo* out = static_cast<CS_UsbCameraInfo*>(
|
||||
wpi::safe_malloc(sizeof(CS_UsbCameraInfo)));
|
||||
ConvertToC(out, info);
|
||||
@@ -64,18 +68,26 @@ CS_UsbCameraInfo* CS_EnumerateUsbCameras(int* count, CS_Status* status) {
|
||||
CS_UsbCameraInfo* out = static_cast<CS_UsbCameraInfo*>(
|
||||
wpi::safe_malloc(cameras.size() * sizeof(CS_UsbCameraInfo)));
|
||||
*count = cameras.size();
|
||||
for (size_t i = 0; i < cameras.size(); ++i) ConvertToC(&out[i], cameras[i]);
|
||||
for (size_t i = 0; i < cameras.size(); ++i) {
|
||||
ConvertToC(&out[i], cameras[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void CS_FreeEnumeratedUsbCameras(CS_UsbCameraInfo* cameras, int count) {
|
||||
if (!cameras) return;
|
||||
for (int i = 0; i < count; ++i) FreeUsbCameraInfo(&cameras[i]);
|
||||
if (!cameras) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
FreeUsbCameraInfo(&cameras[i]);
|
||||
}
|
||||
std::free(cameras);
|
||||
}
|
||||
|
||||
void CS_FreeUsbCameraInfo(CS_UsbCameraInfo* info) {
|
||||
if (!info) return;
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
FreeUsbCameraInfo(info);
|
||||
std::free(info);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,9 @@ CS_PropertyKind CS_GetPropertyKind(CS_Property property, CS_Status* status) {
|
||||
char* CS_GetPropertyName(CS_Property property, CS_Status* status) {
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetPropertyName(property, buf, status);
|
||||
if (*status != 0) return nullptr;
|
||||
if (*status != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return cs::ConvertToC(str);
|
||||
}
|
||||
|
||||
@@ -55,7 +57,9 @@ int CS_GetPropertyDefault(CS_Property property, CS_Status* status) {
|
||||
char* CS_GetStringProperty(CS_Property property, CS_Status* status) {
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetStringProperty(property, buf, status);
|
||||
if (*status != 0) return nullptr;
|
||||
if (*status != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return cs::ConvertToC(str);
|
||||
}
|
||||
|
||||
@@ -70,8 +74,9 @@ char** CS_GetEnumPropertyChoices(CS_Property property, int* count,
|
||||
char** out =
|
||||
static_cast<char**>(wpi::safe_malloc(choices.size() * sizeof(char*)));
|
||||
*count = choices.size();
|
||||
for (size_t i = 0; i < choices.size(); ++i)
|
||||
for (size_t i = 0; i < choices.size(); ++i) {
|
||||
out[i] = cs::ConvertToC(choices[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -82,14 +87,18 @@ CS_SourceKind CS_GetSourceKind(CS_Source source, CS_Status* status) {
|
||||
char* CS_GetSourceName(CS_Source source, CS_Status* status) {
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSourceName(source, buf, status);
|
||||
if (*status != 0) return nullptr;
|
||||
if (*status != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return cs::ConvertToC(str);
|
||||
}
|
||||
|
||||
char* CS_GetSourceDescription(CS_Source source, CS_Status* status) {
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSourceDescription(source, buf, status);
|
||||
if (*status != 0) return nullptr;
|
||||
if (*status != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return cs::ConvertToC(str);
|
||||
}
|
||||
|
||||
@@ -248,14 +257,18 @@ CS_SinkKind CS_GetSinkKind(CS_Sink sink, CS_Status* status) {
|
||||
char* CS_GetSinkName(CS_Sink sink, CS_Status* status) {
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSinkName(sink, buf, status);
|
||||
if (*status != 0) return nullptr;
|
||||
if (*status != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return cs::ConvertToC(str);
|
||||
}
|
||||
|
||||
char* CS_GetSinkDescription(CS_Sink sink, CS_Status* status) {
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSinkDescription(sink, buf, status);
|
||||
if (*status != 0) return nullptr;
|
||||
if (*status != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return cs::ConvertToC(str);
|
||||
}
|
||||
|
||||
@@ -338,9 +351,13 @@ void CS_RemoveListener(CS_Listener handle, CS_Status* status) {
|
||||
return cs::RemoveListener(handle, status);
|
||||
}
|
||||
|
||||
int CS_NotifierDestroyed(void) { return cs::NotifierDestroyed(); }
|
||||
int CS_NotifierDestroyed(void) {
|
||||
return cs::NotifierDestroyed();
|
||||
}
|
||||
|
||||
void CS_SetTelemetryPeriod(double seconds) { cs::SetTelemetryPeriod(seconds); }
|
||||
void CS_SetTelemetryPeriod(double seconds) {
|
||||
cs::SetTelemetryPeriod(seconds);
|
||||
}
|
||||
|
||||
double CS_GetTelemetryElapsedTime(void) {
|
||||
return cs::GetTelemetryElapsedTime();
|
||||
@@ -364,7 +381,9 @@ void CS_SetDefaultLogger(unsigned int min_level) {
|
||||
cs::SetDefaultLogger(min_level);
|
||||
}
|
||||
|
||||
void CS_Shutdown(void) { cs::Shutdown(); }
|
||||
void CS_Shutdown(void) {
|
||||
cs::Shutdown();
|
||||
}
|
||||
|
||||
CS_Source* CS_EnumerateSources(int* count, CS_Status* status) {
|
||||
wpi::SmallVector<CS_Source, 32> buf;
|
||||
@@ -377,10 +396,14 @@ CS_Source* CS_EnumerateSources(int* count, CS_Status* status) {
|
||||
}
|
||||
|
||||
void CS_ReleaseEnumeratedSources(CS_Source* sources, int count) {
|
||||
if (!sources) return;
|
||||
if (!sources) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
CS_Status status = 0;
|
||||
if (sources[i] != 0) cs::ReleaseSource(sources[i], &status);
|
||||
if (sources[i] != 0) {
|
||||
cs::ReleaseSource(sources[i], &status);
|
||||
}
|
||||
}
|
||||
std::free(sources);
|
||||
}
|
||||
@@ -396,19 +419,29 @@ CS_Sink* CS_EnumerateSinks(int* count, CS_Status* status) {
|
||||
}
|
||||
|
||||
void CS_ReleaseEnumeratedSinks(CS_Sink* sinks, int count) {
|
||||
if (!sinks) return;
|
||||
if (!sinks) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
CS_Status status = 0;
|
||||
if (sinks[i] != 0) cs::ReleaseSink(sinks[i], &status);
|
||||
if (sinks[i] != 0) {
|
||||
cs::ReleaseSink(sinks[i], &status);
|
||||
}
|
||||
}
|
||||
std::free(sinks);
|
||||
}
|
||||
|
||||
void CS_FreeString(char* str) { std::free(str); }
|
||||
void CS_FreeString(char* str) {
|
||||
std::free(str);
|
||||
}
|
||||
|
||||
void CS_FreeEnumPropertyChoices(char** choices, int count) {
|
||||
if (!choices) return;
|
||||
for (int i = 0; i < count; ++i) std::free(choices[i]);
|
||||
if (!choices) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
std::free(choices[i]);
|
||||
}
|
||||
std::free(choices);
|
||||
}
|
||||
|
||||
@@ -420,26 +453,35 @@ void CS_FreeEnumeratedVideoModes(CS_VideoMode* modes, int count) {
|
||||
std::free(modes);
|
||||
}
|
||||
|
||||
char* CS_GetHostname() { return cs::ConvertToC(cs::GetHostname()); }
|
||||
char* CS_GetHostname() {
|
||||
return cs::ConvertToC(cs::GetHostname());
|
||||
}
|
||||
|
||||
char** CS_GetNetworkInterfaces(int* count) {
|
||||
auto interfaces = cs::GetNetworkInterfaces();
|
||||
char** out =
|
||||
static_cast<char**>(wpi::safe_malloc(interfaces.size() * sizeof(char*)));
|
||||
*count = interfaces.size();
|
||||
for (size_t i = 0; i < interfaces.size(); ++i)
|
||||
for (size_t i = 0; i < interfaces.size(); ++i) {
|
||||
out[i] = cs::ConvertToC(interfaces[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void CS_FreeNetworkInterfaces(char** interfaces, int count) {
|
||||
if (!interfaces) return;
|
||||
for (int i = 0; i < count; ++i) std::free(interfaces[i]);
|
||||
if (!interfaces) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < count; ++i) {
|
||||
std::free(interfaces[i]);
|
||||
}
|
||||
std::free(interfaces);
|
||||
}
|
||||
|
||||
void CS_AllocateRawFrameData(CS_RawFrame* frame, int requestedSize) {
|
||||
if (frame->dataLength >= requestedSize) return;
|
||||
if (frame->dataLength >= requestedSize) {
|
||||
return;
|
||||
}
|
||||
if (frame->data) {
|
||||
frame->data =
|
||||
static_cast<char*>(wpi::safe_realloc(frame->data, requestedSize));
|
||||
|
||||
@@ -57,7 +57,9 @@ namespace cs {
|
||||
CS_PropertyKind GetPropertyKind(CS_Property property, CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return CS_PROP_NONE;
|
||||
if (!container) {
|
||||
return CS_PROP_NONE;
|
||||
}
|
||||
return container->GetPropertyKind(propertyIndex);
|
||||
}
|
||||
|
||||
@@ -65,7 +67,9 @@ std::string GetPropertyName(CS_Property property, CS_Status* status) {
|
||||
wpi::SmallString<128> buf;
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return std::string{};
|
||||
if (!container) {
|
||||
return {};
|
||||
}
|
||||
return container->GetPropertyName(propertyIndex, buf, status);
|
||||
}
|
||||
|
||||
@@ -74,49 +78,63 @@ wpi::StringRef GetPropertyName(CS_Property property,
|
||||
CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return wpi::StringRef{};
|
||||
if (!container) {
|
||||
return {};
|
||||
}
|
||||
return container->GetPropertyName(propertyIndex, buf, status);
|
||||
}
|
||||
|
||||
int GetProperty(CS_Property property, CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return false;
|
||||
if (!container) {
|
||||
return false;
|
||||
}
|
||||
return container->GetProperty(propertyIndex, status);
|
||||
}
|
||||
|
||||
void SetProperty(CS_Property property, int value, CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return;
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
container->SetProperty(propertyIndex, value, status);
|
||||
}
|
||||
|
||||
int GetPropertyMin(CS_Property property, CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return 0.0;
|
||||
if (!container) {
|
||||
return 0.0;
|
||||
}
|
||||
return container->GetPropertyMin(propertyIndex, status);
|
||||
}
|
||||
|
||||
int GetPropertyMax(CS_Property property, CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return 0.0;
|
||||
if (!container) {
|
||||
return 0.0;
|
||||
}
|
||||
return container->GetPropertyMax(propertyIndex, status);
|
||||
}
|
||||
|
||||
int GetPropertyStep(CS_Property property, CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return 0.0;
|
||||
if (!container) {
|
||||
return 0.0;
|
||||
}
|
||||
return container->GetPropertyStep(propertyIndex, status);
|
||||
}
|
||||
|
||||
int GetPropertyDefault(CS_Property property, CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return 0.0;
|
||||
if (!container) {
|
||||
return 0.0;
|
||||
}
|
||||
return container->GetPropertyDefault(propertyIndex, status);
|
||||
}
|
||||
|
||||
@@ -124,7 +142,9 @@ std::string GetStringProperty(CS_Property property, CS_Status* status) {
|
||||
wpi::SmallString<128> buf;
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return std::string{};
|
||||
if (!container) {
|
||||
return {};
|
||||
}
|
||||
return container->GetStringProperty(propertyIndex, buf, status);
|
||||
}
|
||||
|
||||
@@ -133,7 +153,9 @@ wpi::StringRef GetStringProperty(CS_Property property,
|
||||
CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return wpi::StringRef{};
|
||||
if (!container) {
|
||||
return {};
|
||||
}
|
||||
return container->GetStringProperty(propertyIndex, buf, status);
|
||||
}
|
||||
|
||||
@@ -141,7 +163,9 @@ void SetStringProperty(CS_Property property, const wpi::Twine& value,
|
||||
CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return;
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
container->SetStringProperty(propertyIndex, value, status);
|
||||
}
|
||||
|
||||
@@ -149,7 +173,9 @@ std::vector<std::string> GetEnumPropertyChoices(CS_Property property,
|
||||
CS_Status* status) {
|
||||
int propertyIndex;
|
||||
auto container = GetPropertyContainer(property, &propertyIndex, status);
|
||||
if (!container) return std::vector<std::string>{};
|
||||
if (!container) {
|
||||
return {};
|
||||
}
|
||||
return container->GetEnumPropertyChoices(propertyIndex, status);
|
||||
}
|
||||
|
||||
@@ -269,8 +295,9 @@ wpi::ArrayRef<CS_Property> EnumerateSourceProperties(
|
||||
}
|
||||
wpi::SmallVector<int, 32> properties_buf;
|
||||
for (auto property :
|
||||
data->source->EnumerateProperties(properties_buf, status))
|
||||
data->source->EnumerateProperties(properties_buf, status)) {
|
||||
vec.push_back(Handle{source, property, Handle::kProperty});
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
@@ -383,7 +410,9 @@ wpi::ArrayRef<CS_Sink> EnumerateSourceSinks(CS_Source source,
|
||||
}
|
||||
|
||||
CS_Source CopySource(CS_Source source, CS_Status* status) {
|
||||
if (source == 0) return 0;
|
||||
if (source == 0) {
|
||||
return 0;
|
||||
}
|
||||
auto data = Instance::GetInstance().GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
@@ -394,14 +423,18 @@ CS_Source CopySource(CS_Source source, CS_Status* status) {
|
||||
}
|
||||
|
||||
void ReleaseSource(CS_Source source, CS_Status* status) {
|
||||
if (source == 0) return;
|
||||
if (source == 0) {
|
||||
return;
|
||||
}
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto data = inst.GetSource(source);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
if (data->refCount-- == 0) inst.DestroySource(source);
|
||||
if (data->refCount-- == 0) {
|
||||
inst.DestroySource(source);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -556,8 +589,10 @@ wpi::ArrayRef<CS_Property> EnumerateSinkProperties(
|
||||
return 0;
|
||||
}
|
||||
wpi::SmallVector<int, 32> properties_buf;
|
||||
for (auto property : data->sink->EnumerateProperties(properties_buf, status))
|
||||
for (auto property :
|
||||
data->sink->EnumerateProperties(properties_buf, status)) {
|
||||
vec.push_back(Handle{sink, property, Handle::kSinkProperty});
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
@@ -639,7 +674,9 @@ CS_Property GetSinkSourceProperty(CS_Sink sink, const wpi::Twine& name,
|
||||
}
|
||||
|
||||
CS_Sink CopySink(CS_Sink sink, CS_Status* status) {
|
||||
if (sink == 0) return 0;
|
||||
if (sink == 0) {
|
||||
return 0;
|
||||
}
|
||||
auto data = Instance::GetInstance().GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
@@ -650,14 +687,18 @@ CS_Sink CopySink(CS_Sink sink, CS_Status* status) {
|
||||
}
|
||||
|
||||
void ReleaseSink(CS_Sink sink, CS_Status* status) {
|
||||
if (sink == 0) return;
|
||||
if (sink == 0) {
|
||||
return;
|
||||
}
|
||||
auto& inst = Instance::GetInstance();
|
||||
auto data = inst.GetSink(sink);
|
||||
if (!data) {
|
||||
*status = CS_INVALID_HANDLE;
|
||||
return;
|
||||
}
|
||||
if (data->refCount-- == 0) inst.DestroySink(sink);
|
||||
if (data->refCount-- == 0) {
|
||||
inst.DestroySink(sink);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -680,7 +721,9 @@ CS_Listener AddListener(std::function<void(const RawEvent& event)> callback,
|
||||
if ((eventMask & CS_NETWORK_INTERFACES_CHANGED) != 0) {
|
||||
// start network interface event listener
|
||||
inst.networkListener.Start();
|
||||
if (immediateNotify) inst.notifier.NotifyNetworkInterfacesChanged();
|
||||
if (immediateNotify) {
|
||||
inst.notifier.NotifyNetworkInterfacesChanged();
|
||||
}
|
||||
}
|
||||
if (immediateNotify) {
|
||||
// TODO
|
||||
@@ -697,7 +740,9 @@ void RemoveListener(CS_Listener handle, CS_Status* status) {
|
||||
Instance::GetInstance().notifier.RemoveListener(uid);
|
||||
}
|
||||
|
||||
bool NotifierDestroyed() { return Notifier::destroyed(); }
|
||||
bool NotifierDestroyed() {
|
||||
return Notifier::destroyed();
|
||||
}
|
||||
|
||||
//
|
||||
// Telemetry Functions
|
||||
@@ -741,7 +786,9 @@ void SetDefaultLogger(unsigned int min_level) {
|
||||
//
|
||||
// Shutdown Function
|
||||
//
|
||||
void Shutdown() { Instance::GetInstance().Shutdown(); }
|
||||
void Shutdown() {
|
||||
Instance::GetInstance().Shutdown();
|
||||
}
|
||||
|
||||
//
|
||||
// Utility Functions
|
||||
@@ -757,6 +804,8 @@ wpi::ArrayRef<CS_Sink> EnumerateSinkHandles(wpi::SmallVectorImpl<CS_Sink>& vec,
|
||||
return Instance::GetInstance().EnumerateSinkHandles(vec);
|
||||
}
|
||||
|
||||
std::string GetHostname() { return wpi::GetHostname(); }
|
||||
std::string GetHostname() {
|
||||
return wpi::GetHostname();
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
@@ -25,8 +25,9 @@ std::vector<VideoProperty> VideoSource::EnumerateProperties() const {
|
||||
|
||||
std::vector<VideoProperty> properties;
|
||||
properties.reserve(handles.size());
|
||||
for (CS_Property handle : handles)
|
||||
for (CS_Property handle : handles) {
|
||||
properties.emplace_back(VideoProperty{handle});
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@@ -37,7 +38,9 @@ std::vector<VideoSink> VideoSource::EnumerateSinks() {
|
||||
|
||||
std::vector<VideoSink> sinks;
|
||||
sinks.reserve(handles.size());
|
||||
for (int handle : handles) sinks.emplace_back(VideoSink{handle});
|
||||
for (int handle : handles) {
|
||||
sinks.emplace_back(VideoSink{handle});
|
||||
}
|
||||
return sinks;
|
||||
}
|
||||
|
||||
@@ -48,7 +51,9 @@ std::vector<VideoSource> VideoSource::EnumerateSources() {
|
||||
|
||||
std::vector<VideoSource> sources;
|
||||
sources.reserve(handles.size());
|
||||
for (int handle : handles) sources.emplace_back(VideoSource{handle});
|
||||
for (int handle : handles) {
|
||||
sources.emplace_back(VideoSource{handle});
|
||||
}
|
||||
return sources;
|
||||
}
|
||||
|
||||
@@ -59,8 +64,9 @@ std::vector<VideoProperty> VideoSink::EnumerateProperties() const {
|
||||
|
||||
std::vector<VideoProperty> properties;
|
||||
properties.reserve(handles.size());
|
||||
for (CS_Property handle : handles)
|
||||
for (CS_Property handle : handles) {
|
||||
properties.emplace_back(VideoProperty{handle});
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
@@ -71,6 +77,8 @@ std::vector<VideoSink> VideoSink::EnumerateSinks() {
|
||||
|
||||
std::vector<VideoSink> sinks;
|
||||
sinks.reserve(handles.size());
|
||||
for (int handle : handles) sinks.emplace_back(VideoSink{handle});
|
||||
for (int handle : handles) {
|
||||
sinks.emplace_back(VideoSink{handle});
|
||||
}
|
||||
return sinks;
|
||||
}
|
||||
|
||||
@@ -50,22 +50,29 @@ static const JExceptionInit exceptions[] = {
|
||||
{"java/lang/Exception", &exceptionEx}};
|
||||
|
||||
static void ListenerOnStart() {
|
||||
if (!jvm) return;
|
||||
if (!jvm) {
|
||||
return;
|
||||
}
|
||||
JNIEnv* env;
|
||||
JavaVMAttachArgs args;
|
||||
args.version = JNI_VERSION_1_2;
|
||||
args.name = const_cast<char*>("CSListener");
|
||||
args.group = nullptr;
|
||||
if (jvm->AttachCurrentThreadAsDaemon(reinterpret_cast<void**>(&env), &args) !=
|
||||
JNI_OK)
|
||||
JNI_OK) {
|
||||
return;
|
||||
if (!env || !env->functions) return;
|
||||
}
|
||||
if (!env || !env->functions) {
|
||||
return;
|
||||
}
|
||||
listenerEnv = env;
|
||||
}
|
||||
|
||||
static void ListenerOnExit() {
|
||||
listenerEnv = nullptr;
|
||||
if (!jvm) return;
|
||||
if (!jvm) {
|
||||
return;
|
||||
}
|
||||
jvm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
@@ -89,7 +96,9 @@ static void ThrowJavaException(JNIEnv* env, const std::exception* e) {
|
||||
what = "unknown exception";
|
||||
}
|
||||
|
||||
if (!je) je = exceptionEx;
|
||||
if (!je) {
|
||||
je = exceptionEx;
|
||||
}
|
||||
env->ThrowNew(je, what.c_str());
|
||||
}
|
||||
|
||||
@@ -99,18 +108,23 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
jvm = vm;
|
||||
|
||||
JNIEnv* env;
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
// Cache references to classes
|
||||
for (auto& c : classes) {
|
||||
*c.cls = JClass(env, c.name);
|
||||
if (!*c.cls) return JNI_ERR;
|
||||
if (!*c.cls) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& c : exceptions) {
|
||||
*c.cls = JException(env, c.name);
|
||||
if (!*c.cls) return JNI_ERR;
|
||||
if (!*c.cls) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
// Initial configuration of listener start/exit
|
||||
@@ -124,8 +138,9 @@ JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved) {
|
||||
cs::Shutdown();
|
||||
|
||||
JNIEnv* env;
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK)
|
||||
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
|
||||
return;
|
||||
}
|
||||
// Delete global references
|
||||
for (auto& c : classes) {
|
||||
c.cls->free(env);
|
||||
@@ -147,20 +162,27 @@ class JCSGlobal {
|
||||
JCSGlobal(JNIEnv* env, T obj)
|
||||
: m_obj(static_cast<T>(env->NewGlobalRef(obj))) {}
|
||||
~JCSGlobal() {
|
||||
if (!jvm || cs::NotifierDestroyed()) return;
|
||||
if (!jvm || cs::NotifierDestroyed()) {
|
||||
return;
|
||||
}
|
||||
JNIEnv* env;
|
||||
bool attached = false;
|
||||
// don't attach and de-attach if already attached to a thread.
|
||||
if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) ==
|
||||
JNI_EDETACHED) {
|
||||
if (jvm->AttachCurrentThread(reinterpret_cast<void**>(&env), nullptr) !=
|
||||
JNI_OK)
|
||||
JNI_OK) {
|
||||
return;
|
||||
}
|
||||
attached = true;
|
||||
}
|
||||
if (!env || !env->functions) return;
|
||||
if (!env || !env->functions) {
|
||||
return;
|
||||
}
|
||||
env->DeleteGlobalRef(m_obj);
|
||||
if (attached) jvm->DetachCurrentThread();
|
||||
if (attached) {
|
||||
jvm->DetachCurrentThread();
|
||||
}
|
||||
}
|
||||
operator T() { return m_obj; }
|
||||
T obj() { return m_obj; }
|
||||
@@ -170,7 +192,9 @@ class JCSGlobal {
|
||||
};
|
||||
|
||||
static void ReportError(JNIEnv* env, CS_Status status) {
|
||||
if (status == CS_OK) return;
|
||||
if (status == CS_OK) {
|
||||
return;
|
||||
}
|
||||
wpi::SmallString<64> msg;
|
||||
switch (status) {
|
||||
case CS_PROPERTY_WRITE_FAILED:
|
||||
@@ -213,7 +237,9 @@ static void ReportError(JNIEnv* env, CS_Status status) {
|
||||
}
|
||||
|
||||
static inline bool CheckStatus(JNIEnv* env, CS_Status status) {
|
||||
if (status != CS_OK) ReportError(env, status);
|
||||
if (status != CS_OK) {
|
||||
ReportError(env, status);
|
||||
}
|
||||
return status == CS_OK;
|
||||
}
|
||||
|
||||
@@ -293,7 +319,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getPropertyName
|
||||
CS_Status status = 0;
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetPropertyName(property, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJString(env, str);
|
||||
}
|
||||
|
||||
@@ -398,7 +426,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getStringProperty
|
||||
CS_Status status = 0;
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetStringProperty(property, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJString(env, str);
|
||||
}
|
||||
|
||||
@@ -431,7 +461,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getEnumPropertyChoices
|
||||
{
|
||||
CS_Status status = 0;
|
||||
auto arr = cs::GetEnumPropertyChoices(property, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJStringArray(env, arr);
|
||||
}
|
||||
|
||||
@@ -617,7 +649,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getSourceName
|
||||
CS_Status status = 0;
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSourceName(source, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJString(env, str);
|
||||
}
|
||||
|
||||
@@ -633,7 +667,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getSourceDescription
|
||||
CS_Status status = 0;
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSourceDescription(source, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJString(env, str);
|
||||
}
|
||||
|
||||
@@ -729,7 +765,9 @@ Java_edu_wpi_cscore_CameraServerJNI_enumerateSourceProperties
|
||||
CS_Status status = 0;
|
||||
wpi::SmallVector<CS_Property, 32> buf;
|
||||
auto arr = cs::EnumerateSourceProperties(source, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJIntArray(env, arr);
|
||||
}
|
||||
|
||||
@@ -744,7 +782,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getSourceVideoMode
|
||||
{
|
||||
CS_Status status = 0;
|
||||
auto val = cs::GetSourceVideoMode(source, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJObject(env, val);
|
||||
}
|
||||
|
||||
@@ -855,9 +895,13 @@ Java_edu_wpi_cscore_CameraServerJNI_enumerateSourceVideoModes
|
||||
{
|
||||
CS_Status status = 0;
|
||||
auto arr = cs::EnumerateSourceVideoModes(source, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
jobjectArray jarr = env->NewObjectArray(arr.size(), videoModeCls, nullptr);
|
||||
if (!jarr) return nullptr;
|
||||
if (!jarr) {
|
||||
return nullptr;
|
||||
}
|
||||
for (size_t i = 0; i < arr.size(); ++i) {
|
||||
JLocal<jobject> jelem{env, MakeJObject(env, arr[i])};
|
||||
env->SetObjectArrayElement(jarr, i, jelem);
|
||||
@@ -877,7 +921,9 @@ Java_edu_wpi_cscore_CameraServerJNI_enumerateSourceSinks
|
||||
CS_Status status = 0;
|
||||
wpi::SmallVector<CS_Sink, 16> buf;
|
||||
auto arr = cs::EnumerateSourceSinks(source, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJIntArray(env, arr);
|
||||
}
|
||||
|
||||
@@ -1048,7 +1094,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getUsbCameraPath
|
||||
{
|
||||
CS_Status status = 0;
|
||||
auto str = cs::GetUsbCameraPath(source, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJString(env, str);
|
||||
}
|
||||
|
||||
@@ -1063,7 +1111,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getUsbCameraInfo
|
||||
{
|
||||
CS_Status status = 0;
|
||||
auto info = cs::GetUsbCameraInfo(source, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJObject(env, info);
|
||||
}
|
||||
|
||||
@@ -1078,7 +1128,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getHttpCameraKind
|
||||
{
|
||||
CS_Status status = 0;
|
||||
auto kind = cs::GetHttpCameraKind(source, &status);
|
||||
if (!CheckStatus(env, status)) return 0;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return 0;
|
||||
}
|
||||
return kind;
|
||||
}
|
||||
|
||||
@@ -1123,7 +1175,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getHttpCameraUrls
|
||||
{
|
||||
CS_Status status = 0;
|
||||
auto arr = cs::GetHttpCameraUrls(source, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJStringArray(env, arr);
|
||||
}
|
||||
|
||||
@@ -1381,7 +1435,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getSinkName
|
||||
CS_Status status = 0;
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSinkName(sink, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJString(env, str);
|
||||
}
|
||||
|
||||
@@ -1397,7 +1453,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getSinkDescription
|
||||
CS_Status status = 0;
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSinkDescription(sink, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJString(env, str);
|
||||
}
|
||||
|
||||
@@ -1432,7 +1490,9 @@ Java_edu_wpi_cscore_CameraServerJNI_enumerateSinkProperties
|
||||
CS_Status status = 0;
|
||||
wpi::SmallVector<CS_Property, 32> buf;
|
||||
auto arr = cs::EnumerateSinkProperties(source, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJIntArray(env, arr);
|
||||
}
|
||||
|
||||
@@ -1555,7 +1615,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getMjpegServerListenAddress
|
||||
{
|
||||
CS_Status status = 0;
|
||||
auto str = cs::GetMjpegServerListenAddress(sink, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJString(env, str);
|
||||
}
|
||||
|
||||
@@ -1721,7 +1783,9 @@ Java_edu_wpi_cscore_CameraServerJNI_getSinkError
|
||||
CS_Status status = 0;
|
||||
wpi::SmallString<128> buf;
|
||||
auto str = cs::GetSinkError(sink, buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJString(env, str);
|
||||
}
|
||||
|
||||
@@ -1760,17 +1824,23 @@ Java_edu_wpi_cscore_CameraServerJNI_addListener
|
||||
|
||||
// cls is a temporary here; cannot be used within callback functor
|
||||
jclass cls = envouter->GetObjectClass(listener);
|
||||
if (!cls) return 0;
|
||||
if (!cls) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// method ids, on the other hand, are safe to retain
|
||||
jmethodID mid = envouter->GetMethodID(cls, "accept", "(Ljava/lang/Object;)V");
|
||||
if (!mid) return 0;
|
||||
if (!mid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CS_Status status = 0;
|
||||
CS_Listener handle = cs::AddListener(
|
||||
[=](const cs::RawEvent& event) {
|
||||
JNIEnv* env = listenerEnv;
|
||||
if (!env || !env->functions) return;
|
||||
if (!env || !env->functions) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get the handler
|
||||
auto handler = listener_global->obj();
|
||||
@@ -1782,7 +1852,9 @@ Java_edu_wpi_cscore_CameraServerJNI_addListener
|
||||
env->ExceptionClear();
|
||||
return;
|
||||
}
|
||||
if (!jobj) return;
|
||||
if (!jobj) {
|
||||
return;
|
||||
}
|
||||
|
||||
env->CallVoidMethod(handler, mid, jobj.obj());
|
||||
if (env->ExceptionCheck()) {
|
||||
@@ -1876,10 +1948,14 @@ Java_edu_wpi_cscore_CameraServerJNI_enumerateUsbCameras
|
||||
{
|
||||
CS_Status status = 0;
|
||||
auto arr = cs::EnumerateUsbCameras(&status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
jobjectArray jarr =
|
||||
env->NewObjectArray(arr.size(), usbCameraInfoCls, nullptr);
|
||||
if (!jarr) return nullptr;
|
||||
if (!jarr) {
|
||||
return nullptr;
|
||||
}
|
||||
for (size_t i = 0; i < arr.size(); ++i) {
|
||||
JLocal<jobject> jelem{env, MakeJObject(env, arr[i])};
|
||||
env->SetObjectArrayElement(jarr, i, jelem);
|
||||
@@ -1899,7 +1975,9 @@ Java_edu_wpi_cscore_CameraServerJNI_enumerateSources
|
||||
CS_Status status = 0;
|
||||
wpi::SmallVector<CS_Source, 16> buf;
|
||||
auto arr = cs::EnumerateSourceHandles(buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJIntArray(env, arr);
|
||||
}
|
||||
|
||||
@@ -1915,7 +1993,9 @@ Java_edu_wpi_cscore_CameraServerJNI_enumerateSinks
|
||||
CS_Status status = 0;
|
||||
wpi::SmallVector<CS_Sink, 16> buf;
|
||||
auto arr = cs::EnumerateSinkHandles(buf, &status);
|
||||
if (!CheckStatus(env, status)) return nullptr;
|
||||
if (!CheckStatus(env, status)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MakeJIntArray(env, arr);
|
||||
}
|
||||
|
||||
@@ -1991,12 +2071,16 @@ Java_edu_wpi_cscore_CameraServerJNI_setLogger
|
||||
}
|
||||
// cls is a temporary here; cannot be used within callback functor
|
||||
jclass cls = env->GetObjectClass(func);
|
||||
if (!cls) return;
|
||||
if (!cls) {
|
||||
return;
|
||||
}
|
||||
|
||||
// method ids, on the other hand, are safe to retain
|
||||
jmethodID mid = env->GetMethodID(cls, "apply",
|
||||
"(ILjava/lang/String;ILjava/lang/String;)V");
|
||||
if (!mid) return;
|
||||
if (!mid) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto& logger = LoggerJNI::GetInstance();
|
||||
logger.Start();
|
||||
|
||||
@@ -124,10 +124,11 @@ struct RawEvent {
|
||||
RawEvent(const wpi::Twine& name_, CS_Handle handle_, RawEvent::Kind kind_)
|
||||
: kind{kind_}, name{name_.str()} {
|
||||
if (kind_ == kSinkCreated || kind_ == kSinkDestroyed ||
|
||||
kind_ == kSinkEnabled || kind_ == kSinkDisabled)
|
||||
kind_ == kSinkEnabled || kind_ == kSinkDisabled) {
|
||||
sinkHandle = handle_;
|
||||
else
|
||||
} else {
|
||||
sourceHandle = handle_;
|
||||
}
|
||||
}
|
||||
RawEvent(const wpi::Twine& name_, CS_Source source_, const VideoMode& mode_)
|
||||
: kind{kSourceVideoModeChanged},
|
||||
|
||||
@@ -94,7 +94,8 @@ inline VideoSource& VideoSource::operator=(VideoSource other) noexcept {
|
||||
|
||||
inline VideoSource::~VideoSource() {
|
||||
m_status = 0;
|
||||
if (m_handle != 0) ReleaseSource(m_handle, &m_status);
|
||||
if (m_handle != 0)
|
||||
ReleaseSource(m_handle, &m_status);
|
||||
}
|
||||
|
||||
inline VideoSource::Kind VideoSource::GetKind() const {
|
||||
@@ -309,7 +310,8 @@ inline HttpCamera::HttpCamera(const wpi::Twine& name,
|
||||
HttpCameraKind kind) {
|
||||
std::vector<std::string> vec;
|
||||
vec.reserve(urls.size());
|
||||
for (const auto& url : urls) vec.emplace_back(url);
|
||||
for (const auto& url : urls)
|
||||
vec.emplace_back(url);
|
||||
m_handle = CreateHttpCamera(
|
||||
name, vec, static_cast<CS_HttpCameraKind>(static_cast<int>(kind)),
|
||||
&m_status);
|
||||
@@ -330,7 +332,8 @@ template <typename T>
|
||||
inline void HttpCamera::SetUrls(std::initializer_list<T> urls) {
|
||||
std::vector<std::string> vec;
|
||||
vec.reserve(urls.size());
|
||||
for (const auto& url : urls) vec.emplace_back(url);
|
||||
for (const auto& url : urls)
|
||||
vec.emplace_back(url);
|
||||
m_status = 0;
|
||||
::cs::SetHttpCameraUrls(m_handle, vec, &m_status);
|
||||
}
|
||||
@@ -457,7 +460,8 @@ inline void ImageSource::SetEnumPropertyChoices(
|
||||
const VideoProperty& property, std::initializer_list<T> choices) {
|
||||
std::vector<std::string> vec;
|
||||
vec.reserve(choices.size());
|
||||
for (const auto& choice : choices) vec.emplace_back(choice);
|
||||
for (const auto& choice : choices)
|
||||
vec.emplace_back(choice);
|
||||
m_status = 0;
|
||||
SetSourceEnumPropertyChoices(m_handle, property.m_handle, vec, &m_status);
|
||||
}
|
||||
@@ -476,7 +480,8 @@ inline VideoSink& VideoSink::operator=(VideoSink other) noexcept {
|
||||
|
||||
inline VideoSink::~VideoSink() {
|
||||
m_status = 0;
|
||||
if (m_handle != 0) ReleaseSink(m_handle, &m_status);
|
||||
if (m_handle != 0)
|
||||
ReleaseSink(m_handle, &m_status);
|
||||
}
|
||||
|
||||
inline VideoSink::Kind VideoSink::GetKind() const {
|
||||
@@ -625,7 +630,8 @@ inline VideoListener& VideoListener::operator=(VideoListener&& other) noexcept {
|
||||
|
||||
inline VideoListener::~VideoListener() {
|
||||
CS_Status status = 0;
|
||||
if (m_handle != 0) RemoveListener(m_handle, &status);
|
||||
if (m_handle != 0)
|
||||
RemoveListener(m_handle, &status);
|
||||
}
|
||||
|
||||
} // namespace cs
|
||||
|
||||
@@ -171,22 +171,22 @@ inline RawCvSink::RawCvSink(const wpi::Twine& name,
|
||||
: RawSink{name, processFrame} {}
|
||||
|
||||
inline uint64_t RawCvSink::GrabFrame(cv::Mat& image, double timeout) {
|
||||
cv::Mat tmpMat;
|
||||
auto retVal = GrabFrameDirect(tmpMat);
|
||||
cv::Mat tmpnam;
|
||||
auto retVal = GrabFrameDirect(tmpnam);
|
||||
if (retVal <= 0) {
|
||||
return retVal;
|
||||
}
|
||||
tmpMat.copyTo(image);
|
||||
tmpnam.copyTo(image);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
inline uint64_t RawCvSink::GrabFrameNoTimeout(cv::Mat& image) {
|
||||
cv::Mat tmpMat;
|
||||
auto retVal = GrabFrameNoTimeoutDirect(tmpMat);
|
||||
cv::Mat tmpnam;
|
||||
auto retVal = GrabFrameNoTimeoutDirect(tmpnam);
|
||||
if (retVal <= 0) {
|
||||
return retVal;
|
||||
}
|
||||
tmpMat.copyTo(image);
|
||||
tmpnam.copyTo(image);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -195,7 +195,9 @@ inline uint64_t RawCvSink::GrabFrameDirect(cv::Mat& image, double timeout) {
|
||||
rawFrame.width = 0;
|
||||
rawFrame.pixelFormat = CS_PixelFormat::CS_PIXFMT_BGR;
|
||||
m_status = RawSink::GrabFrame(rawFrame, timeout);
|
||||
if (m_status <= 0) return m_status;
|
||||
if (m_status <= 0) {
|
||||
return m_status;
|
||||
}
|
||||
image = cv::Mat{rawFrame.height, rawFrame.width, CV_8UC3, rawFrame.data};
|
||||
return m_status;
|
||||
}
|
||||
@@ -205,7 +207,9 @@ inline uint64_t RawCvSink::GrabFrameNoTimeoutDirect(cv::Mat& image) {
|
||||
rawFrame.width = 0;
|
||||
rawFrame.pixelFormat = CS_PixelFormat::CS_PIXFMT_BGR;
|
||||
m_status = RawSink::GrabFrameNoTimeout(rawFrame);
|
||||
if (m_status <= 0) return m_status;
|
||||
if (m_status <= 0) {
|
||||
return m_status;
|
||||
}
|
||||
image = cv::Mat{rawFrame.height, rawFrame.width, CV_8UC3, rawFrame.data};
|
||||
return m_status;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ class NetworkListener::Impl {
|
||||
NetworkListener::NetworkListener(wpi::Logger& logger, Notifier& notifier)
|
||||
: m_impl(std::make_unique<Impl>(logger, notifier)) {}
|
||||
|
||||
NetworkListener::~NetworkListener() { Stop(); }
|
||||
NetworkListener::~NetworkListener() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void NetworkListener::Start() {
|
||||
m_impl->m_owner.Start(m_impl->m_logger, m_impl->m_notifier);
|
||||
@@ -57,7 +59,9 @@ void NetworkListener::Stop() {
|
||||
// Wake up thread
|
||||
if (auto thr = m_impl->m_owner.GetThread()) {
|
||||
thr->m_active = false;
|
||||
if (thr->m_command_fd >= 0) eventfd_write(thr->m_command_fd, 1);
|
||||
if (thr->m_command_fd >= 0) {
|
||||
eventfd_write(thr->m_command_fd, 1);
|
||||
}
|
||||
}
|
||||
m_impl->m_owner.Stop();
|
||||
}
|
||||
@@ -114,25 +118,35 @@ void NetworkListener::Impl::Thread::Main() {
|
||||
}
|
||||
|
||||
// Double-check to see if we're shutting down
|
||||
if (!m_active) break;
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!FD_ISSET(sd, &readfds)) continue;
|
||||
if (!FD_ISSET(sd, &readfds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::memset(&addr, 0, sizeof(addr));
|
||||
struct iovec iov = {buf, sizeof(buf)};
|
||||
struct msghdr msg = {&addr, sizeof(addr), &iov, 1, nullptr, 0, 0};
|
||||
int len = ::recvmsg(sd, &msg, 0);
|
||||
if (len < 0) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) continue;
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
continue;
|
||||
}
|
||||
ERROR(
|
||||
"NetworkListener: could not read netlink: " << std::strerror(errno));
|
||||
break; // XXX: is this the right thing to do here?
|
||||
}
|
||||
if (len == 0) continue; // EOF?
|
||||
if (len == 0) {
|
||||
continue; // EOF?
|
||||
}
|
||||
unsigned int ulen = static_cast<unsigned int>(len);
|
||||
for (struct nlmsghdr* nh = reinterpret_cast<struct nlmsghdr*>(buf);
|
||||
NLMSG_OK(nh, ulen); nh = NLMSG_NEXT(nh, ulen)) {
|
||||
if (nh->nlmsg_type == NLMSG_DONE) break;
|
||||
if (nh->nlmsg_type == NLMSG_DONE) {
|
||||
break;
|
||||
}
|
||||
if (nh->nlmsg_type == RTM_NEWLINK || nh->nlmsg_type == RTM_DELLINK ||
|
||||
nh->nlmsg_type == RTM_NEWADDR || nh->nlmsg_type == RTM_DELADDR) {
|
||||
m_notifier.NotifyNetworkInterfacesChanged();
|
||||
|
||||
@@ -13,17 +13,25 @@ namespace cs {
|
||||
|
||||
std::vector<std::string> GetNetworkInterfaces() {
|
||||
struct ifaddrs* ifa;
|
||||
if (::getifaddrs(&ifa) != 0) return std::vector<std::string>{};
|
||||
if (::getifaddrs(&ifa) != 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> rv;
|
||||
char buf[256];
|
||||
for (struct ifaddrs* i = ifa; i; i = i->ifa_next) {
|
||||
if (!i->ifa_addr) continue; // no address
|
||||
if (i->ifa_addr->sa_family != AF_INET) continue; // only return IPv4
|
||||
if (!i->ifa_addr) {
|
||||
continue; // no address
|
||||
}
|
||||
if (i->ifa_addr->sa_family != AF_INET) {
|
||||
continue; // only return IPv4
|
||||
}
|
||||
struct sockaddr_in* addr_in = reinterpret_cast<sockaddr_in*>(i->ifa_addr);
|
||||
const char* addr =
|
||||
::inet_ntop(addr_in->sin_family, &addr_in->sin_addr, buf, sizeof(buf));
|
||||
if (!addr) continue; // error converting address
|
||||
if (!addr) {
|
||||
continue; // error converting address
|
||||
}
|
||||
rv.emplace_back(addr);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,9 @@ class UsbCameraBuffer {
|
||||
}
|
||||
|
||||
~UsbCameraBuffer() {
|
||||
if (m_data) munmap(m_data, m_length);
|
||||
if (m_data) {
|
||||
munmap(m_data, m_length);
|
||||
}
|
||||
}
|
||||
|
||||
friend void swap(UsbCameraBuffer& first, UsbCameraBuffer& second) noexcept {
|
||||
|
||||
@@ -96,7 +96,9 @@ static __u32 FromPixelFormat(VideoMode::PixelFormat pixelFormat) {
|
||||
}
|
||||
|
||||
static bool IsPercentageProperty(wpi::StringRef name) {
|
||||
if (name.startswith("raw_")) name = name.substr(4);
|
||||
if (name.startswith("raw_")) {
|
||||
name = name.substr(4);
|
||||
}
|
||||
return name == "brightness" || name == "contrast" || name == "saturation" ||
|
||||
name == "hue" || name == "sharpness" || name == "gain" ||
|
||||
name == "exposure_absolute" || name == "exposure_time_absolute";
|
||||
@@ -122,7 +124,9 @@ int UsbCameraImpl::RawToPercentage(const UsbCameraProperty& rawProp,
|
||||
rawProp.minimum == 5 && rawProp.maximum == 20000) {
|
||||
int nelems = wpi::array_lengthof(quirkLifeCamHd3000);
|
||||
for (int i = 0; i < nelems; ++i) {
|
||||
if (rawValue < quirkLifeCamHd3000[i]) return 100.0 * i / nelems;
|
||||
if (rawValue < quirkLifeCamHd3000[i]) {
|
||||
return 100.0 * i / nelems;
|
||||
}
|
||||
}
|
||||
return 100;
|
||||
}
|
||||
@@ -137,8 +141,12 @@ int UsbCameraImpl::PercentageToRaw(const UsbCameraProperty& rawProp,
|
||||
rawProp.minimum == 5 && rawProp.maximum == 20000) {
|
||||
int nelems = wpi::array_lengthof(quirkLifeCamHd3000);
|
||||
int ndx = nelems * percentValue / 100.0;
|
||||
if (ndx < 0) ndx = 0;
|
||||
if (ndx >= nelems) ndx = nelems - 1;
|
||||
if (ndx < 0) {
|
||||
ndx = 0;
|
||||
}
|
||||
if (ndx >= nelems) {
|
||||
ndx = nelems - 1;
|
||||
}
|
||||
return quirkLifeCamHd3000[ndx];
|
||||
}
|
||||
return rawProp.minimum +
|
||||
@@ -153,18 +161,28 @@ static bool GetVendorProduct(int dev, int* vendor, int* product) {
|
||||
}
|
||||
|
||||
int fd = open(ifpath.c_str(), O_RDONLY);
|
||||
if (fd < 0) return false;
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char readBuf[128];
|
||||
ssize_t n = read(fd, readBuf, sizeof(readBuf));
|
||||
close(fd);
|
||||
|
||||
if (n <= 0) return false;
|
||||
if (n <= 0) {
|
||||
return false;
|
||||
}
|
||||
wpi::StringRef readStr{readBuf};
|
||||
if (readStr.substr(readStr.find('v')).substr(1, 4).getAsInteger(16, *vendor))
|
||||
if (readStr.substr(readStr.find('v'))
|
||||
.substr(1, 4)
|
||||
.getAsInteger(16, *vendor)) {
|
||||
return false;
|
||||
if (readStr.substr(readStr.find('p')).substr(1, 4).getAsInteger(16, *product))
|
||||
}
|
||||
if (readStr.substr(readStr.find('p'))
|
||||
.substr(1, 4)
|
||||
.getAsInteger(16, *product)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -177,13 +195,17 @@ static bool GetDescriptionSysV4L(int dev, std::string* desc) {
|
||||
}
|
||||
|
||||
int fd = open(ifpath.c_str(), O_RDONLY);
|
||||
if (fd < 0) return false;
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char readBuf[128];
|
||||
ssize_t n = read(fd, readBuf, sizeof(readBuf));
|
||||
close(fd);
|
||||
|
||||
if (n <= 0) return false;
|
||||
if (n <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*desc = wpi::StringRef(readBuf, n).rtrim();
|
||||
return true;
|
||||
@@ -191,7 +213,9 @@ static bool GetDescriptionSysV4L(int dev, std::string* desc) {
|
||||
|
||||
static bool GetDescriptionIoctl(const char* cpath, std::string* desc) {
|
||||
int fd = open(cpath, O_RDWR);
|
||||
if (fd < 0) return false;
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct v4l2_capability vcap;
|
||||
std::memset(&vcap, 0, sizeof(vcap));
|
||||
@@ -222,7 +246,9 @@ static bool GetDescriptionIoctl(const char* cpath, std::string* desc) {
|
||||
|
||||
static bool IsVideoCaptureDevice(const char* cpath) {
|
||||
int fd = open(cpath, O_RDWR);
|
||||
if (fd < 0) return false;
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct v4l2_capability vcap;
|
||||
std::memset(&vcap, 0, sizeof(vcap));
|
||||
@@ -255,9 +281,13 @@ static int GetDeviceNum(const char* cpath) {
|
||||
}
|
||||
|
||||
path = wpi::sys::path::filename(path);
|
||||
if (!path.startswith("video")) return -1;
|
||||
if (!path.startswith("video")) {
|
||||
return -1;
|
||||
}
|
||||
int dev = -1;
|
||||
if (path.substr(5).getAsInteger(10, dev)) return -1;
|
||||
if (path.substr(5).getAsInteger(10, dev)) {
|
||||
return -1;
|
||||
}
|
||||
return dev;
|
||||
}
|
||||
|
||||
@@ -267,11 +297,15 @@ static std::string GetDescriptionImpl(const char* cpath) {
|
||||
int dev = GetDeviceNum(cpath);
|
||||
if (dev >= 0) {
|
||||
// Sometimes the /sys tree gives a better name.
|
||||
if (GetDescriptionSysV4L(dev, &rv)) return rv;
|
||||
if (GetDescriptionSysV4L(dev, &rv)) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise use an ioctl to query the caps and get the card name
|
||||
if (GetDescriptionIoctl(cpath, &rv)) return rv;
|
||||
if (GetDescriptionIoctl(cpath, &rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return std::string{};
|
||||
}
|
||||
@@ -305,17 +339,23 @@ UsbCameraImpl::~UsbCameraImpl() {
|
||||
Send(Message{Message::kNone});
|
||||
|
||||
// join camera thread
|
||||
if (m_cameraThread.joinable()) m_cameraThread.join();
|
||||
if (m_cameraThread.joinable()) {
|
||||
m_cameraThread.join();
|
||||
}
|
||||
|
||||
// close command fd
|
||||
int fd = m_command_fd.exchange(-1);
|
||||
if (fd >= 0) close(fd);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void DoFdSet(int fd, fd_set* set, int* nfds) {
|
||||
if (fd >= 0) {
|
||||
FD_SET(fd, set);
|
||||
if ((fd + 1) > *nfds) *nfds = fd + 1;
|
||||
if ((fd + 1) > *nfds) {
|
||||
*nfds = fd + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,12 +397,16 @@ void UsbCameraImpl::CameraThreadMain() {
|
||||
|
||||
while (m_active) {
|
||||
// If not connected, try to reconnect
|
||||
if (m_fd < 0) DeviceConnect();
|
||||
if (m_fd < 0) {
|
||||
DeviceConnect();
|
||||
}
|
||||
|
||||
// Make copies of fd's in case they go away
|
||||
int command_fd = m_command_fd.load();
|
||||
int fd = m_fd.load();
|
||||
if (!m_active) break;
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset notified flag and restart streaming if necessary
|
||||
if (fd >= 0) {
|
||||
@@ -395,7 +439,9 @@ void UsbCameraImpl::CameraThreadMain() {
|
||||
fd_set readfds;
|
||||
FD_ZERO(&readfds);
|
||||
DoFdSet(command_fd, &readfds, &nfds);
|
||||
if (m_streaming) DoFdSet(fd, &readfds, &nfds);
|
||||
if (m_streaming) {
|
||||
DoFdSet(fd, &readfds, &nfds);
|
||||
}
|
||||
DoFdSet(notify_fd, &readfds, &nfds);
|
||||
|
||||
if (select(nfds, &readfds, nullptr, nullptr, &tv) < 0) {
|
||||
@@ -404,7 +450,9 @@ void UsbCameraImpl::CameraThreadMain() {
|
||||
}
|
||||
|
||||
// Double-check to see if we're shutting down
|
||||
if (!m_active) break;
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle notify events
|
||||
if (notify_fd >= 0 && FD_ISSET(notify_fd, &readfds)) {
|
||||
@@ -508,10 +556,14 @@ void UsbCameraImpl::CameraThreadMain() {
|
||||
|
||||
void UsbCameraImpl::DeviceDisconnect() {
|
||||
int fd = m_fd.exchange(-1);
|
||||
if (fd < 0) return; // already disconnected
|
||||
if (fd < 0) {
|
||||
return; // already disconnected
|
||||
}
|
||||
|
||||
// Unmap buffers
|
||||
for (int i = 0; i < kNumBuffers; ++i) m_buffers[i] = UsbCameraBuffer{};
|
||||
for (int i = 0; i < kNumBuffers; ++i) {
|
||||
m_buffers[i] = UsbCameraBuffer{};
|
||||
}
|
||||
|
||||
// Close device
|
||||
close(fd);
|
||||
@@ -521,14 +573,20 @@ void UsbCameraImpl::DeviceDisconnect() {
|
||||
}
|
||||
|
||||
void UsbCameraImpl::DeviceConnect() {
|
||||
if (m_fd >= 0) return;
|
||||
if (m_fd >= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_connectVerbose) SINFO("Connecting to USB camera on " << m_path);
|
||||
if (m_connectVerbose) {
|
||||
SINFO("Connecting to USB camera on " << m_path);
|
||||
}
|
||||
|
||||
// Try to open the device
|
||||
SDEBUG3("opening device");
|
||||
int fd = open(m_path.c_str(), O_RDWR);
|
||||
if (fd < 0) return;
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
m_fd = fd;
|
||||
|
||||
// Get capabilities
|
||||
@@ -537,8 +595,9 @@ void UsbCameraImpl::DeviceConnect() {
|
||||
std::memset(&vcap, 0, sizeof(vcap));
|
||||
if (DoIoctl(fd, VIDIOC_QUERYCAP, &vcap) >= 0) {
|
||||
m_capabilities = vcap.capabilities;
|
||||
if (m_capabilities & V4L2_CAP_DEVICE_CAPS)
|
||||
if (m_capabilities & V4L2_CAP_DEVICE_CAPS) {
|
||||
m_capabilities = vcap.device_caps;
|
||||
}
|
||||
}
|
||||
|
||||
// Get or restore video mode
|
||||
@@ -559,10 +618,12 @@ void UsbCameraImpl::DeviceConnect() {
|
||||
for (size_t i = 0; i < m_propertyData.size(); ++i) {
|
||||
const auto prop =
|
||||
static_cast<const UsbCameraProperty*>(m_propertyData[i].get());
|
||||
if (!prop || !prop->valueSet || !prop->device || prop->percentage)
|
||||
if (!prop || !prop->valueSet || !prop->device || prop->percentage) {
|
||||
continue;
|
||||
if (!prop->DeviceSet(lock2, m_fd))
|
||||
}
|
||||
if (!prop->DeviceSet(lock2, m_fd)) {
|
||||
SWARNING("failed to set property " << prop->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +662,9 @@ void UsbCameraImpl::DeviceConnect() {
|
||||
if (!m_buffers[i].m_data) {
|
||||
SWARNING("could not map buffer " << i);
|
||||
// release other buffers
|
||||
for (int j = 0; j < i; ++j) m_buffers[j] = UsbCameraBuffer{};
|
||||
for (int j = 0; j < i; ++j) {
|
||||
m_buffers[j] = UsbCameraBuffer{};
|
||||
}
|
||||
close(fd);
|
||||
m_fd = -1;
|
||||
return;
|
||||
@@ -621,9 +684,13 @@ void UsbCameraImpl::DeviceConnect() {
|
||||
}
|
||||
|
||||
bool UsbCameraImpl::DeviceStreamOn() {
|
||||
if (m_streaming) return false; // ignore if already enabled
|
||||
if (m_streaming) {
|
||||
return false; // ignore if already enabled
|
||||
}
|
||||
int fd = m_fd.load();
|
||||
if (fd < 0) return false;
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Queue buffers
|
||||
SDEBUG3("queuing buffers");
|
||||
@@ -660,11 +727,17 @@ bool UsbCameraImpl::DeviceStreamOn() {
|
||||
}
|
||||
|
||||
bool UsbCameraImpl::DeviceStreamOff() {
|
||||
if (!m_streaming) return false; // ignore if already disabled
|
||||
if (!m_streaming) {
|
||||
return false; // ignore if already disabled
|
||||
}
|
||||
int fd = m_fd.load();
|
||||
if (fd < 0) return false;
|
||||
if (fd < 0) {
|
||||
return false;
|
||||
}
|
||||
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (DoIoctl(fd, VIDIOC_STREAMOFF, &type) != 0) return false;
|
||||
if (DoIoctl(fd, VIDIOC_STREAMOFF, &type) != 0) {
|
||||
return false;
|
||||
}
|
||||
SDEBUG4("disabled streaming");
|
||||
m_streaming = false;
|
||||
return true;
|
||||
@@ -703,12 +776,16 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetMode(
|
||||
m_mode = newMode;
|
||||
lock.unlock();
|
||||
bool wasStreaming = m_streaming;
|
||||
if (wasStreaming) DeviceStreamOff();
|
||||
if (wasStreaming) {
|
||||
DeviceStreamOff();
|
||||
}
|
||||
if (m_fd >= 0) {
|
||||
DeviceDisconnect();
|
||||
DeviceConnect();
|
||||
}
|
||||
if (wasStreaming) DeviceStreamOn();
|
||||
if (wasStreaming) {
|
||||
DeviceStreamOn();
|
||||
}
|
||||
m_notifier.NotifySourceVideoMode(*this, newMode);
|
||||
lock.lock();
|
||||
} else if (newMode.fps != m_mode.fps) {
|
||||
@@ -716,9 +793,13 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetMode(
|
||||
lock.unlock();
|
||||
// Need to stop streaming to set FPS
|
||||
bool wasStreaming = m_streaming;
|
||||
if (wasStreaming) DeviceStreamOff();
|
||||
if (wasStreaming) {
|
||||
DeviceStreamOff();
|
||||
}
|
||||
DeviceSetFPS();
|
||||
if (wasStreaming) DeviceStreamOn();
|
||||
if (wasStreaming) {
|
||||
DeviceStreamOn();
|
||||
}
|
||||
m_notifier.NotifySourceVideoMode(*this, newMode);
|
||||
lock.lock();
|
||||
}
|
||||
@@ -735,21 +816,25 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetProperty(
|
||||
|
||||
// Look up
|
||||
auto prop = static_cast<UsbCameraProperty*>(GetProperty(property));
|
||||
if (!prop) return CS_INVALID_PROPERTY;
|
||||
if (!prop) {
|
||||
return CS_INVALID_PROPERTY;
|
||||
}
|
||||
|
||||
// If setting before we get, guess initial type based on set
|
||||
if (prop->propKind == CS_PROP_NONE) {
|
||||
if (setString)
|
||||
if (setString) {
|
||||
prop->propKind = CS_PROP_STRING;
|
||||
else
|
||||
} else {
|
||||
prop->propKind = CS_PROP_INTEGER;
|
||||
}
|
||||
}
|
||||
|
||||
// Check kind match
|
||||
if ((setString && prop->propKind != CS_PROP_STRING) ||
|
||||
(!setString && (prop->propKind &
|
||||
(CS_PROP_BOOLEAN | CS_PROP_INTEGER | CS_PROP_ENUM)) == 0))
|
||||
(!setString && (prop->propKind & (CS_PROP_BOOLEAN | CS_PROP_INTEGER |
|
||||
CS_PROP_ENUM)) == 0)) {
|
||||
return CS_WRONG_PROPERTY_TYPE;
|
||||
}
|
||||
|
||||
// Handle percentage property
|
||||
int percentageProperty = prop->propPair;
|
||||
@@ -766,17 +851,21 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetProperty(
|
||||
|
||||
// Actually set the new value on the device (if possible)
|
||||
if (!prop->device) {
|
||||
if (prop->id == kPropConnectVerboseId) m_connectVerbose = value;
|
||||
if (prop->id == kPropConnectVerboseId) {
|
||||
m_connectVerbose = value;
|
||||
}
|
||||
} else {
|
||||
if (!prop->DeviceSet(lock, m_fd, value, valueStr))
|
||||
if (!prop->DeviceSet(lock, m_fd, value, valueStr)) {
|
||||
return CS_PROPERTY_WRITE_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
// Cache the set values
|
||||
UpdatePropertyValue(property, setString, value, valueStr);
|
||||
if (percentageProperty != 0)
|
||||
if (percentageProperty != 0) {
|
||||
UpdatePropertyValue(percentageProperty, setString, percentageValue,
|
||||
valueStr);
|
||||
}
|
||||
|
||||
return CS_OK;
|
||||
}
|
||||
@@ -787,12 +876,16 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetPath(
|
||||
lock.unlock();
|
||||
// disconnect and reconnect
|
||||
bool wasStreaming = m_streaming;
|
||||
if (wasStreaming) DeviceStreamOff();
|
||||
if (wasStreaming) {
|
||||
DeviceStreamOff();
|
||||
}
|
||||
if (m_fd >= 0) {
|
||||
DeviceDisconnect();
|
||||
DeviceConnect();
|
||||
}
|
||||
if (wasStreaming) DeviceStreamOn();
|
||||
if (wasStreaming) {
|
||||
DeviceStreamOn();
|
||||
}
|
||||
lock.lock();
|
||||
return CS_OK;
|
||||
}
|
||||
@@ -819,15 +912,18 @@ CS_StatusValue UsbCameraImpl::DeviceProcessCommand(
|
||||
|
||||
void UsbCameraImpl::DeviceProcessCommands() {
|
||||
std::unique_lock lock(m_mutex);
|
||||
if (m_commands.empty()) return;
|
||||
if (m_commands.empty()) {
|
||||
return;
|
||||
}
|
||||
while (!m_commands.empty()) {
|
||||
auto msg = std::move(m_commands.back());
|
||||
m_commands.pop_back();
|
||||
|
||||
CS_StatusValue status = DeviceProcessCommand(lock, msg);
|
||||
if (msg.kind != Message::kNumSinksChanged &&
|
||||
msg.kind != Message::kNumSinksEnabledChanged)
|
||||
msg.kind != Message::kNumSinksEnabledChanged) {
|
||||
m_responses.emplace_back(msg.from, status);
|
||||
}
|
||||
}
|
||||
lock.unlock();
|
||||
m_responseCv.notify_all();
|
||||
@@ -835,7 +931,9 @@ void UsbCameraImpl::DeviceProcessCommands() {
|
||||
|
||||
void UsbCameraImpl::DeviceSetMode() {
|
||||
int fd = m_fd.load();
|
||||
if (fd < 0) return;
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct v4l2_format vfmt;
|
||||
std::memset(&vfmt, 0, sizeof(vfmt));
|
||||
@@ -866,25 +964,34 @@ void UsbCameraImpl::DeviceSetMode() {
|
||||
|
||||
void UsbCameraImpl::DeviceSetFPS() {
|
||||
int fd = m_fd.load();
|
||||
if (fd < 0) return;
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct v4l2_streamparm parm;
|
||||
std::memset(&parm, 0, sizeof(parm));
|
||||
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (DoIoctl(fd, VIDIOC_G_PARM, &parm) != 0) return;
|
||||
if ((parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) return;
|
||||
if (DoIoctl(fd, VIDIOC_G_PARM, &parm) != 0) {
|
||||
return;
|
||||
}
|
||||
if ((parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
|
||||
return;
|
||||
}
|
||||
std::memset(&parm, 0, sizeof(parm));
|
||||
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
parm.parm.capture.timeperframe = FPSToFract(m_mode.fps);
|
||||
if (DoIoctl(fd, VIDIOC_S_PARM, &parm) != 0)
|
||||
if (DoIoctl(fd, VIDIOC_S_PARM, &parm) != 0) {
|
||||
SWARNING("could not set FPS to " << m_mode.fps);
|
||||
else
|
||||
} else {
|
||||
SINFO("set FPS to " << m_mode.fps);
|
||||
}
|
||||
}
|
||||
|
||||
void UsbCameraImpl::DeviceCacheMode() {
|
||||
int fd = m_fd.load();
|
||||
if (fd < 0) return;
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get format
|
||||
struct v4l2_format vfmt;
|
||||
@@ -911,8 +1018,9 @@ void UsbCameraImpl::DeviceCacheMode() {
|
||||
std::memset(&parm, 0, sizeof(parm));
|
||||
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (TryIoctl(fd, VIDIOC_G_PARM, &parm) == 0) {
|
||||
if (parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME)
|
||||
if (parm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) {
|
||||
fps = FractToFPS(parm.parm.capture.timeperframe);
|
||||
}
|
||||
}
|
||||
|
||||
// Update format with user changes.
|
||||
@@ -943,7 +1051,9 @@ void UsbCameraImpl::DeviceCacheMode() {
|
||||
// Default to lowest known resolution (based on number of total pixels)
|
||||
int numPixels = width * height;
|
||||
for (const auto& mode : m_videoModes) {
|
||||
if (mode.pixelFormat != pixelFormat) continue;
|
||||
if (mode.pixelFormat != pixelFormat) {
|
||||
continue;
|
||||
}
|
||||
int numPixelsHere = mode.width * mode.height;
|
||||
if (numPixelsHere < numPixels) {
|
||||
formatChanged = true;
|
||||
@@ -970,8 +1080,12 @@ void UsbCameraImpl::DeviceCacheMode() {
|
||||
m_mode.fps = fps;
|
||||
}
|
||||
|
||||
if (formatChanged) DeviceSetMode();
|
||||
if (fpsChanged) DeviceSetFPS();
|
||||
if (formatChanged) {
|
||||
DeviceSetMode();
|
||||
}
|
||||
if (fpsChanged) {
|
||||
DeviceSetFPS();
|
||||
}
|
||||
|
||||
m_notifier.NotifySourceVideoMode(*this, m_mode);
|
||||
}
|
||||
@@ -1024,8 +1138,9 @@ void UsbCameraImpl::DeviceCacheProperty(
|
||||
rawProp->valueStr = perProp->valueStr; // copy
|
||||
} else {
|
||||
// Read current raw value and set percentage from it
|
||||
if (!rawProp->DeviceGet(lock, m_fd))
|
||||
if (!rawProp->DeviceGet(lock, m_fd)) {
|
||||
SWARNING("failed to get property " << rawProp->name);
|
||||
}
|
||||
|
||||
if (perProp) {
|
||||
perProp->SetValue(RawToPercentage(*rawProp, rawProp->value));
|
||||
@@ -1035,8 +1150,9 @@ void UsbCameraImpl::DeviceCacheProperty(
|
||||
|
||||
// Set value on device if user-configured
|
||||
if (rawProp->valueSet) {
|
||||
if (!rawProp->DeviceSet(lock, m_fd))
|
||||
if (!rawProp->DeviceSet(lock, m_fd)) {
|
||||
SWARNING("failed to set property " << rawProp->name);
|
||||
}
|
||||
}
|
||||
|
||||
// Update pointers since we released the lock
|
||||
@@ -1076,12 +1192,16 @@ void UsbCameraImpl::DeviceCacheProperty(
|
||||
}
|
||||
|
||||
NotifyPropertyCreated(*rawIndex, *rawPropPtr);
|
||||
if (perPropPtr) NotifyPropertyCreated(*perIndex, *perPropPtr);
|
||||
if (perPropPtr) {
|
||||
NotifyPropertyCreated(*perIndex, *perPropPtr);
|
||||
}
|
||||
}
|
||||
|
||||
void UsbCameraImpl::DeviceCacheProperties() {
|
||||
int fd = m_fd.load();
|
||||
if (fd < 0) return;
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef V4L2_CTRL_FLAG_NEXT_COMPOUND
|
||||
constexpr __u32 nextFlags =
|
||||
@@ -1099,20 +1219,24 @@ void UsbCameraImpl::DeviceCacheProperties() {
|
||||
if (id == nextFlags) {
|
||||
// try just enumerating standard...
|
||||
for (id = V4L2_CID_BASE; id < V4L2_CID_LASTP1; ++id) {
|
||||
if (auto prop = UsbCameraProperty::DeviceQuery(fd, &id))
|
||||
if (auto prop = UsbCameraProperty::DeviceQuery(fd, &id)) {
|
||||
DeviceCacheProperty(std::move(prop));
|
||||
}
|
||||
}
|
||||
// ... and custom controls
|
||||
std::unique_ptr<UsbCameraProperty> prop;
|
||||
for (id = V4L2_CID_PRIVATE_BASE;
|
||||
(prop = UsbCameraProperty::DeviceQuery(fd, &id)); ++id)
|
||||
(prop = UsbCameraProperty::DeviceQuery(fd, &id)); ++id) {
|
||||
DeviceCacheProperty(std::move(prop));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UsbCameraImpl::DeviceCacheVideoModes() {
|
||||
int fd = m_fd.load();
|
||||
if (fd < 0) return;
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<VideoMode> modes;
|
||||
|
||||
@@ -1122,7 +1246,9 @@ void UsbCameraImpl::DeviceCacheVideoModes() {
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
for (fmt.index = 0; TryIoctl(fd, VIDIOC_ENUM_FMT, &fmt) >= 0; ++fmt.index) {
|
||||
VideoMode::PixelFormat pixelFormat = ToPixelFormat(fmt.pixelformat);
|
||||
if (pixelFormat == VideoMode::kUnknown) continue;
|
||||
if (pixelFormat == VideoMode::kUnknown) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Frame sizes
|
||||
struct v4l2_frmsizeenum frmsize;
|
||||
@@ -1130,7 +1256,9 @@ void UsbCameraImpl::DeviceCacheVideoModes() {
|
||||
frmsize.pixel_format = fmt.pixelformat;
|
||||
for (frmsize.index = 0; TryIoctl(fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) >= 0;
|
||||
++frmsize.index) {
|
||||
if (frmsize.type != V4L2_FRMSIZE_TYPE_DISCRETE) continue;
|
||||
if (frmsize.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Frame intervals
|
||||
struct v4l2_frmivalenum frmival;
|
||||
@@ -1141,7 +1269,9 @@ void UsbCameraImpl::DeviceCacheVideoModes() {
|
||||
for (frmival.index = 0;
|
||||
TryIoctl(fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) >= 0;
|
||||
++frmival.index) {
|
||||
if (frmival.type != V4L2_FRMIVAL_TYPE_DISCRETE) continue;
|
||||
if (frmival.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
modes.emplace_back(pixelFormat,
|
||||
static_cast<int>(frmsize.discrete.width),
|
||||
@@ -1180,7 +1310,9 @@ void UsbCameraImpl::DeviceCacheVideoModes() {
|
||||
CS_StatusValue UsbCameraImpl::SendAndWait(Message&& msg) const {
|
||||
int fd = m_command_fd.load();
|
||||
// exit early if not possible to signal
|
||||
if (fd < 0) return CS_SOURCE_IS_DISCONNECTED;
|
||||
if (fd < 0) {
|
||||
return CS_SOURCE_IS_DISCONNECTED;
|
||||
}
|
||||
|
||||
auto from = msg.from;
|
||||
|
||||
@@ -1191,7 +1323,9 @@ CS_StatusValue UsbCameraImpl::SendAndWait(Message&& msg) const {
|
||||
}
|
||||
|
||||
// Signal the camera thread
|
||||
if (eventfd_write(fd, 1) < 0) return CS_SOURCE_IS_DISCONNECTED;
|
||||
if (eventfd_write(fd, 1) < 0) {
|
||||
return CS_SOURCE_IS_DISCONNECTED;
|
||||
}
|
||||
|
||||
std::unique_lock lock(m_mutex);
|
||||
while (m_active) {
|
||||
@@ -1217,7 +1351,9 @@ CS_StatusValue UsbCameraImpl::SendAndWait(Message&& msg) const {
|
||||
void UsbCameraImpl::Send(Message&& msg) const {
|
||||
int fd = m_command_fd.load();
|
||||
// exit early if not possible to signal
|
||||
if (fd < 0) return;
|
||||
if (fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the message to the command queue
|
||||
{
|
||||
@@ -1237,7 +1373,9 @@ std::unique_ptr<PropertyImpl> UsbCameraImpl::CreateEmptyProperty(
|
||||
bool UsbCameraImpl::CacheProperties(CS_Status* status) const {
|
||||
// Wake up camera thread; this will try to reconnect
|
||||
*status = SendAndWait(Message{Message::kNone});
|
||||
if (*status != CS_OK) return false;
|
||||
if (*status != CS_OK) {
|
||||
return false;
|
||||
}
|
||||
if (!m_properties_cached) {
|
||||
*status = CS_SOURCE_IS_DISCONNECTED;
|
||||
return false;
|
||||
@@ -1473,7 +1611,9 @@ UsbCameraInfo GetUsbCameraInfo(CS_Source source, CS_Status* status) {
|
||||
path += ep->d_name;
|
||||
char* target = ::realpath(path.c_str(), nullptr);
|
||||
if (target) {
|
||||
if (keypath == target) info.otherPaths.emplace_back(path.str());
|
||||
if (keypath == target) {
|
||||
info.otherPaths.emplace_back(path.str());
|
||||
}
|
||||
std::free(target);
|
||||
}
|
||||
}
|
||||
@@ -1496,10 +1636,14 @@ std::vector<UsbCameraInfo> EnumerateUsbCameras(CS_Status* status) {
|
||||
if (DIR* dp = ::opendir("/dev")) {
|
||||
while (struct dirent* ep = ::readdir(dp)) {
|
||||
wpi::StringRef fname{ep->d_name};
|
||||
if (!fname.startswith("video")) continue;
|
||||
if (!fname.startswith("video")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int dev = 0;
|
||||
if (fname.substr(5).getAsInteger(10, dev)) continue;
|
||||
if (fname.substr(5).getAsInteger(10, dev)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UsbCameraInfo info;
|
||||
info.dev = dev;
|
||||
@@ -1508,14 +1652,20 @@ std::vector<UsbCameraInfo> EnumerateUsbCameras(CS_Status* status) {
|
||||
path += fname;
|
||||
info.path = path.str();
|
||||
|
||||
if (!IsVideoCaptureDevice(path.c_str())) continue;
|
||||
if (!IsVideoCaptureDevice(path.c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
info.name = GetDescriptionImpl(path.c_str());
|
||||
if (info.name.empty()) continue;
|
||||
if (info.name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GetVendorProduct(dev, &info.vendorId, &info.productId);
|
||||
|
||||
if (dev >= retval.size()) retval.resize(info.dev + 1);
|
||||
if (dev >= retval.size()) {
|
||||
retval.resize(info.dev + 1);
|
||||
}
|
||||
retval[info.dev] = std::move(info);
|
||||
}
|
||||
::closedir(dp);
|
||||
|
||||
@@ -26,7 +26,9 @@ static int GetIntCtrlIoctl(int fd, unsigned id, int type, int64_t* value) {
|
||||
ctrls.count = 1;
|
||||
ctrls.controls = &ctrl;
|
||||
int rc = DoIoctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls);
|
||||
if (rc < 0) return rc;
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
*value = ctrl.value;
|
||||
} else {
|
||||
// Use normal control
|
||||
@@ -34,7 +36,9 @@ static int GetIntCtrlIoctl(int fd, unsigned id, int type, int64_t* value) {
|
||||
std::memset(&ctrl, 0, sizeof(ctrl));
|
||||
ctrl.id = id;
|
||||
int rc = DoIoctl(fd, VIDIOC_G_CTRL, &ctrl);
|
||||
if (rc < 0) return rc;
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
}
|
||||
*value = ctrl.value;
|
||||
}
|
||||
return 0;
|
||||
@@ -51,10 +55,11 @@ static int SetIntCtrlIoctl(int fd, unsigned id, int type, int64_t value) {
|
||||
std::memset(&ctrl, 0, sizeof(ctrl));
|
||||
std::memset(&ctrls, 0, sizeof(ctrls));
|
||||
ctrl.id = id;
|
||||
if (type == V4L2_CTRL_TYPE_INTEGER64)
|
||||
if (type == V4L2_CTRL_TYPE_INTEGER64) {
|
||||
ctrl.value64 = value;
|
||||
else
|
||||
} else {
|
||||
ctrl.value = static_cast<__s32>(value);
|
||||
}
|
||||
ctrls.ctrl_class = ctrl_class;
|
||||
ctrls.count = 1;
|
||||
ctrls.controls = &ctrl;
|
||||
@@ -117,7 +122,9 @@ static wpi::StringRef NormalizeName(wpi::StringRef name,
|
||||
bool newWord = false;
|
||||
for (auto ch : name) {
|
||||
if (std::isalnum(ch)) {
|
||||
if (newWord) buf.push_back('_');
|
||||
if (newWord) {
|
||||
buf.push_back('_');
|
||||
}
|
||||
newWord = false;
|
||||
buf.push_back(std::tolower(ch));
|
||||
} else if (!buf.empty()) {
|
||||
@@ -163,7 +170,9 @@ UsbCameraProperty::UsbCameraProperty(const struct v4l2_query_ext_ctrl& ctrl)
|
||||
|
||||
// name
|
||||
size_t len = 0;
|
||||
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') ++len;
|
||||
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') {
|
||||
++len;
|
||||
}
|
||||
wpi::SmallString<64> name_buf;
|
||||
name = NormalizeName(wpi::StringRef(ctrl.name, len), name_buf);
|
||||
}
|
||||
@@ -201,7 +210,9 @@ UsbCameraProperty::UsbCameraProperty(const struct v4l2_queryctrl& ctrl)
|
||||
|
||||
// name
|
||||
size_t len = 0;
|
||||
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') ++len;
|
||||
while (len < sizeof(ctrl.name) && ctrl.name[len] != '\0') {
|
||||
++len;
|
||||
}
|
||||
wpi::SmallString<64> name_buf;
|
||||
name = NormalizeName(
|
||||
wpi::StringRef(reinterpret_cast<const char*>(ctrl.name), len), name_buf);
|
||||
@@ -219,7 +230,9 @@ std::unique_ptr<UsbCameraProperty> UsbCameraProperty::DeviceQuery(int fd,
|
||||
if (rc == 0) {
|
||||
*id = qc_ext.id; // copy back
|
||||
// We don't support array types
|
||||
if (qc_ext.elems > 1 || qc_ext.nr_of_dims > 0) return nullptr;
|
||||
if (qc_ext.elems > 1 || qc_ext.nr_of_dims > 0) {
|
||||
return nullptr;
|
||||
}
|
||||
prop = std::make_unique<UsbCameraProperty>(qc_ext);
|
||||
}
|
||||
#endif
|
||||
@@ -230,7 +243,9 @@ std::unique_ptr<UsbCameraProperty> UsbCameraProperty::DeviceQuery(int fd,
|
||||
qc.id = *id;
|
||||
rc = TryIoctl(fd, VIDIOC_QUERYCTRL, &qc);
|
||||
*id = qc.id; // copy back
|
||||
if (rc != 0) return nullptr;
|
||||
if (rc != 0) {
|
||||
return nullptr;
|
||||
}
|
||||
prop = std::make_unique<UsbCameraProperty>(qc);
|
||||
}
|
||||
|
||||
@@ -242,7 +257,9 @@ std::unique_ptr<UsbCameraProperty> UsbCameraProperty::DeviceQuery(int fd,
|
||||
qmenu.id = *id;
|
||||
for (int i = prop->minimum; i <= prop->maximum; ++i) {
|
||||
qmenu.index = static_cast<__u32>(i);
|
||||
if (TryIoctl(fd, VIDIOC_QUERYMENU, &qmenu) != 0) continue;
|
||||
if (TryIoctl(fd, VIDIOC_QUERYMENU, &qmenu) != 0) {
|
||||
continue;
|
||||
}
|
||||
if (prop->intMenu) {
|
||||
wpi::raw_string_ostream os(prop->enumChoices[i]);
|
||||
os << qmenu.value;
|
||||
@@ -256,7 +273,9 @@ std::unique_ptr<UsbCameraProperty> UsbCameraProperty::DeviceQuery(int fd,
|
||||
}
|
||||
|
||||
bool UsbCameraProperty::DeviceGet(std::unique_lock<wpi::mutex>& lock, int fd) {
|
||||
if (fd < 0) return true;
|
||||
if (fd < 0) {
|
||||
return true;
|
||||
}
|
||||
unsigned idCopy = id;
|
||||
int rv = 0;
|
||||
|
||||
@@ -269,7 +288,9 @@ bool UsbCameraProperty::DeviceGet(std::unique_lock<wpi::mutex>& lock, int fd) {
|
||||
lock.unlock();
|
||||
rv = GetIntCtrlIoctl(fd, idCopy, typeCopy, &newValue);
|
||||
lock.lock();
|
||||
if (rv >= 0) value = newValue;
|
||||
if (rv >= 0) {
|
||||
value = newValue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CS_PROP_STRING: {
|
||||
@@ -278,7 +299,9 @@ bool UsbCameraProperty::DeviceGet(std::unique_lock<wpi::mutex>& lock, int fd) {
|
||||
lock.unlock();
|
||||
rv = GetStringCtrlIoctl(fd, idCopy, maximumCopy, &newValueStr);
|
||||
lock.lock();
|
||||
if (rv >= 0) valueStr = std::move(newValueStr);
|
||||
if (rv >= 0) {
|
||||
valueStr = std::move(newValueStr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -298,7 +321,9 @@ bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock,
|
||||
bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock, int fd,
|
||||
int newValue,
|
||||
const wpi::Twine& newValueStr) const {
|
||||
if (!device || fd < 0) return true;
|
||||
if (!device || fd < 0) {
|
||||
return true;
|
||||
}
|
||||
unsigned idCopy = id;
|
||||
int rv = 0;
|
||||
|
||||
|
||||
@@ -21,7 +21,9 @@ namespace cs {
|
||||
static wpi::StringRef GetUsbNameFromFile(int vendor, int product,
|
||||
wpi::SmallVectorImpl<char>& buf) {
|
||||
int fd = open("/var/lib/usbutils/usb.ids", O_RDONLY);
|
||||
if (fd < 0) return wpi::StringRef{};
|
||||
if (fd < 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
wpi::raw_svector_ostream os{buf};
|
||||
wpi::raw_fd_istream is{fd, true};
|
||||
@@ -37,9 +39,13 @@ static wpi::StringRef GetUsbNameFromFile(int vendor, int product,
|
||||
bool foundVendor = false;
|
||||
for (;;) {
|
||||
auto line = is.getline(lineBuf, 4096);
|
||||
if (is.has_error()) break;
|
||||
if (is.has_error()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (line.empty()) continue;
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// look for vendor at start of line
|
||||
if (line.startswith(vendorStr)) {
|
||||
@@ -63,14 +69,16 @@ static wpi::StringRef GetUsbNameFromFile(int vendor, int product,
|
||||
}
|
||||
}
|
||||
|
||||
return wpi::StringRef{};
|
||||
return {};
|
||||
}
|
||||
|
||||
wpi::StringRef GetUsbNameFromId(int vendor, int product,
|
||||
wpi::SmallVectorImpl<char>& buf) {
|
||||
// try reading usb.ids
|
||||
wpi::StringRef rv = GetUsbNameFromFile(vendor, product, buf);
|
||||
if (!rv.empty()) return rv;
|
||||
if (!rv.empty()) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Fall back to internal database
|
||||
wpi::raw_svector_ostream os{buf};
|
||||
|
||||
@@ -56,9 +56,13 @@ STDMETHODIMP_(ULONG) SourceReaderCB::Release() {
|
||||
return uCount;
|
||||
}
|
||||
|
||||
STDMETHODIMP SourceReaderCB::OnEvent(DWORD, IMFMediaEvent*) { return S_OK; }
|
||||
STDMETHODIMP SourceReaderCB::OnEvent(DWORD, IMFMediaEvent*) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP SourceReaderCB::OnFlush(DWORD) { return S_OK; }
|
||||
STDMETHODIMP SourceReaderCB::OnFlush(DWORD) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void SourceReaderCB::NotifyError(HRESULT hr) {
|
||||
wprintf(L"Source Reader error: 0x%X\n", hr);
|
||||
@@ -70,7 +74,8 @@ STDMETHODIMP SourceReaderCB::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex,
|
||||
IMFSample* pSample // Can be NULL
|
||||
) {
|
||||
auto source = m_source.lock();
|
||||
if (!source) return S_OK;
|
||||
if (!source)
|
||||
return S_OK;
|
||||
if (SUCCEEDED(hrStatus)) {
|
||||
if (pSample) {
|
||||
// Prcoess sample
|
||||
|
||||
@@ -44,7 +44,9 @@ static void WINAPI OnInterfaceChange(PVOID callerContext,
|
||||
NetworkListener::NetworkListener(wpi::Logger& logger, Notifier& notifier)
|
||||
: m_impl(std::make_unique<Impl>(logger, notifier)) {}
|
||||
|
||||
NetworkListener::~NetworkListener() { Stop(); }
|
||||
NetworkListener::~NetworkListener() {
|
||||
Stop();
|
||||
}
|
||||
|
||||
void NetworkListener::Start() {
|
||||
NotifyIpInterfaceChange(AF_INET, OnInterfaceChange, &m_impl->m_notifier, true,
|
||||
|
||||
@@ -21,7 +21,9 @@ std::vector<std::string> GetNetworkInterfaces() {
|
||||
char ip[50];
|
||||
|
||||
for (int i = 0; i < counts; i++) {
|
||||
if (adrs[i].is_internal) continue;
|
||||
if (adrs[i].is_internal) {
|
||||
continue;
|
||||
}
|
||||
InetNtop(PF_INET, &(adrs[i].netmask.netmask4.sin_addr.s_addr), ip,
|
||||
sizeof(ip) - 1);
|
||||
ip[49] = '\0';
|
||||
|
||||
@@ -86,7 +86,9 @@ UsbCameraImpl::UsbCameraImpl(const wpi::Twine& name, wpi::Logger& logger,
|
||||
StartMessagePump();
|
||||
}
|
||||
|
||||
UsbCameraImpl::~UsbCameraImpl() { m_messagePump = nullptr; }
|
||||
UsbCameraImpl::~UsbCameraImpl() {
|
||||
m_messagePump = nullptr;
|
||||
}
|
||||
|
||||
void UsbCameraImpl::SetProperty(int property, int value, CS_Status* status) {
|
||||
Message msg{Message::kCmdSetProperty};
|
||||
@@ -254,7 +256,8 @@ bool UsbCameraImpl::CheckDeviceChange(WPARAM wParam, DEV_BROADCAST_HDR* pHdr,
|
||||
}
|
||||
|
||||
void UsbCameraImpl::DeviceDisconnect() {
|
||||
if (m_connectVerbose) SINFO("Disconnected from " << m_path);
|
||||
if (m_connectVerbose)
|
||||
SINFO("Disconnected from " << m_path);
|
||||
m_sourceReader.Reset();
|
||||
m_mediaSource.Reset();
|
||||
if (m_imageCallback) {
|
||||
@@ -266,7 +269,8 @@ void UsbCameraImpl::DeviceDisconnect() {
|
||||
}
|
||||
|
||||
static bool IsPercentageProperty(wpi::StringRef name) {
|
||||
if (name.startswith("raw_")) name = name.substr(4);
|
||||
if (name.startswith("raw_"))
|
||||
name = name.substr(4);
|
||||
return name == "Brightness" || name == "Contrast" || name == "Saturation" ||
|
||||
name == "Hue" || name == "Sharpness" || name == "Gain" ||
|
||||
name == "Exposure";
|
||||
@@ -274,14 +278,17 @@ static bool IsPercentageProperty(wpi::StringRef name) {
|
||||
|
||||
void UsbCameraImpl::ProcessFrame(IMFSample* videoSample,
|
||||
const VideoMode& mode) {
|
||||
if (!videoSample) return;
|
||||
if (!videoSample)
|
||||
return;
|
||||
|
||||
ComPtr<IMFMediaBuffer> buf;
|
||||
|
||||
if (!SUCCEEDED(videoSample->ConvertToContiguousBuffer(buf.GetAddressOf()))) {
|
||||
DWORD bcnt = 0;
|
||||
if (!SUCCEEDED(videoSample->GetBufferCount(&bcnt))) return;
|
||||
if (bcnt == 0) return;
|
||||
if (!SUCCEEDED(videoSample->GetBufferCount(&bcnt)))
|
||||
return;
|
||||
if (bcnt == 0)
|
||||
return;
|
||||
if (!SUCCEEDED(videoSample->GetBufferByIndex(0, buf.GetAddressOf())))
|
||||
return;
|
||||
}
|
||||
@@ -310,7 +317,8 @@ void UsbCameraImpl::ProcessFrame(IMFSample* videoSample,
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!ptr) return;
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
cv::Mat tmpMat;
|
||||
std::unique_ptr<Image> dest;
|
||||
@@ -451,16 +459,19 @@ static cs::VideoMode::PixelFormat GetFromGUID(const GUID& guid) {
|
||||
}
|
||||
|
||||
bool UsbCameraImpl::DeviceConnect() {
|
||||
if (m_mediaSource && m_sourceReader) return true;
|
||||
if (m_mediaSource && m_sourceReader)
|
||||
return true;
|
||||
|
||||
if (m_connectVerbose) SINFO("Connecting to USB camera on " << m_path);
|
||||
if (m_connectVerbose)
|
||||
SINFO("Connecting to USB camera on " << m_path);
|
||||
|
||||
SDEBUG3("opening device");
|
||||
|
||||
const wchar_t* path = m_widePath.c_str();
|
||||
m_mediaSource = CreateVideoCaptureDevice(path);
|
||||
|
||||
if (!m_mediaSource) return false;
|
||||
if (!m_mediaSource)
|
||||
return false;
|
||||
m_imageCallback = CreateSourceReaderCB(shared_from_this(), m_mode);
|
||||
|
||||
m_sourceReader =
|
||||
@@ -510,7 +521,8 @@ bool UsbCameraImpl::CacheProperties(CS_Status* status) const {
|
||||
auto result = m_messagePump->SendWindowMessage<CS_Status>(
|
||||
WaitForStartupMessage, nullptr, nullptr);
|
||||
*status = result;
|
||||
if (*status != CS_OK) return false;
|
||||
if (*status != CS_OK)
|
||||
return false;
|
||||
if (!m_properties_cached) {
|
||||
*status = CS_SOURCE_IS_DISCONNECTED;
|
||||
return false;
|
||||
@@ -545,7 +557,8 @@ template void UsbCameraImpl::DeviceAddProperty(const wpi::Twine& name_,
|
||||
DeviceAddProperty(#val, CameraControl_##val, pCamControl);
|
||||
|
||||
void UsbCameraImpl::DeviceCacheProperties() {
|
||||
if (!m_sourceReader) return;
|
||||
if (!m_sourceReader)
|
||||
return;
|
||||
|
||||
IAMVideoProcAmp* pProcAmp = NULL;
|
||||
|
||||
@@ -693,7 +706,8 @@ void UsbCameraImpl::DeviceCacheProperty(
|
||||
}
|
||||
|
||||
NotifyPropertyCreated(*rawIndex, *rawPropPtr);
|
||||
if (perPropPtr && perIndex) NotifyPropertyCreated(*perIndex, *perPropPtr);
|
||||
if (perPropPtr && perIndex)
|
||||
NotifyPropertyCreated(*perIndex, *perPropPtr);
|
||||
}
|
||||
|
||||
CS_StatusValue UsbCameraImpl::DeviceProcessCommand(
|
||||
@@ -740,7 +754,8 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetProperty(
|
||||
|
||||
// Look up
|
||||
auto prop = static_cast<UsbCameraProperty*>(GetProperty(property));
|
||||
if (!prop) return CS_INVALID_PROPERTY;
|
||||
if (!prop)
|
||||
return CS_INVALID_PROPERTY;
|
||||
|
||||
// If setting before we get, guess initial type based on set
|
||||
if (prop->propKind == CS_PROP_NONE) {
|
||||
@@ -771,7 +786,8 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetProperty(
|
||||
|
||||
// Actually set the new value on the device (if possible)
|
||||
if (!prop->device) {
|
||||
if (prop->id == kPropConnectVerboseId) m_connectVerbose = value;
|
||||
if (prop->id == kPropConnectVerboseId)
|
||||
m_connectVerbose = value;
|
||||
} else {
|
||||
if (!prop->DeviceSet(lock, m_sourceReader.Get())) {
|
||||
return CS_PROPERTY_WRITE_FAILED;
|
||||
@@ -855,8 +871,10 @@ CS_StatusValue UsbCameraImpl::DeviceCmdSetMode(
|
||||
}
|
||||
|
||||
bool UsbCameraImpl::DeviceStreamOn() {
|
||||
if (m_streaming) return false;
|
||||
if (!m_deviceValid) return false;
|
||||
if (m_streaming)
|
||||
return false;
|
||||
if (!m_deviceValid)
|
||||
return false;
|
||||
m_streaming = true;
|
||||
m_sourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL,
|
||||
NULL, NULL);
|
||||
@@ -869,9 +887,11 @@ bool UsbCameraImpl::DeviceStreamOff() {
|
||||
}
|
||||
|
||||
void UsbCameraImpl::DeviceCacheMode() {
|
||||
if (!m_sourceReader) return;
|
||||
if (!m_sourceReader)
|
||||
return;
|
||||
|
||||
if (m_windowsVideoModes.size() == 0) return;
|
||||
if (m_windowsVideoModes.size() == 0)
|
||||
return;
|
||||
|
||||
if (!m_currentMode) {
|
||||
// First, see if our set mode is valid
|
||||
@@ -936,7 +956,8 @@ CS_StatusValue UsbCameraImpl::DeviceSetMode() {
|
||||
}
|
||||
|
||||
void UsbCameraImpl::DeviceCacheVideoModes() {
|
||||
if (!m_sourceReader) return;
|
||||
if (!m_sourceReader)
|
||||
return;
|
||||
|
||||
std::vector<VideoMode> modes;
|
||||
m_windowsVideoModes.clear();
|
||||
|
||||
@@ -38,7 +38,8 @@ UsbCameraProperty::UsbCameraProperty(const wpi::Twine& name_,
|
||||
|
||||
bool UsbCameraProperty::DeviceGet(std::unique_lock<wpi::mutex>& lock,
|
||||
IAMVideoProcAmp* pProcAmp) {
|
||||
if (!pProcAmp) return true;
|
||||
if (!pProcAmp)
|
||||
return true;
|
||||
|
||||
lock.unlock();
|
||||
long newValue = 0, paramFlag = 0; // NOLINT(runtime/int)
|
||||
@@ -57,7 +58,8 @@ bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock,
|
||||
bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock,
|
||||
IAMVideoProcAmp* pProcAmp,
|
||||
int newValue) const {
|
||||
if (!pProcAmp) return true;
|
||||
if (!pProcAmp)
|
||||
return true;
|
||||
|
||||
lock.unlock();
|
||||
if (SUCCEEDED(
|
||||
@@ -100,7 +102,8 @@ UsbCameraProperty::UsbCameraProperty(const wpi::Twine& name_,
|
||||
|
||||
bool UsbCameraProperty::DeviceGet(std::unique_lock<wpi::mutex>& lock,
|
||||
IAMCameraControl* pProcAmp) {
|
||||
if (!pProcAmp) return true;
|
||||
if (!pProcAmp)
|
||||
return true;
|
||||
|
||||
lock.unlock();
|
||||
long newValue = 0, paramFlag = 0; // NOLINT(runtime/int)
|
||||
@@ -119,7 +122,8 @@ bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock,
|
||||
bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock,
|
||||
IAMCameraControl* pProcAmp,
|
||||
int newValue) const {
|
||||
if (!pProcAmp) return true;
|
||||
if (!pProcAmp)
|
||||
return true;
|
||||
|
||||
lock.unlock();
|
||||
if (SUCCEEDED(pProcAmp->Set(tagCameraControl, newValue,
|
||||
@@ -133,7 +137,8 @@ bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock,
|
||||
|
||||
bool UsbCameraProperty::DeviceGet(std::unique_lock<wpi::mutex>& lock,
|
||||
IMFSourceReader* sourceReader) {
|
||||
if (!sourceReader) return true;
|
||||
if (!sourceReader)
|
||||
return true;
|
||||
|
||||
if (isControlProperty) {
|
||||
ComPtr<IAMCameraControl> pProcAmp;
|
||||
@@ -162,7 +167,8 @@ bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock,
|
||||
bool UsbCameraProperty::DeviceSet(std::unique_lock<wpi::mutex>& lock,
|
||||
IMFSourceReader* sourceReader,
|
||||
int newValue) const {
|
||||
if (!sourceReader) return true;
|
||||
if (!sourceReader)
|
||||
return true;
|
||||
|
||||
if (isControlProperty) {
|
||||
ComPtr<IAMCameraControl> pProcAmp;
|
||||
|
||||
@@ -99,7 +99,8 @@ WindowsMessagePump::WindowsMessagePump(
|
||||
|
||||
WindowsMessagePump::~WindowsMessagePump() {
|
||||
auto res = SendMessage(hwnd, WM_CLOSE, NULL, NULL);
|
||||
if (m_mainThread.joinable()) m_mainThread.join();
|
||||
if (m_mainThread.joinable())
|
||||
m_mainThread.join();
|
||||
}
|
||||
|
||||
void WindowsMessagePump::ThreadMain(HANDLE eventHandle) {
|
||||
|
||||
Reference in New Issue
Block a user