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