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}