Skip to content

Commit

Permalink
Remove socket camera streaming (#985)
Browse files Browse the repository at this point in the history
Removes websocket-based camera streaming functionality. 

Fixes #975. This was caused by destroying the camera streams and recreating them on nickname change. Even when directly using `MJPGFrameConsumer` and the streams were exactly the same, the freeze would occur when creating a new `MjpegServer` and require a refresh. I think this is simply how cscore works?
  • Loading branch information
amquake authored Oct 30, 2023
1 parent 0898dfe commit 76e3c6d
Show file tree
Hide file tree
Showing 8 changed files with 30 additions and 474 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,18 @@
import org.opencv.core.Rect;
import org.opencv.imgproc.Imgproc;
import org.photonvision.common.util.ColorHelper;
import org.photonvision.common.util.math.MathUtils;
import org.photonvision.vision.opencv.CVMat;

public class MJPGFrameConsumer {
public static final Mat EMPTY_MAT = new Mat(60, 15 * 7, CvType.CV_8UC3);
public class MJPGFrameConsumer implements AutoCloseable {
private static final double MAX_FRAMERATE = -1;
private static final long MAX_FRAME_PERIOD_NS = Math.round(1e9 / MAX_FRAMERATE);
private long lastFrameTimeNs;

private static final Mat EMPTY_MAT = new Mat(60, 15 * 7, CvType.CV_8UC3);
private static final double EMPTY_FRAMERATE = 2;
private long lastEmptyTime;
private static final long EMPTY_FRAME_PERIOD_NS = Math.round(1e9 / EMPTY_FRAMERATE);
private long lastEmptyTimeNs;

static {
EMPTY_MAT.setTo(ColorHelper.colorToScalar(Color.BLACK));
Expand Down Expand Up @@ -168,11 +174,15 @@ public MJPGFrameConsumer(String name, int port) {

public void accept(CVMat image) {
if (image != null && !image.getMat().empty()) {
cvSource.putFrame(image.getMat());
long now = MathUtils.wpiNanoTime();
if (now - lastFrameTimeNs > MAX_FRAME_PERIOD_NS) {
lastFrameTimeNs = now;
cvSource.putFrame(image.getMat());
}

// Make sure our disabled framerate limiting doesn't get confused
isDisabled = false;
lastEmptyTime = 0;
lastEmptyTimeNs = 0;
}
}

Expand All @@ -182,9 +192,10 @@ public void disabledTick() {
isDisabled = true;
}

if (System.currentTimeMillis() - lastEmptyTime > 1000.0 / EMPTY_FRAMERATE) {
long now = MathUtils.wpiNanoTime();
if (now - lastEmptyTimeNs > EMPTY_FRAME_PERIOD_NS) {
lastEmptyTimeNs = now;
cvSource.putFrame(EMPTY_MAT);
lastEmptyTime = System.currentTimeMillis();
}
}

Expand Down Expand Up @@ -233,6 +244,7 @@ private static String pixelFormatToString(VideoMode.PixelFormat pixelFormat) {
}
}

@Override
public void close() {
table.getEntry("connected").setBoolean(false);
mjpegServer.close();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.photonvision.vision.processes;

import edu.wpi.first.cscore.CameraServerJNI;
import edu.wpi.first.cscore.VideoException;
import edu.wpi.first.math.util.Units;
import io.javalin.websocket.WsContext;
Expand Down Expand Up @@ -44,15 +45,14 @@
import org.photonvision.vision.camera.USBCameraSource;
import org.photonvision.vision.frame.Frame;
import org.photonvision.vision.frame.consumer.FileSaveFrameConsumer;
import org.photonvision.vision.frame.consumer.MJPGFrameConsumer;
import org.photonvision.vision.pipeline.AdvancedPipelineSettings;
import org.photonvision.vision.pipeline.OutputStreamPipeline;
import org.photonvision.vision.pipeline.ReflectivePipelineSettings;
import org.photonvision.vision.pipeline.UICalibrationData;
import org.photonvision.vision.pipeline.result.CVPipelineResult;
import org.photonvision.vision.target.TargetModel;
import org.photonvision.vision.target.TrackedTarget;
import org.photonvision.vision.videoStream.SocketVideoStream;
import org.photonvision.vision.videoStream.SocketVideoStreamManager;

/**
* This is the God Class
Expand Down Expand Up @@ -83,8 +83,8 @@ public class VisionModule {
FileSaveFrameConsumer inputFrameSaver;
FileSaveFrameConsumer outputFrameSaver;

SocketVideoStream inputVideoStreamer;
SocketVideoStream outputVideoStreamer;
MJPGFrameConsumer inputVideoStreamer;
MJPGFrameConsumer outputVideoStreamer;

public VisionModule(PipelineManager pipelineManager, VisionSource visionSource, int index) {
logger =
Expand Down Expand Up @@ -169,11 +169,6 @@ public VisionModule(PipelineManager pipelineManager, VisionSource visionSource,
saveAndBroadcastAll();
}

private void destroyStreams() {
SocketVideoStreamManager.getInstance().removeStream(inputVideoStreamer);
SocketVideoStreamManager.getInstance().removeStream(outputVideoStreamer);
}

private void createStreams() {
var camStreamIdx = visionSource.getSettables().getConfiguration().streamIndex;
// If idx = 0, we want (1181, 1182)
Expand All @@ -186,10 +181,13 @@ private void createStreams() {
new FileSaveFrameConsumer(
visionSource.getSettables().getConfiguration().nickname, "output");

inputVideoStreamer = new SocketVideoStream(this.inputStreamPort);
outputVideoStreamer = new SocketVideoStream(this.outputStreamPort);
SocketVideoStreamManager.getInstance().addStream(inputVideoStreamer);
SocketVideoStreamManager.getInstance().addStream(outputVideoStreamer);
String camHostname = CameraServerJNI.getHostname();
inputVideoStreamer =
new MJPGFrameConsumer(
camHostname + "_Port_" + inputStreamPort + "_Input_MJPEG_Server", inputStreamPort);
outputVideoStreamer =
new MJPGFrameConsumer(
camHostname + "_Port_" + outputStreamPort + "_Output_MJPEG_Server", outputStreamPort);
}

private void recreateStreamResultConsumers() {
Expand Down Expand Up @@ -483,16 +481,6 @@ public void setCameraNickname(String newName) {
inputFrameSaver.updateCameraNickname(newName);
outputFrameSaver.updateCameraNickname(newName);

// Rename streams
streamResultConsumers.clear();

// Teardown and recreate streams
destroyStreams();
createStreams();

// Rebuild streamers
recreateStreamResultConsumers();

// Push new data to the UI
saveAndBroadcastAll();
}
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit 76e3c6d

Please sign in to comment.