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}