Use CameraServer directly instead of duplicating its functionality

This commit is contained in:
Gold856
2025-04-14 16:55:21 -04:00
committed by Matt Morley
parent a4295275ed
commit 1bb861545b

View File

@@ -17,11 +17,9 @@
package org.photonvision.vision.frame.consumer;
import edu.wpi.first.cameraserver.CameraServer;
import edu.wpi.first.cscore.*;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableInstance;
import edu.wpi.first.util.PixelFormat;
import java.util.ArrayList;
import org.photonvision.common.util.math.MathUtils;
import org.photonvision.vision.frame.StaticFrames;
import org.photonvision.vision.opencv.CVMat;
@@ -34,59 +32,13 @@ public class MJPGFrameConsumer implements AutoCloseable {
private CvSource cvSource;
private MjpegServer mjpegServer;
private VideoListener listener;
private final NetworkTable table;
public MJPGFrameConsumer(String sourceName, int width, int height, int port) {
this.cvSource = new CvSource(sourceName, PixelFormat.kMJPEG, width, height, 30);
this.table =
NetworkTableInstance.getDefault().getTable("/CameraPublisher").getSubTable(sourceName);
this.mjpegServer = new MjpegServer("serve_" + cvSource.getName(), port);
mjpegServer.setSource(cvSource);
mjpegServer.setCompression(75);
listener =
new VideoListener(
event -> {
if (event.kind == VideoEvent.Kind.kNetworkInterfacesChanged) {
table.getEntry("source").setString("cv:");
table.getEntry("streams");
table.getEntry("connected").setBoolean(true);
table.getEntry("mode").setString(videoModeToString(cvSource.getVideoMode()));
table.getEntry("modes").setStringArray(getSourceModeValues(cvSource.getHandle()));
updateStreamValues();
}
},
0x4fff,
true);
}
private synchronized void updateStreamValues() {
// Get port
int port = mjpegServer.getPort();
// Generate values
var addresses = CameraServerJNI.getNetworkInterfaces();
ArrayList<String> values = new ArrayList<>(addresses.length + 1);
String listenAddress = CameraServerJNI.getMjpegServerListenAddress(mjpegServer.getHandle());
if (!listenAddress.isEmpty()) {
// If a listen address is specified, only use that
values.add(makeStreamValue(listenAddress, port));
} else {
// Otherwise generate for hostname and all interface addresses
values.add(makeStreamValue(CameraServerJNI.getHostname() + ".local", port));
for (String addr : addresses) {
if ("127.0.0.1".equals(addr)) {
continue; // ignore localhost
}
values.add(makeStreamValue(addr, port));
}
}
String[] streamAddresses = values.toArray(new String[0]);
table.getEntry("streams").setStringArray(streamAddresses);
CameraServer.addServer(mjpegServer);
}
public MJPGFrameConsumer(String name, int port) {
@@ -106,53 +58,12 @@ public class MJPGFrameConsumer implements AutoCloseable {
}
}
public int getCurrentStreamPort() {
return mjpegServer.getPort();
}
private static String makeStreamValue(String address, int port) {
return "mjpg:http://" + address + ":" + port + "/?action=stream";
}
private static String[] getSourceModeValues(int sourceHandle) {
VideoMode[] modes = CameraServerJNI.enumerateSourceVideoModes(sourceHandle);
String[] modeStrings = new String[modes.length];
for (int i = 0; i < modes.length; i++) {
modeStrings[i] = videoModeToString(modes[i]);
}
return modeStrings;
}
private static String videoModeToString(VideoMode mode) {
return mode.width
+ "x"
+ mode.height
+ " "
+ pixelFormatToString(mode.pixelFormat)
+ " "
+ mode.fps
+ " fps";
}
private static String pixelFormatToString(PixelFormat pixelFormat) {
return switch (pixelFormat) {
case kMJPEG -> "MJPEG";
case kYUYV -> "YUYV";
case kRGB565 -> "RGB565";
case kBGR -> "BGR";
case kGray -> "Gray";
case kUYVY, kUnknown, kY16, kBGRA -> "Unknown";
};
}
@Override
public void close() {
table.getEntry("connected").setBoolean(false);
CameraServer.removeServer(mjpegServer.getName());
mjpegServer.close();
cvSource.close();
listener.close();
mjpegServer = null;
cvSource = null;
listener = null;
}
}