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