mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-24 01:31:44 +00:00
Rename MJPEG streams when camera name changes (#136)
* Rename MJPEG streams when camera name changes * Change camera name to HTTP request This allows us to wait for it to for sure be done * Fix reload logic * whee lnt * Reload on backend connect too * Update CameraAndPipelineSelect.vue
This commit is contained in:
@@ -198,6 +198,7 @@ import Logs from "./views/LogsView"
|
||||
};
|
||||
this.$options.sockets.onopen = () => {
|
||||
this.$store.state.backendConnected = true;
|
||||
this.$store.state.connectedCallbacks.forEach(it => it())
|
||||
};
|
||||
|
||||
let closed = () => {
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
name: "CvImage",
|
||||
// eslint-disable-next-line vue/require-prop-types
|
||||
props: ['address', 'scale', 'maxHeight', 'maxHeightMd', 'maxHeightXl', 'colorPicking', 'id', 'disconnected'],
|
||||
data() {
|
||||
return {
|
||||
seed: 1.0,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
styleObject: {
|
||||
get() {
|
||||
@@ -41,9 +46,17 @@
|
||||
},
|
||||
src: {
|
||||
get() {
|
||||
return this.disconnected ? require("../../assets/noStream.jpg") : this.address;
|
||||
return this.disconnected ? require("../../assets/noStream.jpg") : this.address + "?" + this.seed // This prevents caching
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.reload(); // Force reload image on creation
|
||||
},
|
||||
methods: {
|
||||
reload() {
|
||||
this.seed = new Date().getTime();
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -34,7 +34,7 @@
|
||||
:hover="true"
|
||||
text="edit"
|
||||
tooltip="Edit camera name"
|
||||
@click="toCameraNameChange"
|
||||
@click="changeCameraName"
|
||||
/>
|
||||
<div v-else>
|
||||
<CVicon
|
||||
@@ -292,13 +292,23 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toCameraNameChange() {
|
||||
changeCameraName() {
|
||||
this.newCameraName = this.$store.getters.cameraList[this.currentCameraIndex];
|
||||
this.isCameraNameEdit = true;
|
||||
},
|
||||
saveCameraNameChange() {
|
||||
if (this.checkCameraName === "") {
|
||||
this.handleInputWithIndex("changeCameraName", this.newCameraName);
|
||||
// this.handleInputWithIndex("changeCameraName", this.newCameraName);
|
||||
this.axios.post('http://' + this.$address + '/api/setCameraNickname',
|
||||
{name: this.newCameraName, cameraIndex: this.$store.getters.currentCameraIndex})
|
||||
// eslint-disable-next-line
|
||||
.then(r => {
|
||||
this.$emit('camera-name-changed')
|
||||
})
|
||||
.catch(e => {
|
||||
console.log("HTTP error while changing camera name " + e);
|
||||
this.$emit('camera-name-changed')
|
||||
})
|
||||
this.discardCameraNameChange();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -15,6 +15,7 @@ export default new Vuex.Store({
|
||||
},
|
||||
state: {
|
||||
backendConnected: false,
|
||||
connectedCallbacks: [],
|
||||
colorPicking: false,
|
||||
logsOverlay: false,
|
||||
compactMode: localStorage.getItem("compactMode") === undefined ? undefined : localStorage.getItem("compactMode") === "true", // Compact mode is initially unset on purpose
|
||||
|
||||
@@ -45,8 +45,9 @@
|
||||
style="height: 100%;"
|
||||
>
|
||||
<div style="position: relative; width: 100%; height: 100%;">
|
||||
<cvImage
|
||||
<cv-image
|
||||
:id="idx === 0 ? 'normal-stream' : ''"
|
||||
ref="streams"
|
||||
:address="$store.getters.streamAddress[idx]"
|
||||
:disconnected="!$store.state.backendConnected"
|
||||
scale="100"
|
||||
@@ -71,7 +72,10 @@
|
||||
<v-card
|
||||
color="primary"
|
||||
>
|
||||
<camera-and-pipeline-select />
|
||||
<!-- <v-btn @click="onCamNameChange">-->
|
||||
<!-- Reload-->
|
||||
<!-- </v-btn>-->
|
||||
<camera-and-pipeline-select @camera-name-changed="reloadStreams" />
|
||||
</v-card>
|
||||
<v-card
|
||||
:disabled="$store.getters.isDriverMode || $store.state.colorPicking"
|
||||
@@ -212,8 +216,12 @@
|
||||
</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
Because the current resolution {{ this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex].width }}
|
||||
x {{ this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex].height }}
|
||||
Because the current resolution {{
|
||||
this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex].width
|
||||
}}
|
||||
x {{
|
||||
this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex].height
|
||||
}}
|
||||
is not yet calibrated, 3D mode cannot be enabled. Please
|
||||
<a
|
||||
href="/#/cameras"
|
||||
@@ -240,202 +248,209 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CameraAndPipelineSelect from "../components/pipeline/CameraAndPipelineSelect";
|
||||
import cvImage from '../components/common/cv-image';
|
||||
import InputTab from './PipelineViews/InputTab';
|
||||
import ThresholdTab from './PipelineViews/ThresholdTab';
|
||||
import ContoursTab from './PipelineViews/ContoursTab';
|
||||
import OutputTab from './PipelineViews/OutputTab';
|
||||
import TargetsTab from "./PipelineViews/TargetsTab";
|
||||
import PnPTab from './PipelineViews/PnPTab';
|
||||
import CameraAndPipelineSelect from "../components/pipeline/CameraAndPipelineSelect";
|
||||
import cvImage from '../components/common/cv-image';
|
||||
import InputTab from './PipelineViews/InputTab';
|
||||
import ThresholdTab from './PipelineViews/ThresholdTab';
|
||||
import ContoursTab from './PipelineViews/ContoursTab';
|
||||
import OutputTab from './PipelineViews/OutputTab';
|
||||
import TargetsTab from "./PipelineViews/TargetsTab";
|
||||
import PnPTab from './PipelineViews/PnPTab';
|
||||
|
||||
export default {
|
||||
name: 'CameraTab',
|
||||
components: {
|
||||
CameraAndPipelineSelect,
|
||||
cvImage,
|
||||
InputTab,
|
||||
ThresholdTab,
|
||||
ContoursTab,
|
||||
OutputTab,
|
||||
TargetsTab,
|
||||
PnPTab,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedTabsData: [0, 0, 0, 0],
|
||||
snackbar: false,
|
||||
counterData: 0,
|
||||
dialog: false,
|
||||
processingModeOverride: false
|
||||
export default {
|
||||
name: 'CameraTab',
|
||||
components: {
|
||||
CameraAndPipelineSelect,
|
||||
cvImage,
|
||||
InputTab,
|
||||
ThresholdTab,
|
||||
ContoursTab,
|
||||
OutputTab,
|
||||
TargetsTab,
|
||||
PnPTab,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
selectedTabsData: [0, 0, 0, 0],
|
||||
snackbar: false,
|
||||
counterData: 0,
|
||||
dialog: false,
|
||||
processingModeOverride: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedTabs: {
|
||||
get() {
|
||||
return this.$store.getters.isDriverMode ? [0] : this.selectedTabsData;
|
||||
},
|
||||
set(value) {
|
||||
this.selectedTabsData = value;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedTabs: {
|
||||
get() {
|
||||
return this.$store.getters.isDriverMode ? [0] : this.selectedTabsData;
|
||||
},
|
||||
set(value) {
|
||||
this.selectedTabsData = value;
|
||||
}
|
||||
},
|
||||
tabGroups: {
|
||||
get() {
|
||||
let tabs = {
|
||||
input: {
|
||||
name: "Input",
|
||||
component: "InputTab",
|
||||
},
|
||||
threshold: {
|
||||
name: "Threshold",
|
||||
component: "ThresholdTab",
|
||||
},
|
||||
contours: {
|
||||
name: "Contours",
|
||||
component: "ContoursTab",
|
||||
},
|
||||
output: {
|
||||
name: "Output",
|
||||
component: "OutputTab",
|
||||
},
|
||||
targets: {
|
||||
name: "Target Info",
|
||||
component: "TargetsTab",
|
||||
},
|
||||
pnp: {
|
||||
name: "3D",
|
||||
component: "PnPTab",
|
||||
}
|
||||
};
|
||||
|
||||
// 2D array of tab names and component names; each sub-array is a separate tab group
|
||||
let ret = [];
|
||||
if (this.$vuetify.breakpoint.smAndDown || this.$store.getters.isDriverMode || (this.$vuetify.breakpoint.mdAndDown && !this.$store.state.compactMode)) {
|
||||
// One big tab group with all the tabs
|
||||
ret[0] = Object.values(tabs);
|
||||
} else if (this.$vuetify.breakpoint.mdAndDown || !this.$store.state.compactMode) {
|
||||
// Two tab groups, one with "input, threshold, contours, output" and the other with "target info, 3D"
|
||||
ret[0] = [tabs.input, tabs.threshold, tabs.contours, tabs.output];
|
||||
ret[1] = [tabs.targets, tabs.pnp];
|
||||
} else if (this.$vuetify.breakpoint.lgAndDown) {
|
||||
// Three tab groups, one with "input", one with "threshold, contours, output", and the other with "target info, 3D"
|
||||
ret[0] = [tabs.input];
|
||||
ret[1] = [tabs.threshold, tabs.contours, tabs.output];
|
||||
ret[2] = [tabs.targets, tabs.pnp];
|
||||
} else if (this.$vuetify.breakpoint.xl) {
|
||||
// Three tab groups, one with "input", one with "threshold, contours", and the other with "output, target info, 3D"
|
||||
ret[0] = [tabs.input];
|
||||
ret[1] = [tabs.threshold];
|
||||
ret[2] = [tabs.contours, tabs.output]
|
||||
ret[3] = [tabs.targets, tabs.pnp];
|
||||
tabGroups: {
|
||||
get() {
|
||||
let tabs = {
|
||||
input: {
|
||||
name: "Input",
|
||||
component: "InputTab",
|
||||
},
|
||||
threshold: {
|
||||
name: "Threshold",
|
||||
component: "ThresholdTab",
|
||||
},
|
||||
contours: {
|
||||
name: "Contours",
|
||||
component: "ContoursTab",
|
||||
},
|
||||
output: {
|
||||
name: "Output",
|
||||
component: "OutputTab",
|
||||
},
|
||||
targets: {
|
||||
name: "Target Info",
|
||||
component: "TargetsTab",
|
||||
},
|
||||
pnp: {
|
||||
name: "3D",
|
||||
component: "PnPTab",
|
||||
}
|
||||
};
|
||||
|
||||
// 2D array of tab names and component names; each sub-array is a separate tab group
|
||||
let ret = [];
|
||||
if (this.$vuetify.breakpoint.smAndDown || this.$store.getters.isDriverMode || (this.$vuetify.breakpoint.mdAndDown && !this.$store.state.compactMode)) {
|
||||
// One big tab group with all the tabs
|
||||
ret[0] = Object.values(tabs);
|
||||
} else if (this.$vuetify.breakpoint.mdAndDown || !this.$store.state.compactMode) {
|
||||
// Two tab groups, one with "input, threshold, contours, output" and the other with "target info, 3D"
|
||||
ret[0] = [tabs.input, tabs.threshold, tabs.contours, tabs.output];
|
||||
ret[1] = [tabs.targets, tabs.pnp];
|
||||
} else if (this.$vuetify.breakpoint.lgAndDown) {
|
||||
// Three tab groups, one with "input", one with "threshold, contours, output", and the other with "target info, 3D"
|
||||
ret[0] = [tabs.input];
|
||||
ret[1] = [tabs.threshold, tabs.contours, tabs.output];
|
||||
ret[2] = [tabs.targets, tabs.pnp];
|
||||
} else if (this.$vuetify.breakpoint.xl) {
|
||||
// Three tab groups, one with "input", one with "threshold, contours", and the other with "output, target info, 3D"
|
||||
ret[0] = [tabs.input];
|
||||
ret[1] = [tabs.threshold];
|
||||
ret[2] = [tabs.contours, tabs.output]
|
||||
ret[3] = [tabs.targets, tabs.pnp];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
},
|
||||
processingMode: {
|
||||
get() {
|
||||
return (this.$store.getters.currentPipelineSettings.solvePNPEnabled || this.processingModeOverride) ? 1 : 0;
|
||||
},
|
||||
set(value) {
|
||||
if (this.$store.getters.isCalibrated) {
|
||||
this.$store.getters.currentPipelineSettings.solvePNPEnabled = value === 1;
|
||||
this.handlePipelineUpdate("solvePNPEnabled", value === 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
driverMode: {
|
||||
get() {
|
||||
return this.$store.getters.isDriverMode;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.getters.currentCameraSettings.currentPipelineIndex = value ? -1 : 0;
|
||||
this.handleInputWithIndex('currentPipeline', value ? -1 : 0);
|
||||
}
|
||||
},
|
||||
selectedOutputs: {
|
||||
// All this logic exists to deal with the reality that the output select buttons sometimes need an array and sometimes need a number (depending on whether or not they're exclusive)
|
||||
get() {
|
||||
// We switch the selector to single-select only on sm-and-down size devices, so we have to return a Number instead of an Array in that state
|
||||
let ret;
|
||||
if (this.$store.state.colorPicking) {
|
||||
ret = [0]; // We want the input stream only while color picking
|
||||
} else if (!this.$store.getters.isDriverMode) {
|
||||
ret = this.$store.state.selectedOutputs || [0];
|
||||
} else {
|
||||
ret = [1]; // We want the output stream in driver mode
|
||||
}
|
||||
|
||||
if (this.$vuetify.breakpoint.mdAndUp) {
|
||||
return ret;
|
||||
} else {
|
||||
return ret[0] || 0;
|
||||
}
|
||||
},
|
||||
processingMode: {
|
||||
get() {
|
||||
return (this.$store.getters.currentPipelineSettings.solvePNPEnabled || this.processingModeOverride) ? 1 : 0;
|
||||
},
|
||||
set(value) {
|
||||
if (this.$store.getters.isCalibrated) {
|
||||
this.$store.getters.currentPipelineSettings.solvePNPEnabled = value === 1;
|
||||
this.handlePipelineUpdate("solvePNPEnabled", value === 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
driverMode: {
|
||||
get() {
|
||||
return this.$store.getters.isDriverMode;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.getters.currentCameraSettings.currentPipelineIndex = value ? -1 : 0;
|
||||
this.handleInputWithIndex('currentPipeline', value ? -1 : 0);
|
||||
}
|
||||
},
|
||||
selectedOutputs: {
|
||||
// All this logic exists to deal with the reality that the output select buttons sometimes need an array and sometimes need a number (depending on whether or not they're exclusive)
|
||||
get() {
|
||||
// We switch the selector to single-select only on sm-and-down size devices, so we have to return a Number instead of an Array in that state
|
||||
let ret;
|
||||
if (this.$store.state.colorPicking) {
|
||||
ret = [0]; // We want the input stream only while color picking
|
||||
} else if (!this.$store.getters.isDriverMode) {
|
||||
ret = this.$store.state.selectedOutputs || [0];
|
||||
} else {
|
||||
ret = [1]; // We want the output stream in driver mode
|
||||
}
|
||||
|
||||
if (this.$vuetify.breakpoint.mdAndUp) {
|
||||
return ret;
|
||||
} else {
|
||||
return ret[0] || 0;
|
||||
}
|
||||
},
|
||||
set(value) {
|
||||
let valToCommit = [0];
|
||||
if (value instanceof Array) {
|
||||
// Value is already an array, we don't need to do anything
|
||||
value.sort(); // Sort for visual consistency
|
||||
valToCommit = value;
|
||||
} else if (value) {
|
||||
// Value is assumed to be a number, so we wrap it into an array
|
||||
valToCommit = [value];
|
||||
}
|
||||
this.$store.commit("selectedOutputs", valToCommit);
|
||||
// TODO: Currently the backend just sends both streams regardless of the selected outputs value, so we don't need to send anything
|
||||
// this.handlePipelineUpdate('selectedOutputs', valToCommit);
|
||||
}
|
||||
},
|
||||
latency: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineResults.latency;
|
||||
set(value) {
|
||||
let valToCommit = [0];
|
||||
if (value instanceof Array) {
|
||||
// Value is already an array, we don't need to do anything
|
||||
value.sort(); // Sort for visual consistency
|
||||
valToCommit = value;
|
||||
} else if (value) {
|
||||
// Value is assumed to be a number, so we wrap it into an array
|
||||
valToCommit = [value];
|
||||
}
|
||||
this.$store.commit("selectedOutputs", valToCommit);
|
||||
// TODO: Currently the backend just sends both streams regardless of the selected outputs value, so we don't need to send anything
|
||||
// this.handlePipelineUpdate('selectedOutputs', valToCommit);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
isCalibrated() {
|
||||
const resolution = this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex];
|
||||
return this.$store.getters.currentCameraSettings.calibrations
|
||||
.some(e => e.width === resolution.width && e.height === resolution.height)
|
||||
},
|
||||
onImageClick(event) {
|
||||
// Only run on the input stream
|
||||
if (event.target.alt !== "Stream0") return;
|
||||
// Get a reference to the threshold tab (if it is shown) and call its "onClick" method
|
||||
let ref = this.$refs["Threshold"];
|
||||
if (ref && ref[0])
|
||||
ref[0].onClick(event)
|
||||
},
|
||||
on3DClick() {
|
||||
if (!this.$store.getters.isCalibrated) {
|
||||
this.dialog = true;
|
||||
this.processingModeOverride = true;
|
||||
}
|
||||
},
|
||||
closeUncalibratedDialog() {
|
||||
this.dialog = false;
|
||||
this.processingModeOverride = false;
|
||||
// this.$store.getters.currentPipelineSettings.solvePNPEnabled = false;
|
||||
this.handlePipelineUpdate("solvePNPEnabled", false);
|
||||
latency: {
|
||||
get() {
|
||||
return this.$store.getters.currentPipelineResults.latency;
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.state.connectedCallbacks.push(this.reloadStreams)
|
||||
},
|
||||
methods: {
|
||||
reloadStreams() {
|
||||
// Reload the streams as we technically close and reopen them
|
||||
this.$refs.streams.forEach(it => it.reload())
|
||||
},
|
||||
isCalibrated() {
|
||||
const resolution = this.$store.getters.videoFormatList[this.$store.getters.currentPipelineSettings.cameraVideoModeIndex];
|
||||
return this.$store.getters.currentCameraSettings.calibrations
|
||||
.some(e => e.width === resolution.width && e.height === resolution.height)
|
||||
},
|
||||
onImageClick(event) {
|
||||
// Only run on the input stream
|
||||
if (event.target.alt !== "Stream0") return;
|
||||
// Get a reference to the threshold tab (if it is shown) and call its "onClick" method
|
||||
let ref = this.$refs["Threshold"];
|
||||
if (ref && ref[0])
|
||||
ref[0].onClick(event)
|
||||
},
|
||||
on3DClick() {
|
||||
if (!this.$store.getters.isCalibrated) {
|
||||
this.dialog = true;
|
||||
this.processingModeOverride = true;
|
||||
}
|
||||
},
|
||||
closeUncalibratedDialog() {
|
||||
this.dialog = false;
|
||||
this.processingModeOverride = false;
|
||||
// this.$store.getters.currentPipelineSettings.solvePNPEnabled = false;
|
||||
this.handlePipelineUpdate("solvePNPEnabled", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.v-btn-toggle.fill {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.v-btn-toggle.fill {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.v-btn-toggle.fill > .v-btn {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
.v-btn-toggle.fill > .v-btn {
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
th {
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
th {
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -160,6 +160,20 @@ public class RequestHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setCameraNickname(Context ctx) {
|
||||
try {
|
||||
var data = kObjectMapper.readValue(ctx.body(), HashMap.class);
|
||||
String name = String.valueOf(data.get("name"));
|
||||
int idx = Integer.parseInt(String.valueOf(data.get("cameraIndex")));
|
||||
VisionModuleManager.getInstance().getModule(idx).setCameraNickname(name);
|
||||
ctx.status(200);
|
||||
return;
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
ctx.status(500);
|
||||
}
|
||||
|
||||
public static void uploadPnpModel(Context ctx) {
|
||||
UITargetData data;
|
||||
try {
|
||||
|
||||
@@ -81,6 +81,7 @@ public class Server {
|
||||
app.post("api/restartProgram", RequestHandler::restartProgram);
|
||||
app.post("api/vision/pnpModel", RequestHandler::uploadPnpModel);
|
||||
app.post("api/sendMetrics", RequestHandler::sendMetrics);
|
||||
app.post("api/setCameraNickname", RequestHandler::setCameraNickname);
|
||||
|
||||
app.start(port);
|
||||
}
|
||||
|
||||
@@ -34,12 +34,12 @@ import org.photonvision.vision.frame.FrameDivisor;
|
||||
|
||||
public class MJPGFrameConsumer {
|
||||
|
||||
private final CvSource cvSource;
|
||||
private final MjpegServer mjpegServer;
|
||||
private CvSource cvSource;
|
||||
private MjpegServer mjpegServer;
|
||||
private FrameDivisor divisor = FrameDivisor.NONE;
|
||||
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private final VideoListener listener;
|
||||
private VideoListener listener;
|
||||
|
||||
private final NetworkTable table;
|
||||
|
||||
@@ -163,4 +163,14 @@ public class MJPGFrameConsumer {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public void close() {
|
||||
table.getEntry("connected").setBoolean(false);
|
||||
mjpegServer.close();
|
||||
cvSource.close();
|
||||
listener.close();
|
||||
mjpegServer = null;
|
||||
cvSource = null;
|
||||
listener = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,11 @@ public class VisionModule {
|
||||
saveAndBroadcastAll();
|
||||
}
|
||||
|
||||
private void destroyStreams() {
|
||||
dashboardInputStreamer.close();
|
||||
dashboardOutputStreamer.close();
|
||||
}
|
||||
|
||||
private void createStreams() {
|
||||
var camStreamIdx = visionSource.getSettables().getConfiguration().streamIndex;
|
||||
// If idx = 0, we want (1181, 1182)
|
||||
@@ -143,11 +148,10 @@ public class VisionModule {
|
||||
|
||||
dashboardOutputStreamer =
|
||||
new MJPGFrameConsumer(
|
||||
visionSource.getSettables().getConfiguration().uniqueName + "-output",
|
||||
outputStreamPort);
|
||||
visionSource.getSettables().getConfiguration().nickname + "-output", outputStreamPort);
|
||||
dashboardInputStreamer =
|
||||
new MJPGFrameConsumer(
|
||||
visionSource.getSettables().getConfiguration().uniqueName + "-input", inputStreamPort);
|
||||
visionSource.getSettables().getConfiguration().nickname + "-input", inputStreamPort);
|
||||
}
|
||||
|
||||
void setDriverMode(boolean isDriverMode) {
|
||||
@@ -280,17 +284,22 @@ public class VisionModule {
|
||||
OutgoingUIEvent.wrappedOf("mutatePipeline", propertyName, value, originContext));
|
||||
}
|
||||
|
||||
void setCameraNickname(String newName) {
|
||||
public void setCameraNickname(String newName) {
|
||||
visionSource.getSettables().getConfiguration().nickname = newName;
|
||||
ntConsumer.updateCameraNickname(newName);
|
||||
|
||||
// rename streams
|
||||
fpsLimitedResultConsumers.clear();
|
||||
|
||||
// Teardown and recreate streams
|
||||
destroyStreams();
|
||||
createStreams();
|
||||
|
||||
fpsLimitedResultConsumers.add(result -> dashboardInputStreamer.accept(result.inputFrame));
|
||||
fpsLimitedResultConsumers.add(result -> dashboardOutputStreamer.accept(result.outputFrame));
|
||||
|
||||
// Push new data to the UI
|
||||
saveAndBroadcastAll();
|
||||
}
|
||||
|
||||
public PhotonConfiguration.UICameraConfiguration toUICameraConfig() {
|
||||
|
||||
@@ -62,12 +62,11 @@ public class VisionModuleChangeSubscriber extends DataChangeSubscriber {
|
||||
|
||||
// special case for non-PipelineSetting changes
|
||||
switch (propName) {
|
||||
case "cameraNickname": // rename camera
|
||||
var newNickname = (String) newPropValue;
|
||||
logger.info("Changing nickname to " + newNickname);
|
||||
parentModule.setCameraNickname(newNickname);
|
||||
parentModule.saveAndBroadcastAll();
|
||||
return;
|
||||
// case "cameraNickname": // rename camera
|
||||
// var newNickname = (String) newPropValue;
|
||||
// logger.info("Changing nickname to " + newNickname);
|
||||
// parentModule.setCameraNickname(newNickname);
|
||||
// return;
|
||||
case "pipelineName": // rename current pipeline
|
||||
logger.info("Changing nick to " + newPropValue);
|
||||
parentModule.pipelineManager.getCurrentPipelineSettings().pipelineNickname =
|
||||
|
||||
Reference in New Issue
Block a user