001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.cscore; 006 007import edu.wpi.first.util.PixelFormat; 008 009/** 010 * A source for video that provides a sequence of frames. Each frame may consist of multiple images 011 * (e.g. from a stereo or depth camera); these are called channels. 012 */ 013public class VideoSource implements AutoCloseable { 014 /** Video source kind. */ 015 public enum Kind { 016 /** Unknown video source. */ 017 kUnknown(0), 018 /** USB video source. */ 019 kUsb(1), 020 /** HTTP video source. */ 021 kHttp(2), 022 /** CV video source. */ 023 kCv(4), 024 /** Raw video source. */ 025 kRaw(8); 026 027 private final int value; 028 029 Kind(int value) { 030 this.value = value; 031 } 032 033 /** 034 * Returns the Kind value. 035 * 036 * @return The Kind value. 037 */ 038 public int getValue() { 039 return value; 040 } 041 } 042 043 /** Connection strategy. */ 044 public enum ConnectionStrategy { 045 /** 046 * Automatically connect or disconnect based on whether any sinks are connected to this source. 047 * This is the default behavior. 048 */ 049 kAutoManage(0), 050 051 /** Try to keep the connection open regardless of whether any sinks are connected. */ 052 kKeepOpen(1), 053 054 /** 055 * Never open the connection. If this is set when the connection is open, close the connection. 056 */ 057 kForceClose(2); 058 059 private final int value; 060 061 ConnectionStrategy(int value) { 062 this.value = value; 063 } 064 065 /** 066 * Returns the ConnectionStrategy value. 067 * 068 * @return The ConnectionStrategy value. 069 */ 070 public int getValue() { 071 return value; 072 } 073 } 074 075 /** 076 * Convert from the numerical representation of kind to an enum type. 077 * 078 * @param kind The numerical representation of kind 079 * @return The kind 080 */ 081 public static Kind getKindFromInt(int kind) { 082 switch (kind) { 083 case 1: 084 return Kind.kUsb; 085 case 2: 086 return Kind.kHttp; 087 case 4: 088 return Kind.kCv; 089 default: 090 return Kind.kUnknown; 091 } 092 } 093 094 /** 095 * Constructs a VideoSource. 096 * 097 * @param handle The video source handle. 098 */ 099 protected VideoSource(int handle) { 100 m_handle = handle; 101 } 102 103 @Override 104 public synchronized void close() { 105 if (m_handle != 0) { 106 CameraServerJNI.releaseSource(m_handle); 107 } 108 m_handle = 0; 109 } 110 111 /** 112 * Returns true if the VideoSource is valid. 113 * 114 * @return True if the VideoSource is valid. 115 */ 116 public boolean isValid() { 117 return m_handle != 0; 118 } 119 120 /** 121 * Returns the video source handle. 122 * 123 * @return The video source handle. 124 */ 125 public int getHandle() { 126 return m_handle; 127 } 128 129 @Override 130 public boolean equals(Object other) { 131 if (this == other) { 132 return true; 133 } 134 if (other == null) { 135 return false; 136 } 137 if (getClass() != other.getClass()) { 138 return false; 139 } 140 VideoSource source = (VideoSource) other; 141 return m_handle == source.m_handle; 142 } 143 144 @Override 145 public int hashCode() { 146 return m_handle; 147 } 148 149 /** 150 * Get the kind of the source. 151 * 152 * @return The kind of the source. 153 */ 154 public Kind getKind() { 155 return getKindFromInt(CameraServerJNI.getSourceKind(m_handle)); 156 } 157 158 /** 159 * Get the name of the source. The name is an arbitrary identifier provided when the source is 160 * created, and should be unique. 161 * 162 * @return The name of the source. 163 */ 164 public String getName() { 165 return CameraServerJNI.getSourceName(m_handle); 166 } 167 168 /** 169 * Get the source description. This is source-kind specific. 170 * 171 * @return The source description. 172 */ 173 public String getDescription() { 174 return CameraServerJNI.getSourceDescription(m_handle); 175 } 176 177 /** 178 * Get the last time a frame was captured. 179 * 180 * @return Time in 1 us increments. 181 */ 182 public long getLastFrameTime() { 183 return CameraServerJNI.getSourceLastFrameTime(m_handle); 184 } 185 186 /** 187 * Sets the connection strategy. By default, the source will automatically connect or disconnect 188 * based on whether any sinks are connected. 189 * 190 * <p>This function is non-blocking; look for either a connection open or close event or call 191 * {@link #isConnected()} to determine the connection state. 192 * 193 * @param strategy connection strategy (auto, keep open, or force close) 194 */ 195 public void setConnectionStrategy(ConnectionStrategy strategy) { 196 CameraServerJNI.setSourceConnectionStrategy(m_handle, strategy.getValue()); 197 } 198 199 /** 200 * Returns true if the source currently connected to whatever is providing the images. 201 * 202 * @return True if the source currently connected to whatever is providing the images. 203 */ 204 public boolean isConnected() { 205 return CameraServerJNI.isSourceConnected(m_handle); 206 } 207 208 /** 209 * Gets source enable status. This is determined with a combination of connection strategy and the 210 * number of sinks connected. 211 * 212 * @return True if enabled, false otherwise. 213 */ 214 public boolean isEnabled() { 215 return CameraServerJNI.isSourceEnabled(m_handle); 216 } 217 218 /** 219 * Get a property. 220 * 221 * @param name Property name 222 * @return Property contents (of kind Property::kNone if no property with the given name exists) 223 */ 224 public VideoProperty getProperty(String name) { 225 return new VideoProperty(CameraServerJNI.getSourceProperty(m_handle, name)); 226 } 227 228 /** 229 * Enumerate all properties of this source. 230 * 231 * @return Array of video properties. 232 */ 233 public VideoProperty[] enumerateProperties() { 234 int[] handles = CameraServerJNI.enumerateSourceProperties(m_handle); 235 VideoProperty[] rv = new VideoProperty[handles.length]; 236 for (int i = 0; i < handles.length; i++) { 237 rv[i] = new VideoProperty(handles[i]); 238 } 239 return rv; 240 } 241 242 /** 243 * Get the current video mode. 244 * 245 * @return The current video mode. 246 */ 247 public VideoMode getVideoMode() { 248 return CameraServerJNI.getSourceVideoMode(m_handle); 249 } 250 251 /** 252 * Set the video mode. 253 * 254 * @param mode Video mode 255 * @return True if set successfully. 256 */ 257 public boolean setVideoMode(VideoMode mode) { 258 return CameraServerJNI.setSourceVideoMode( 259 m_handle, mode.pixelFormat.getValue(), mode.width, mode.height, mode.fps); 260 } 261 262 /** 263 * Set the video mode. 264 * 265 * @param pixelFormat desired pixel format 266 * @param width desired width 267 * @param height desired height 268 * @param fps desired FPS 269 * @return True if set successfully 270 */ 271 public boolean setVideoMode(PixelFormat pixelFormat, int width, int height, int fps) { 272 return CameraServerJNI.setSourceVideoMode(m_handle, pixelFormat.getValue(), width, height, fps); 273 } 274 275 /** 276 * Set the pixel format. 277 * 278 * @param pixelFormat desired pixel format 279 * @return True if set successfully 280 */ 281 public boolean setPixelFormat(PixelFormat pixelFormat) { 282 return CameraServerJNI.setSourcePixelFormat(m_handle, pixelFormat.getValue()); 283 } 284 285 /** 286 * Set the resolution. 287 * 288 * @param width desired width 289 * @param height desired height 290 * @return True if set successfully 291 */ 292 public boolean setResolution(int width, int height) { 293 return CameraServerJNI.setSourceResolution(m_handle, width, height); 294 } 295 296 /** 297 * Set the frames per second (FPS). 298 * 299 * @param fps desired FPS 300 * @return True if set successfully 301 */ 302 public boolean setFPS(int fps) { 303 return CameraServerJNI.setSourceFPS(m_handle, fps); 304 } 305 306 /** 307 * Set video mode and properties from a JSON configuration string. 308 * 309 * <p>The format of the JSON input is: 310 * 311 * <pre> 312 * { 313 * "pixel format": "MJPEG", "YUYV", etc 314 * "width": video mode width 315 * "height": video mode height 316 * "fps": video mode fps 317 * "brightness": percentage brightness 318 * "white balance": "auto", "hold", or value 319 * "exposure": "auto", "hold", or value 320 * "properties": [ 321 * { 322 * "name": property name 323 * "value": property value 324 * } 325 * ] 326 * } 327 * </pre> 328 * 329 * @param config configuration 330 * @return True if set successfully 331 */ 332 public boolean setConfigJson(String config) { 333 return CameraServerJNI.setSourceConfigJson(m_handle, config); 334 } 335 336 /** 337 * Get a JSON configuration string. 338 * 339 * @return JSON configuration string 340 */ 341 public String getConfigJson() { 342 return CameraServerJNI.getSourceConfigJson(m_handle); 343 } 344 345 /** 346 * Get the actual FPS. 347 * 348 * <p>CameraServerJNI#setTelemetryPeriod() must be called for this to be valid (throws 349 * VisionException if telemetry is not enabled). 350 * 351 * @return Actual FPS averaged over the telemetry period. 352 */ 353 public double getActualFPS() { 354 return CameraServerJNI.getTelemetryAverageValue( 355 m_handle, CameraServerJNI.TelemetryKind.kSourceFramesReceived); 356 } 357 358 /** 359 * Get the data rate (in bytes per second). 360 * 361 * <p>CameraServerJNI#setTelemetryPeriod() must be called for this to be valid (throws 362 * VisionException if telemetry is not enabled). 363 * 364 * @return Data rate averaged over the telemetry period. 365 */ 366 public double getActualDataRate() { 367 return CameraServerJNI.getTelemetryAverageValue( 368 m_handle, CameraServerJNI.TelemetryKind.kSourceBytesReceived); 369 } 370 371 /** 372 * Enumerate all known video modes for this source. 373 * 374 * @return Vector of video modes. 375 */ 376 public VideoMode[] enumerateVideoModes() { 377 return CameraServerJNI.enumerateSourceVideoModes(m_handle); 378 } 379 380 /** 381 * Enumerate all sinks connected to this source. 382 * 383 * @return Vector of sinks. 384 */ 385 public VideoSink[] enumerateSinks() { 386 int[] handles = CameraServerJNI.enumerateSourceSinks(m_handle); 387 VideoSink[] rv = new VideoSink[handles.length]; 388 for (int i = 0; i < handles.length; i++) { 389 rv[i] = new VideoSink(handles[i]); 390 } 391 return rv; 392 } 393 394 /** 395 * Enumerate all existing sources. 396 * 397 * @return Vector of sources. 398 */ 399 public static VideoSource[] enumerateSources() { 400 int[] handles = CameraServerJNI.enumerateSources(); 401 VideoSource[] rv = new VideoSource[handles.length]; 402 for (int i = 0; i < handles.length; i++) { 403 rv[i] = new VideoSource(handles[i]); 404 } 405 return rv; 406 } 407 408 /** Video source handle. */ 409 protected int m_handle; 410}