Squashed 'third_party/allwpilib_2019/' changes from 99e4f7dd2..c36bbcc9a
936627bd9 wpilibc: Remove direct CameraServer dependency (#1989)
8e333c0aa Use FPGA Time instead of wall clock time for odometry (#1996)
d4430b765 Gearsbot example: Use standard argument order (#1995)
75438ab2c Add RamseteCommand (#1951)
989df1b46 Bump Native Utils and OpenCV dependencies (#1993)
dbc33b61e Fix Timer usage in TrapezoidProfileCommand (#1992)
79f8c5644 Add TrapezoidProfileCommand (#1962)
9440edf2b Refactor TrajectoryGenerator (#1972)
73a30182c Add frc2::Timer (#1968)
36ea865ed Add toString for geometry and trajectory classes (#1991)
cbe05e7e8 Update ProfiledPIDController API (#1967)
d04eb3546 Deprecate old PID classes (#1964)
02264db69 Add JNI dependencies to myRobotCpp (#1980)
2a76c996e Use VID/PID detection for PS3Eye (#1977)
a3820bbdf Remove HAL_BaseInitialize (#1981)
a83fb4793 Update to 2020v5 image (#1983)
4b0ed910e Make SwerveDriveKinematics.toChassisSpeeds() public (#1976)
103c1b121 Remove DS caching from the HAL level (#1971)
6635ea75e Fix NPE in SendableRegistry.foreachLiveWindow() (#1974)
cfe23c5cd Fix grammar error in comment for configureButtonBindings (#1969)
4bde2654e Fix mac azure build (#1973)
4f034e6c1 generateTrajectory: default reversed param to false (#1953)
acf960f72 Sim GUI: Add option to disable outputs on DS disable
2d3dac99f Sim GUI: Handle low resolutions and scale default window positions
07c86e0cd Sim GUI: Support High DPI monitors
46ad95512 SimDeviceData: Add missing null check
5bce489b9 Add ProggyDotted font to imgui (both cmake and gradle)
55af553ac Simulation GUI: Map gamepad the same way as DS
c59f9cea5 CameraServer: Add VID/PID support for Linux USB devices (#1960)
3fc89c84d Make splinePointsFromSplines public (#1963)
2c5093797 Fix implicitly deleted move constructors (#1954)
f3ad927f4 Update Java SmartDashboard and LiveWindow to match C++
05c25deb7 Fix move handling of C++ Sendable in SmartDashboard and LiveWindow
d726591ce Fix Gazebo sim plugin build (#1959)
2ff694fa4 Unbreak gradle build when other compilers installed (#1958)
53816155b Improve command decorator names (#1945)
a38f183a9 Fix GenResources.cmake so it's usable in a submodule (#1956)
b3398dca3 Set gradlebase correctly for all examples (#1950)
2c311013d Add Aarch64Bionic platform detection (#1922)
c10f2003c Add generateTrajectory overload (#1944)
63cfa64fb Add getters for pose in odometry classes (#1943)
2402c2bad Fix C++ command group recursive constructor bug (#1941)
f4eedf597 Fix ConcurrentModificationException in CommandScheduler (#1938)
bb0b207d2 Fix array out of bounds exception caused by parallel race group (#1935)
7bd69e591 Fix typo in temperature (#1940)
ec9738245 Bump to 2020 v4 image (#1931)
46303a822 Add messaging to extension loading in the HAL (#1926)
d169d6be9 Set extract_static for Doxygen config so that static members show up (#1930)
4e183eb10 Bump to 2020 v3 image (#1929)
84c185803 LiveWindow: catch errors in callback/builder functions (#1921)
0e3b0f3da Remove deprecated free() calls (#1925)
7f839b87c Remove timeouts from azure builds (#1924)
45b766a5d Fix main thread ID being potentially incorrect for simulation (#1923)
56d782b16 Add secondary camera name for PS3Eye (#1920)
2b4894038 Add simulation GUI plugin
f97d16073 Add imgui build to cmake
55a844a3e HAL sim: Add encoder channel B access
10deba854 Remove sendables from SendableRegistry when close() is called (#1917)
a9f0e4668 Implement sim devices for ADXL345, ADXL362, ADXRS450, Ultrasonic
aa9064586 Add ability to associate other devices with a SimDevice
81c2c8a7d Add simulation generic device/value support
e8d6f8a2c Move mockdata/HAL_Value.h to hal/Value.h
1b266717a Add simulation module support to cmake build (#1906)
fb8f3bd06 Add testbench yaml file (#1915)
846d8def0 Update to 2020 v2 image (#1913)
d6ac6e512 Fix PortForwarder package declaration (#1912)
227157086 Fix PS3Eye exposure setting (#1911)
885744d7e Add myRobot C++ version to cmake build (#1907)
366091fa8 Document that ConditionalCommand requires all subsystems (#1909)
c58b072c8 Fix Drive usage reporting order (#1908)
762c88adb Update compiler versions in readme (#1905)
af8ce568d Add Ramsete unicycle controller (#1790)
b2c2934d0 Fix javadoc warnings about invalid usage of ">" (#1904)
cce26ec78 Replace CRLF line endings with LF (#1902)
cb54602d4 Add support for writing RTR CAN Frames to the CAN API (#1900)
9f740e590 Use OS for serial port instead of NI VISA (#1875)
b23baf611 Add ability to run robot main loop in a separate thread (#1895)
457f94ba2 Add trajectory generation using hermite splines (#1843)
fd612052f Update native utils to use new frchome directory (#1884)
8858ec55c Remove periodic can read call (#1868)
41efb8015 Update CANAPITypes.h (#1860)
c93be1b2d Remove LabVIEW HAL support (#1901)
680f8919e Remove eigen, units and libuv from doxygen generation (#1898)
c5812524f Bump GradleJNI plugin version (#1899)
971303da8 Add PortForwarder class (#1890)
50db77bf2 Fix wpiutil cmake eigen install source directory (#1891)
85d42c199 C++ PIDCommand: Add GetMeasurement() and UseOutput() (#1892)
2dfbb855d wpilibj: Fix SwerveDriveKinematics ctor parameter name (#1889)
471f375a3 Simplify Sendable interface (#1864)
1d8c4d016 Replace ::value and ::type with _v and _t suffixes (#1885)
a5650b943 Add Units Utility class for Java (#1829)
904479ad4 Deprecate GearTooth class for removal (#1878)
86b666bba Add equality comparator to geometry classes (#1882)
62f07c182 Make one-arg Rotation2d constructor implicit (#1883)
f405582f8 Add kinematics suite (#1787)
561cbbd14 Deprecate Filter class for removal (#1876)
84e2973aa Remove unused include from Filesystem.h (#1877)
f49859ebf Remove NI VISA headers, as they are now included in NI Libraries (#1879)
bc59db5e6 Rename DEBUG macro to DEBUG0 (#1871)
dd928b4cb Remove JNI logging (#1872)
3e0f7d099 Use units for new NotifierCommand (#1869)
5ffe15d5f Remove ability to build all combined artifacts (#1867)
516cbef2c Remove RoboRIO ifdef from simulation headers (#1859)
9b6ffc201 Replace SetOutputRange() with SetIntegratorRange()
ff8b8f0a8 Remove percent tolerance from PID controller
0ca8d667d Clean up AutoCloseable and other Java warnings (#1866)
7112add67 Watchdog: use units::second_t instead of double (#1863)
761bc3ef8 Change C++ WaitCommand to use units (#1865)
1fb301123 Add MathUtils.clamp() for Java (#1861)
eb3e0c9c9 Fix cmake Eigen include directory (#1862)
2250b7fbe Rename GearsBotNew example to GearsBot
c9f9feff1 Replace deprecated API usage in C++ examples
d6b9c7e14 CONTRIBUTING.md: Point to frc-docs instead of screensteps (#1858)
d10a1a797 Fix eigen build in vcpkg (#1856)
2bdb44325 Add frc2 includes to list of "other lib" regexes (#1855)
4b2b21d24 Replace outdated Java collections (#508)
8993ce5bf Move Eigen headers out of main include folder (#1854)
0f532a117 Add PWMSparkMax (#1751)
f7ad363d8 Add jni cross compile options for aarch64 (#1853)
9afea3340 Add support for aarch64 jetson bionic builds (#1844)
d787b5d60 Add more items to .gitignore (#1850)
5dd0d1b7d Use units in SPI
07ac711b3 Fix units deprecated warning in IterativeRobot
decfd858b Correctly report -1 for POV on disconnected joystick (#1852)
076ed7770 Add new C++ Command framework (#1785)
a0be07c37 Refactor HAL handle move construction/assignment (#1845)
558c38308 Add new Java Command framework (#1682)
1379735af Delete RobotState and SensorUtil constructors (#1847)
e3d86fee4 Move circular buffer class from wpilib to wpiutil (#1840)
4cd8a5667 TimedRobot.cpp: Fix deprecation warning (#1846)
b2861f894 Use 2020 artifacts and artifactory server (#1838)
98cc32703 Update to use artifactory to publish artifacts (#1833)
fa0640300 Move drive integration tests into wpilibj/src/test (#1836)
e716c36b8 Fix Nat.java generation to be incremental (#1831)
9fd2b5e3f Fix MSVC builds on cmake windows in vcpkg (#1835)
7e95010a2 Add compile-time EJML matrix wrapper to wpiutil (#1804)
3ebc5a6d3 Add ProfiledPIDController
fc98a79db Clean up PIDController interface in preparation for ProfiledPIDController
fdc098267 Fix compilation error in elevator trapezoid profile example (#1826)
a3dd84e85 Make XBoxController Button enum public (#1823)
a216b9e9e Add TrapezoidProfile example (#1814)
8f386f6bb wpilibc: Add unit-safety to C++ geometry classes (#1811)
c07ac2353 wpilibc: Add overloads for units (#1815)
f1d71da8a Move GetStackTrace and Demangle to wpiutil, add Windows support (#1819)
ef037457e Make LinearFilter copyable and moveable (#1789)
76930250c Remove objective-cpp support (#1816)
1c246418f Move TrapezoidProfileTest to trajectory folder (#1812)
95a54a0f2 Add java arcade drive example (#1810)
a4530243e HAL sim: Fix incorrectly setting dio port to initialized on cleanup (#1813)
09d00a622 Update Java examples to use new PIDController (#1809)
ba9b51742 Add missing Java examples (#841)
6411bd79c InterruptableSensorBase: Fix callback function deletion (#1807)
810e58ea8 I2C: Add tip about writeBulk() to transaction() (#1806)
607d6c148 Fix wpilibj integration tests jar name (#1808)
c9873e81b Remove PIDControllerRunner and mutex from new PIDController (#1795)
98d0706de Fix cscore build with OpenCV 4 (#1803)
fbe67c90c Make Sendable setters synchronous (#1799)
c67a488a0 Format SendableBuilderImpl javadocs (#1802)
8e93ce892 Fix PIDControllerRunner member destruction order (#1801)
c98ca7310 Add EJML dependency to wpiutil (#1769)
3b12276bc SendableBase: remove unnecessary synchronization (#1797)
e6d348f38 Fix missing default name in Java PIDController (#1792)
df12fc2a8 Java cleanups (#1776)
39561751f Update GradleVSCode version (#1786)
37d316aa0 Add C++20 std::math constants shim (#1788)
dd4310959 Deprecate frc/WPILib.h (#1779)
823174f30 Update native utils to 2020.0.4 (#1783)
37c695266 Squelch -Wdeprecated-copy for Eigen with GCC >= 9
04c9b000f Revert "Fix build of Eigen 3.3.7 with GCC 9"
ca3e71e21 wpiutil: Fix Process::Spawn() (#1778)
d946d5a2b Fix Eigen compilation errors and add tests (#1777)
8b1b9ac75 Fix build of Eigen 3.3.7 with GCC 9
2f680ba99 Add Eigen linear algebra library
a885db7d4 Make MotorEncoderTest use LinearFilter (#1775)
ee2410169 Add geometry classes (#1766)
48fe54271 Add HALSIM_SetSendError implementation (#1773)
dff58c87f Fix unused warning in release build (#1771)
dde61aad3 Remove TimerEventHandler typedef from Notifier class (#1767)
0f6ef80ab Add RobotState#IsEStopped and DriverStation#IsEStopped (#952)
e48886187 Move unit tests from integration test suite (#1170)
dffa1a5cb Make null checks more descriptive (#1688)
fe59d854d Notifier: add null check (#1684)
10731f3d6 Update uv Udp wrapper for latest features
89f7b72b6 Update libuv to 1.30.1 release
85f2f8740 wpiutil: Add unique_function (#1761)
73ec94078 Remove SampleRobot (#1658)
62be0392b Replace std::lock_guard and std::lock with std::scoped_lock (#1758)
24d31df55 Make sure move constructor is generated for TrapezoidProfile (#1757)
841ef5d73 Remove template types from lock RAII wrapper usages (#1756)
e582518ba Fix some move constructors (#1754)
8757bc471 Remove pre-C++17 shims (#1752)
ea9512977 Add replacement PIDController class (#1300)
9b798d228 Add TrapezoidProfile class (#1673)
804926fb5 Unconditionally skip athena builds for sim (#1748)
118e9d29d Add C++14 units library (#1749)
c705953d7 Add usage reporting to LinearFilter (#1750)
852d1b9ca Don't cross-build gazebo for raspbian (#1747)
eedb3a1ad Fix GCC 9 warnings (#1730)
60dce66a4 Remove wpi::ArrayRef std::initializer_list constructor (#1745)
9e19b29c3 Use base azure image for primary wpilib build (#1744)
299425071 Update jni library, fix cross builds of the jni symbol check (#1742)
a6b0e9b85 Only disable execution of cross compile google tests (#1741)
3c2093119 Use docker container to run wpiformat (#1740)
5fe2eebce Revert "Don't build halsim_gazebo on raspbian (#1737)" (#1743)
4b1b92bb7 Replace wpi::optional with C++17 std::optional (#1732)
0fbb0d989 Update to 2020 compilers (#1733)
2dc94e605 Disable google tests on cross compilers (#1738)
d9cb57a42 Don't build halsim_gazebo on raspbian (#1737)
f7cfdd7ce Replace crlf line endings with lf (#1731)
b6d5d90d9 Add JaCoCo Support (#1734)
c7ab2baa6 Add way to disable the jni check tasks from a property (#1736)
0c45c5b7e Fix skip athena and skip raspbian flags (#1735)
3dfb01d45 Update to new Native Utils (#1696)
30e936837 Clean up LinearDigitalFilter class (#782)
311e2de4c Remove deprecated Joystick constants (#1715)
c08fd6682 Update CAN manufacturer list (#1706)
258bba0c2 ErrorBase and WPIError improvements (#1727)
372ca4f45 cmake: Enable googletest unit tests (#1720)
223d47af0 HALSIM: support mocking of HAL_SendError() (#1728)
55cb683db Change compiler flags to C++17 (#1723)
ee8a33c56 wpiutil: SafeThread: Add thread id, support getting shared_ptr (#1722)
61426d08d wpiutil: Signal: make operator() const (#1721)
b630b63ef Remove functions in LiveWindow deprecated since 2018 (#1716)
1d0c05d4f Styleguide fixes for #1718 (#1719)
f07569df1 Fix newer GCC/clang compiler warnings (#1718)
0120f3124 C++ SPI: Fix SetClockRate to take int (#1717)
c2829ed98 Configure gradle to ignore unresolved headers (#1711)
221e66f46 Allow disabling static init of JNI libraries (#1672)
738852e11 cmake: Add cross toolchain files for Rio and Pi (#1710)
27b697b08 Remove frc directory include shims (#1714)
9e45373a7 Remove functions and classes deprecated for 2018 season (#1059)
eeb1025ac SPI: Report port as instance for usage reporting (#1704)
bc6f1e246 Windows compiler options improvements (#1709)
bb48ae391 cmake: Move example programs into folders (#1654)
221011494 Update for C++17 and fix MSVC warnings (#1694)
fb1239a2a Add raw sources and sinks to cscore (#1670)
7de947734 Add lambda overloads for interrupts (#1636)
90957aeea Move libuv to its own subfolder in build (#1661)
47aae502a Styleguide fixes (#1702)
0bff98b5e Correct DifferentialDrive::ArcadeDrive param docs (#1698)
b52e40b80 Allow widgets to be added by passing value suppliers (#1690)
4a00cd77b Add usage reporting for the Shuffleboard API (#1685)
e25e515f2 Publish artifacts on azure (#1678)
322ef9b96 Force Java 11, fix javadoc generation (#1695)
d42ef5df0 Fix Watchdog print formatting (#1693)
f432f65be Update copyright year in license to 2019 (#1524)
1726b77ac wpiutil: uv: Remove copy from SimpleBufferPool (#1680)
620bec9ca wpiutil: uv: Add LoopClosing status to Handle (#1647)
7cd6e2e7f UsbCamera: Solve race in windows initialization (#1638)
7732836bd Completely disable watchdog tests on mac (#1679)
698edfda9 Remove framework load, disable mac timeout test (#1676)
1c454b000 Add Shuffleboard calls to IterativeRobotBase in C++ (#1607)
f42905b32 Include missing headers in HAL.h (#1660)
bdc822fad Only generate passthrough URLs for RoboRIO (#1624)
d3affb16b Make failure of HAL_GetFPGATime() more descriptive (#1633)
2de3bf7f5 Update LLVM from stable upstream (#1653)
3cf4f38f5 Fix build on macos10.14.4 (#1648)
4e0c10f48 Fix CAN Clean using wrong ID (#1668)
3b0631324 Fix Gray to BGR conversion in CameraServer (#1665)
6cd1c73ef Fix GUID comparison creating weird symbol (#1659)
063bbab6f MavenArtifacts.md: update links to HTTPS (#1674)
aab4c494d Fix type in build.gradle (#1604)
bf46af260 Disable extraneous data warnings in libjpeg (#1630)
655763a9a Limit length of message sent to DS SendError call (#1618)
a095ec2d8 Fix linker errors with free functions in Threads.h (#1625)
12ab035aa Fix receive side of LabVIEW USB streams (#1621)
Change-Id: Ibd382e1a48925c200850cf90a8121e35c0fcffe3
git-subtree-dir: third_party/allwpilib_2019
git-subtree-split: c36bbcc9a9095489fc078229db4fba3ecd0f9b78
diff --git a/cscore/CMakeLists.txt b/cscore/CMakeLists.txt
index 52bcb54..a87ab7d 100644
--- a/cscore/CMakeLists.txt
+++ b/cscore/CMakeLists.txt
@@ -1,6 +1,8 @@
project(cscore)
include(SubDirList)
+include(CompileWarnings)
+include(AddTest)
find_package( OpenCV REQUIRED )
@@ -21,14 +23,15 @@
endif()
else()
target_sources(cscore PRIVATE ${cscore_windows_src})
- target_compile_options(cscore PUBLIC -DNOMINMAX)
- target_compile_options(cscore PRIVATE -D_CRT_SECURE_NO_WARNINGS)
+ target_compile_definitions(cscore PUBLIC -DNOMINMAX)
+ target_compile_definitions(cscore PRIVATE -D_CRT_SECURE_NO_WARNINGS)
endif()
target_include_directories(cscore PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
$<INSTALL_INTERFACE:${include_dest}/cscore>)
target_include_directories(cscore PRIVATE src/main/native/cpp)
+wpilib_target_warnings(cscore)
target_link_libraries(cscore PUBLIC wpiutil ${OpenCV_LIBS})
set_property(TARGET cscore PROPERTY FOLDER "libraries")
@@ -36,13 +39,14 @@
install(TARGETS cscore EXPORT cscore DESTINATION "${main_lib_dest}")
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/cscore")
-if (MSVC)
+if (MSVC OR FLAT_INSTALL_WPILIB)
set (cscore_config_dir ${wpilib_dest})
else()
set (cscore_config_dir share/cscore)
endif()
-install(FILES cscore-config.cmake DESTINATION ${cscore_config_dir})
+configure_file(cscore-config.cmake.in ${CMAKE_BINARY_DIR}/cscore-config.cmake )
+install(FILES ${CMAKE_BINARY_DIR}/cscore-config.cmake DESTINATION ${cscore_config_dir})
install(EXPORT cscore DESTINATION ${cscore_config_dir})
SUBDIR_LIST(cscore_examples "${CMAKE_CURRENT_SOURCE_DIR}/examples")
@@ -50,7 +54,9 @@
file(GLOB cscore_example_src examples/${example}/*.cpp)
if(cscore_example_src)
add_executable(cscore_${example} ${cscore_example_src})
+ wpilib_target_warnings(cscore_${example})
target_link_libraries(cscore_${example} cscore)
+ set_property(TARGET cscore_${example} PROPERTY FOLDER "examples")
endif()
endforeach()
@@ -101,6 +107,7 @@
set_property(TARGET cscore_jar PROPERTY FOLDER "java")
add_library(cscorejni ${cscore_jni_src})
+ wpilib_target_warnings(cscorejni)
target_link_libraries(cscorejni PUBLIC cscore wpiutil ${OpenCV_LIBS})
set_property(TARGET cscorejni PROPERTY FOLDER "libraries")
@@ -120,3 +127,8 @@
install(TARGETS cscorejni EXPORT cscorejni DESTINATION "${main_lib_dest}")
endif()
+
+if (WITH_TESTS)
+ wpilib_add_test(cscore src/test/native/cpp)
+ target_link_libraries(cscore_test cscore gmock)
+endif()
diff --git a/cscore/build.gradle b/cscore/build.gradle
index 3162c88..4514b95 100644
--- a/cscore/build.gradle
+++ b/cscore/build.gradle
@@ -5,9 +5,13 @@
devMain = 'edu.wpi.cscore.DevMain'
}
-if (OperatingSystem.current().isMacOsX()) {
- apply plugin: 'objective-cpp'
-}
+// Removed because having the objective-cpp plugin added breaks
+// embedded tools and its toolchain check. It causes an obj-cpp
+// source set to be added to all binaries, even cross binaries
+// with no support.
+// if (OperatingSystem.current().isMacOsX()) {
+// apply plugin: 'objective-cpp'
+// }
apply from: "${rootDir}/shared/jni/setupBuild.gradle"
@@ -20,18 +24,18 @@
useJava = true
useCpp = true
splitSetup = {
- if (it.targetPlatform.operatingSystem.name == 'osx') {
+ if (it.targetPlatform.operatingSystem.isMacOsX()) {
it.sources {
- macObjCpp(ObjectiveCppSourceSet) {
- source {
- srcDirs = ['src/main/native/objcpp']
- include '**/*.mm'
- }
- exportedHeaders {
- srcDirs 'src/main/native/include'
- include '**/*.h'
- }
- }
+ // macObjCpp(ObjectiveCppSourceSet) {
+ // source {
+ // srcDirs = ['src/main/native/objcpp']
+ // include '**/*.mm'
+ // }
+ // exportedHeaders {
+ // srcDirs 'src/main/native/include'
+ // include '**/*.h'
+ // }
+ // }
cscoreMacCpp(CppSourceSet) {
source {
srcDirs 'src/main/native/osx'
@@ -43,7 +47,7 @@
}
}
}
- } else if (it.targetPlatform.operatingSystem.name == 'linux') {
+ } else if (it.targetPlatform.operatingSystem.isLinux()) {
it.sources {
cscoreLinuxCpp(CppSourceSet) {
source {
@@ -56,7 +60,7 @@
}
}
}
- } else if (it.targetPlatform.operatingSystem.name == 'windows') {
+ } else if (it.targetPlatform.operatingSystem.isWindows()) {
it.sources {
cscoreWindowsCpp(CppSourceSet) {
source {
@@ -88,43 +92,28 @@
apply from: "${rootDir}/shared/opencv.gradle"
-model {
- // Exports config is a utility to enable exporting all symbols in a C++ library on windows to a DLL.
- // This removes the need for DllExport on a library. However, the gradle C++ builder has a bug
- // where some extra symbols are added that cannot be resolved at link time. This configuration
- // lets you specify specific symbols to exlude from exporting.
- exportsConfigs {
- cscore(ExportsConfig) {
- x86ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
- '_CT??_R0?AVbad_cast',
- '_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
- '_TI5?AVfailure', '==']
- x64ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
- '_CT??_R0?AVbad_cast',
- '_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
- '_TI5?AVfailure', '==']
+nativeUtils.exportsConfigs {
+ cscore {
+ x86ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
+ '_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
+ '_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
+ '_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
+ x64ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
+ '_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
+ '_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
+ '_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
+ }
+ cscoreJNI {
+ x86SymbolFilter = { symbols ->
+ symbols.removeIf({ !it.startsWith('CS_') })
}
- cscoreJNI(ExportsConfig) {
- x86SymbolFilter = { symbols ->
- def retList = []
- symbols.each { symbol ->
- if (symbol.startsWith('CS_')) {
- retList << symbol
- }
- }
- return retList
- }
- x64SymbolFilter = { symbols ->
- def retList = []
- symbols.each { symbol ->
- if (symbol.startsWith('CS_')) {
- retList << symbol
- }
- }
- return retList
- }
+ x64SymbolFilter = { symbols ->
+ symbols.removeIf({ !it.startsWith('CS_') })
}
}
+}
+
+model {
components {
examplesMap.each { key, value ->
"${key}"(NativeExecutableSpec) {
diff --git a/cscore/cscore-config.cmake b/cscore/cscore-config.cmake
deleted file mode 100644
index 790633b..0000000
--- a/cscore/cscore-config.cmake
+++ /dev/null
@@ -1,6 +0,0 @@
-include(CMakeFindDependencyMacro)
-find_dependency(wpiutil)
-find_dependency(OpenCV)
-
-get_filename_component(SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-include(${SELF_DIR}/cscore.cmake)
diff --git a/cscore/cscore-config.cmake.in b/cscore/cscore-config.cmake.in
new file mode 100644
index 0000000..da85e8b
--- /dev/null
+++ b/cscore/cscore-config.cmake.in
@@ -0,0 +1,6 @@
+include(CMakeFindDependencyMacro)
+@FILENAME_DEP_REPLACE@
+@WPIUTIL_DEP_REPLACE@
+find_dependency(OpenCV)
+
+include(${SELF_DIR}/cscore.cmake)
diff --git a/cscore/examples/httpcvstream/httpcvstream.cpp b/cscore/examples/httpcvstream/httpcvstream.cpp
index db8e0d7..90d61d5 100644
--- a/cscore/examples/httpcvstream/httpcvstream.cpp
+++ b/cscore/examples/httpcvstream/httpcvstream.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -11,6 +11,7 @@
#include <opencv2/core/core.hpp>
#include "cscore.h"
+#include "cscore_cv.h"
int main() {
cs::HttpCamera camera{"httpcam", "http://localhost:8081/?action=stream"};
diff --git a/cscore/examples/usbcvstream/usbcvstream.cpp b/cscore/examples/usbcvstream/usbcvstream.cpp
index 68796b4..9a4ab06 100644
--- a/cscore/examples/usbcvstream/usbcvstream.cpp
+++ b/cscore/examples/usbcvstream/usbcvstream.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -11,6 +11,7 @@
#include <opencv2/core/core.hpp>
#include "cscore.h"
+#include "cscore_cv.h"
int main() {
cs::UsbCamera camera{"usbcam", 0};
diff --git a/cscore/java-examples/RawCVMatSink.java b/cscore/java-examples/RawCVMatSink.java
new file mode 100644
index 0000000..d9557f7
--- /dev/null
+++ b/cscore/java-examples/RawCVMatSink.java
@@ -0,0 +1,96 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.cscore;
+
+import java.nio.ByteBuffer;
+
+import org.opencv.core.CvType;
+import org.opencv.core.Mat;
+
+import edu.wpi.cscore.VideoMode.PixelFormat;
+import edu.wpi.cscore.raw.RawFrame;
+
+public class RawCVMatSink extends ImageSink {
+ RawFrame frame = new RawFrame();
+ Mat tmpMat;
+ ByteBuffer origByteBuffer;
+ int width;
+ int height;
+ int pixelFormat;
+ int bgrValue = PixelFormat.kBGR.getValue();
+
+ private int getCVFormat(PixelFormat pixelFormat) {
+ int type = 0;
+ switch (pixelFormat) {
+ case kYUYV:
+ case kRGB565:
+ type = CvType.CV_8UC2;
+ break;
+ case kBGR:
+ type = CvType.CV_8UC3;
+ break;
+ case kGray:
+ case kMJPEG:
+ default:
+ type = CvType.CV_8UC1;
+ break;
+ }
+ return type;
+ }
+
+ /**
+ * Create a sink for accepting OpenCV images.
+ * WaitForFrame() must be called on the created sink to get each new
+ * image.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ */
+ public RawCVMatSink(String name) {
+ super(CameraServerJNI.createRawSink(name));
+ }
+
+ /**
+ * Wait for the next frame and get the image.
+ * Times out (returning 0) after 0.225 seconds.
+ * The provided image will have three 3-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message)
+ */
+ public long grabFrame(Mat image) {
+ return grabFrame(image, 0.225);
+ }
+
+ /**
+ * Wait for the next frame and get the image.
+ * Times out (returning 0) after timeout seconds.
+ * The provided image will have three 3-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message); the frame time is in 1 us increments.
+ */
+ public long grabFrame(Mat image, double timeout) {
+ frame.setWidth(0);
+ frame.setHeight(0);
+ frame.setPixelFormat(bgrValue);
+ long rv = CameraServerJNI.grabSinkFrameTimeout(m_handle, frame, timeout);
+ if (rv <= 0) {
+ return rv;
+ }
+
+ if (frame.getDataByteBuffer() != origByteBuffer || width != frame.getWidth() || height != frame.getHeight() || pixelFormat != frame.getPixelFormat()) {
+ origByteBuffer = frame.getDataByteBuffer();
+ height = frame.getHeight();
+ width = frame.getWidth();
+ pixelFormat = frame.getPixelFormat();
+ tmpMat = new Mat(frame.getHeight(), frame.getWidth(), getCVFormat(VideoMode.getPixelFormatFromInt(pixelFormat)), origByteBuffer);
+ }
+ tmpMat.copyTo(image);
+ return rv;
+ }
+}
diff --git a/cscore/java-examples/RawCVMatSource.java b/cscore/java-examples/RawCVMatSource.java
new file mode 100644
index 0000000..65bd7d2
--- /dev/null
+++ b/cscore/java-examples/RawCVMatSource.java
@@ -0,0 +1,59 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.cscore;
+
+import org.opencv.core.Mat;
+
+import edu.wpi.cscore.VideoMode.PixelFormat;
+
+public class RawCVMatSource extends ImageSource {
+ /**
+ * Create an OpenCV source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param mode Video mode being generated
+ */
+ public RawCVMatSource(String name, VideoMode mode) {
+ super(CameraServerJNI.createRawSource(name,
+ mode.pixelFormat.getValue(),
+ mode.width,
+ mode.height,
+ mode.fps));
+ }
+
+ /**
+ * Create an OpenCV source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param pixelFormat Pixel format
+ * @param width width
+ * @param height height
+ * @param fps fps
+ */
+ public RawCVMatSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
+ super(CameraServerJNI.createRawSource(name, pixelFormat.getValue(), width, height, fps));
+ }
+
+ /**
+ * Put an OpenCV image and notify sinks.
+ *
+ * <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
+ * are supported. If the format, depth or channel order is different, use
+ * Mat.convertTo() and/or cvtColor() to convert it first.
+ *
+ * @param image OpenCV image
+ */
+ public void putFrame(Mat image) {
+ int channels = image.channels();
+ if (channels != 1 && channels != 3) {
+ throw new VideoException("Unsupported Image Type");
+ }
+ int imgType = channels == 1 ? PixelFormat.kGray.getValue() : PixelFormat.kBGR.getValue();
+ CameraServerJNI.putRawSourceFrame(m_handle, image.dataAddr(), image.width(), image.height(), imgType, (int)image.total() * channels);
+ }
+}
diff --git a/cscore/src/dev/java/edu/wpi/cscore/DevMain.java b/cscore/src/dev/java/edu/wpi/cscore/DevMain.java
index e7fd516..51bfd26 100644
--- a/cscore/src/dev/java/edu/wpi/cscore/DevMain.java
+++ b/cscore/src/dev/java/edu/wpi/cscore/DevMain.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/cscore/src/dev/native/cpp/main.cpp b/cscore/src/dev/native/cpp/main.cpp
index b95de47..f27f61f 100644
--- a/cscore/src/dev/native/cpp/main.cpp
+++ b/cscore/src/dev/native/cpp/main.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/cscore/src/main/java/edu/wpi/cscore/CameraServerCvJNI.java b/cscore/src/main/java/edu/wpi/cscore/CameraServerCvJNI.java
new file mode 100644
index 0000000..78b4ff8
--- /dev/null
+++ b/cscore/src/main/java/edu/wpi/cscore/CameraServerCvJNI.java
@@ -0,0 +1,72 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.cscore;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.opencv.core.Core;
+
+import edu.wpi.first.wpiutil.RuntimeLoader;
+
+public class CameraServerCvJNI {
+ static boolean libraryLoaded = false;
+
+ static RuntimeLoader<Core> loader = null;
+
+ public static class Helper {
+ private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true);
+
+ public static boolean getExtractOnStaticLoad() {
+ return extractOnStaticLoad.get();
+ }
+
+ public static void setExtractOnStaticLoad(boolean load) {
+ extractOnStaticLoad.set(load);
+ }
+ }
+
+ static {
+ String opencvName = Core.NATIVE_LIBRARY_NAME;
+ if (Helper.getExtractOnStaticLoad()) {
+ try {
+ CameraServerJNI.forceLoad();
+ loader = new RuntimeLoader<>(opencvName, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
+ loader.loadLibraryHashed();
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ System.exit(1);
+ }
+ libraryLoaded = true;
+ }
+ }
+
+ /**
+ * Force load the library.
+ */
+ public static synchronized void forceLoad() throws IOException {
+ if (libraryLoaded) {
+ return;
+ }
+ CameraServerJNI.forceLoad();
+ loader = new RuntimeLoader<>(Core.NATIVE_LIBRARY_NAME, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
+ loader.loadLibrary();
+ libraryLoaded = true;
+ }
+
+ public static native int createCvSource(String name, int pixelFormat, int width, int height, int fps);
+
+ public static native void putSourceFrame(int source, long imageNativeObj);
+
+ public static native int createCvSink(String name);
+ //public static native int createCvSinkCallback(String name,
+ // void (*processFrame)(long time));
+
+ public static native long grabSinkFrame(int sink, long imageNativeObj);
+ public static native long grabSinkFrameTimeout(int sink, long imageNativeObj, double timeout);
+}
diff --git a/cscore/src/main/java/edu/wpi/cscore/CameraServerJNI.java b/cscore/src/main/java/edu/wpi/cscore/CameraServerJNI.java
index cb6202d..ac18408 100644
--- a/cscore/src/main/java/edu/wpi/cscore/CameraServerJNI.java
+++ b/cscore/src/main/java/edu/wpi/cscore/CameraServerJNI.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -8,21 +8,32 @@
package edu.wpi.cscore;
import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
-import org.opencv.core.Core;
-
+import edu.wpi.cscore.raw.RawFrame;
import edu.wpi.first.wpiutil.RuntimeLoader;
public class CameraServerJNI {
static boolean libraryLoaded = false;
- static boolean cvLibraryLoaded = false;
static RuntimeLoader<CameraServerJNI> loader = null;
- static RuntimeLoader<Core> cvLoader = null;
+
+ public static class Helper {
+ private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true);
+
+ public static boolean getExtractOnStaticLoad() {
+ return extractOnStaticLoad.get();
+ }
+
+ public static void setExtractOnStaticLoad(boolean load) {
+ extractOnStaticLoad.set(load);
+ }
+ }
static {
- if (!libraryLoaded) {
+ if (Helper.getExtractOnStaticLoad()) {
try {
loader = new RuntimeLoader<>("cscorejni", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class);
loader.loadLibrary();
@@ -32,21 +43,19 @@
}
libraryLoaded = true;
}
-
- String opencvName = Core.NATIVE_LIBRARY_NAME;
- if (!cvLibraryLoaded) {
- try {
- cvLoader = new RuntimeLoader<>(opencvName, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
- cvLoader.loadLibraryHashed();
- } catch (IOException ex) {
- ex.printStackTrace();
- System.exit(1);
- }
- cvLibraryLoaded = true;
- }
}
- public static void forceLoad() {}
+ /**
+ * Force load the library.
+ */
+ public static synchronized void forceLoad() throws IOException {
+ if (libraryLoaded) {
+ return;
+ }
+ loader = new RuntimeLoader<>("cscorejni", RuntimeLoader.getDefaultExtractionRoot(), CameraServerJNI.class);
+ loader.loadLibrary();
+ libraryLoaded = true;
+ }
//
// Property Functions
@@ -70,7 +79,7 @@
public static native int createUsbCameraPath(String name, String path);
public static native int createHttpCamera(String name, String url, int kind);
public static native int createHttpCameraMulti(String name, String[] urls, int kind);
- public static native int createCvSource(String name, int pixelFormat, int width, int height, int fps);
+ public static native int createRawSource(String name, int pixelFormat, int width, int height, int fps);
//
// Source Functions
@@ -122,9 +131,13 @@
public static native String[] getHttpCameraUrls(int source);
//
- // OpenCV Source Functions
+ // Image Source Functions
//
- public static native void putSourceFrame(int source, long imageNativeObj);
+ public static native void putRawSourceFrameBB(int source, ByteBuffer data, int width, int height, int pixelFormat, int totalData);
+ public static native void putRawSourceFrame(int source, long data, int width, int height, int pixelFormat, int totalData);
+ public static void putRawSourceFrame(int source, RawFrame raw) {
+ putRawSourceFrame(source, raw.getDataPtr(), raw.getWidth(), raw.getHeight(), raw.getPixelFormat(), raw.getTotalData());
+ }
public static native void notifySourceError(int source, String msg);
public static native void setSourceConnected(int source, boolean connected);
public static native void setSourceDescription(int source, String description);
@@ -135,9 +148,8 @@
// Sink Creation Functions
//
public static native int createMjpegServer(String name, String listenAddress, int port);
- public static native int createCvSink(String name);
- //public static native int createCvSinkCallback(String name,
- // void (*processFrame)(long time));
+
+ public static native int createRawSink(String name);
//
// Sink Functions
@@ -162,11 +174,19 @@
public static native int getMjpegServerPort(int sink);
//
- // OpenCV Sink Functions
+ // Image Sink Functions
//
public static native void setSinkDescription(int sink, String description);
- public static native long grabSinkFrame(int sink, long imageNativeObj);
- public static native long grabSinkFrameTimeout(int sink, long imageNativeObj, double timeout);
+
+ private static native long grabRawSinkFrameImpl(int sink, RawFrame rawFrame, long rawFramePtr, ByteBuffer byteBuffer, int width, int height, int pixelFormat);
+ private static native long grabRawSinkFrameTimeoutImpl(int sink, RawFrame rawFrame, long rawFramePtr, ByteBuffer byteBuffer, int width, int height, int pixelFormat, double timeout);
+
+ public static long grabSinkFrame(int sink, RawFrame rawFrame) {
+ return grabRawSinkFrameImpl(sink, rawFrame, rawFrame.getFramePtr(), rawFrame.getDataByteBuffer(), rawFrame.getWidth(), rawFrame.getHeight(), rawFrame.getPixelFormat());
+ }
+ public static long grabSinkFrameTimeout(int sink, RawFrame rawFrame, double timeout) {
+ return grabRawSinkFrameTimeoutImpl(sink, rawFrame, rawFrame.getFramePtr(), rawFrame.getDataByteBuffer(), rawFrame.getWidth(), rawFrame.getHeight(), rawFrame.getPixelFormat(), timeout);
+ }
public static native String getSinkError(int sink);
public static native void setSinkEnabled(int sink, boolean enabled);
@@ -228,4 +248,8 @@
public static native String getHostname();
public static native String[] getNetworkInterfaces();
+
+ public static native long allocateRawFrame();
+
+ public static native void freeRawFrame(long frame);
}
diff --git a/cscore/src/main/java/edu/wpi/cscore/CvSink.java b/cscore/src/main/java/edu/wpi/cscore/CvSink.java
index c2c7d0e..f12dcc7 100644
--- a/cscore/src/main/java/edu/wpi/cscore/CvSink.java
+++ b/cscore/src/main/java/edu/wpi/cscore/CvSink.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -11,8 +11,11 @@
/**
* A sink for user code to accept video frames as OpenCV images.
+ * These sinks require the WPILib OpenCV builds.
+ * For an alternate OpenCV, see the documentation how to build your own
+ * with RawSink.
*/
-public class CvSink extends VideoSink {
+public class CvSink extends ImageSink {
/**
* Create a sink for accepting OpenCV images.
* WaitForFrame() must be called on the created sink to get each new
@@ -21,7 +24,7 @@
* @param name Source name (arbitrary unique identifier)
*/
public CvSink(String name) {
- super(CameraServerJNI.createCvSink(name));
+ super(CameraServerCvJNI.createCvSink(name));
}
/// Create a sink for accepting OpenCV images in a separate thread.
@@ -38,15 +41,6 @@
//}
/**
- * Set sink description.
- *
- * @param description Description
- */
- public void setDescription(String description) {
- CameraServerJNI.setSinkDescription(m_handle, description);
- }
-
- /**
* Wait for the next frame and get the image.
* Times out (returning 0) after 0.225 seconds.
* The provided image will have three 3-bit channels stored in BGR order.
@@ -67,7 +61,7 @@
* message); the frame time is in 1 us increments.
*/
public long grabFrame(Mat image, double timeout) {
- return CameraServerJNI.grabSinkFrameTimeout(m_handle, image.nativeObj, timeout);
+ return CameraServerCvJNI.grabSinkFrameTimeout(m_handle, image.nativeObj, timeout);
}
/**
@@ -78,24 +72,6 @@
* message); the frame time is in 1 us increments.
*/
public long grabFrameNoTimeout(Mat image) {
- return CameraServerJNI.grabSinkFrame(m_handle, image.nativeObj);
- }
-
- /**
- * Get error string. Call this if WaitForFrame() returns 0 to determine
- * what the error is.
- */
- public String getError() {
- return CameraServerJNI.getSinkError(m_handle);
- }
-
- /**
- * Enable or disable getting new frames.
- * Disabling will cause processFrame (for callback-based CvSinks) to not
- * be called and WaitForFrame() to not return. This can be used to save
- * processor resources when frames are not needed.
- */
- public void setEnabled(boolean enabled) {
- CameraServerJNI.setSinkEnabled(m_handle, enabled);
+ return CameraServerCvJNI.grabSinkFrame(m_handle, image.nativeObj);
}
}
diff --git a/cscore/src/main/java/edu/wpi/cscore/CvSource.java b/cscore/src/main/java/edu/wpi/cscore/CvSource.java
index 47cd409..c04d197 100644
--- a/cscore/src/main/java/edu/wpi/cscore/CvSource.java
+++ b/cscore/src/main/java/edu/wpi/cscore/CvSource.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -11,8 +11,11 @@
/**
* A source that represents a video camera.
+ * These sources require the WPILib OpenCV builds.
+ * For an alternate OpenCV, see the documentation how to build your own
+ * with RawSource.
*/
-public class CvSource extends VideoSource {
+public class CvSource extends ImageSource {
/**
* Create an OpenCV source.
*
@@ -20,7 +23,7 @@
* @param mode Video mode being generated
*/
public CvSource(String name, VideoMode mode) {
- super(CameraServerJNI.createCvSource(name,
+ super(CameraServerCvJNI.createCvSource(name,
mode.pixelFormat.getValue(),
mode.width,
mode.height,
@@ -37,7 +40,7 @@
* @param fps fps
*/
public CvSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
- super(CameraServerJNI.createCvSource(name, pixelFormat.getValue(), width, height, fps));
+ super(CameraServerCvJNI.createCvSource(name, pixelFormat.getValue(), width, height, fps));
}
/**
@@ -50,154 +53,7 @@
* @param image OpenCV image
*/
public void putFrame(Mat image) {
- CameraServerJNI.putSourceFrame(m_handle, image.nativeObj);
+ CameraServerCvJNI.putSourceFrame(m_handle, image.nativeObj);
}
- /**
- * Signal sinks that an error has occurred. This should be called instead
- * of NotifyFrame when an error occurs.
- */
- public void notifyError(String msg) {
- CameraServerJNI.notifySourceError(m_handle, msg);
- }
-
- /**
- * Set source connection status. Defaults to true.
- *
- * @param connected True for connected, false for disconnected
- */
- public void setConnected(boolean connected) {
- CameraServerJNI.setSourceConnected(m_handle, connected);
- }
-
- /**
- * Set source description.
- *
- * @param description Description
- */
- public void setDescription(String description) {
- CameraServerJNI.setSourceDescription(m_handle, description);
- }
-
- /**
- * Create a property.
- *
- * @param name Property name
- * @param kind Property kind
- * @param minimum Minimum value
- * @param maximum Maximum value
- * @param step Step value
- * @param defaultValue Default value
- * @param value Current value
- * @return Property
- */
- public VideoProperty createProperty(String name,
- VideoProperty.Kind kind,
- int minimum,
- int maximum,
- int step,
- int defaultValue,
- int value) {
- return new VideoProperty(
- CameraServerJNI.createSourceProperty(m_handle,
- name,
- kind.getValue(),
- minimum,
- maximum,
- step,
- defaultValue,
- value));
- }
-
- /**
- * Create an integer property.
- *
- * @param name Property name
- * @param minimum Minimum value
- * @param maximum Maximum value
- * @param step Step value
- * @param defaultValue Default value
- * @param value Current value
- * @return Property
- */
- public VideoProperty createIntegerProperty(String name,
- int minimum,
- int maximum,
- int step,
- int defaultValue,
- int value) {
- return new VideoProperty(
- CameraServerJNI.createSourceProperty(m_handle,
- name,
- VideoProperty.Kind.kInteger.getValue(),
- minimum,
- maximum,
- step,
- defaultValue,
- value));
- }
-
- /**
- * Create a boolean property.
- *
- * @param name Property name
- * @param defaultValue Default value
- * @param value Current value
- * @return Property
- */
- public VideoProperty createBooleanProperty(String name, boolean defaultValue, boolean value) {
- return new VideoProperty(
- CameraServerJNI.createSourceProperty(m_handle,
- name,
- VideoProperty.Kind.kBoolean.getValue(),
- 0,
- 1,
- 1,
- defaultValue ? 1 : 0,
- value ? 1 : 0));
- }
-
- /**
- * Create a string property.
- *
- * @param name Property name
- * @param value Current value
- * @return Property
- */
- public VideoProperty createStringProperty(String name, String value) {
- VideoProperty prop = new VideoProperty(
- CameraServerJNI.createSourceProperty(m_handle,
- name,
- VideoProperty.Kind.kString.getValue(),
- 0,
- 0,
- 0,
- 0,
- 0));
- prop.setString(value);
- return prop;
- }
-
- /**
- * Configure enum property choices.
- *
- * @param property Property
- * @param choices Choices
- */
- public void setEnumPropertyChoices(VideoProperty property, String[] choices) {
- CameraServerJNI.setSourceEnumPropertyChoices(m_handle, property.m_handle, choices);
- }
-
- /**
- * Configure enum property choices.
- *
- * @param property Property
- * @param choices Choices
- * @deprecated Use {@code setEnumPropertyChoices} instead.
- */
- @Deprecated
- @SuppressWarnings("MethodName")
- public void SetEnumPropertyChoices(VideoProperty property, String[] choices) {
- setEnumPropertyChoices(property, choices);
- }
}
diff --git a/cscore/src/main/java/edu/wpi/cscore/ImageSink.java b/cscore/src/main/java/edu/wpi/cscore/ImageSink.java
new file mode 100644
index 0000000..f755fb6
--- /dev/null
+++ b/cscore/src/main/java/edu/wpi/cscore/ImageSink.java
@@ -0,0 +1,41 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.cscore;
+
+public abstract class ImageSink extends VideoSink {
+ protected ImageSink(int handle) {
+ super(handle);
+ }
+
+ /**
+ * Set sink description.
+ *
+ * @param description Description
+ */
+ public void setDescription(String description) {
+ CameraServerJNI.setSinkDescription(m_handle, description);
+ }
+
+ /**
+ * Get error string. Call this if WaitForFrame() returns 0 to determine
+ * what the error is.
+ */
+ public String getError() {
+ return CameraServerJNI.getSinkError(m_handle);
+ }
+
+ /**
+ * Enable or disable getting new frames.
+ * Disabling will cause processFrame (for callback-based CvSinks) to not
+ * be called and WaitForFrame() to not return. This can be used to save
+ * processor resources when frames are not needed.
+ */
+ public void setEnabled(boolean enabled) {
+ CameraServerJNI.setSinkEnabled(m_handle, enabled);
+ }
+}
diff --git a/cscore/src/main/java/edu/wpi/cscore/ImageSource.java b/cscore/src/main/java/edu/wpi/cscore/ImageSource.java
new file mode 100644
index 0000000..3787516
--- /dev/null
+++ b/cscore/src/main/java/edu/wpi/cscore/ImageSource.java
@@ -0,0 +1,162 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.cscore;
+
+public abstract class ImageSource extends VideoSource {
+ protected ImageSource(int handle) {
+ super(handle);
+ }
+
+ /**
+ * Signal sinks that an error has occurred. This should be called instead
+ * of NotifyFrame when an error occurs.
+ */
+ public void notifyError(String msg) {
+ CameraServerJNI.notifySourceError(m_handle, msg);
+ }
+
+ /**
+ * Set source connection status. Defaults to true.
+ *
+ * @param connected True for connected, false for disconnected
+ */
+ public void setConnected(boolean connected) {
+ CameraServerJNI.setSourceConnected(m_handle, connected);
+ }
+
+ /**
+ * Set source description.
+ *
+ * @param description Description
+ */
+ public void setDescription(String description) {
+ CameraServerJNI.setSourceDescription(m_handle, description);
+ }
+
+ /**
+ * Create a property.
+ *
+ * @param name Property name
+ * @param kind Property kind
+ * @param minimum Minimum value
+ * @param maximum Maximum value
+ * @param step Step value
+ * @param defaultValue Default value
+ * @param value Current value
+ * @return Property
+ */
+ public VideoProperty createProperty(String name,
+ VideoProperty.Kind kind,
+ int minimum,
+ int maximum,
+ int step,
+ int defaultValue,
+ int value) {
+ return new VideoProperty(
+ CameraServerJNI.createSourceProperty(m_handle,
+ name,
+ kind.getValue(),
+ minimum,
+ maximum,
+ step,
+ defaultValue,
+ value));
+ }
+
+ /**
+ * Create an integer property.
+ *
+ * @param name Property name
+ * @param minimum Minimum value
+ * @param maximum Maximum value
+ * @param step Step value
+ * @param defaultValue Default value
+ * @param value Current value
+ * @return Property
+ */
+ public VideoProperty createIntegerProperty(String name,
+ int minimum,
+ int maximum,
+ int step,
+ int defaultValue,
+ int value) {
+ return new VideoProperty(
+ CameraServerJNI.createSourceProperty(m_handle,
+ name,
+ VideoProperty.Kind.kInteger.getValue(),
+ minimum,
+ maximum,
+ step,
+ defaultValue,
+ value));
+ }
+
+ /**
+ * Create a boolean property.
+ *
+ * @param name Property name
+ * @param defaultValue Default value
+ * @param value Current value
+ * @return Property
+ */
+ public VideoProperty createBooleanProperty(String name, boolean defaultValue, boolean value) {
+ return new VideoProperty(
+ CameraServerJNI.createSourceProperty(m_handle,
+ name,
+ VideoProperty.Kind.kBoolean.getValue(),
+ 0,
+ 1,
+ 1,
+ defaultValue ? 1 : 0,
+ value ? 1 : 0));
+ }
+
+ /**
+ * Create a string property.
+ *
+ * @param name Property name
+ * @param value Current value
+ * @return Property
+ */
+ public VideoProperty createStringProperty(String name, String value) {
+ VideoProperty prop = new VideoProperty(
+ CameraServerJNI.createSourceProperty(m_handle,
+ name,
+ VideoProperty.Kind.kString.getValue(),
+ 0,
+ 0,
+ 0,
+ 0,
+ 0));
+ prop.setString(value);
+ return prop;
+ }
+
+ /**
+ * Configure enum property choices.
+ *
+ * @param property Property
+ * @param choices Choices
+ */
+ public void setEnumPropertyChoices(VideoProperty property, String[] choices) {
+ CameraServerJNI.setSourceEnumPropertyChoices(m_handle, property.m_handle, choices);
+ }
+
+ /**
+ * Configure enum property choices.
+ *
+ * @param property Property
+ * @param choices Choices
+ * @deprecated Use {@code setEnumPropertyChoices} instead.
+ */
+ @Deprecated
+ @SuppressWarnings("MethodName")
+ public void SetEnumPropertyChoices(VideoProperty property, String[] choices) {
+ setEnumPropertyChoices(property, choices);
+ }
+}
diff --git a/cscore/src/main/java/edu/wpi/cscore/MjpegServer.java b/cscore/src/main/java/edu/wpi/cscore/MjpegServer.java
index fbbddf8..4c00aed 100644
--- a/cscore/src/main/java/edu/wpi/cscore/MjpegServer.java
+++ b/cscore/src/main/java/edu/wpi/cscore/MjpegServer.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/cscore/src/main/java/edu/wpi/cscore/UsbCameraInfo.java b/cscore/src/main/java/edu/wpi/cscore/UsbCameraInfo.java
index 42ef466..c3a8309 100644
--- a/cscore/src/main/java/edu/wpi/cscore/UsbCameraInfo.java
+++ b/cscore/src/main/java/edu/wpi/cscore/UsbCameraInfo.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -18,13 +18,18 @@
* @param path Path to device if available (e.g. '/dev/video0' on Linux)
* @param name Vendor/model name of the camera as provided by the USB driver
* @param otherPaths Other path aliases to device
+ * @param vendorId USB vendor id
+ * @param productId USB product id
*/
@SuppressWarnings("PMD.ArrayIsStoredDirectly")
- public UsbCameraInfo(int dev, String path, String name, String[] otherPaths) {
+ public UsbCameraInfo(int dev, String path, String name, String[] otherPaths, int vendorId,
+ int productId) {
this.dev = dev;
this.path = path;
this.name = name;
this.otherPaths = otherPaths;
+ this.vendorId = vendorId;
+ this.productId = productId;
}
/**
@@ -50,4 +55,16 @@
*/
@SuppressWarnings("MemberName")
public String[] otherPaths;
+
+ /**
+ * USB vendor id.
+ */
+ @SuppressWarnings("MemberName")
+ public int vendorId;
+
+ /**
+ * USB product id.
+ */
+ @SuppressWarnings("MemberName")
+ public int productId;
}
diff --git a/cscore/src/main/java/edu/wpi/cscore/VideoListener.java b/cscore/src/main/java/edu/wpi/cscore/VideoListener.java
index 8dd62fa..2a35505 100644
--- a/cscore/src/main/java/edu/wpi/cscore/VideoListener.java
+++ b/cscore/src/main/java/edu/wpi/cscore/VideoListener.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -27,11 +27,6 @@
m_handle = CameraServerJNI.addListener(listener, eventMask, immediateNotify);
}
- @Deprecated
- public void free() {
- close();
- }
-
@Override
public synchronized void close() {
if (m_handle != 0) {
diff --git a/cscore/src/main/java/edu/wpi/cscore/VideoSink.java b/cscore/src/main/java/edu/wpi/cscore/VideoSink.java
index a59a952..107f6d9 100644
--- a/cscore/src/main/java/edu/wpi/cscore/VideoSink.java
+++ b/cscore/src/main/java/edu/wpi/cscore/VideoSink.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -14,7 +14,7 @@
*/
public class VideoSink implements AutoCloseable {
public enum Kind {
- kUnknown(0), kMjpeg(2), kCv(4);
+ kUnknown(0), kMjpeg(2), kCv(4), kRaw(8);
@SuppressWarnings("MemberName")
private final int value;
@@ -46,11 +46,6 @@
m_handle = handle;
}
- @Deprecated
- public void free() {
- close();
- }
-
@Override
public synchronized void close() {
if (m_handle != 0) {
@@ -186,7 +181,7 @@
* @return Connected source; nullptr if no source connected.
*/
public VideoSource getSource() {
- // While VideoSource.free() will call releaseSource(), getSinkSource()
+ // While VideoSource.close() will call releaseSource(), getSinkSource()
// increments the internal reference count so this is okay to do.
return new VideoSource(CameraServerJNI.getSinkSource(m_handle));
}
diff --git a/cscore/src/main/java/edu/wpi/cscore/VideoSource.java b/cscore/src/main/java/edu/wpi/cscore/VideoSource.java
index cac344c..51d3821 100644
--- a/cscore/src/main/java/edu/wpi/cscore/VideoSource.java
+++ b/cscore/src/main/java/edu/wpi/cscore/VideoSource.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -14,7 +14,7 @@
*/
public class VideoSource implements AutoCloseable {
public enum Kind {
- kUnknown(0), kUsb(1), kHttp(2), kCv(4);
+ kUnknown(0), kUsb(1), kHttp(2), kCv(4), kRaw(8);
@SuppressWarnings("MemberName")
private final int value;
@@ -81,11 +81,6 @@
m_handle = handle;
}
- @Deprecated
- public void free() {
- close();
- }
-
@Override
public synchronized void close() {
if (m_handle != 0) {
diff --git a/cscore/src/main/java/edu/wpi/cscore/raw/RawFrame.java b/cscore/src/main/java/edu/wpi/cscore/raw/RawFrame.java
new file mode 100644
index 0000000..0e7a9ce
--- /dev/null
+++ b/cscore/src/main/java/edu/wpi/cscore/raw/RawFrame.java
@@ -0,0 +1,130 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.cscore.raw;
+
+import java.nio.ByteBuffer;
+
+import edu.wpi.cscore.CameraServerJNI;
+
+/**
+ * Class for storing raw frame data between image read call.
+ *
+ * <p>Data is reused for each frame read, rather then reallocating every frame.
+ */
+public class RawFrame implements AutoCloseable {
+ private final long m_framePtr;
+ private ByteBuffer m_dataByteBuffer;
+ private long m_dataPtr;
+ private int m_totalData;
+ private int m_width;
+ private int m_height;
+ private int m_pixelFormat;
+
+ /**
+ * Construct a new RawFrame.
+ */
+ public RawFrame() {
+ m_framePtr = CameraServerJNI.allocateRawFrame();
+ }
+
+ /**
+ * Close the RawFrame, releasing native resources.
+ * Any images currently using the data will be invalidated.
+ */
+ @Override
+ public void close() {
+ CameraServerJNI.freeRawFrame(m_framePtr);
+ }
+
+ /**
+ * Called from JNI to set data in class.
+ */
+ public void setData(ByteBuffer dataByteBuffer, long dataPtr, int totalData,
+ int width, int height, int pixelFormat) {
+ m_dataByteBuffer = dataByteBuffer;
+ m_dataPtr = dataPtr;
+ m_totalData = totalData;
+ m_width = width;
+ m_height = height;
+ m_pixelFormat = pixelFormat;
+ }
+
+ /**
+ * Get the pointer to native representation of this frame.
+ */
+ public long getFramePtr() {
+ return m_framePtr;
+ }
+
+ /**
+ * Get a ByteBuffer pointing to the frame data.
+ * This ByteBuffer is backed by the frame directly. Its lifetime is controlled by
+ * the frame. If a new frame gets read, it will overwrite the current one.
+ */
+ public ByteBuffer getDataByteBuffer() {
+ return m_dataByteBuffer;
+ }
+
+ /**
+ * Get a long (is a char* in native code) pointing to the frame data.
+ * This pointer is backed by the frame directly. Its lifetime is controlled by
+ * the frame. If a new frame gets read, it will overwrite the current one.
+ */
+ public long getDataPtr() {
+ return m_dataPtr;
+ }
+
+ /**
+ * Get the total length of the data stored in the frame.
+ */
+ public int getTotalData() {
+ return m_totalData;
+ }
+
+ /**
+ * Get the width of the frame.
+ */
+ public int getWidth() {
+ return m_width;
+ }
+
+ /**
+ * Set the width of the frame.
+ */
+ public void setWidth(int width) {
+ this.m_width = width;
+ }
+
+ /**
+ * Get the height of the frame.
+ */
+ public int getHeight() {
+ return m_height;
+ }
+
+ /**
+ * Set the height of the frame.
+ */
+ public void setHeight(int height) {
+ this.m_height = height;
+ }
+
+ /**
+ * Get the PixelFormat of the frame.
+ */
+ public int getPixelFormat() {
+ return m_pixelFormat;
+ }
+
+ /**
+ * Set the PixelFormat of the frame.
+ */
+ public void setPixelFormat(int pixelFormat) {
+ this.m_pixelFormat = pixelFormat;
+ }
+}
diff --git a/cscore/src/main/java/edu/wpi/cscore/raw/RawSink.java b/cscore/src/main/java/edu/wpi/cscore/raw/RawSink.java
new file mode 100644
index 0000000..535f356
--- /dev/null
+++ b/cscore/src/main/java/edu/wpi/cscore/raw/RawSink.java
@@ -0,0 +1,68 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.cscore.raw;
+
+import edu.wpi.cscore.CameraServerJNI;
+import edu.wpi.cscore.ImageSink;
+
+/**
+ * A sink for user code to accept video frames as raw bytes.
+ *
+ * <p>This is a complex API, most cases should use CvSink.
+ */
+public class RawSink extends ImageSink {
+ /**
+ * Create a sink for accepting raw images.
+ *
+ * <p>grabFrame() must be called on the created sink to get each new
+ * image.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ */
+ public RawSink(String name) {
+ super(CameraServerJNI.createRawSink(name));
+ }
+
+ /**
+ * Wait for the next frame and get the image.
+ * Times out (returning 0) after 0.225 seconds.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call getError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ protected long grabFrame(RawFrame frame) {
+ return grabFrame(frame, 0.225);
+ }
+
+ /**
+ * Wait for the next frame and get the image.
+ * Times out (returning 0) after timeout seconds.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call getError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ protected long grabFrame(RawFrame frame, double timeout) {
+ return CameraServerJNI.grabSinkFrameTimeout(m_handle, frame, timeout);
+ }
+
+ /**
+ * Wait for the next frame and get the image. May block forever.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call getError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ protected long grabFrameNoTimeout(RawFrame frame) {
+ return CameraServerJNI.grabSinkFrame(m_handle, frame);
+ }
+}
diff --git a/cscore/src/main/java/edu/wpi/cscore/raw/RawSource.java b/cscore/src/main/java/edu/wpi/cscore/raw/RawSource.java
new file mode 100644
index 0000000..9dfb3f3
--- /dev/null
+++ b/cscore/src/main/java/edu/wpi/cscore/raw/RawSource.java
@@ -0,0 +1,85 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+package edu.wpi.cscore.raw;
+
+import edu.wpi.cscore.CameraServerJNI;
+import edu.wpi.cscore.ImageSource;
+import edu.wpi.cscore.VideoMode;
+
+/**
+ * A source for user code to provide video frames as raw bytes.
+ *
+ * <p>This is a complex API, most cases should use CvSource.
+ */
+public class RawSource extends ImageSource {
+ /**
+ * Create a raw frame source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param mode Video mode being generated
+ */
+ public RawSource(String name, VideoMode mode) {
+ super(CameraServerJNI.createRawSource(name,
+ mode.pixelFormat.getValue(),
+ mode.width, mode.height,
+ mode.fps));
+ }
+
+ /**
+ * Create a raw frame source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param pixelFormat Pixel format
+ * @param width width
+ * @param height height
+ * @param fps fps
+ */
+ public RawSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
+ super(CameraServerJNI.createRawSource(name,
+ pixelFormat.getValue(),
+ width, height,
+ fps));
+ }
+
+ /**
+ * Put a raw image and notify sinks.
+ *
+ * @param image raw frame image
+ */
+ protected void putFrame(RawFrame image) {
+ CameraServerJNI.putRawSourceFrame(m_handle, image);
+ }
+
+ /**
+ * Put a raw image and notify sinks.
+ *
+ * @param data raw frame data pointer
+ * @param width frame width
+ * @param height frame height
+ * @param pixelFormat pixel format
+ * @param totalData length of data in total
+ */
+ protected void putFrame(long data, int width, int height, int pixelFormat, int totalData) {
+ CameraServerJNI.putRawSourceFrame(m_handle, data, width, height, pixelFormat, totalData);
+ }
+
+ /**
+ * Put a raw image and notify sinks.
+ *
+ * @param data raw frame data pointer
+ * @param width frame width
+ * @param height frame height
+ * @param pixelFormat pixel format
+ * @param totalData length of data in total
+ */
+ protected void putFrame(long data, int width, int height, VideoMode.PixelFormat pixelFormat,
+ int totalData) {
+ CameraServerJNI.putRawSourceFrame(m_handle, data, width, height, pixelFormat.getValue(),
+ totalData);
+ }
+}
diff --git a/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp b/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp
new file mode 100644
index 0000000..b974169
--- /dev/null
+++ b/cscore/src/main/native/cpp/ConfigurableSourceImpl.cpp
@@ -0,0 +1,109 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#include "ConfigurableSourceImpl.h"
+
+#include <wpi/timestamp.h>
+
+#include "Handle.h"
+#include "Instance.h"
+#include "Log.h"
+#include "Notifier.h"
+
+using namespace cs;
+
+ConfigurableSourceImpl::ConfigurableSourceImpl(const wpi::Twine& name,
+ wpi::Logger& logger,
+ Notifier& notifier,
+ Telemetry& telemetry,
+ const VideoMode& mode)
+ : SourceImpl{name, logger, notifier, telemetry} {
+ m_mode = mode;
+ m_videoModes.push_back(m_mode);
+}
+
+ConfigurableSourceImpl::~ConfigurableSourceImpl() {}
+
+void ConfigurableSourceImpl::Start() {
+ m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);
+ m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
+ m_notifier.NotifySourceVideoMode(*this, m_mode);
+}
+
+bool ConfigurableSourceImpl::SetVideoMode(const VideoMode& mode,
+ CS_Status* status) {
+ {
+ std::scoped_lock lock(m_mutex);
+ m_mode = mode;
+ m_videoModes[0] = mode;
+ }
+ m_notifier.NotifySourceVideoMode(*this, mode);
+ return true;
+}
+
+void ConfigurableSourceImpl::NumSinksChanged() {
+ // ignore
+}
+
+void ConfigurableSourceImpl::NumSinksEnabledChanged() {
+ // ignore
+}
+
+void ConfigurableSourceImpl::NotifyError(const wpi::Twine& msg) {
+ PutError(msg, wpi::Now());
+}
+
+int ConfigurableSourceImpl::CreateProperty(const wpi::Twine& name,
+ CS_PropertyKind kind, int minimum,
+ int maximum, int step,
+ int defaultValue, int value) {
+ std::scoped_lock lock(m_mutex);
+ int ndx = CreateOrUpdateProperty(name,
+ [=] {
+ return std::make_unique<PropertyImpl>(
+ name, kind, minimum, maximum, step,
+ defaultValue, value);
+ },
+ [&](PropertyImpl& prop) {
+ // update all but value
+ prop.propKind = kind;
+ prop.minimum = minimum;
+ prop.maximum = maximum;
+ prop.step = step;
+ prop.defaultValue = defaultValue;
+ value = prop.value;
+ });
+ m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name, ndx,
+ kind, value, wpi::Twine{});
+ return ndx;
+}
+
+int ConfigurableSourceImpl::CreateProperty(
+ const wpi::Twine& name, CS_PropertyKind kind, int minimum, int maximum,
+ int step, int defaultValue, int value,
+ std::function<void(CS_Property property)> onChange) {
+ // TODO
+ return 0;
+}
+
+void ConfigurableSourceImpl::SetEnumPropertyChoices(
+ int property, wpi::ArrayRef<std::string> choices, CS_Status* status) {
+ std::scoped_lock lock(m_mutex);
+ auto prop = GetProperty(property);
+ if (!prop) {
+ *status = CS_INVALID_PROPERTY;
+ return;
+ }
+ if (prop->propKind != CS_PROP_ENUM) {
+ *status = CS_WRONG_PROPERTY_TYPE;
+ return;
+ }
+ prop->enumChoices = choices;
+ m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
+ prop->name, property, CS_PROP_ENUM,
+ prop->value, wpi::Twine{});
+}
diff --git a/cscore/src/main/native/cpp/ConfigurableSourceImpl.h b/cscore/src/main/native/cpp/ConfigurableSourceImpl.h
new file mode 100644
index 0000000..a10f27e
--- /dev/null
+++ b/cscore/src/main/native/cpp/ConfigurableSourceImpl.h
@@ -0,0 +1,56 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#ifndef CSCORE_CONFIGURABLESOURCEIMPL_H_
+#define CSCORE_CONFIGURABLESOURCEIMPL_H_
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <wpi/ArrayRef.h>
+#include <wpi/Twine.h>
+
+#include "SourceImpl.h"
+
+namespace cs {
+
+class ConfigurableSourceImpl : public SourceImpl {
+ protected:
+ ConfigurableSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
+ Notifier& notifier, Telemetry& telemetry,
+ const VideoMode& mode);
+
+ public:
+ ~ConfigurableSourceImpl() override;
+
+ void Start() override;
+
+ bool SetVideoMode(const VideoMode& mode, CS_Status* status) override;
+
+ void NumSinksChanged() override;
+ void NumSinksEnabledChanged() override;
+
+ // OpenCV-specific functions
+ void NotifyError(const wpi::Twine& msg);
+ int CreateProperty(const wpi::Twine& name, CS_PropertyKind kind, int minimum,
+ int maximum, int step, int defaultValue, int value);
+ int CreateProperty(const wpi::Twine& name, CS_PropertyKind kind, int minimum,
+ int maximum, int step, int defaultValue, int value,
+ std::function<void(CS_Property property)> onChange);
+ void SetEnumPropertyChoices(int property, wpi::ArrayRef<std::string> choices,
+ CS_Status* status);
+
+ private:
+ std::atomic_bool m_connected{true};
+};
+
+} // namespace cs
+
+#endif // CSCORE_CONFIGURABLESOURCEIMPL_H_
diff --git a/cscore/src/main/native/cpp/CvSinkImpl.cpp b/cscore/src/main/native/cpp/CvSinkImpl.cpp
index 17dbd18..7ba505a 100644
--- a/cscore/src/main/native/cpp/CvSinkImpl.cpp
+++ b/cscore/src/main/native/cpp/CvSinkImpl.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -138,10 +138,12 @@
inst.telemetry, processFrame));
}
+static constexpr unsigned SinkMask = CS_SINK_CV | CS_SINK_RAW;
+
void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
- if (!data || data->kind != CS_SINK_CV) {
+ if (!data || (data->kind & SinkMask) == 0) {
*status = CS_INVALID_HANDLE;
return;
}
@@ -169,7 +171,7 @@
std::string GetSinkError(CS_Sink sink, CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
- if (!data || data->kind != CS_SINK_CV) {
+ if (!data || (data->kind & SinkMask) == 0) {
*status = CS_INVALID_HANDLE;
return std::string{};
}
@@ -179,7 +181,7 @@
wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
- if (!data || data->kind != CS_SINK_CV) {
+ if (!data || (data->kind & SinkMask) == 0) {
*status = CS_INVALID_HANDLE;
return wpi::StringRef{};
}
@@ -188,7 +190,7 @@
void SetSinkEnabled(CS_Sink sink, bool enabled, CS_Status* status) {
auto data = Instance::GetInstance().GetSink(sink);
- if (!data || data->kind != CS_SINK_CV) {
+ if (!data || (data->kind & SinkMask) == 0) {
*status = CS_INVALID_HANDLE;
return;
}
@@ -215,6 +217,7 @@
return cs::SetSinkDescription(sink, description, status);
}
+#if CV_VERSION_MAJOR < 4
uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image,
CS_Status* status) {
auto mat = cv::cvarrToMat(image);
@@ -226,6 +229,7 @@
auto mat = cv::cvarrToMat(image);
return cs::GrabSinkFrameTimeout(sink, mat, timeout, status);
}
+#endif // CV_VERSION_MAJOR < 4
uint64_t CS_GrabSinkFrameCpp(CS_Sink sink, cv::Mat* image, CS_Status* status) {
return cs::GrabSinkFrame(sink, *image, status);
diff --git a/cscore/src/main/native/cpp/CvSourceImpl.cpp b/cscore/src/main/native/cpp/CvSourceImpl.cpp
index 449a9ee..49b9d28 100644
--- a/cscore/src/main/native/cpp/CvSourceImpl.cpp
+++ b/cscore/src/main/native/cpp/CvSourceImpl.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -25,37 +25,10 @@
CvSourceImpl::CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
const VideoMode& mode)
- : SourceImpl{name, logger, notifier, telemetry} {
- m_mode = mode;
- m_videoModes.push_back(m_mode);
-}
+ : ConfigurableSourceImpl{name, logger, notifier, telemetry, mode} {}
CvSourceImpl::~CvSourceImpl() {}
-void CvSourceImpl::Start() {
- m_notifier.NotifySource(*this, CS_SOURCE_CONNECTED);
- m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
- m_notifier.NotifySourceVideoMode(*this, m_mode);
-}
-
-bool CvSourceImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) {
- {
- std::lock_guard<wpi::mutex> lock(m_mutex);
- m_mode = mode;
- m_videoModes[0] = mode;
- }
- m_notifier.NotifySourceVideoMode(*this, mode);
- return true;
-}
-
-void CvSourceImpl::NumSinksChanged() {
- // ignore
-}
-
-void CvSourceImpl::NumSinksEnabledChanged() {
- // ignore
-}
-
void CvSourceImpl::PutFrame(cv::Mat& image) {
// We only support 8-bit images; convert if necessary.
cv::Mat finalImage;
@@ -89,61 +62,6 @@
SourceImpl::PutFrame(std::move(dest), wpi::Now());
}
-void CvSourceImpl::NotifyError(const wpi::Twine& msg) {
- PutError(msg, wpi::Now());
-}
-
-int CvSourceImpl::CreateProperty(const wpi::Twine& name, CS_PropertyKind kind,
- int minimum, int maximum, int step,
- int defaultValue, int value) {
- std::lock_guard<wpi::mutex> lock(m_mutex);
- int ndx = CreateOrUpdateProperty(name,
- [=] {
- return wpi::make_unique<PropertyImpl>(
- name, kind, minimum, maximum, step,
- defaultValue, value);
- },
- [&](PropertyImpl& prop) {
- // update all but value
- prop.propKind = kind;
- prop.minimum = minimum;
- prop.maximum = maximum;
- prop.step = step;
- prop.defaultValue = defaultValue;
- value = prop.value;
- });
- m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CREATED, name, ndx,
- kind, value, wpi::Twine{});
- return ndx;
-}
-
-int CvSourceImpl::CreateProperty(
- const wpi::Twine& name, CS_PropertyKind kind, int minimum, int maximum,
- int step, int defaultValue, int value,
- std::function<void(CS_Property property)> onChange) {
- // TODO
- return 0;
-}
-
-void CvSourceImpl::SetEnumPropertyChoices(int property,
- wpi::ArrayRef<std::string> choices,
- CS_Status* status) {
- std::lock_guard<wpi::mutex> lock(m_mutex);
- auto prop = GetProperty(property);
- if (!prop) {
- *status = CS_INVALID_PROPERTY;
- return;
- }
- if (prop->propKind != CS_PROP_ENUM) {
- *status = CS_WRONG_PROPERTY_TYPE;
- return;
- }
- prop->enumChoices = choices;
- m_notifier.NotifySourceProperty(*this, CS_SOURCE_PROPERTY_CHOICES_UPDATED,
- prop->name, property, CS_PROP_ENUM,
- prop->value, wpi::Twine{});
-}
-
namespace cs {
CS_Source CreateCvSource(const wpi::Twine& name, const VideoMode& mode,
@@ -163,10 +81,12 @@
static_cast<CvSourceImpl&>(*data->source).PutFrame(image);
}
+static constexpr unsigned SourceMask = CS_SINK_CV | CS_SINK_RAW;
+
void NotifySourceError(CS_Source source, const wpi::Twine& msg,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
- if (!data || data->kind != CS_SOURCE_CV) {
+ if (!data || (data->kind & SourceMask) == 0) {
*status = CS_INVALID_HANDLE;
return;
}
@@ -175,7 +95,7 @@
void SetSourceConnected(CS_Source source, bool connected, CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
- if (!data || data->kind != CS_SOURCE_CV) {
+ if (!data || (data->kind & SourceMask) == 0) {
*status = CS_INVALID_HANDLE;
return;
}
@@ -185,7 +105,7 @@
void SetSourceDescription(CS_Source source, const wpi::Twine& description,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
- if (!data || data->kind != CS_SOURCE_CV) {
+ if (!data || (data->kind & SourceMask) == 0) {
*status = CS_INVALID_HANDLE;
return;
}
@@ -197,7 +117,7 @@
int step, int defaultValue, int value,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
- if (!data || data->kind != CS_SOURCE_CV) {
+ if (!data || (data->kind & SourceMask) == 0) {
*status = CS_INVALID_HANDLE;
return -1;
}
@@ -212,7 +132,7 @@
int maximum, int step, int defaultValue, int value,
std::function<void(CS_Property property)> onChange, CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
- if (!data || data->kind != CS_SOURCE_CV) {
+ if (!data || (data->kind & SourceMask) == 0) {
*status = CS_INVALID_HANDLE;
return -1;
}
@@ -226,7 +146,7 @@
wpi::ArrayRef<std::string> choices,
CS_Status* status) {
auto data = Instance::GetInstance().GetSource(source);
- if (!data || data->kind != CS_SOURCE_CV) {
+ if (!data || (data->kind & SourceMask) == 0) {
*status = CS_INVALID_HANDLE;
return;
}
@@ -258,11 +178,13 @@
status);
}
+#if CV_VERSION_MAJOR < 4
void CS_PutSourceFrame(CS_Source source, struct CvMat* image,
CS_Status* status) {
auto mat = cv::cvarrToMat(image);
return cs::PutSourceFrame(source, mat, status);
}
+#endif // CV_VERSION_MAJOR < 4
void CS_PutSourceFrameCpp(CS_Source source, cv::Mat* image, CS_Status* status) {
return cs::PutSourceFrame(source, *image, status);
diff --git a/cscore/src/main/native/cpp/CvSourceImpl.h b/cscore/src/main/native/cpp/CvSourceImpl.h
index e1a9cd2..978d012 100644
--- a/cscore/src/main/native/cpp/CvSourceImpl.h
+++ b/cscore/src/main/native/cpp/CvSourceImpl.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -18,33 +18,19 @@
#include <wpi/ArrayRef.h>
#include <wpi/Twine.h>
+#include "ConfigurableSourceImpl.h"
#include "SourceImpl.h"
namespace cs {
-class CvSourceImpl : public SourceImpl {
+class CvSourceImpl : public ConfigurableSourceImpl {
public:
CvSourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
Telemetry& telemetry, const VideoMode& mode);
~CvSourceImpl() override;
- void Start() override;
-
- bool SetVideoMode(const VideoMode& mode, CS_Status* status) override;
-
- void NumSinksChanged() override;
- void NumSinksEnabledChanged() override;
-
// OpenCV-specific functions
void PutFrame(cv::Mat& image);
- void NotifyError(const wpi::Twine& msg);
- int CreateProperty(const wpi::Twine& name, CS_PropertyKind kind, int minimum,
- int maximum, int step, int defaultValue, int value);
- int CreateProperty(const wpi::Twine& name, CS_PropertyKind kind, int minimum,
- int maximum, int step, int defaultValue, int value,
- std::function<void(CS_Property property)> onChange);
- void SetEnumPropertyChoices(int property, wpi::ArrayRef<std::string> choices,
- CS_Status* status);
private:
std::atomic_bool m_connected{true};
diff --git a/cscore/src/main/native/cpp/Frame.cpp b/cscore/src/main/native/cpp/Frame.cpp
index 15f9b2d..466cb52 100644
--- a/cscore/src/main/native/cpp/Frame.cpp
+++ b/cscore/src/main/native/cpp/Frame.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -36,7 +36,7 @@
Image* Frame::GetNearestImage(int width, int height) const {
if (!m_impl) return nullptr;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
Image* found = nullptr;
// Ideally we want the smallest image at least width/height in size
@@ -60,7 +60,7 @@
VideoMode::PixelFormat pixelFormat,
int jpegQuality) const {
if (!m_impl) return nullptr;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
Image* found = nullptr;
// We want the smallest image at least width/height (or the next largest),
@@ -253,7 +253,7 @@
// Save the result
Image* rv = newImage.release();
if (m_impl) {
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
@@ -274,7 +274,7 @@
// Save the result
Image* rv = newImage.release();
if (m_impl) {
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
@@ -294,7 +294,7 @@
// Save the result
Image* rv = newImage.release();
if (m_impl) {
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
@@ -314,7 +314,7 @@
// Save the result
Image* rv = newImage.release();
if (m_impl) {
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
@@ -334,7 +334,7 @@
// Save the result
Image* rv = newImage.release();
if (m_impl) {
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
@@ -354,14 +354,14 @@
// Save the result
Image* rv = newImage.release();
if (m_impl) {
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
}
Image* Frame::ConvertGrayToBGR(Image* image) {
- if (!image || image->pixelFormat != VideoMode::kBGR) return nullptr;
+ if (!image || image->pixelFormat != VideoMode::kGray) return nullptr;
// Allocate a BGR image
auto newImage =
@@ -374,7 +374,7 @@
// Save the result
Image* rv = newImage.release();
if (m_impl) {
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
m_impl->images.push_back(rv);
}
return rv;
@@ -383,7 +383,7 @@
Image* Frame::ConvertBGRToMJPEG(Image* image, int quality) {
if (!image || image->pixelFormat != VideoMode::kBGR) return nullptr;
if (!m_impl) return nullptr;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
// Allocate a JPEG image. We don't actually know what the resulting size
// will be; while the destination will automatically grow, doing so will
@@ -397,7 +397,7 @@
// Compress
if (m_impl->compressionParams.empty()) {
- m_impl->compressionParams.push_back(CV_IMWRITE_JPEG_QUALITY);
+ m_impl->compressionParams.push_back(cv::IMWRITE_JPEG_QUALITY);
m_impl->compressionParams.push_back(quality);
} else {
m_impl->compressionParams[1] = quality;
@@ -414,7 +414,7 @@
Image* Frame::ConvertGrayToMJPEG(Image* image, int quality) {
if (!image || image->pixelFormat != VideoMode::kGray) return nullptr;
if (!m_impl) return nullptr;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
// Allocate a JPEG image. We don't actually know what the resulting size
// will be; while the destination will automatically grow, doing so will
@@ -428,7 +428,7 @@
// Compress
if (m_impl->compressionParams.empty()) {
- m_impl->compressionParams.push_back(CV_IMWRITE_JPEG_QUALITY);
+ m_impl->compressionParams.push_back(cv::IMWRITE_JPEG_QUALITY);
m_impl->compressionParams.push_back(quality);
} else {
m_impl->compressionParams[1] = quality;
@@ -446,7 +446,7 @@
VideoMode::PixelFormat pixelFormat,
int requiredJpegQuality, int defaultJpegQuality) {
if (!m_impl) return nullptr;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
Image* cur = GetNearestImage(width, height, pixelFormat, requiredJpegQuality);
if (!cur || cur->Is(width, height, pixelFormat, requiredJpegQuality))
return cur;
diff --git a/cscore/src/main/native/cpp/Frame.h b/cscore/src/main/native/cpp/Frame.h
index b977f24..07fa24f 100644
--- a/cscore/src/main/native/cpp/Frame.h
+++ b/cscore/src/main/native/cpp/Frame.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -80,42 +80,42 @@
int GetOriginalWidth() const {
if (!m_impl) return 0;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
if (m_impl->images.empty()) return 0;
return m_impl->images[0]->width;
}
int GetOriginalHeight() const {
if (!m_impl) return 0;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
if (m_impl->images.empty()) return 0;
return m_impl->images[0]->height;
}
int GetOriginalPixelFormat() const {
if (!m_impl) return 0;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
if (m_impl->images.empty()) return 0;
return m_impl->images[0]->pixelFormat;
}
int GetOriginalJpegQuality() const {
if (!m_impl) return 0;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
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;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
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;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
for (auto i : m_impl->images) {
if (i->Is(width, height)) return i;
}
@@ -125,7 +125,7 @@
Image* GetExistingImage(int width, int height,
VideoMode::PixelFormat pixelFormat) const {
if (!m_impl) return nullptr;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
for (auto i : m_impl->images) {
if (i->Is(width, height, pixelFormat)) return i;
}
@@ -136,7 +136,7 @@
VideoMode::PixelFormat pixelFormat,
int jpegQuality) const {
if (!m_impl) return nullptr;
- std::lock_guard<wpi::recursive_mutex> lock(m_impl->mutex);
+ std::scoped_lock lock(m_impl->mutex);
for (auto i : m_impl->images) {
if (i->Is(width, height, pixelFormat, jpegQuality)) return i;
}
diff --git a/cscore/src/main/native/cpp/HttpCameraImpl.cpp b/cscore/src/main/native/cpp/HttpCameraImpl.cpp
index f15fc5f..5bf7a8a 100644
--- a/cscore/src/main/native/cpp/HttpCameraImpl.cpp
+++ b/cscore/src/main/native/cpp/HttpCameraImpl.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -7,9 +7,8 @@
#include "HttpCameraImpl.h"
-#include <wpi/STLExtras.h>
+#include <wpi/MemAlloc.h>
#include <wpi/TCPConnector.h>
-#include <wpi/memory.h>
#include <wpi/timestamp.h>
#include "Handle.h"
@@ -38,7 +37,7 @@
// Close file if it's open
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (m_streamConn) m_streamConn->stream->close();
if (m_settingsConn) m_settingsConn->stream->close();
}
@@ -65,7 +64,7 @@
void HttpCameraImpl::MonitorThreadMain() {
while (m_active) {
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
// sleep for 1 second between checks
m_monitorCond.wait_for(lock, std::chrono::seconds(1),
[=] { return !m_active; });
@@ -96,7 +95,7 @@
// disconnect if not enabled
if (!IsEnabled()) {
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
if (m_streamConn) m_streamConn->stream->close();
// Wait for enable
m_sinkEnabledCond.wait(lock, [=] { return !m_active || IsEnabled(); });
@@ -118,7 +117,7 @@
// stream
DeviceStream(conn->is, boundary);
{
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
m_streamConn = nullptr;
}
}
@@ -132,7 +131,7 @@
// Build the request
wpi::HttpRequest req;
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (m_locations.empty()) {
SERROR("locations array is empty!?");
std::this_thread::sleep_for(std::chrono::seconds(1));
@@ -149,12 +148,12 @@
if (!m_active || !stream) return nullptr;
- auto connPtr = wpi::make_unique<wpi::HttpConnection>(std::move(stream), 1);
+ auto connPtr = std::make_unique<wpi::HttpConnection>(std::move(stream), 1);
wpi::HttpConnection* conn = connPtr.get();
// update m_streamConn
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_frameCount = 1; // avoid a race with monitor thread
m_streamConn = std::move(connPtr);
}
@@ -162,7 +161,7 @@
std::string warn;
if (!conn->Handshake(req, &warn)) {
SWARNING(GetName() << ": " << warn);
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_streamConn = nullptr;
return nullptr;
}
@@ -174,7 +173,7 @@
if (mediaType != "multipart/x-mixed-replace") {
SWARNING("\"" << req.host << "\": unrecognized Content-Type \"" << mediaType
<< "\"");
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_streamConn = nullptr;
return nullptr;
}
@@ -189,6 +188,9 @@
std::tie(key, value) = keyvalue.split('=');
if (key.trim() == "boundary") {
value = value.trim().trim('"'); // value may be quoted
+ if (value.startswith("--")) {
+ value = value.substr(2);
+ }
boundary.append(value.begin(), value.end());
}
}
@@ -196,7 +198,7 @@
if (boundary.empty()) {
SWARNING("\"" << req.host
<< "\": empty multi-part boundary or no Content-Type");
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_streamConn = nullptr;
return nullptr;
}
@@ -219,11 +221,16 @@
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, 2);
+ is.read(eol, 1);
if (!m_active || is.has_error()) break;
- // End-of-stream is indicated with trailing --
- if (eol[0] == '-' && eol[1] == '-') break;
+ if (eol[0] != '\n') {
+ is.read(eol + 1, 1);
+ if (!m_active || is.has_error()) break;
+ // End-of-stream is indicated with trailing --
+ if (eol[0] == '-' && eol[1] == '-') break;
+ }
if (!DeviceStreamFrame(is, imageBuf))
++numErrors;
@@ -291,7 +298,7 @@
for (;;) {
wpi::HttpRequest req;
{
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
m_settingsCond.wait(lock, [=] {
return !m_active || (m_prefLocation != -1 && !m_settings.empty());
});
@@ -314,12 +321,12 @@
if (!m_active || !stream) return;
- auto connPtr = wpi::make_unique<wpi::HttpConnection>(std::move(stream), 1);
+ auto connPtr = std::make_unique<wpi::HttpConnection>(std::move(stream), 1);
wpi::HttpConnection* conn = connPtr.get();
// update m_settingsConn
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_settingsConn = std::move(connPtr);
}
@@ -331,7 +338,7 @@
}
CS_HttpCameraKind HttpCameraImpl::GetKind() const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
return m_kind;
}
@@ -349,7 +356,7 @@
}
}
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_locations.swap(locations);
m_nextLocation = 0;
m_streamSettingsUpdated = true;
@@ -357,7 +364,7 @@
}
std::vector<std::string> HttpCameraImpl::GetUrls() const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
std::vector<std::string> urls;
for (const auto& loc : m_locations) urls.push_back(loc.url);
return urls;
@@ -368,8 +375,8 @@
bool viaSettings, CS_PropertyKind kind,
int minimum, int maximum, int step,
int defaultValue, int value) const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
- m_propertyData.emplace_back(wpi::make_unique<PropertyData>(
+ std::scoped_lock lock(m_mutex);
+ m_propertyData.emplace_back(std::make_unique<PropertyData>(
name, httpParam, viaSettings, kind, minimum, maximum, step, defaultValue,
value));
@@ -382,8 +389,8 @@
void HttpCameraImpl::CreateEnumProperty(
const wpi::Twine& name, const wpi::Twine& httpParam, bool viaSettings,
int defaultValue, int value, std::initializer_list<T> choices) const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
- m_propertyData.emplace_back(wpi::make_unique<PropertyData>(
+ std::scoped_lock lock(m_mutex);
+ m_propertyData.emplace_back(std::make_unique<PropertyData>(
name, httpParam, viaSettings, CS_PROP_ENUM, 0, choices.size() - 1, 1,
defaultValue, value));
@@ -401,11 +408,11 @@
std::unique_ptr<PropertyImpl> HttpCameraImpl::CreateEmptyProperty(
const wpi::Twine& name) const {
- return wpi::make_unique<PropertyData>(name);
+ return std::make_unique<PropertyData>(name);
}
bool HttpCameraImpl::CacheProperties(CS_Status* status) const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
// Pretty typical set of video modes
m_videoModes.clear();
@@ -461,7 +468,7 @@
bool HttpCameraImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) {
if (mode.pixelFormat != VideoMode::kMJPEG) return false;
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_mode = mode;
m_streamSettingsUpdated = true;
return true;
@@ -490,7 +497,7 @@
true, CS_PROP_INTEGER, 0, 100, 1, 50, 50);
// TODO: get video modes from device
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_videoModes.clear();
m_videoModes.emplace_back(VideoMode::kMJPEG, 640, 480, 30);
m_videoModes.emplace_back(VideoMode::kMJPEG, 480, 360, 30);
@@ -603,7 +610,7 @@
char** CS_GetHttpCameraUrls(CS_Source source, int* count, CS_Status* status) {
auto urls = cs::GetHttpCameraUrls(source, status);
char** out =
- static_cast<char**>(wpi::CheckedMalloc(urls.size() * sizeof(char*)));
+ 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]);
return out;
diff --git a/cscore/src/main/native/cpp/Log.h b/cscore/src/main/native/cpp/Log.h
index 9ca0e1b..b9fd9ab 100644
--- a/cscore/src/main/native/cpp/Log.h
+++ b/cscore/src/main/native/cpp/Log.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -17,7 +17,7 @@
#define WARNING(x) WPI_WARNING(m_logger, x)
#define INFO(x) WPI_INFO(m_logger, x)
-#define DEBUG(x) WPI_DEBUG(m_logger, x)
+#define DEBUG0(x) WPI_DEBUG(m_logger, x)
#define DEBUG1(x) WPI_DEBUG1(m_logger, x)
#define DEBUG2(x) WPI_DEBUG2(m_logger, x)
#define DEBUG3(x) WPI_DEBUG3(m_logger, x)
@@ -27,7 +27,7 @@
#define SWARNING(x) WARNING(GetName() << ": " << x)
#define SINFO(x) INFO(GetName() << ": " << x)
-#define SDEBUG(x) DEBUG(GetName() << ": " << x)
+#define SDEBUG(x) DEBUG0(GetName() << ": " << x)
#define SDEBUG1(x) DEBUG1(GetName() << ": " << x)
#define SDEBUG2(x) DEBUG2(GetName() << ": " << x)
#define SDEBUG3(x) DEBUG3(GetName() << ": " << x)
diff --git a/cscore/src/main/native/cpp/MjpegServerImpl.cpp b/cscore/src/main/native/cpp/MjpegServerImpl.cpp
index f548f9c..e30b745 100644
--- a/cscore/src/main/native/cpp/MjpegServerImpl.cpp
+++ b/cscore/src/main/native/cpp/MjpegServerImpl.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -105,18 +105,18 @@
wpi::StringRef GetName() { return m_name; }
std::shared_ptr<SourceImpl> GetSource() {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
return m_source;
}
void StartStream() {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (m_source) m_source->EnableSink();
m_streaming = true;
}
void StopStream() {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (m_source) m_source->DisableSink();
m_streaming = false;
}
@@ -865,7 +865,7 @@
// worker thread for clients that connected to this server
void MjpegServerImpl::ConnThread::Main() {
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
while (m_active) {
while (!m_stream) {
m_cond.wait(lock);
@@ -898,7 +898,7 @@
auto source = GetSource();
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
// Find unoccupied worker thread, or create one if necessary
auto it = std::find_if(m_connThreads.begin(), m_connThreads.end(),
[](const wpi::SafeThreadOwner<ConnThread>& owner) {
@@ -937,7 +937,7 @@
}
void MjpegServerImpl::SetSourceImpl(std::shared_ptr<SourceImpl> source) {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
for (auto& connThread : m_connThreads) {
if (auto thr = connThread.GetThread()) {
if (thr->m_source != source) {
diff --git a/cscore/src/main/native/cpp/Notifier.cpp b/cscore/src/main/native/cpp/Notifier.cpp
index 45bd050..e4645c9 100644
--- a/cscore/src/main/native/cpp/Notifier.cpp
+++ b/cscore/src/main/native/cpp/Notifier.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -102,7 +102,7 @@
void Notifier::Thread::Main() {
if (m_on_start) m_on_start();
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
while (m_active) {
while (m_notifications.empty()) {
m_cond.wait(lock);
diff --git a/cscore/src/main/native/cpp/PropertyContainer.cpp b/cscore/src/main/native/cpp/PropertyContainer.cpp
index 46ea77d..17bf94b 100644
--- a/cscore/src/main/native/cpp/PropertyContainer.cpp
+++ b/cscore/src/main/native/cpp/PropertyContainer.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -18,7 +18,7 @@
// We can't fail, so instead we create a new index if caching fails.
CS_Status status = 0;
if (!m_properties_cached) CacheProperties(&status);
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
wpi::SmallVector<char, 64> nameBuf;
int& ndx = m_properties[name.toStringRef(nameBuf)];
if (ndx == 0) {
@@ -33,7 +33,7 @@
wpi::SmallVectorImpl<int>& vec, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status))
return wpi::ArrayRef<int>{};
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ 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);
}
@@ -43,7 +43,7 @@
CS_PropertyKind PropertyContainer::GetPropertyKind(int property) const {
CS_Status status = 0;
if (!m_properties_cached && !CacheProperties(&status)) return CS_PROP_NONE;
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) return CS_PROP_NONE;
return prop->propKind;
@@ -52,7 +52,7 @@
wpi::StringRef PropertyContainer::GetPropertyName(
int property, wpi::SmallVectorImpl<char>& buf, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) return wpi::StringRef{};
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -64,7 +64,7 @@
int PropertyContainer::GetProperty(int property, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) return 0;
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -80,7 +80,7 @@
void PropertyContainer::SetProperty(int property, int value,
CS_Status* status) {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -101,7 +101,7 @@
int PropertyContainer::GetPropertyMin(int property, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) return 0;
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -112,7 +112,7 @@
int PropertyContainer::GetPropertyMax(int property, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) return 0;
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -123,7 +123,7 @@
int PropertyContainer::GetPropertyStep(int property, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) return 0;
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -135,7 +135,7 @@
int PropertyContainer::GetPropertyDefault(int property,
CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) return 0;
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -147,7 +147,7 @@
wpi::StringRef PropertyContainer::GetStringProperty(
int property, wpi::SmallVectorImpl<char>& buf, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) return wpi::StringRef{};
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -164,7 +164,7 @@
void PropertyContainer::SetStringProperty(int property, const wpi::Twine& value,
CS_Status* status) {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -186,7 +186,7 @@
int property, CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status))
return std::vector<std::string>{};
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
auto prop = GetProperty(property);
if (!prop) {
*status = CS_INVALID_PROPERTY;
@@ -201,7 +201,7 @@
std::unique_ptr<PropertyImpl> PropertyContainer::CreateEmptyProperty(
const wpi::Twine& name) const {
- return wpi::make_unique<PropertyImpl>(name);
+ return std::make_unique<PropertyImpl>(name);
}
bool PropertyContainer::CacheProperties(CS_Status* status) const {
diff --git a/cscore/src/main/native/cpp/PropertyContainer.h b/cscore/src/main/native/cpp/PropertyContainer.h
index 19197b2..9bbb9c7 100644
--- a/cscore/src/main/native/cpp/PropertyContainer.h
+++ b/cscore/src/main/native/cpp/PropertyContainer.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/cscore/src/main/native/cpp/RawSinkImpl.cpp b/cscore/src/main/native/cpp/RawSinkImpl.cpp
new file mode 100644
index 0000000..986378f
--- /dev/null
+++ b/cscore/src/main/native/cpp/RawSinkImpl.cpp
@@ -0,0 +1,199 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#include "RawSinkImpl.h"
+
+#include "Instance.h"
+#include "cscore.h"
+#include "cscore_raw.h"
+
+using namespace cs;
+
+RawSinkImpl::RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
+ Notifier& notifier, Telemetry& telemetry)
+ : SinkImpl{name, logger, notifier, telemetry} {
+ m_active = true;
+ // m_thread = std::thread(&RawSinkImpl::ThreadMain, this);
+}
+
+RawSinkImpl::RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger,
+ Notifier& notifier, Telemetry& telemetry,
+ std::function<void(uint64_t time)> processFrame)
+ : SinkImpl{name, logger, notifier, telemetry} {}
+
+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();
+
+ // join thread
+ if (m_thread.joinable()) m_thread.join();
+}
+
+uint64_t RawSinkImpl::GrabFrame(CS_RawFrame& image) {
+ SetEnabled(true);
+
+ auto source = GetSource();
+ if (!source) {
+ // Source disconnected; sleep for one second
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ return 0;
+ }
+
+ auto frame = source->GetNextFrame(); // blocks
+ if (!frame) {
+ // Bad frame; sleep for 20 ms so we don't consume all processor time.
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ return 0; // signal error
+ }
+
+ return GrabFrameImpl(image, frame);
+}
+
+uint64_t RawSinkImpl::GrabFrame(CS_RawFrame& image, double timeout) {
+ SetEnabled(true);
+
+ auto source = GetSource();
+ if (!source) {
+ // Source disconnected; sleep for one second
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ return 0;
+ }
+
+ auto frame = source->GetNextFrame(timeout); // blocks
+ if (!frame) {
+ // Bad frame; sleep for 20 ms so we don't consume all processor time.
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ return 0; // signal error
+ }
+
+ return GrabFrameImpl(image, frame);
+}
+
+uint64_t RawSinkImpl::GrabFrameImpl(CS_RawFrame& rawFrame,
+ Frame& incomingFrame) {
+ Image* newImage = nullptr;
+
+ if (rawFrame.pixelFormat == CS_PixelFormat::CS_PIXFMT_UNKNOWN) {
+ // Always get incoming image directly on unknown
+ newImage = incomingFrame.GetExistingImage(0);
+ } else {
+ // Format is known, ask for it
+ auto width = rawFrame.width;
+ auto height = rawFrame.height;
+ auto pixelFormat =
+ static_cast<VideoMode::PixelFormat>(rawFrame.pixelFormat);
+ if (width <= 0 || height <= 0) {
+ width = incomingFrame.GetOriginalWidth();
+ height = incomingFrame.GetOriginalHeight();
+ }
+ newImage = incomingFrame.GetImage(width, height, pixelFormat);
+ }
+
+ if (!newImage) {
+ // Shouldn't happen, but just in case...
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ return 0;
+ }
+
+ CS_AllocateRawFrameData(&rawFrame, newImage->size());
+ rawFrame.height = newImage->height;
+ rawFrame.width = newImage->width;
+ rawFrame.pixelFormat = newImage->pixelFormat;
+ rawFrame.totalData = newImage->size();
+ std::copy(newImage->data(), newImage->data() + rawFrame.totalData,
+ rawFrame.data);
+
+ return incomingFrame.GetTime();
+}
+
+// Send HTTP response and a stream of JPG-frames
+void RawSinkImpl::ThreadMain() {
+ Enable();
+ while (m_active) {
+ auto source = GetSource();
+ if (!source) {
+ // Source disconnected; sleep for one second
+ std::this_thread::sleep_for(std::chrono::seconds(1));
+ continue;
+ }
+ SDEBUG4("waiting for frame");
+ Frame frame = source->GetNextFrame(); // blocks
+ 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));
+ continue;
+ }
+ // TODO m_processFrame();
+ }
+ Disable();
+}
+
+namespace cs {
+CS_Sink CreateRawSink(const wpi::Twine& name, CS_Status* status) {
+ auto& inst = Instance::GetInstance();
+ return inst.CreateSink(CS_SINK_RAW,
+ std::make_shared<RawSinkImpl>(
+ name, inst.logger, inst.notifier, inst.telemetry));
+}
+
+CS_Sink CreateRawSinkCallback(const wpi::Twine& name,
+ std::function<void(uint64_t time)> processFrame,
+ CS_Status* status) {
+ auto& inst = Instance::GetInstance();
+ return inst.CreateSink(CS_SINK_RAW, std::make_shared<RawSinkImpl>(
+ name, inst.logger, inst.notifier,
+ inst.telemetry, processFrame));
+}
+
+uint64_t GrabSinkFrame(CS_Sink sink, CS_RawFrame& image, CS_Status* status) {
+ auto data = Instance::GetInstance().GetSink(sink);
+ if (!data || data->kind != CS_SINK_RAW) {
+ *status = CS_INVALID_HANDLE;
+ return 0;
+ }
+ return static_cast<RawSinkImpl&>(*data->sink).GrabFrame(image);
+}
+
+uint64_t GrabSinkFrameTimeout(CS_Sink sink, CS_RawFrame& image, double timeout,
+ CS_Status* status) {
+ auto data = Instance::GetInstance().GetSink(sink);
+ if (!data || data->kind != CS_SINK_RAW) {
+ *status = CS_INVALID_HANDLE;
+ return 0;
+ }
+ return static_cast<RawSinkImpl&>(*data->sink).GrabFrame(image, timeout);
+}
+} // namespace cs
+
+extern "C" {
+CS_Sink CS_CreateRawSink(const char* name, CS_Status* status) {
+ return cs::CreateRawSink(name, status);
+}
+
+CS_Sink CS_CreateRawSinkCallback(const char* name, void* data,
+ void (*processFrame)(void* data,
+ uint64_t time),
+ CS_Status* status) {
+ return cs::CreateRawSinkCallback(
+ name, [=](uint64_t time) { processFrame(data, time); }, status);
+}
+
+uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct CS_RawFrame* image,
+ CS_Status* status) {
+ return cs::GrabSinkFrame(sink, *image, status);
+}
+
+uint64_t CS_GrabRawSinkFrameTimeout(CS_Sink sink, struct CS_RawFrame* image,
+ double timeout, CS_Status* status) {
+ return cs::GrabSinkFrameTimeout(sink, *image, timeout, status);
+}
+} // extern "C"
diff --git a/cscore/src/main/native/cpp/RawSinkImpl.h b/cscore/src/main/native/cpp/RawSinkImpl.h
new file mode 100644
index 0000000..3e69485
--- /dev/null
+++ b/cscore/src/main/native/cpp/RawSinkImpl.h
@@ -0,0 +1,52 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#ifndef CSCORE_RAWSINKIMPL_H_
+#define CSCORE_RAWSINKIMPL_H_
+
+#include <stdint.h>
+
+#include <atomic>
+#include <functional>
+#include <thread>
+
+#include <wpi/Twine.h>
+#include <wpi/condition_variable.h>
+
+#include "Frame.h"
+#include "SinkImpl.h"
+#include "cscore_raw.h"
+
+namespace cs {
+class SourceImpl;
+
+class RawSinkImpl : public SinkImpl {
+ public:
+ RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
+ Telemetry& telemetry);
+ RawSinkImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
+ Telemetry& telemetry,
+ std::function<void(uint64_t time)> processFrame);
+ ~RawSinkImpl() override;
+
+ void Stop();
+
+ uint64_t GrabFrame(CS_RawFrame& frame);
+ uint64_t GrabFrame(CS_RawFrame& frame, double timeout);
+
+ private:
+ void ThreadMain();
+
+ uint64_t GrabFrameImpl(CS_RawFrame& rawFrame, Frame& incomingFrame);
+
+ std::atomic_bool m_active; // set to false to terminate threads
+ std::thread m_thread;
+ std::function<void(uint64_t time)> m_processFrame;
+};
+} // namespace cs
+
+#endif // CSCORE_RAWSINKIMPL_H_
diff --git a/cscore/src/main/native/cpp/RawSourceImpl.cpp b/cscore/src/main/native/cpp/RawSourceImpl.cpp
new file mode 100644
index 0000000..e0dba2d
--- /dev/null
+++ b/cscore/src/main/native/cpp/RawSourceImpl.cpp
@@ -0,0 +1,83 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#include "RawSourceImpl.h"
+
+#include <wpi/timestamp.h>
+
+#include "Handle.h"
+#include "Instance.h"
+#include "Log.h"
+#include "Notifier.h"
+#include "cscore_raw.h"
+
+using namespace cs;
+
+RawSourceImpl::RawSourceImpl(const wpi::Twine& name, wpi::Logger& logger,
+ Notifier& notifier, Telemetry& telemetry,
+ const VideoMode& mode)
+ : ConfigurableSourceImpl{name, logger, notifier, telemetry, mode} {}
+
+RawSourceImpl::~RawSourceImpl() {}
+
+void RawSourceImpl::PutFrame(const CS_RawFrame& image) {
+ int type;
+ switch (image.pixelFormat) {
+ case VideoMode::kYUYV:
+ case VideoMode::kRGB565:
+ type = CV_8UC2;
+ break;
+ case VideoMode::kBGR:
+ type = CV_8UC3;
+ break;
+ case VideoMode::kGray:
+ case VideoMode::kMJPEG:
+ default:
+ type = CV_8UC1;
+ break;
+ }
+ cv::Mat finalImage{image.height, image.width, type, image.data};
+ std::unique_ptr<Image> dest =
+ AllocImage(static_cast<VideoMode::PixelFormat>(image.pixelFormat),
+ image.width, image.height, image.totalData);
+ finalImage.copyTo(dest->AsMat());
+
+ SourceImpl::PutFrame(std::move(dest), wpi::Now());
+}
+
+namespace cs {
+CS_Source CreateRawSource(const wpi::Twine& name, const VideoMode& mode,
+ CS_Status* status) {
+ auto& inst = Instance::GetInstance();
+ return inst.CreateSource(CS_SOURCE_RAW, std::make_shared<RawSourceImpl>(
+ name, inst.logger, inst.notifier,
+ inst.telemetry, mode));
+}
+
+void PutSourceFrame(CS_Source source, const CS_RawFrame& image,
+ CS_Status* status) {
+ auto data = Instance::GetInstance().GetSource(source);
+ if (!data || data->kind != CS_SOURCE_RAW) {
+ *status = CS_INVALID_HANDLE;
+ return;
+ }
+ static_cast<RawSourceImpl&>(*data->source).PutFrame(image);
+}
+} // namespace cs
+
+extern "C" {
+CS_Source CS_CreateRawSource(const char* name, const CS_VideoMode* mode,
+ CS_Status* status) {
+ return cs::CreateRawSource(name, static_cast<const cs::VideoMode&>(*mode),
+ status);
+}
+
+void CS_PutRawSourceFrame(CS_Source source, const struct CS_RawFrame* image,
+ CS_Status* status) {
+ return cs::PutSourceFrame(source, *image, status);
+}
+} // extern "C"
diff --git a/cscore/src/main/native/cpp/RawSourceImpl.h b/cscore/src/main/native/cpp/RawSourceImpl.h
new file mode 100644
index 0000000..1fdc749
--- /dev/null
+++ b/cscore/src/main/native/cpp/RawSourceImpl.h
@@ -0,0 +1,41 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#ifndef CSCORE_RAWSOURCEIMPL_H_
+#define CSCORE_RAWSOURCEIMPL_H_
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <wpi/ArrayRef.h>
+#include <wpi/Twine.h>
+
+#include "ConfigurableSourceImpl.h"
+#include "SourceImpl.h"
+#include "cscore_raw.h"
+
+namespace cs {
+
+class RawSourceImpl : public ConfigurableSourceImpl {
+ public:
+ RawSourceImpl(const wpi::Twine& name, wpi::Logger& logger, Notifier& notifier,
+ Telemetry& telemetry, const VideoMode& mode);
+ ~RawSourceImpl() override;
+
+ // Raw-specific functions
+ void PutFrame(const CS_RawFrame& image);
+
+ private:
+ std::atomic_bool m_connected{true};
+};
+
+} // namespace cs
+
+#endif // CSCORE_RAWSOURCEIMPL_H_
diff --git a/cscore/src/main/native/cpp/SinkImpl.cpp b/cscore/src/main/native/cpp/SinkImpl.cpp
index 637b407..5d4235a 100644
--- a/cscore/src/main/native/cpp/SinkImpl.cpp
+++ b/cscore/src/main/native/cpp/SinkImpl.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -30,18 +30,18 @@
}
void SinkImpl::SetDescription(const wpi::Twine& description) {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_description = description.str();
}
wpi::StringRef SinkImpl::GetDescription(wpi::SmallVectorImpl<char>& buf) const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
buf.append(m_description.begin(), m_description.end());
return wpi::StringRef{buf.data(), buf.size()};
}
void SinkImpl::Enable() {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
++m_enabledCount;
if (m_enabledCount == 1) {
if (m_source) m_source->EnableSink();
@@ -50,7 +50,7 @@
}
void SinkImpl::Disable() {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
--m_enabledCount;
if (m_enabledCount == 0) {
if (m_source) m_source->DisableSink();
@@ -59,7 +59,7 @@
}
void SinkImpl::SetEnabled(bool enabled) {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (enabled && m_enabledCount == 0) {
if (m_source) m_source->EnableSink();
m_enabledCount = 1;
@@ -73,7 +73,7 @@
void SinkImpl::SetSource(std::shared_ptr<SourceImpl> source) {
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (m_source == source) return;
if (m_source) {
if (m_enabledCount > 0) m_source->DisableSink();
@@ -89,13 +89,13 @@
}
std::string SinkImpl::GetError() const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (!m_source) return "no source connected";
return m_source->GetCurFrame().GetError();
}
wpi::StringRef SinkImpl::GetError(wpi::SmallVectorImpl<char>& buf) const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
if (!m_source) return "no source connected";
// Make a copy as it's shared data
wpi::StringRef error = m_source->GetCurFrame().GetError();
diff --git a/cscore/src/main/native/cpp/SinkImpl.h b/cscore/src/main/native/cpp/SinkImpl.h
index 147268f..7ad831f 100644
--- a/cscore/src/main/native/cpp/SinkImpl.h
+++ b/cscore/src/main/native/cpp/SinkImpl.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -48,7 +48,7 @@
void SetSource(std::shared_ptr<SourceImpl> source);
std::shared_ptr<SourceImpl> GetSource() const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
return m_source;
}
diff --git a/cscore/src/main/native/cpp/SourceImpl.cpp b/cscore/src/main/native/cpp/SourceImpl.cpp
index e646eb6..455b6cd 100644
--- a/cscore/src/main/native/cpp/SourceImpl.cpp
+++ b/cscore/src/main/native/cpp/SourceImpl.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -10,7 +10,6 @@
#include <algorithm>
#include <cstring>
-#include <wpi/STLExtras.h>
#include <wpi/json.h>
#include <wpi/timestamp.h>
@@ -45,13 +44,13 @@
}
void SourceImpl::SetDescription(const wpi::Twine& description) {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_description = description.str();
}
wpi::StringRef SourceImpl::GetDescription(
wpi::SmallVectorImpl<char>& buf) const {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
buf.append(m_description.begin(), m_description.end());
return wpi::StringRef{buf.data(), buf.size()};
}
@@ -65,24 +64,24 @@
}
uint64_t SourceImpl::GetCurFrameTime() {
- std::unique_lock<wpi::mutex> lock{m_frameMutex};
+ std::unique_lock lock{m_frameMutex};
return m_frame.GetTime();
}
Frame SourceImpl::GetCurFrame() {
- std::unique_lock<wpi::mutex> lock{m_frameMutex};
+ std::unique_lock lock{m_frameMutex};
return m_frame;
}
Frame SourceImpl::GetNextFrame() {
- std::unique_lock<wpi::mutex> lock{m_frameMutex};
+ std::unique_lock lock{m_frameMutex};
auto oldTime = m_frame.GetTime();
m_frameCv.wait(lock, [=] { return m_frame.GetTime() != oldTime; });
return m_frame;
}
Frame SourceImpl::GetNextFrame(double timeout) {
- std::unique_lock<wpi::mutex> lock{m_frameMutex};
+ std::unique_lock lock{m_frameMutex};
auto oldTime = m_frame.GetTime();
if (!m_frameCv.wait_for(
lock, std::chrono::milliseconds(static_cast<int>(timeout * 1000)),
@@ -94,7 +93,7 @@
void SourceImpl::Wakeup() {
{
- std::lock_guard<wpi::mutex> lock{m_frameMutex};
+ std::scoped_lock lock{m_frameMutex};
m_frame = Frame{*this, wpi::StringRef{}, 0};
}
m_frameCv.notify_all();
@@ -135,7 +134,7 @@
VideoMode SourceImpl::GetVideoMode(CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status)) return VideoMode{};
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
return m_mode;
}
@@ -381,7 +380,7 @@
CS_Status* status) const {
if (!m_properties_cached && !CacheProperties(status))
return std::vector<VideoMode>{};
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
return m_videoModes;
}
@@ -389,7 +388,7 @@
VideoMode::PixelFormat pixelFormat, int width, int height, size_t size) {
std::unique_ptr<Image> image;
{
- std::lock_guard<wpi::mutex> lock{m_poolMutex};
+ std::scoped_lock lock{m_poolMutex};
// find the smallest existing frame that is at least big enough.
int found = -1;
for (size_t i = 0; i < m_imagesAvail.size(); ++i) {
@@ -441,7 +440,7 @@
// Update frame
{
- std::lock_guard<wpi::mutex> lock{m_frameMutex};
+ std::scoped_lock lock{m_frameMutex};
m_frame = Frame{*this, std::move(image), time};
}
@@ -452,7 +451,7 @@
void SourceImpl::PutError(const wpi::Twine& msg, Frame::Time time) {
// Update frame
{
- std::lock_guard<wpi::mutex> lock{m_frameMutex};
+ std::scoped_lock lock{m_frameMutex};
m_frame = Frame{*this, msg, time};
}
@@ -490,7 +489,7 @@
}
void SourceImpl::ReleaseImage(std::unique_ptr<Image> image) {
- std::lock_guard<wpi::mutex> lock{m_poolMutex};
+ std::scoped_lock lock{m_poolMutex};
if (m_destroyFrames) return;
// Return the frame to the pool. First try to find an empty slot, otherwise
// add it to the end.
@@ -512,9 +511,9 @@
}
std::unique_ptr<Frame::Impl> SourceImpl::AllocFrameImpl() {
- std::lock_guard<wpi::mutex> lock{m_poolMutex};
+ std::scoped_lock lock{m_poolMutex};
- if (m_framesAvail.empty()) return wpi::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();
@@ -522,7 +521,7 @@
}
void SourceImpl::ReleaseFrameImpl(std::unique_ptr<Frame::Impl> impl) {
- std::lock_guard<wpi::mutex> lock{m_poolMutex};
+ std::scoped_lock lock{m_poolMutex};
if (m_destroyFrames) return;
m_framesAvail.push_back(std::move(impl));
}
diff --git a/cscore/src/main/native/cpp/Telemetry.cpp b/cscore/src/main/native/cpp/Telemetry.cpp
index fa6c93c..77130f6 100644
--- a/cscore/src/main/native/cpp/Telemetry.cpp
+++ b/cscore/src/main/native/cpp/Telemetry.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -53,7 +53,7 @@
void Telemetry::Stop() { m_owner.Stop(); }
void Telemetry::Thread::Main() {
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
auto prevTime = std::chrono::steady_clock::now();
while (m_active) {
double period = m_period;
diff --git a/cscore/src/main/native/cpp/UnlimitedHandleResource.h b/cscore/src/main/native/cpp/UnlimitedHandleResource.h
index c297cfa..6c9a538 100644
--- a/cscore/src/main/native/cpp/UnlimitedHandleResource.h
+++ b/cscore/src/main/native/cpp/UnlimitedHandleResource.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -78,7 +78,7 @@
template <typename... Args>
THandle UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Allocate(
Args&&... args) {
- std::lock_guard<TMutex> sync(m_handleMutex);
+ std::scoped_lock sync(m_handleMutex);
size_t i;
for (i = 0; i < m_structures.size(); i++) {
if (m_structures[i] == nullptr) {
@@ -96,7 +96,7 @@
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
THandle UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::Allocate(
std::shared_ptr<THandle> structure) {
- std::lock_guard<TMutex> sync(m_handleMutex);
+ std::scoped_lock sync(m_handleMutex);
size_t i;
for (i = 0; i < m_structures.size(); i++) {
if (m_structures[i] == nullptr) {
@@ -117,7 +117,7 @@
auto index =
handle.GetTypedIndex(static_cast<typename THandle::Type>(typeValue));
if (index < 0) return nullptr;
- std::lock_guard<TMutex> sync(m_handleMutex);
+ std::scoped_lock sync(m_handleMutex);
if (index >= static_cast<int>(m_structures.size())) return nullptr;
return m_structures[index];
}
@@ -129,7 +129,7 @@
auto index =
handle.GetTypedIndex(static_cast<typename THandle::Type>(typeValue));
if (index < 0) return nullptr;
- std::lock_guard<TMutex> sync(m_handleMutex);
+ std::scoped_lock sync(m_handleMutex);
if (index >= static_cast<int>(m_structures.size())) return nullptr;
auto rv = std::move(m_structures[index]);
m_structures[index].reset();
@@ -148,7 +148,7 @@
template <typename THandle, typename TStruct, int typeValue, typename TMutex>
inline std::vector<std::shared_ptr<TStruct>>
UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::FreeAll() {
- std::lock_guard<TMutex> sync(m_handleMutex);
+ std::scoped_lock sync(m_handleMutex);
auto rv = std::move(m_structures);
m_structures.clear();
return rv;
@@ -158,7 +158,7 @@
template <typename F>
inline void
UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::ForEach(F func) {
- std::lock_guard<TMutex> sync(m_handleMutex);
+ 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]));
}
@@ -168,7 +168,7 @@
template <typename F>
inline std::pair<THandle, std::shared_ptr<TStruct>>
UnlimitedHandleResource<THandle, TStruct, typeValue, TMutex>::FindIf(F func) {
- std::lock_guard<TMutex> sync(m_handleMutex);
+ 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))
diff --git a/cscore/src/main/native/cpp/UsbCameraImplCommon.cpp b/cscore/src/main/native/cpp/UsbCameraImplCommon.cpp
index 082e398..2b3fb08 100644
--- a/cscore/src/main/native/cpp/UsbCameraImplCommon.cpp
+++ b/cscore/src/main/native/cpp/UsbCameraImplCommon.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -17,10 +17,12 @@
out->path = ConvertToC(in.path);
out->name = ConvertToC(in.name);
out->otherPaths = static_cast<char**>(
- wpi::CheckedMalloc(in.otherPaths.size() * sizeof(char*)));
+ wpi::safe_malloc(in.otherPaths.size() * sizeof(char*)));
out->otherPathsCount = in.otherPaths.size();
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;
}
static void FreeUsbCameraInfo(CS_UsbCameraInfo* info) {
@@ -50,7 +52,7 @@
auto info = cs::GetUsbCameraInfo(source, status);
if (*status != CS_OK) return nullptr;
CS_UsbCameraInfo* out = static_cast<CS_UsbCameraInfo*>(
- wpi::CheckedMalloc(sizeof(CS_UsbCameraInfo)));
+ wpi::safe_malloc(sizeof(CS_UsbCameraInfo)));
ConvertToC(out, info);
return out;
}
@@ -58,7 +60,7 @@
CS_UsbCameraInfo* CS_EnumerateUsbCameras(int* count, CS_Status* status) {
auto cameras = cs::EnumerateUsbCameras(status);
CS_UsbCameraInfo* out = static_cast<CS_UsbCameraInfo*>(
- wpi::CheckedMalloc(cameras.size() * sizeof(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]);
return out;
diff --git a/cscore/src/main/native/cpp/c_util.h b/cscore/src/main/native/cpp/c_util.h
index 6264e1f..f985fe2 100644
--- a/cscore/src/main/native/cpp/c_util.h
+++ b/cscore/src/main/native/cpp/c_util.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -11,13 +11,13 @@
#include <cstdlib>
#include <cstring>
+#include <wpi/MemAlloc.h>
#include <wpi/StringRef.h>
-#include <wpi/memory.h>
namespace cs {
inline char* ConvertToC(wpi::StringRef in) {
- char* out = static_cast<char*>(wpi::CheckedMalloc(in.size() + 1));
+ char* out = static_cast<char*>(wpi::safe_malloc(in.size() + 1));
std::memmove(out, in.data(), in.size());
out[in.size()] = '\0';
return out;
diff --git a/cscore/src/main/native/cpp/cscore_c.cpp b/cscore/src/main/native/cpp/cscore_c.cpp
index 1819d13..321572e 100644
--- a/cscore/src/main/native/cpp/cscore_c.cpp
+++ b/cscore/src/main/native/cpp/cscore_c.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -11,11 +11,12 @@
#include <cstdlib>
#include <opencv2/core/core.hpp>
+#include <wpi/MemAlloc.h>
#include <wpi/SmallString.h>
-#include <wpi/memory.h>
#include "c_util.h"
#include "cscore_cpp.h"
+#include "cscore_raw.h"
extern "C" {
@@ -70,7 +71,7 @@
CS_Status* status) {
auto choices = cs::GetEnumPropertyChoices(property, status);
char** out =
- static_cast<char**>(wpi::CheckedMalloc(choices.size() * sizeof(char*)));
+ static_cast<char**>(wpi::safe_malloc(choices.size() * sizeof(char*)));
*count = choices.size();
for (size_t i = 0; i < choices.size(); ++i)
out[i] = cs::ConvertToC(choices[i]);
@@ -123,7 +124,7 @@
wpi::SmallVector<CS_Property, 32> buf;
auto vec = cs::EnumerateSourceProperties(source, buf, status);
CS_Property* out = static_cast<CS_Property*>(
- wpi::CheckedMalloc(vec.size() * sizeof(CS_Property)));
+ wpi::safe_malloc(vec.size() * sizeof(CS_Property)));
*count = vec.size();
std::copy(vec.begin(), vec.end(), out);
return out;
@@ -183,7 +184,7 @@
CS_Status* status) {
auto vec = cs::EnumerateSourceVideoModes(source, status);
CS_VideoMode* out = static_cast<CS_VideoMode*>(
- wpi::CheckedMalloc(vec.size() * sizeof(CS_VideoMode)));
+ wpi::safe_malloc(vec.size() * sizeof(CS_VideoMode)));
*count = vec.size();
std::copy(vec.begin(), vec.end(), out);
return out;
@@ -193,8 +194,8 @@
CS_Status* status) {
wpi::SmallVector<CS_Sink, 32> buf;
auto handles = cs::EnumerateSourceSinks(source, buf, status);
- CS_Sink* sinks = static_cast<CS_Sink*>(
- wpi::CheckedMalloc(handles.size() * sizeof(CS_Sink)));
+ CS_Sink* sinks =
+ static_cast<CS_Sink*>(wpi::safe_malloc(handles.size() * sizeof(CS_Sink)));
*count = handles.size();
std::copy(handles.begin(), handles.end(), sinks);
return sinks;
@@ -271,7 +272,7 @@
wpi::SmallVector<CS_Property, 32> buf;
auto vec = cs::EnumerateSinkProperties(sink, buf, status);
CS_Property* out = static_cast<CS_Property*>(
- wpi::CheckedMalloc(vec.size() * sizeof(CS_Property)));
+ wpi::safe_malloc(vec.size() * sizeof(CS_Property)));
*count = vec.size();
std::copy(vec.begin(), vec.end(), out);
return out;
@@ -372,7 +373,7 @@
wpi::SmallVector<CS_Source, 32> buf;
auto handles = cs::EnumerateSourceHandles(buf, status);
CS_Source* sources = static_cast<CS_Source*>(
- wpi::CheckedMalloc(handles.size() * sizeof(CS_Source)));
+ wpi::safe_malloc(handles.size() * sizeof(CS_Source)));
*count = handles.size();
std::copy(handles.begin(), handles.end(), sources);
return sources;
@@ -390,8 +391,8 @@
CS_Sink* CS_EnumerateSinks(int* count, CS_Status* status) {
wpi::SmallVector<CS_Sink, 32> buf;
auto handles = cs::EnumerateSinkHandles(buf, status);
- CS_Sink* sinks = static_cast<CS_Sink*>(
- wpi::CheckedMalloc(handles.size() * sizeof(CS_Sink)));
+ CS_Sink* sinks =
+ static_cast<CS_Sink*>(wpi::safe_malloc(handles.size() * sizeof(CS_Sink)));
*count = handles.size();
std::copy(handles.begin(), handles.end(), sinks);
return sinks;
@@ -426,8 +427,8 @@
char** CS_GetNetworkInterfaces(int* count) {
auto interfaces = cs::GetNetworkInterfaces();
- char** out = static_cast<char**>(
- wpi::CheckedMalloc(interfaces.size() * sizeof(char*)));
+ char** out =
+ static_cast<char**>(wpi::safe_malloc(interfaces.size() * sizeof(char*)));
*count = interfaces.size();
for (size_t i = 0; i < interfaces.size(); ++i)
out[i] = cs::ConvertToC(interfaces[i]);
@@ -440,4 +441,23 @@
std::free(interfaces);
}
+void CS_AllocateRawFrameData(CS_RawFrame* frame, int requestedSize) {
+ if (frame->dataLength >= requestedSize) return;
+ if (frame->data) {
+ frame->data =
+ static_cast<char*>(wpi::safe_realloc(frame->data, requestedSize));
+ } else {
+ frame->data = static_cast<char*>(wpi::safe_malloc(requestedSize));
+ }
+ frame->dataLength = requestedSize;
+}
+
+void CS_FreeRawFrameData(CS_RawFrame* frame) {
+ if (frame->data) {
+ std::free(frame->data);
+ frame->data = nullptr;
+ frame->dataLength = 0;
+ }
+}
+
} // extern "C"
diff --git a/cscore/src/main/native/cpp/cscore_cpp.cpp b/cscore/src/main/native/cpp/cscore_cpp.cpp
index 83b4e87..d49fb04 100644
--- a/cscore/src/main/native/cpp/cscore_cpp.cpp
+++ b/cscore/src/main/native/cpp/cscore_cpp.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/cscore/src/main/native/cpp/cscore_oo.cpp b/cscore/src/main/native/cpp/cscore_oo.cpp
index f455273..f42ed5a 100644
--- a/cscore/src/main/native/cpp/cscore_oo.cpp
+++ b/cscore/src/main/native/cpp/cscore_oo.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp b/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp
index 528d5e4..c50a7db 100644
--- a/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp
+++ b/cscore/src/main/native/cpp/jni/CameraServerJNI.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -10,8 +10,14 @@
#include <wpi/raw_ostream.h>
#include "cscore_cpp.h"
+#include "cscore_cv.h"
+#include "cscore_raw.h"
#include "edu_wpi_cscore_CameraServerJNI.h"
+namespace cv {
+class Mat;
+} // namespace cv
+
using namespace wpi::java;
//
@@ -23,6 +29,7 @@
static JClass usbCameraInfoCls;
static JClass videoModeCls;
static JClass videoEventCls;
+static JClass rawFrameCls;
static JException videoEx;
static JException nullPointerEx;
static JException unsupportedEx;
@@ -32,7 +39,8 @@
static const JClassInit classes[] = {
{"edu/wpi/cscore/UsbCameraInfo", &usbCameraInfoCls},
{"edu/wpi/cscore/VideoMode", &videoModeCls},
- {"edu/wpi/cscore/VideoEvent", &videoEventCls}};
+ {"edu/wpi/cscore/VideoEvent", &videoEventCls},
+ {"edu/wpi/cscore/raw/RawFrame", &rawFrameCls}};
static const JExceptionInit exceptions[] = {
{"edu/wpi/cscore/VideoException", &videoEx},
@@ -186,13 +194,14 @@
static jobject MakeJObject(JNIEnv* env, const cs::UsbCameraInfo& info) {
static jmethodID constructor = env->GetMethodID(
usbCameraInfoCls, "<init>",
- "(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V");
+ "(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;II)V");
JLocal<jstring> path(env, MakeJString(env, info.path));
JLocal<jstring> name(env, MakeJString(env, info.name));
JLocal<jobjectArray> otherPaths(env, MakeJStringArray(env, info.otherPaths));
return env->NewObject(usbCameraInfoCls, constructor,
static_cast<jint>(info.dev), path.obj(), name.obj(),
- otherPaths.obj());
+ otherPaths.obj(), static_cast<jint>(info.vendorId),
+ static_cast<jint>(info.productId));
}
static jobject MakeJObject(JNIEnv* env, const cs::VideoMode& videoMode) {
@@ -506,12 +515,12 @@
}
/*
- * Class: edu_wpi_cscore_CameraServerJNI
+ * Class: edu_wpi_cscore_CameraServerCvJNI
* Method: createCvSource
* Signature: (Ljava/lang/String;IIII)I
*/
JNIEXPORT jint JNICALL
-Java_edu_wpi_cscore_CameraServerJNI_createCvSource
+Java_edu_wpi_cscore_CameraServerCvJNI_createCvSource
(JNIEnv* env, jclass, jstring name, jint pixelFormat, jint width, jint height,
jint fps)
{
@@ -532,6 +541,31 @@
/*
* Class: edu_wpi_cscore_CameraServerJNI
+ * Method: createRawSource
+ * Signature: (Ljava/lang/String;IIII)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_cscore_CameraServerJNI_createRawSource
+ (JNIEnv* env, jclass, jstring name, jint pixelFormat, jint width, jint height,
+ jint fps)
+{
+ if (!name) {
+ nullPointerEx.Throw(env, "name cannot be null");
+ return 0;
+ }
+ CS_Status status = 0;
+ auto val = cs::CreateRawSource(
+ JStringRef{env, name}.str(),
+ cs::VideoMode{static_cast<cs::VideoMode::PixelFormat>(pixelFormat),
+ static_cast<int>(width), static_cast<int>(height),
+ static_cast<int>(fps)},
+ &status);
+ CheckStatus(env, status);
+ return val;
+}
+
+/*
+ * Class: edu_wpi_cscore_CameraServerJNI
* Method: getSourceKind
* Signature: (I)I
*/
@@ -1054,12 +1088,12 @@
}
/*
- * Class: edu_wpi_cscore_CameraServerJNI
+ * Class: edu_wpi_cscore_CameraServerCvJNI
* Method: putSourceFrame
* Signature: (IJ)V
*/
JNIEXPORT void JNICALL
-Java_edu_wpi_cscore_CameraServerJNI_putSourceFrame
+Java_edu_wpi_cscore_CameraServerCvJNI_putSourceFrame
(JNIEnv* env, jclass, jint source, jlong imageNativeObj)
{
cv::Mat& image = *((cv::Mat*)imageNativeObj);
@@ -1068,6 +1102,51 @@
CheckStatus(env, status);
}
+// int width, int height, int pixelFormat, int totalData
+
+/*
+ * Class: edu_wpi_cscore_CameraServerJNI
+ * Method: putRawSourceFrameBB
+ * Signature: (ILjava/lang/Object;IIII)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_cscore_CameraServerJNI_putRawSourceFrameBB
+ (JNIEnv* env, jclass, jint source, jobject byteBuffer, jint width,
+ jint height, jint pixelFormat, jint totalData)
+{
+ CS_RawFrame rawFrame;
+ rawFrame.data =
+ reinterpret_cast<char*>(env->GetDirectBufferAddress(byteBuffer));
+ rawFrame.totalData = totalData;
+ rawFrame.pixelFormat = pixelFormat;
+ rawFrame.width = width;
+ rawFrame.height = height;
+ CS_Status status = 0;
+ cs::PutSourceFrame(source, rawFrame, &status);
+ CheckStatus(env, status);
+}
+
+/*
+ * Class: edu_wpi_cscore_CameraServerJNI
+ * Method: putRawSourceFrame
+ * Signature: (IJIIII)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_cscore_CameraServerJNI_putRawSourceFrame
+ (JNIEnv* env, jclass, jint source, jlong ptr, jint width, jint height,
+ jint pixelFormat, jint totalData)
+{
+ CS_RawFrame rawFrame;
+ rawFrame.data = reinterpret_cast<char*>(static_cast<intptr_t>(ptr));
+ rawFrame.totalData = totalData;
+ rawFrame.pixelFormat = pixelFormat;
+ rawFrame.width = width;
+ rawFrame.height = height;
+ CS_Status status = 0;
+ cs::PutSourceFrame(source, rawFrame, &status);
+ CheckStatus(env, status);
+}
+
/*
* Class: edu_wpi_cscore_CameraServerJNI
* Method: notifySourceError
@@ -1192,12 +1271,12 @@
}
/*
- * Class: edu_wpi_cscore_CameraServerJNI
+ * Class: edu_wpi_cscore_CameraServerCvJNI
* Method: createCvSink
* Signature: (Ljava/lang/String;)I
*/
JNIEXPORT jint JNICALL
-Java_edu_wpi_cscore_CameraServerJNI_createCvSink
+Java_edu_wpi_cscore_CameraServerCvJNI_createCvSink
(JNIEnv* env, jclass, jstring name)
{
if (!name) {
@@ -1212,6 +1291,25 @@
/*
* Class: edu_wpi_cscore_CameraServerJNI
+ * Method: createRawSink
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_cscore_CameraServerJNI_createRawSink
+ (JNIEnv* env, jclass, jstring name)
+{
+ if (!name) {
+ nullPointerEx.Throw(env, "name cannot be null");
+ return 0;
+ }
+ CS_Status status = 0;
+ auto val = cs::CreateRawSink(JStringRef{env, name}.str(), &status);
+ CheckStatus(env, status);
+ return val;
+}
+
+/*
+ * Class: edu_wpi_cscore_CameraServerJNI
* Method: getSinkKind
* Signature: (I)I
*/
@@ -1449,12 +1547,12 @@
}
/*
- * Class: edu_wpi_cscore_CameraServerJNI
+ * Class: edu_wpi_cscore_CameraServerCvJNI
* Method: grabSinkFrame
* Signature: (IJ)J
*/
JNIEXPORT jlong JNICALL
-Java_edu_wpi_cscore_CameraServerJNI_grabSinkFrame
+Java_edu_wpi_cscore_CameraServerCvJNI_grabSinkFrame
(JNIEnv* env, jclass, jint sink, jlong imageNativeObj)
{
cv::Mat& image = *((cv::Mat*)imageNativeObj);
@@ -1465,12 +1563,12 @@
}
/*
- * Class: edu_wpi_cscore_CameraServerJNI
+ * Class: edu_wpi_cscore_CameraServerCvJNI
* Method: grabSinkFrameTimeout
* Signature: (IJD)J
*/
JNIEXPORT jlong JNICALL
-Java_edu_wpi_cscore_CameraServerJNI_grabSinkFrameTimeout
+Java_edu_wpi_cscore_CameraServerCvJNI_grabSinkFrameTimeout
(JNIEnv* env, jclass, jint sink, jlong imageNativeObj, jdouble timeout)
{
cv::Mat& image = *((cv::Mat*)imageNativeObj);
@@ -1480,6 +1578,75 @@
return rv;
}
+static void SetRawFrameData(JNIEnv* env, jobject rawFrameObj,
+ jobject byteBuffer, bool didChangeDataPtr,
+ const CS_RawFrame& frame) {
+ static jmethodID setMethod =
+ env->GetMethodID(rawFrameCls, "setData", "(Ljava/nio/ByteBuffer;JIIII)V");
+ jlong framePtr = static_cast<jlong>(reinterpret_cast<intptr_t>(frame.data));
+
+ if (didChangeDataPtr) {
+ byteBuffer = env->NewDirectByteBuffer(frame.data, frame.dataLength);
+ }
+
+ env->CallVoidMethod(
+ rawFrameObj, setMethod, byteBuffer, framePtr,
+ static_cast<jint>(frame.totalData), static_cast<jint>(frame.width),
+ static_cast<jint>(frame.height), static_cast<jint>(frame.pixelFormat));
+}
+
+/*
+ * Class: edu_wpi_cscore_CameraServerJNI
+ * Method: grabRawSinkFrameImpl
+ * Signature: (ILjava/lang/Object;JLjava/lang/Object;III)J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_cscore_CameraServerJNI_grabRawSinkFrameImpl
+ (JNIEnv* env, jclass, jint sink, jobject rawFrameObj, jlong rawFramePtr,
+ jobject byteBuffer, jint width, jint height, jint pixelFormat)
+{
+ CS_RawFrame* ptr =
+ reinterpret_cast<CS_RawFrame*>(static_cast<intptr_t>(rawFramePtr));
+ auto origDataPtr = ptr->data;
+ ptr->width = width;
+ ptr->height = height;
+ ptr->pixelFormat = pixelFormat;
+ CS_Status status = 0;
+ auto rv = cs::GrabSinkFrame(static_cast<CS_Sink>(sink), *ptr, &status);
+ if (!CheckStatus(env, status)) {
+ return 0;
+ }
+ SetRawFrameData(env, rawFrameObj, byteBuffer, origDataPtr != ptr->data, *ptr);
+ return rv;
+}
+
+/*
+ * Class: edu_wpi_cscore_CameraServerJNI
+ * Method: grabRawSinkFrameTimeoutImpl
+ * Signature: (ILjava/lang/Object;JLjava/lang/Object;IIID)J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_cscore_CameraServerJNI_grabRawSinkFrameTimeoutImpl
+ (JNIEnv* env, jclass, jint sink, jobject rawFrameObj, jlong rawFramePtr,
+ jobject byteBuffer, jint width, jint height, jint pixelFormat,
+ jdouble timeout)
+{
+ CS_RawFrame* ptr =
+ reinterpret_cast<CS_RawFrame*>(static_cast<intptr_t>(rawFramePtr));
+ auto origDataPtr = ptr->data;
+ ptr->width = width;
+ ptr->height = height;
+ ptr->pixelFormat = pixelFormat;
+ CS_Status status = 0;
+ auto rv = cs::GrabSinkFrameTimeout(static_cast<CS_Sink>(sink), *ptr, timeout,
+ &status);
+ if (!CheckStatus(env, status)) {
+ return 0;
+ }
+ SetRawFrameData(env, rawFrameObj, byteBuffer, origDataPtr != ptr->data, *ptr);
+ return rv;
+}
+
/*
* Class: edu_wpi_cscore_CameraServerJNI
* Method: getSinkError
@@ -1781,4 +1948,32 @@
minLevel);
}
+/*
+ * Class: edu_wpi_cscore_CameraServerJNI
+ * Method: allocateRawFrame
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_cscore_CameraServerJNI_allocateRawFrame
+ (JNIEnv*, jclass)
+{
+ cs::RawFrame* rawFrame = new cs::RawFrame{};
+ intptr_t rawFrameIntPtr = reinterpret_cast<intptr_t>(rawFrame);
+ return static_cast<jlong>(rawFrameIntPtr);
+}
+
+/*
+ * Class: edu_wpi_cscore_CameraServerJNI
+ * Method: freeRawFrame
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_cscore_CameraServerJNI_freeRawFrame
+ (JNIEnv*, jclass, jlong rawFrame)
+{
+ cs::RawFrame* ptr =
+ reinterpret_cast<cs::RawFrame*>(static_cast<intptr_t>(rawFrame));
+ delete ptr;
+}
+
} // extern "C"
diff --git a/cscore/src/main/native/include/cscore_c.h b/cscore/src/main/native/include/cscore_c.h
index 182b9b2..24e30b4 100644
--- a/cscore/src/main/native/include/cscore_c.h
+++ b/cscore/src/main/native/include/cscore_c.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -20,8 +20,6 @@
extern "C" {
#endif
-struct CvMat;
-
/**
* @defgroup cscore_c_api cscore C API
*
@@ -128,7 +126,8 @@
CS_SOURCE_UNKNOWN = 0,
CS_SOURCE_USB = 1,
CS_SOURCE_HTTP = 2,
- CS_SOURCE_CV = 4
+ CS_SOURCE_CV = 4,
+ CS_SOURCE_RAW = 8,
};
/**
@@ -144,7 +143,12 @@
/**
* Sink kinds
*/
-enum CS_SinkKind { CS_SINK_UNKNOWN = 0, CS_SINK_MJPEG = 2, CS_SINK_CV = 4 };
+enum CS_SinkKind {
+ CS_SINK_UNKNOWN = 0,
+ CS_SINK_MJPEG = 2,
+ CS_SINK_CV = 4,
+ CS_SINK_RAW = 8
+};
/**
* Listener event kinds
@@ -232,6 +236,8 @@
char* name;
int otherPathsCount;
char** otherPaths;
+ int vendorId;
+ int productId;
} CS_UsbCameraInfo;
/**
@@ -351,8 +357,6 @@
* @defgroup cscore_opencv_source_cfunc OpenCV Source Functions
* @{
*/
-void CS_PutSourceFrame(CS_Source source, struct CvMat* image,
- CS_Status* status);
void CS_NotifySourceError(CS_Source source, const char* msg, CS_Status* status);
void CS_SetSourceConnected(CS_Source source, CS_Bool connected,
CS_Status* status);
@@ -415,9 +419,6 @@
*/
void CS_SetSinkDescription(CS_Sink sink, const char* description,
CS_Status* status);
-uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image, CS_Status* status);
-uint64_t CS_GrabSinkFrameTimeout(CS_Sink sink, struct CvMat* image,
- double timeout, CS_Status* status);
char* CS_GetSinkError(CS_Sink sink, CS_Status* status);
void CS_SetSinkEnabled(CS_Sink sink, CS_Bool enabled, CS_Status* status);
/** @} */
diff --git a/cscore/src/main/native/include/cscore_cpp.h b/cscore/src/main/native/include/cscore_cpp.h
index a400b78..c1ec024 100644
--- a/cscore/src/main/native/include/cscore_cpp.h
+++ b/cscore/src/main/native/include/cscore_cpp.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -21,9 +21,11 @@
#include "cscore_c.h"
-namespace cv {
-class Mat;
-} // namespace cv
+#ifdef _WIN32
+// Disable uninitialized variable warnings
+#pragma warning(push)
+#pragma warning(disable : 26495)
+#endif
namespace wpi {
class json;
@@ -54,6 +56,10 @@
std::string name;
/** Other path aliases to device (e.g. '/dev/v4l/by-id/...' etc on Linux) */
std::vector<std::string> otherPaths;
+ /** USB Vendor Id */
+ int vendorId = -1;
+ /** USB Product Id */
+ int productId = -1;
};
/**
@@ -286,7 +292,6 @@
* @defgroup cscore_opencv_source_func OpenCV Source Functions
* @{
*/
-void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status);
void NotifySourceError(CS_Source source, const wpi::Twine& msg,
CS_Status* status);
void SetSourceConnected(CS_Source source, bool connected, CS_Status* status);
@@ -312,6 +317,7 @@
CS_Sink CreateCvSinkCallback(const wpi::Twine& name,
std::function<void(uint64_t time)> processFrame,
CS_Status* status);
+
/** @} */
/**
@@ -356,9 +362,6 @@
*/
void SetSinkDescription(CS_Sink sink, const wpi::Twine& description,
CS_Status* status);
-uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status);
-uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
- CS_Status* status);
std::string GetSinkError(CS_Sink sink, CS_Status* status);
wpi::StringRef GetSinkError(CS_Sink sink, wpi::SmallVectorImpl<char>& buf,
CS_Status* status);
@@ -429,18 +432,9 @@
} // namespace cs
-/**
- * @defgroup cscore_cpp_opencv_special cscore C functions taking a cv::Mat*
- *
- * These are needed for specific interop implementations.
- * @{
- */
-extern "C" {
-uint64_t CS_GrabSinkFrameCpp(CS_Sink sink, cv::Mat* image, CS_Status* status);
-uint64_t CS_GrabSinkFrameTimeoutCpp(CS_Sink sink, cv::Mat* image,
- double timeout, CS_Status* status);
-void CS_PutSourceFrameCpp(CS_Source source, cv::Mat* image, CS_Status* status);
-} // extern "C"
-/** @} */
+#ifdef _WIN32
+// Disable uninitialized variable warnings
+#pragma warning(pop)
+#endif
#endif // CSCORE_CSCORE_CPP_H_
diff --git a/cscore/src/main/native/include/cscore_cv.h b/cscore/src/main/native/include/cscore_cv.h
new file mode 100644
index 0000000..650399b
--- /dev/null
+++ b/cscore/src/main/native/include/cscore_cv.h
@@ -0,0 +1,209 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#ifndef CSCORE_CSCORE_CV_H_
+#define CSCORE_CSCORE_CV_H_
+
+#include "cscore_c.h"
+
+#ifdef CSCORE_CSCORE_RAW_CV_H_
+#error "Cannot include both cscore_cv.h and cscore_raw_cv.h in the same file"
+#endif
+
+#ifdef __cplusplus
+#include "cscore_oo.h" // NOLINT(build/include_order)
+
+#endif
+
+#if CV_VERSION_MAJOR < 4
+
+#ifdef __cplusplus
+extern "C" { // NOLINT(build/include_order)
+#endif
+
+struct CvMat;
+
+void CS_PutSourceFrame(CS_Source source, struct CvMat* image,
+ CS_Status* status);
+
+uint64_t CS_GrabSinkFrame(CS_Sink sink, struct CvMat* image, CS_Status* status);
+uint64_t CS_GrabSinkFrameTimeout(CS_Sink sink, struct CvMat* image,
+ double timeout, CS_Status* status);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // CV_VERSION_MAJOR < 4
+
+#ifdef __cplusplus
+
+#include "cscore_oo.h"
+
+namespace cv {
+class Mat;
+} // namespace cv
+
+namespace cs {
+
+/**
+ * @defgroup cscore_cpp_opencv_special cscore C functions taking a cv::Mat*
+ *
+ * These are needed for specific interop implementations.
+ * @{
+ */
+extern "C" {
+uint64_t CS_GrabSinkFrameCpp(CS_Sink sink, cv::Mat* image, CS_Status* status);
+uint64_t CS_GrabSinkFrameTimeoutCpp(CS_Sink sink, cv::Mat* image,
+ double timeout, CS_Status* status);
+void CS_PutSourceFrameCpp(CS_Source source, cv::Mat* image, CS_Status* status);
+} // extern "C"
+/** @} */
+
+void PutSourceFrame(CS_Source source, cv::Mat& image, CS_Status* status);
+uint64_t GrabSinkFrame(CS_Sink sink, cv::Mat& image, CS_Status* status);
+uint64_t GrabSinkFrameTimeout(CS_Sink sink, cv::Mat& image, double timeout,
+ CS_Status* status);
+
+/**
+ * A source for user code to provide OpenCV images as video frames.
+ * These sources require the WPILib OpenCV builds.
+ * For an alternate OpenCV, include "cscore_raw_cv.h" instead, and
+ * include your Mat header before that header.
+ */
+class CvSource : public ImageSource {
+ public:
+ CvSource() = default;
+
+ /**
+ * Create an OpenCV source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param mode Video mode being generated
+ */
+ CvSource(const wpi::Twine& name, const VideoMode& mode);
+
+ /**
+ * Create an OpenCV source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param pixelFormat Pixel format
+ * @param width width
+ * @param height height
+ * @param fps fps
+ */
+ CvSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
+ int width, int height, int fps);
+
+ /**
+ * Put an OpenCV image and notify sinks.
+ *
+ * <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
+ * are supported. If the format, depth or channel order is different, use
+ * cv::Mat::convertTo() and/or cv::cvtColor() to convert it first.
+ *
+ * @param image OpenCV image
+ */
+ void PutFrame(cv::Mat& image);
+};
+
+/**
+ * A sink for user code to accept video frames as OpenCV images.
+ * These sinks require the WPILib OpenCV builds.
+ * For an alternate OpenCV, include "cscore_raw_cv.h" instead, and
+ * include your Mat header before that header.
+ */
+class CvSink : public ImageSink {
+ public:
+ CvSink() = default;
+
+ /**
+ * Create a sink for accepting OpenCV images.
+ *
+ * <p>WaitForFrame() must be called on the created sink to get each new
+ * image.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ */
+ explicit CvSink(const wpi::Twine& name);
+
+ /**
+ * Create a sink for accepting OpenCV images in a separate thread.
+ *
+ * <p>A thread will be created that calls WaitForFrame() and calls the
+ * processFrame() callback each time a new frame arrives.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param processFrame Frame processing function; will be called with a
+ * time=0 if an error occurred. processFrame should call GetImage()
+ * or GetError() as needed, but should not call (except in very
+ * unusual circumstances) WaitForImage().
+ */
+ CvSink(const wpi::Twine& name,
+ std::function<void(uint64_t time)> processFrame);
+
+ /**
+ * Wait for the next frame and get the image.
+ * Times out (returning 0) after timeout seconds.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ uint64_t GrabFrame(cv::Mat& image, double timeout = 0.225) const;
+
+ /**
+ * Wait for the next frame and get the image. May block forever.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ uint64_t GrabFrameNoTimeout(cv::Mat& image) const;
+};
+
+inline CvSource::CvSource(const wpi::Twine& name, const VideoMode& mode) {
+ m_handle = CreateCvSource(name, mode, &m_status);
+}
+
+inline CvSource::CvSource(const wpi::Twine& name, VideoMode::PixelFormat format,
+ int width, int height, int fps) {
+ m_handle =
+ CreateCvSource(name, VideoMode{format, width, height, fps}, &m_status);
+}
+
+inline void CvSource::PutFrame(cv::Mat& image) {
+ m_status = 0;
+ PutSourceFrame(m_handle, image, &m_status);
+}
+
+inline CvSink::CvSink(const wpi::Twine& name) {
+ m_handle = CreateCvSink(name, &m_status);
+}
+
+inline CvSink::CvSink(const wpi::Twine& name,
+ std::function<void(uint64_t time)> processFrame) {
+ m_handle = CreateCvSinkCallback(name, processFrame, &m_status);
+}
+
+inline uint64_t CvSink::GrabFrame(cv::Mat& image, double timeout) const {
+ m_status = 0;
+ return GrabSinkFrameTimeout(m_handle, image, timeout, &m_status);
+}
+
+inline uint64_t CvSink::GrabFrameNoTimeout(cv::Mat& image) const {
+ m_status = 0;
+ return GrabSinkFrame(m_handle, image, &m_status);
+}
+
+} // namespace cs
+
+#endif
+
+#endif // CSCORE_CSCORE_CV_H_
diff --git a/cscore/src/main/native/include/cscore_oo.h b/cscore/src/main/native/include/cscore_oo.h
index 7e0cb9f..5ab0f70 100644
--- a/cscore/src/main/native/include/cscore_oo.h
+++ b/cscore/src/main/native/include/cscore_oo.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -28,7 +28,7 @@
*/
// Forward declarations so friend declarations work correctly
-class CvSource;
+class ImageSource;
class VideoEvent;
class VideoSink;
class VideoSource;
@@ -37,7 +37,7 @@
* A source or sink property.
*/
class VideoProperty {
- friend class CvSource;
+ friend class ImageSource;
friend class VideoEvent;
friend class VideoSink;
friend class VideoSource;
@@ -51,7 +51,7 @@
kEnum = CS_PROP_ENUM
};
- VideoProperty() : m_handle(0), m_kind(kNone) {}
+ VideoProperty() : m_status(0), m_handle(0), m_kind(kNone) {}
std::string GetName() const;
@@ -617,43 +617,13 @@
};
/**
- * A source for user code to provide OpenCV images as video frames.
+ * A base class for single image providing sources.
*/
-class CvSource : public VideoSource {
+class ImageSource : public VideoSource {
+ protected:
+ ImageSource() = default;
+
public:
- CvSource() = default;
-
- /**
- * Create an OpenCV source.
- *
- * @param name Source name (arbitrary unique identifier)
- * @param mode Video mode being generated
- */
- CvSource(const wpi::Twine& name, const VideoMode& mode);
-
- /**
- * Create an OpenCV source.
- *
- * @param name Source name (arbitrary unique identifier)
- * @param pixelFormat Pixel format
- * @param width width
- * @param height height
- * @param fps fps
- */
- CvSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
- int width, int height, int fps);
-
- /**
- * Put an OpenCV image and notify sinks.
- *
- * <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
- * are supported. If the format, depth or channel order is different, use
- * cv::Mat::convertTo() and/or cv::cvtColor() to convert it first.
- *
- * @param image OpenCV image
- */
- void PutFrame(cv::Mat& image);
-
/**
* Signal sinks that an error has occurred. This should be called instead
* of NotifyFrame when an error occurs.
@@ -979,37 +949,13 @@
};
/**
- * A sink for user code to accept video frames as OpenCV images.
+ * A base class for single image reading sinks.
*/
-class CvSink : public VideoSink {
+class ImageSink : public VideoSink {
+ protected:
+ ImageSink() = default;
+
public:
- CvSink() = default;
-
- /**
- * Create a sink for accepting OpenCV images.
- *
- * <p>WaitForFrame() must be called on the created sink to get each new
- * image.
- *
- * @param name Source name (arbitrary unique identifier)
- */
- explicit CvSink(const wpi::Twine& name);
-
- /**
- * Create a sink for accepting OpenCV images in a separate thread.
- *
- * <p>A thread will be created that calls WaitForFrame() and calls the
- * processFrame() callback each time a new frame arrives.
- *
- * @param name Source name (arbitrary unique identifier)
- * @param processFrame Frame processing function; will be called with a
- * time=0 if an error occurred. processFrame should call GetImage()
- * or GetError() as needed, but should not call (except in very
- * unusual circumstances) WaitForImage().
- */
- CvSink(const wpi::Twine& name,
- std::function<void(uint64_t time)> processFrame);
-
/**
* Set sink description.
*
@@ -1018,27 +964,6 @@
void SetDescription(const wpi::Twine& description);
/**
- * Wait for the next frame and get the image.
- * Times out (returning 0) after timeout seconds.
- * The provided image will have three 8-bit channels stored in BGR order.
- *
- * @return Frame time, or 0 on error (call GetError() to obtain the error
- * message); the frame time is in the same time base as wpi::Now(),
- * and is in 1 us increments.
- */
- uint64_t GrabFrame(cv::Mat& image, double timeout = 0.225) const;
-
- /**
- * Wait for the next frame and get the image. May block forever.
- * The provided image will have three 8-bit channels stored in BGR order.
- *
- * @return Frame time, or 0 on error (call GetError() to obtain the error
- * message); the frame time is in the same time base as wpi::Now(),
- * and is in 1 us increments.
- */
- uint64_t GrabFrameNoTimeout(cv::Mat& image) const;
-
- /**
* Get error string. Call this if WaitForFrame() returns 0 to determine
* what the error is.
*/
diff --git a/cscore/src/main/native/include/cscore_oo.inl b/cscore/src/main/native/include/cscore_oo.inl
index 5162e1d..ffd2b23 100644
--- a/cscore/src/main/native/include/cscore_oo.inl
+++ b/cscore/src/main/native/include/cscore_oo.inl
@@ -76,7 +76,7 @@
}
inline VideoProperty::VideoProperty(CS_Property handle, Kind kind)
- : m_handle(handle), m_kind(kind) {}
+ : m_status(0), m_handle(handle), m_kind(kind) {}
inline VideoSource::VideoSource(const VideoSource& source)
: m_handle(source.m_handle == 0 ? 0
@@ -378,37 +378,22 @@
std::initializer_list<T> hosts)
: HttpCamera(name, HostToUrl(hosts), kAxis) {}
-inline CvSource::CvSource(const wpi::Twine& name, const VideoMode& mode) {
- m_handle = CreateCvSource(name, mode, &m_status);
-}
-
-inline CvSource::CvSource(const wpi::Twine& name, VideoMode::PixelFormat format,
- int width, int height, int fps) {
- m_handle =
- CreateCvSource(name, VideoMode{format, width, height, fps}, &m_status);
-}
-
-inline void CvSource::PutFrame(cv::Mat& image) {
- m_status = 0;
- PutSourceFrame(m_handle, image, &m_status);
-}
-
-inline void CvSource::NotifyError(const wpi::Twine& msg) {
+inline void ImageSource::NotifyError(const wpi::Twine& msg) {
m_status = 0;
NotifySourceError(m_handle, msg, &m_status);
}
-inline void CvSource::SetConnected(bool connected) {
+inline void ImageSource::SetConnected(bool connected) {
m_status = 0;
SetSourceConnected(m_handle, connected, &m_status);
}
-inline void CvSource::SetDescription(const wpi::Twine& description) {
+inline void ImageSource::SetDescription(const wpi::Twine& description) {
m_status = 0;
SetSourceDescription(m_handle, description, &m_status);
}
-inline VideoProperty CvSource::CreateProperty(const wpi::Twine& name,
+inline VideoProperty ImageSource::CreateProperty(const wpi::Twine& name,
VideoProperty::Kind kind,
int minimum, int maximum,
int step, int defaultValue,
@@ -419,7 +404,7 @@
minimum, maximum, step, defaultValue, value, &m_status)};
}
-inline VideoProperty CvSource::CreateIntegerProperty(const wpi::Twine& name,
+inline VideoProperty ImageSource::CreateIntegerProperty(const wpi::Twine& name,
int minimum, int maximum,
int step, int defaultValue,
int value) {
@@ -429,7 +414,7 @@
minimum, maximum, step, defaultValue, value, &m_status)};
}
-inline VideoProperty CvSource::CreateBooleanProperty(const wpi::Twine& name,
+inline VideoProperty ImageSource::CreateBooleanProperty(const wpi::Twine& name,
bool defaultValue,
bool value) {
m_status = 0;
@@ -438,7 +423,7 @@
0, 1, 1, defaultValue ? 1 : 0, value ? 1 : 0, &m_status)};
}
-inline VideoProperty CvSource::CreateStringProperty(const wpi::Twine& name,
+inline VideoProperty ImageSource::CreateStringProperty(const wpi::Twine& name,
const wpi::Twine& value) {
m_status = 0;
auto prop = VideoProperty{CreateSourceProperty(
@@ -449,14 +434,14 @@
}
-inline void CvSource::SetEnumPropertyChoices(
+inline void ImageSource::SetEnumPropertyChoices(
const VideoProperty& property, wpi::ArrayRef<std::string> choices) {
m_status = 0;
SetSourceEnumPropertyChoices(m_handle, property.m_handle, choices, &m_status);
}
template <typename T>
-inline void CvSource::SetEnumPropertyChoices(const VideoProperty& property,
+inline void ImageSource::SetEnumPropertyChoices(const VideoProperty& property,
std::initializer_list<T> choices) {
std::vector<std::string> vec;
vec.reserve(choices.size());
@@ -575,36 +560,17 @@
quality, &m_status);
}
-inline CvSink::CvSink(const wpi::Twine& name) {
- m_handle = CreateCvSink(name, &m_status);
-}
-
-inline CvSink::CvSink(const wpi::Twine& name,
- std::function<void(uint64_t time)> processFrame) {
- m_handle = CreateCvSinkCallback(name, processFrame, &m_status);
-}
-
-inline void CvSink::SetDescription(const wpi::Twine& description) {
+inline void ImageSink::SetDescription(const wpi::Twine& description) {
m_status = 0;
SetSinkDescription(m_handle, description, &m_status);
}
-inline uint64_t CvSink::GrabFrame(cv::Mat& image, double timeout) const {
- m_status = 0;
- return GrabSinkFrameTimeout(m_handle, image, timeout, &m_status);
-}
-
-inline uint64_t CvSink::GrabFrameNoTimeout(cv::Mat& image) const {
- m_status = 0;
- return GrabSinkFrame(m_handle, image, &m_status);
-}
-
-inline std::string CvSink::GetError() const {
+inline std::string ImageSink::GetError() const {
m_status = 0;
return GetSinkError(m_handle, &m_status);
}
-inline void CvSink::SetEnabled(bool enabled) {
+inline void ImageSink::SetEnabled(bool enabled) {
m_status = 0;
SetSinkEnabled(m_handle, enabled, &m_status);
}
diff --git a/cscore/src/main/native/include/cscore_raw.h b/cscore/src/main/native/include/cscore_raw.h
new file mode 100644
index 0000000..902d90e
--- /dev/null
+++ b/cscore/src/main/native/include/cscore_raw.h
@@ -0,0 +1,234 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#ifndef CSCORE_CSCORE_RAW_H_
+#define CSCORE_CSCORE_RAW_H_
+
+#include "cscore_c.h"
+
+#ifdef __cplusplus
+#include "cscore_oo.h"
+#endif
+
+/**
+ * Raw Frame
+ */
+typedef struct CS_RawFrame {
+ char* data;
+ int dataLength;
+ int pixelFormat;
+ int width;
+ int height;
+ int totalData;
+} CS_RawFrame;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup cscore_raw_cfunc Raw Image Functions
+ * @{
+ */
+void CS_AllocateRawFrameData(CS_RawFrame* frame, int requestedSize);
+void CS_FreeRawFrameData(CS_RawFrame* frame);
+
+uint64_t CS_GrabRawSinkFrame(CS_Sink sink, struct CS_RawFrame* rawImage,
+ CS_Status* status);
+uint64_t CS_GrabRawSinkFrameTimeout(CS_Sink sink, struct CS_RawFrame* rawImage,
+ double timeout, CS_Status* status);
+
+CS_Sink CS_CreateRawSink(const char* name, CS_Status* status);
+
+CS_Sink CS_CreateRawSinkCallback(const char* name, void* data,
+ void (*processFrame)(void* data,
+ uint64_t time),
+ CS_Status* status);
+
+void CS_PutRawSourceFrame(CS_Source source, const struct CS_RawFrame* image,
+ CS_Status* status);
+
+CS_Source CS_CreateRawSource(const char* name, const CS_VideoMode* mode,
+ CS_Status* status);
+/** @} */
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#ifdef __cplusplus
+namespace cs {
+
+struct RawFrame : public CS_RawFrame {
+ RawFrame() {
+ data = nullptr;
+ dataLength = 0;
+ pixelFormat = CS_PIXFMT_UNKNOWN;
+ width = 0;
+ height = 0;
+ totalData = 0;
+ }
+
+ ~RawFrame() { CS_FreeRawFrameData(this); }
+};
+
+/**
+ * @defgroup cscore_raw_func Raw Image Functions
+ * @{
+ */
+
+CS_Source CreateRawSource(const wpi::Twine& name, const VideoMode& mode,
+ CS_Status* status);
+
+CS_Sink CreateRawSink(const wpi::Twine& name, CS_Status* status);
+CS_Sink CreateRawSinkCallback(const wpi::Twine& name,
+ std::function<void(uint64_t time)> processFrame,
+ CS_Status* status);
+
+void PutSourceFrame(CS_Source source, const CS_RawFrame& image,
+ CS_Status* status);
+uint64_t GrabSinkFrame(CS_Sink sink, CS_RawFrame& image, CS_Status* status);
+uint64_t GrabSinkFrameTimeout(CS_Sink sink, CS_RawFrame& image, double timeout,
+ CS_Status* status);
+
+/**
+ * A source for user code to provide video frames as raw bytes.
+ *
+ * This is a complex API, most cases should use CvSource.
+ */
+class RawSource : public ImageSource {
+ public:
+ RawSource() = default;
+
+ /**
+ * Create a raw frame source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param mode Video mode being generated
+ */
+ RawSource(const wpi::Twine& name, const VideoMode& mode);
+
+ /**
+ * Create a raw frame source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param pixelFormat Pixel format
+ * @param width width
+ * @param height height
+ * @param fps fps
+ */
+ RawSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
+ int width, int height, int fps);
+
+ protected:
+ /**
+ * Put a raw image and notify sinks.
+ *
+ * @param image raw frame image
+ */
+ void PutFrame(RawFrame& image);
+};
+
+/**
+ * A sink for user code to accept video frames as raw bytes.
+ *
+ * This is a complex API, most cases should use CvSource.
+ */
+class RawSink : public ImageSink {
+ public:
+ RawSink() = default;
+
+ /**
+ * Create a sink for accepting raw images.
+ *
+ * <p>GrabFrame() must be called on the created sink to get each new
+ * image.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ */
+ explicit RawSink(const wpi::Twine& name);
+
+ /**
+ * Create a sink for accepting raws images in a separate thread.
+ *
+ * <p>A thread will be created that calls WaitForFrame() and calls the
+ * processFrame() callback each time a new frame arrives.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param processFrame Frame processing function; will be called with a
+ * time=0 if an error occurred. processFrame should call GetImage()
+ * or GetError() as needed, but should not call (except in very
+ * unusual circumstances) WaitForImage().
+ */
+ RawSink(const wpi::Twine& name,
+ std::function<void(uint64_t time)> processFrame);
+
+ protected:
+ /**
+ * Wait for the next frame and get the image.
+ * Times out (returning 0) after timeout seconds.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ uint64_t GrabFrame(RawFrame& image, double timeout = 0.225) const;
+
+ /**
+ * Wait for the next frame and get the image. May block forever.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ uint64_t GrabFrameNoTimeout(RawFrame& image) const;
+};
+
+inline RawSource::RawSource(const wpi::Twine& name, const VideoMode& mode) {
+ m_handle = CreateRawSource(name, mode, &m_status);
+}
+
+inline RawSource::RawSource(const wpi::Twine& name,
+ VideoMode::PixelFormat format, int width,
+ int height, int fps) {
+ m_handle =
+ CreateRawSource(name, VideoMode{format, width, height, fps}, &m_status);
+}
+
+inline void RawSource::PutFrame(RawFrame& image) {
+ m_status = 0;
+ PutSourceFrame(m_handle, image, &m_status);
+}
+
+inline RawSink::RawSink(const wpi::Twine& name) {
+ m_handle = CreateRawSink(name, &m_status);
+}
+
+inline RawSink::RawSink(const wpi::Twine& name,
+ std::function<void(uint64_t time)> processFrame) {
+ m_handle = CreateRawSinkCallback(name, processFrame, &m_status);
+}
+
+inline uint64_t RawSink::GrabFrame(RawFrame& image, double timeout) const {
+ m_status = 0;
+ return GrabSinkFrameTimeout(m_handle, image, timeout, &m_status);
+}
+
+inline uint64_t RawSink::GrabFrameNoTimeout(RawFrame& image) const {
+ m_status = 0;
+ return GrabSinkFrame(m_handle, image, &m_status);
+}
+
+} // namespace cs
+
+/** @} */
+
+#endif
+
+#endif // CSCORE_CSCORE_RAW_H_
diff --git a/cscore/src/main/native/include/cscore_raw_cv.h b/cscore/src/main/native/include/cscore_raw_cv.h
new file mode 100644
index 0000000..ed40006
--- /dev/null
+++ b/cscore/src/main/native/include/cscore_raw_cv.h
@@ -0,0 +1,218 @@
+/*----------------------------------------------------------------------------*/
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
+/* Open Source Software - may be modified and shared by FRC teams. The code */
+/* must be accompanied by the FIRST BSD license file in the root directory of */
+/* the project. */
+/*----------------------------------------------------------------------------*/
+
+#ifndef CSCORE_CSCORE_RAW_CV_H_
+#define CSCORE_CSCORE_RAW_CV_H_
+
+#ifdef CSCORE_CSCORE_CV_H_
+#error "Cannot include both cscore_cv.h and cscore_raw_cv.h in the same file"
+#endif
+
+#include "cscore_raw.h"
+
+namespace cs {
+/**
+ * A source for using the raw frame API to provide opencv images.
+ *
+ * If you are using the WPILib OpenCV builds, do not use this, and
+ * instead include "cscore_cv.h" to get a more performant version.
+ *
+ * This is not dependent on any opencv binary ABI, and can be used
+ * with versions of OpenCV that are not 3. If using OpenCV 3, use
+ * CvSource.
+ */
+class RawCvSource : public RawSource {
+ public:
+ RawCvSource() = default;
+
+ /**
+ * Create a Raw OpenCV source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param mode Video mode being generated
+ */
+ RawCvSource(const wpi::Twine& name, const VideoMode& mode);
+
+ /**
+ * Create a Raw OpenCV source.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param pixelFormat Pixel format
+ * @param width width
+ * @param height height
+ * @param fps fps
+ */
+ RawCvSource(const wpi::Twine& name, VideoMode::PixelFormat pixelFormat,
+ int width, int height, int fps);
+
+ /**
+ * Put an OpenCV image and notify sinks.
+ *
+ * <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images
+ * are supported. If the format, depth or channel order is different, use
+ * cv::Mat::convertTo() and/or cv::cvtColor() to convert it first.
+ *
+ * @param image OpenCV image
+ */
+ void PutFrame(cv::Mat& image);
+
+ private:
+ RawFrame rawFrame;
+};
+
+/**
+ * A sink for user code to accept raw video frames as OpenCV images.
+ *
+ * If you are using the WPILib OpenCV builds, do not use this, and
+ * instead include "cscore_cv.h" to get a more performant version.
+ *
+ * This is not dependent on any opencv binary ABI, and can be used
+ * with versions of OpenCV that are not 3. If using OpenCV 3, use
+ * CvSink.
+ */
+class RawCvSink : public RawSink {
+ public:
+ RawCvSink() = default;
+
+ /**
+ * Create a sink for accepting OpenCV images.
+ *
+ * <p>WaitForFrame() must be called on the created sink to get each new
+ * image.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ */
+ explicit RawCvSink(const wpi::Twine& name);
+
+ /**
+ * Create a sink for accepting OpenCV images in a separate thread.
+ *
+ * <p>A thread will be created that calls WaitForFrame() and calls the
+ * processFrame() callback each time a new frame arrives.
+ *
+ * @param name Source name (arbitrary unique identifier)
+ * @param processFrame Frame processing function; will be called with a
+ * time=0 if an error occurred. processFrame should call GetImage()
+ * or GetError() as needed, but should not call (except in very
+ * unusual circumstances) WaitForImage().
+ */
+ RawCvSink(const wpi::Twine& name,
+ std::function<void(uint64_t time)> processFrame);
+
+ /**
+ * Wait for the next frame and get the image.
+ * Times out (returning 0) after timeout seconds.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ uint64_t GrabFrame(cv::Mat& image, double timeout = 0.225);
+
+ /**
+ * Wait for the next frame and get the image. May block forever.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ uint64_t GrabFrameNoTimeout(cv::Mat& image);
+
+ /**
+ * Wait for the next frame and get the image.
+ * Times out (returning 0) after timeout seconds.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ uint64_t GrabFrameDirect(cv::Mat& image, double timeout = 0.225);
+
+ /**
+ * Wait for the next frame and get the image. May block forever.
+ * The provided image will have three 8-bit channels stored in BGR order.
+ *
+ * @return Frame time, or 0 on error (call GetError() to obtain the error
+ * message); the frame time is in the same time base as wpi::Now(),
+ * and is in 1 us increments.
+ */
+ uint64_t GrabFrameNoTimeoutDirect(cv::Mat& image);
+
+ private:
+ RawFrame rawFrame;
+};
+
+inline RawCvSource::RawCvSource(const wpi::Twine& name, const VideoMode& mode)
+ : RawSource{name, mode} {}
+
+inline RawCvSource::RawCvSource(const wpi::Twine& name,
+ VideoMode::PixelFormat format, int width,
+ int height, int fps)
+ : RawSource{name, format, width, height, fps} {}
+
+inline void RawCvSource::PutFrame(cv::Mat& image) {
+ m_status = 0;
+ rawFrame.data = reinterpret_cast<char*>(image.data);
+ rawFrame.width = image.cols;
+ rawFrame.height = image.rows;
+ rawFrame.totalData = image.total() * image.channels;
+ rawFrame.pixelFormat = image.channels == 3 ? CS_PIXFMT_BGR : CS_PIXFMT_GRAY;
+ PutSourceFrame(m_handle, rawFrame, &m_status);
+}
+
+inline RawCvSink::RawCvSink(const wpi::Twine& name) : RawSink{name} {}
+
+inline RawCvSink::RawCvSink(const wpi::Twine& name,
+ std::function<void(uint64_t time)> processFrame)
+ : RawSink{name, processFrame} {}
+
+inline uint64_t RawCvSink::GrabFrame(cv::Mat& image, double timeout) {
+ cv::Mat tmpMat;
+ auto retVal = GrabFrameDirect(tmpMat);
+ if (retVal <= 0) {
+ return retVal;
+ }
+ tmpMat.copyTo(image);
+ return retVal;
+}
+
+inline uint64_t RawCvSink::GrabFrameNoTimeout(cv::Mat& image) {
+ cv::Mat tmpMat;
+ auto retVal = GrabFrameNoTimeoutDirect(tmpMat);
+ if (retVal <= 0) {
+ return retVal;
+ }
+ tmpMat.copyTo(image);
+ return retVal;
+}
+
+inline uint64_t RawCvSink::GrabFrameDirect(cv::Mat& image, double timeout) {
+ rawFrame.height = 0;
+ rawFrame.width = 0;
+ rawFrame.pixelFormat = CS_PixelFormat::CS_PIXFMT_BGR;
+ m_status = RawSink::GrabFrame(rawFrame, timeout);
+ if (m_status <= 0) return m_status;
+ image = cv::Mat{rawFrame.height, rawFrame.width, CV_8UC3, rawFrame.data};
+ return m_status;
+}
+
+inline uint64_t RawCvSink::GrabFrameNoTimeoutDirect(cv::Mat& image) {
+ rawFrame.height = 0;
+ rawFrame.width = 0;
+ rawFrame.pixelFormat = CS_PixelFormat::CS_PIXFMT_BGR;
+ m_status = RawSink::GrabFrameNoTimeout(rawFrame);
+ if (m_status <= 0) return m_status;
+ image = cv::Mat{rawFrame.height, rawFrame.width, CV_8UC3, rawFrame.data};
+ return m_status;
+}
+
+} // namespace cs
+
+#endif // CSCORE_CSCORE_RAW_CV_H_
diff --git a/cscore/src/main/native/linux/NetworkListener.cpp b/cscore/src/main/native/linux/NetworkListener.cpp
index ed3d966..6915b30 100644
--- a/cscore/src/main/native/linux/NetworkListener.cpp
+++ b/cscore/src/main/native/linux/NetworkListener.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2015-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -132,8 +132,9 @@
break; // XXX: is this the right thing to do here?
}
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, len); nh = NLMSG_NEXT(nh, len)) {
+ NLMSG_OK(nh, ulen); nh = NLMSG_NEXT(nh, ulen)) {
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) {
diff --git a/cscore/src/main/native/linux/UsbCameraImpl.cpp b/cscore/src/main/native/linux/UsbCameraImpl.cpp
index 125c936..6bed486 100644
--- a/cscore/src/main/native/linux/UsbCameraImpl.cpp
+++ b/cscore/src/main/native/linux/UsbCameraImpl.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -25,9 +25,9 @@
#include <algorithm>
#include <wpi/FileSystem.h>
+#include <wpi/MemAlloc.h>
#include <wpi/Path.h>
#include <wpi/SmallString.h>
-#include <wpi/memory.h>
#include <wpi/raw_ostream.h>
#include <wpi/timestamp.h>
@@ -108,6 +108,11 @@
static constexpr const int quirkLifeCamHd3000[] = {
5, 10, 20, 39, 78, 156, 312, 625, 1250, 2500, 5000, 10000, 20000};
+static constexpr char const* quirkPS3EyePropExAuto = "auto_exposure";
+static constexpr char const* quirkPS3EyePropExValue = "exposure";
+static constexpr const int quirkPS3EyePropExAutoOn = 0;
+static constexpr const int quirkPS3EyePropExAutoOff = 1;
+
int UsbCameraImpl::RawToPercentage(const UsbCameraProperty& rawProp,
int rawValue) {
// LifeCam exposure setting quirk
@@ -138,10 +143,36 @@
(rawProp.maximum - rawProp.minimum) * (percentValue / 100.0);
}
-static bool GetDescriptionSysV4L(wpi::StringRef path, std::string* desc) {
- wpi::SmallString<64> ifpath{"/sys/class/video4linux/"};
- ifpath += path.substr(5);
- ifpath += "/device/interface";
+static bool GetVendorProduct(int dev, int* vendor, int* product) {
+ wpi::SmallString<64> ifpath;
+ {
+ wpi::raw_svector_ostream oss{ifpath};
+ oss << "/sys/class/video4linux/video" << dev << "/device/modalias";
+ }
+
+ int fd = open(ifpath.c_str(), O_RDONLY);
+ if (fd < 0) return false;
+
+ char readBuf[128];
+ ssize_t n = read(fd, readBuf, sizeof(readBuf));
+ close(fd);
+
+ if (n <= 0) return false;
+ wpi::StringRef readStr{readBuf};
+ 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))
+ return false;
+
+ return true;
+}
+
+static bool GetDescriptionSysV4L(int dev, std::string* desc) {
+ wpi::SmallString<64> ifpath;
+ {
+ wpi::raw_svector_ostream oss{ifpath};
+ oss << "/sys/class/video4linux/video" << dev << "/device/interface";
+ }
int fd = open(ifpath.c_str(), O_RDONLY);
if (fd < 0) return false;
@@ -187,23 +218,35 @@
return true;
}
-static std::string GetDescriptionImpl(const char* cpath) {
+static int GetDeviceNum(const char* cpath) {
wpi::StringRef path{cpath};
- char pathBuf[128];
- std::string rv;
+ std::string pathBuf;
- // If trying to get by id or path, follow symlink
- if (path.startswith("/dev/v4l/by-id/")) {
- ssize_t n = readlink(cpath, pathBuf, sizeof(pathBuf));
- if (n > 0) path = wpi::StringRef(pathBuf, n);
- } else if (path.startswith("/dev/v4l/by-path/")) {
- ssize_t n = readlink(cpath, pathBuf, sizeof(pathBuf));
- if (n > 0) path = wpi::StringRef(pathBuf, n);
+ // it might be a symlink; if so, find the symlink target (e.g. /dev/videoN),
+ // add that to the list and make it the keypath
+ if (wpi::sys::fs::is_symlink_file(cpath)) {
+ char* target = ::realpath(cpath, nullptr);
+ if (target) {
+ pathBuf = target;
+ path = pathBuf;
+ std::free(target);
+ }
}
- if (path.startswith("/dev/video")) {
+ path = wpi::sys::path::filename(path);
+ if (!path.startswith("video")) return -1;
+ int dev = -1;
+ if (path.substr(5).getAsInteger(10, dev)) return -1;
+ return dev;
+}
+
+static std::string GetDescriptionImpl(const char* cpath) {
+ std::string rv;
+
+ int dev = GetDeviceNum(cpath);
+ if (dev >= 0) {
// Sometimes the /sys tree gives a better name.
- if (GetDescriptionSysV4L(path, &rv)) return rv;
+ if (GetDescriptionSysV4L(dev, &rv)) return rv;
}
// Otherwise use an ioctl to query the caps and get the card name
@@ -447,8 +490,7 @@
if (fd < 0) return; // already disconnected
// Unmap buffers
- for (int i = 0; i < kNumBuffers; ++i)
- m_buffers[i] = std::move(UsbCameraBuffer{});
+ for (int i = 0; i < kNumBuffers; ++i) m_buffers[i] = UsbCameraBuffer{};
// Close device
close(fd);
@@ -492,7 +534,7 @@
// Restore settings
SDEBUG3("restoring settings");
- std::unique_lock<wpi::mutex> lock2(m_mutex);
+ std::unique_lock lock2(m_mutex);
for (size_t i = 0; i < m_propertyData.size(); ++i) {
const auto prop =
static_cast<const UsbCameraProperty*>(m_propertyData[i].get());
@@ -534,11 +576,11 @@
SDEBUG4("buf " << i << " length=" << buf.length
<< " offset=" << buf.m.offset);
- m_buffers[i] = std::move(UsbCameraBuffer(fd, buf.length, buf.m.offset));
+ m_buffers[i] = UsbCameraBuffer(fd, buf.length, buf.m.offset);
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] = std::move(UsbCameraBuffer{});
+ for (int j = 0; j < i; ++j) m_buffers[j] = UsbCameraBuffer{};
close(fd);
m_fd = -1;
return;
@@ -737,7 +779,7 @@
}
void UsbCameraImpl::DeviceProcessCommands() {
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
if (m_commands.empty()) return;
while (!m_commands.empty()) {
auto msg = std::move(m_commands.back());
@@ -816,7 +858,7 @@
vfmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (DoIoctl(fd, VIDIOC_G_FMT, &vfmt) != 0) {
SERROR("could not read current video mode");
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_mode = VideoMode{VideoMode::kMJPEG, 320, 240, 30};
return;
}
@@ -882,7 +924,7 @@
// Save to global mode
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_mode.pixelFormat = pixelFormat;
m_mode.width = width;
m_mode.height = height;
@@ -908,11 +950,11 @@
std::unique_ptr<UsbCameraProperty> perProp;
if (IsPercentageProperty(rawProp->name)) {
perProp =
- wpi::make_unique<UsbCameraProperty>(rawProp->name, 0, *rawProp, 0, 0);
+ std::make_unique<UsbCameraProperty>(rawProp->name, 0, *rawProp, 0, 0);
rawProp->name = "raw_" + perProp->name;
}
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
int* rawIndex = &m_properties[rawProp->name];
bool newRaw = *rawIndex == 0;
UsbCameraProperty* oldRawProp =
@@ -1071,7 +1113,7 @@
}
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_videoModes.swap(modes);
}
m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
@@ -1086,14 +1128,14 @@
// Add the message to the command queue
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_commands.emplace_back(std::move(msg));
}
// Signal the camera thread
if (eventfd_write(fd, 1) < 0) return CS_SOURCE_IS_DISCONNECTED;
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
while (m_active) {
// Did we get a response to *our* request?
auto it =
@@ -1121,7 +1163,7 @@
// Add the message to the command queue
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_commands.emplace_back(std::move(msg));
}
@@ -1131,7 +1173,7 @@
std::unique_ptr<PropertyImpl> UsbCameraImpl::CreateEmptyProperty(
const wpi::Twine& name) const {
- return wpi::make_unique<UsbCameraProperty>(name);
+ return std::make_unique<UsbCameraProperty>(name);
}
bool UsbCameraImpl::CacheProperties(CS_Status* status) const {
@@ -1150,6 +1192,14 @@
wpi::StringRef desc = GetDescription(descbuf);
m_lifecam_exposure =
desc.endswith("LifeCam HD-3000") || desc.endswith("LifeCam Cinema (TM)");
+
+ int deviceNum = GetDeviceNum(m_path.c_str());
+ if (deviceNum >= 0) {
+ int vendorId, productId;
+ if (GetVendorProduct(deviceNum, &vendorId, &productId)) {
+ m_ps3eyecam_exposure = vendorId == 0x2000 && productId == 0x0145;
+ }
+ }
}
void UsbCameraImpl::SetProperty(int property, int value, CS_Status* status) {
@@ -1195,21 +1245,41 @@
void UsbCameraImpl::SetExposureAuto(CS_Status* status) {
// auto; this is an enum value
- SetProperty(GetPropertyIndex(kPropExAuto), 3, status);
+ if (m_ps3eyecam_exposure) {
+ SetProperty(GetPropertyIndex(quirkPS3EyePropExAuto),
+ quirkPS3EyePropExAutoOn, status);
+
+ } else {
+ SetProperty(GetPropertyIndex(kPropExAuto), 3, status);
+ }
}
void UsbCameraImpl::SetExposureHoldCurrent(CS_Status* status) {
- SetProperty(GetPropertyIndex(kPropExAuto), 1, status); // manual
+ if (m_ps3eyecam_exposure) {
+ SetProperty(GetPropertyIndex(quirkPS3EyePropExAuto),
+ quirkPS3EyePropExAutoOff, status); // manual
+ } else {
+ SetProperty(GetPropertyIndex(kPropExAuto), 1, status); // manual
+ }
}
void UsbCameraImpl::SetExposureManual(int value, CS_Status* status) {
- SetProperty(GetPropertyIndex(kPropExAuto), 1, status); // manual
+ if (m_ps3eyecam_exposure) {
+ SetProperty(GetPropertyIndex(quirkPS3EyePropExAuto),
+ quirkPS3EyePropExAutoOff, status); // manual
+ } else {
+ SetProperty(GetPropertyIndex(kPropExAuto), 1, status); // manual
+ }
if (value > 100) {
value = 100;
} else if (value < 0) {
value = 0;
}
- SetProperty(GetPropertyIndex(kPropExValue), value, status);
+ if (m_ps3eyecam_exposure) {
+ SetProperty(GetPropertyIndex(quirkPS3EyePropExValue), value, status);
+ } else {
+ SetProperty(GetPropertyIndex(kPropExValue), value, status);
+ }
}
bool UsbCameraImpl::SetVideoMode(const VideoMode& mode, CS_Status* status) {
@@ -1292,24 +1362,15 @@
std::string keypath = static_cast<UsbCameraImpl&>(*data->source).GetPath();
info.path = keypath;
- // it might be a symlink; if so, find the symlink target (e.g. /dev/videoN),
- // add that to the list and make it the keypath
- if (wpi::sys::fs::is_symlink_file(keypath)) {
- char* target = ::realpath(keypath.c_str(), nullptr);
- if (target) {
- keypath.assign(target);
- info.otherPaths.emplace_back(keypath);
- std::free(target);
- }
- }
-
// device number
- wpi::StringRef fname = wpi::sys::path::filename(keypath);
- if (fname.startswith("video")) fname.substr(5).getAsInteger(10, info.dev);
+ info.dev = GetDeviceNum(keypath.c_str());
// description
info.name = GetDescriptionImpl(keypath.c_str());
+ // vendor/product id
+ GetVendorProduct(info.dev, &info.vendorId, &info.productId);
+
// look through /dev/v4l/by-id and /dev/v4l/by-path for symlinks to the
// keypath
wpi::SmallString<128> path;
@@ -1360,6 +1421,8 @@
info.name = GetDescriptionImpl(path.c_str());
if (info.name.empty()) continue;
+ GetVendorProduct(dev, &info.vendorId, &info.productId);
+
if (dev >= retval.size()) retval.resize(info.dev + 1);
retval[info.dev] = std::move(info);
}
diff --git a/cscore/src/main/native/linux/UsbCameraImpl.h b/cscore/src/main/native/linux/UsbCameraImpl.h
index eb4a311..3627228 100644
--- a/cscore/src/main/native/linux/UsbCameraImpl.h
+++ b/cscore/src/main/native/linux/UsbCameraImpl.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -164,7 +164,8 @@
std::thread m_cameraThread;
// Quirks
- bool m_lifecam_exposure{false}; // Microsoft LifeCam exposure
+ bool m_lifecam_exposure{false}; // Microsoft LifeCam exposure
+ bool m_ps3eyecam_exposure{false}; // PS3 Eyecam exposure
//
// Variables protected by m_mutex
diff --git a/cscore/src/main/native/linux/UsbCameraProperty.cpp b/cscore/src/main/native/linux/UsbCameraProperty.cpp
index 4f51976..4dfa39c 100644
--- a/cscore/src/main/native/linux/UsbCameraProperty.cpp
+++ b/cscore/src/main/native/linux/UsbCameraProperty.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -7,7 +7,6 @@
#include "UsbCameraProperty.h"
-#include <wpi/STLExtras.h>
#include <wpi/SmallString.h>
#include <wpi/raw_ostream.h>
@@ -224,7 +223,7 @@
*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;
- prop = wpi::make_unique<UsbCameraProperty>(qc_ext);
+ prop = std::make_unique<UsbCameraProperty>(qc_ext);
}
#endif
if (!prop) {
@@ -235,7 +234,7 @@
rc = TryIoctl(fd, VIDIOC_QUERYCTRL, &qc);
*id = qc.id; // copy back
if (rc != 0) return nullptr;
- prop = wpi::make_unique<UsbCameraProperty>(qc);
+ prop = std::make_unique<UsbCameraProperty>(qc);
}
// Cache enum property choices
diff --git a/cscore/src/main/native/linux/UsbCameraProperty.h b/cscore/src/main/native/linux/UsbCameraProperty.h
index d3569cc..32c5e19 100644
--- a/cscore/src/main/native/linux/UsbCameraProperty.h
+++ b/cscore/src/main/native/linux/UsbCameraProperty.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/cscore/src/main/native/windows/NetworkUtil.cpp b/cscore/src/main/native/windows/NetworkUtil.cpp
index e994eb8..151ba79 100644
--- a/cscore/src/main/native/windows/NetworkUtil.cpp
+++ b/cscore/src/main/native/windows/NetworkUtil.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/cscore/src/main/native/windows/UsbCameraImpl.cpp b/cscore/src/main/native/windows/UsbCameraImpl.cpp
index e45f361..69c1fcb 100644
--- a/cscore/src/main/native/windows/UsbCameraImpl.cpp
+++ b/cscore/src/main/native/windows/UsbCameraImpl.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -28,8 +28,8 @@
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
+#include <wpi/MemAlloc.h>
#include <wpi/SmallString.h>
-#include <wpi/memory.h>
#include <wpi/raw_ostream.h>
#include <wpi/timestamp.h>
@@ -54,6 +54,8 @@
#pragma comment(lib, "Mfreadwrite.lib")
#pragma comment(lib, "Shlwapi.lib")
+#pragma warning(disable : 4996 4018 26451)
+
static constexpr int NewImageMessage = 0x0400 + 4488;
static constexpr int SetCameraMessage = 0x0400 + 254;
static constexpr int WaitForStartupMessage = 0x0400 + 294;
@@ -76,12 +78,16 @@
: SourceImpl{name, logger, notifier, telemetry}, m_path{path.str()} {
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
m_widePath = utf8_conv.from_bytes(m_path.c_str());
+ m_deviceId = -1;
+ StartMessagePump();
}
UsbCameraImpl::UsbCameraImpl(const wpi::Twine& name, wpi::Logger& logger,
Notifier& notifier, Telemetry& telemetry,
int deviceId)
- : SourceImpl{name, logger, notifier, telemetry}, m_deviceId(deviceId) {}
+ : SourceImpl{name, logger, notifier, telemetry}, m_deviceId(deviceId) {
+ StartMessagePump();
+}
UsbCameraImpl::~UsbCameraImpl() { m_messagePump = nullptr; }
@@ -192,11 +198,14 @@
SetCameraMessage, Message::kNumSinksEnabledChanged, nullptr);
}
-void UsbCameraImpl::Start() {
+void UsbCameraImpl::StartMessagePump() {
m_messagePump = std::make_unique<WindowsMessagePump>(
[this](HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
return this->PumpMain(hwnd, uiMsg, wParam, lParam);
});
+}
+
+void UsbCameraImpl::Start() {
m_messagePump->PostWindowMessage(PumpReadyMessage, nullptr, nullptr);
}
@@ -354,6 +363,7 @@
DeviceConnect();
break;
case WaitForStartupMessage:
+ DeviceConnect();
return CS_OK;
case WM_DEVICECHANGE: {
// Device potentially changed
@@ -401,7 +411,7 @@
{
Message* msg = reinterpret_cast<Message*>(lParam);
Message::Kind msgKind = static_cast<Message::Kind>(wParam);
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
auto retVal = DeviceProcessCommand(lock, msgKind, msg);
return retVal;
}
@@ -413,16 +423,16 @@
static cs::VideoMode::PixelFormat GetFromGUID(const GUID& guid) {
// Compare GUID to one of the supported ones
- if (guid == MFVideoFormat_NV12) {
+ if (IsEqualGUID(guid, MFVideoFormat_NV12)) {
// GrayScale
return cs::VideoMode::PixelFormat::kGray;
- } else if (guid == MFVideoFormat_YUY2) {
+ } else if (IsEqualGUID(guid, MFVideoFormat_YUY2)) {
return cs::VideoMode::PixelFormat::kYUYV;
- } else if (guid == MFVideoFormat_RGB24) {
+ } else if (IsEqualGUID(guid, MFVideoFormat_RGB24)) {
return cs::VideoMode::PixelFormat::kBGR;
- } else if (guid == MFVideoFormat_MJPG) {
+ } else if (IsEqualGUID(guid, MFVideoFormat_MJPG)) {
return cs::VideoMode::PixelFormat::kMJPEG;
- } else if (guid == MFVideoFormat_RGB565) {
+ } else if (IsEqualGUID(guid, MFVideoFormat_RGB565)) {
return cs::VideoMode::PixelFormat::kRGB565;
} else {
return cs::VideoMode::PixelFormat::kUnknown;
@@ -585,11 +595,11 @@
std::unique_ptr<UsbCameraProperty> perProp;
if (IsPercentageProperty(rawProp->name)) {
perProp =
- wpi::make_unique<UsbCameraProperty>(rawProp->name, 0, *rawProp, 0, 0);
+ std::make_unique<UsbCameraProperty>(rawProp->name, 0, *rawProp, 0, 0);
rawProp->name = "raw_" + perProp->name;
}
- std::unique_lock<wpi::mutex> lock(m_mutex);
+ std::unique_lock lock(m_mutex);
int* rawIndex = &m_properties[rawProp->name];
bool newRaw = *rawIndex == 0;
UsbCameraProperty* oldRawProp =
@@ -672,7 +682,7 @@
}
NotifyPropertyCreated(*rawIndex, *rawPropPtr);
- if (perPropPtr) NotifyPropertyCreated(*perIndex, *perPropPtr);
+ if (perPropPtr && perIndex) NotifyPropertyCreated(*perIndex, *perPropPtr);
}
CS_StatusValue UsbCameraImpl::DeviceProcessCommand(
@@ -808,7 +818,10 @@
m_currentMode = std::move(newModeType);
m_mode = newMode;
+#pragma warning(push)
+#pragma warning(disable : 26110)
lock.unlock();
+#pragma warning(pop)
if (m_sourceReader) {
DeviceDisconnect();
DeviceConnect();
@@ -862,10 +875,10 @@
// Default mode is not supported. Grab first supported image
auto&& firstSupported = m_windowsVideoModes[0];
m_currentMode = firstSupported.second;
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_mode = firstSupported.first;
} else {
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_mode = result->first;
}
}
@@ -947,7 +960,7 @@
count++;
}
{
- std::lock_guard<wpi::mutex> lock(m_mutex);
+ std::scoped_lock lock(m_mutex);
m_videoModes.swap(modes);
}
m_notifier.NotifySource(*this, CS_SOURCE_VIDEOMODES_UPDATED);
@@ -962,6 +975,7 @@
std::wstring_convert<std::codecvt_utf8<wchar_t>> utf8_conv;
ComPtr<IMFAttributes> pAttributes;
IMFActivate** ppDevices = nullptr;
+ UINT32 count = 0;
// Create an attribute store to specify the enumeration parameters.
HRESULT hr = MFCreateAttributes(pAttributes.GetAddressOf(), 1);
@@ -977,7 +991,6 @@
}
// Enumerate devices.
- UINT32 count;
hr = MFEnumDeviceSources(pAttributes.Get(), &ppDevices, &count);
if (FAILED(hr)) {
goto done;
@@ -993,11 +1006,11 @@
info.dev = i;
WCHAR buf[512];
ppDevices[i]->GetString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, buf,
- sizeof(buf), NULL);
+ sizeof(buf) / sizeof(WCHAR), NULL);
info.name = utf8_conv.to_bytes(buf);
ppDevices[i]->GetString(
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, buf,
- sizeof(buf), NULL);
+ sizeof(buf) / sizeof(WCHAR), NULL);
info.path = utf8_conv.to_bytes(buf);
retval.emplace_back(std::move(info));
}
@@ -1005,12 +1018,15 @@
done:
pAttributes.Reset();
- for (DWORD i = 0; i < count; i++) {
- if (ppDevices[i]) {
- ppDevices[i]->Release();
- ppDevices[i] = nullptr;
+ if (ppDevices) {
+ for (DWORD i = 0; i < count; i++) {
+ if (ppDevices[i]) {
+ ppDevices[i]->Release();
+ ppDevices[i] = nullptr;
+ }
}
}
+
CoTaskMemFree(ppDevices);
return retval;
}
diff --git a/cscore/src/main/native/windows/UsbCameraImpl.h b/cscore/src/main/native/windows/UsbCameraImpl.h
index 4013cda..11e07aa 100644
--- a/cscore/src/main/native/windows/UsbCameraImpl.h
+++ b/cscore/src/main/native/windows/UsbCameraImpl.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -98,7 +98,7 @@
};
explicit Message(Kind kind_)
- : kind(kind_), from(std::this_thread::get_id()) {}
+ : kind(kind_), data{0}, from(std::this_thread::get_id()) {}
Kind kind;
int data[4];
@@ -154,6 +154,8 @@
int RawToPercentage(const UsbCameraProperty& rawProp, int rawValue);
int PercentageToRaw(const UsbCameraProperty& rawProp, int percentValue);
+ void StartMessagePump();
+
//
// Variables only used within camera thread
//
diff --git a/cscore/src/main/native/windows/UsbCameraProperty.cpp b/cscore/src/main/native/windows/UsbCameraProperty.cpp
index ee4198b..ae22436 100644
--- a/cscore/src/main/native/windows/UsbCameraProperty.cpp
+++ b/cscore/src/main/native/windows/UsbCameraProperty.cpp
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
diff --git a/cscore/src/main/native/windows/UsbCameraProperty.h b/cscore/src/main/native/windows/UsbCameraProperty.h
index 68795fc..11888e9 100644
--- a/cscore/src/main/native/windows/UsbCameraProperty.h
+++ b/cscore/src/main/native/windows/UsbCameraProperty.h
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -68,8 +68,10 @@
bool isAutoProp{true};
bool isControlProperty{false};
- tagVideoProcAmpProperty tagVideoProc;
- tagCameraControlProperty tagCameraControl;
+ tagVideoProcAmpProperty tagVideoProc{
+ tagVideoProcAmpProperty::VideoProcAmp_Brightness};
+ tagCameraControlProperty tagCameraControl{
+ tagCameraControlProperty::CameraControl_Pan};
// If this is a percentage (rather than raw) property
bool percentage{false};
diff --git a/cscore/src/test/java/edu/wpi/cscore/UsbCameraTest.java b/cscore/src/test/java/edu/wpi/cscore/UsbCameraTest.java
index b55dc4e..9df3645 100644
--- a/cscore/src/test/java/edu/wpi/cscore/UsbCameraTest.java
+++ b/cscore/src/test/java/edu/wpi/cscore/UsbCameraTest.java
@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------*/
-/* Copyright (c) 2018 FIRST. All Rights Reserved. */
+/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project. */
@@ -25,16 +25,14 @@
class UsbCameraTest {
@Nested
@EnabledOnOs(OS.LINUX)
- static class ConnectVerbose {
+ class ConnectVerbose {
@Test
void setConnectVerboseEnabledTest() {
try (UsbCamera camera = new UsbCamera("Nonexistant Camera", getNonexistentCameraDev())) {
camera.setConnectVerbose(1);
CompletableFuture<String> result = new CompletableFuture<>();
- CameraServerJNI.setLogger((level, file, line, message) -> {
- result.complete(message);
- }, 20);
+ CameraServerJNI.setLogger((level, file, line, message) -> result.complete(message), 20);
assertTimeoutPreemptively(Duration.ofSeconds(5),
() -> assertTrue(result.get().contains("Connecting to USB camera on ")));
@@ -47,9 +45,7 @@
camera.setConnectVerbose(0);
CompletableFuture<String> result = new CompletableFuture<>();
- CameraServerJNI.setLogger((level, file, line, message) -> {
- result.complete(message);
- }, 20);
+ CameraServerJNI.setLogger((level, file, line, message) -> result.complete(message), 20);
assertThrows(TimeoutException.class,
() -> result.get(3, TimeUnit.SECONDS));
@@ -60,6 +56,6 @@
private static int getNonexistentCameraDev() {
return Arrays.stream(CameraServerJNI.enumerateUsbCameras())
.mapToInt(info -> info.dev)
- .max().orElseGet(() -> -1) + 1;
+ .max().orElse(-1) + 1;
}
}