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 007/** 008 * A source for video that provides a sequence of frames. Each frame may consist of multiple images 009 * (e.g. from a stereo or depth camera); these are called channels. 010 */ 011public class VideoSink implements AutoCloseable { 012 /** Video sink types. */ 013 public enum Kind { 014 /** Unknown video sink type. */ 015 kUnknown(0), 016 /** MJPEG video sink. */ 017 kMjpeg(2), 018 /** CV video sink. */ 019 kCv(4), 020 /** Raw video sink. */ 021 kRaw(8); 022 023 private final int value; 024 025 Kind(int value) { 026 this.value = value; 027 } 028 029 /** 030 * Returns the Kind value. 031 * 032 * @return The Kind value. 033 */ 034 public int getValue() { 035 return value; 036 } 037 } 038 039 /** 040 * Convert from the numerical representation of kind to an enum type. 041 * 042 * @param kind The numerical representation of kind 043 * @return The kind 044 */ 045 public static Kind getKindFromInt(int kind) { 046 switch (kind) { 047 case 2: 048 return Kind.kMjpeg; 049 case 4: 050 return Kind.kCv; 051 case 8: 052 return Kind.kRaw; 053 default: 054 return Kind.kUnknown; 055 } 056 } 057 058 /** 059 * Constructs a VideoSink. 060 * 061 * @param handle The video sink handle. 062 */ 063 protected VideoSink(int handle) { 064 m_handle = handle; 065 } 066 067 @Override 068 public synchronized void close() { 069 if (m_handle != 0) { 070 CameraServerJNI.releaseSink(m_handle); 071 } 072 m_handle = 0; 073 } 074 075 /** 076 * Returns true if the VideoSink is valid. 077 * 078 * @return True if the VideoSink is valid. 079 */ 080 public boolean isValid() { 081 return m_handle != 0; 082 } 083 084 /** 085 * Returns the video sink handle. 086 * 087 * @return The video sink handle. 088 */ 089 public int getHandle() { 090 return m_handle; 091 } 092 093 @Override 094 public boolean equals(Object other) { 095 if (this == other) { 096 return true; 097 } 098 if (other == null) { 099 return false; 100 } 101 if (getClass() != other.getClass()) { 102 return false; 103 } 104 VideoSink sink = (VideoSink) other; 105 return m_handle == sink.m_handle; 106 } 107 108 @Override 109 public int hashCode() { 110 return m_handle; 111 } 112 113 /** 114 * Get the kind of the sink. 115 * 116 * @return The kind of the sink. 117 */ 118 public Kind getKind() { 119 return getKindFromInt(CameraServerJNI.getSinkKind(m_handle)); 120 } 121 122 /** 123 * Get the name of the sink. The name is an arbitrary identifier provided when the sink is 124 * created, and should be unique. 125 * 126 * @return The name of the sink. 127 */ 128 public String getName() { 129 return CameraServerJNI.getSinkName(m_handle); 130 } 131 132 /** 133 * Get the sink description. This is sink-kind specific. 134 * 135 * @return The sink description. 136 */ 137 public String getDescription() { 138 return CameraServerJNI.getSinkDescription(m_handle); 139 } 140 141 /** 142 * Get a property of the sink. 143 * 144 * @param name Property name 145 * @return Property (kind Property::kNone if no property with the given name exists) 146 */ 147 public VideoProperty getProperty(String name) { 148 return new VideoProperty(CameraServerJNI.getSinkProperty(m_handle, name)); 149 } 150 151 /** 152 * Enumerate all properties of this sink. 153 * 154 * @return List of properties. 155 */ 156 public VideoProperty[] enumerateProperties() { 157 int[] handles = CameraServerJNI.enumerateSinkProperties(m_handle); 158 VideoProperty[] rv = new VideoProperty[handles.length]; 159 for (int i = 0; i < handles.length; i++) { 160 rv[i] = new VideoProperty(handles[i]); 161 } 162 return rv; 163 } 164 165 /** 166 * Set properties from a JSON configuration string. 167 * 168 * <p>The format of the JSON input is: 169 * 170 * <pre> 171 * { 172 * "properties": [ 173 * { 174 * "name": property name 175 * "value": property value 176 * } 177 * ] 178 * } 179 * </pre> 180 * 181 * @param config configuration 182 * @return True if set successfully 183 */ 184 public boolean setConfigJson(String config) { 185 return CameraServerJNI.setSinkConfigJson(m_handle, config); 186 } 187 188 /** 189 * Get a JSON configuration string. 190 * 191 * @return JSON configuration string 192 */ 193 public String getConfigJson() { 194 return CameraServerJNI.getSinkConfigJson(m_handle); 195 } 196 197 /** 198 * Configure which source should provide frames to this sink. Each sink can accept frames from 199 * only a single source, but a single source can provide frames to multiple clients. 200 * 201 * @param source Source 202 */ 203 public void setSource(VideoSource source) { 204 if (source == null) { 205 CameraServerJNI.setSinkSource(m_handle, 0); 206 } else { 207 CameraServerJNI.setSinkSource(m_handle, source.m_handle); 208 } 209 } 210 211 /** 212 * Get the connected source. 213 * 214 * @return Connected source; nullptr if no source connected. 215 */ 216 public VideoSource getSource() { 217 // While VideoSource.close() will call releaseSource(), getSinkSource() 218 // increments the internal reference count so this is okay to do. 219 return new VideoSource(CameraServerJNI.getSinkSource(m_handle)); 220 } 221 222 /** 223 * Get a property of the associated source. 224 * 225 * @param name Property name 226 * @return Property (kind Property::kNone if no property with the given name exists or no source 227 * connected) 228 */ 229 public VideoProperty getSourceProperty(String name) { 230 return new VideoProperty(CameraServerJNI.getSinkSourceProperty(m_handle, name)); 231 } 232 233 /** 234 * Enumerate all existing sinks. 235 * 236 * @return Vector of sinks. 237 */ 238 public static VideoSink[] enumerateSinks() { 239 int[] handles = CameraServerJNI.enumerateSinks(); 240 VideoSink[] rv = new VideoSink[handles.length]; 241 for (int i = 0; i < handles.length; i++) { 242 rv[i] = new VideoSink(handles[i]); 243 } 244 return rv; 245 } 246 247 /** The VideoSink handle. */ 248 protected int m_handle; 249}