Skip to content

Commit 03b6212

Browse files
committedFeb 28, 2025·
Improve InputSourceInitializer
1 parent 3d7d227 commit 03b6212

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed
 

‎EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/InputSourceInitializer.kt

+3-2
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,15 @@ object InputSourceInitializer {
4747

4848

4949
@OptIn(DelicateCoroutinesApi::class)
50+
@JvmOverloads
5051
fun runWithTimeout(sourceName: String, manager: InputSourceManager? = null, callback: () -> Boolean): Boolean {
5152
var result = false
5253

5354
val job = GlobalScope.launch {
5455
try {
5556
result = callback()
5657
} catch (e: Exception) {
57-
logger.error("Error initializing InputSource", e)
58+
logger.error("Error running InputSource", e)
5859
}
5960
}
6061

@@ -66,7 +67,7 @@ object InputSourceInitializer {
6667
job.join()
6768
}
6869
} catch (e: CancellationException) {
69-
logger.error("InputSource initialization timed out after $TIMEOUT ms", e)
70+
logger.error("InputSource run timed out after $TIMEOUT ms", e)
7071
} finally {
7172
job.cancel()
7273
dialog?.destroyDialog()

‎EOCV-Sim/src/main/java/com/github/serivesmejia/eocvsim/input/source/HttpSource.java

+72-6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
package com.github.serivesmejia.eocvsim.input.source;
2525

2626
import com.github.serivesmejia.eocvsim.input.InputSource;
27+
import com.github.serivesmejia.eocvsim.input.InputSourceInitializer;
2728
import com.google.gson.annotations.Expose;
2829
import io.github.deltacv.papervision.plugin.ipc.stream.MjpegHttpReader;
2930
import org.opencv.core.Mat;
@@ -86,11 +87,20 @@ public boolean init() {
8687
return mjpegHttpReader != null && iterator != null;
8788
}
8889

90+
byte[] frame;
91+
8992
@Override
9093
public Mat update() {
9194
if (mjpegHttpReader == null) return null;
9295

93-
byte[] frame = iterator.next();
96+
boolean result = InputSourceInitializer.INSTANCE.runWithTimeout(name, () -> {
97+
frame = iterator.next();
98+
return frame != null;
99+
});
100+
101+
if(!result) {
102+
return null;
103+
}
94104

95105
if(!dataIsValidJPEG(frame)) {
96106
logger.error("Received data is not a valid JPEG image");
@@ -129,15 +139,13 @@ public void close() {
129139
@Override
130140
public void onPause() {
131141
if (mjpegHttpReader != null) {
132-
mjpegHttpReader.stop();
142+
reset();
133143
}
134144
}
135145

136146
@Override
137147
public void onResume() {
138-
if (mjpegHttpReader != null) {
139-
mjpegHttpReader.start();
140-
}
148+
InputSourceInitializer.INSTANCE.runWithTimeout(name, eocvSim.inputSourceManager, this::init);
141149
}
142150

143151
@Override
@@ -165,10 +173,68 @@ private static boolean dataIsValidJPEG(byte[] data) {
165173
return false;
166174
}
167175

168-
int totalBytes = data.length;
176+
int totalBytes = getJPEGSize(data, data.length);
177+
178+
if (totalBytes == -1) {
179+
return false;
180+
}
181+
169182
return (data[0] == (byte) 0xFF &&
170183
data[1] == (byte) 0xD8 &&
171184
data[totalBytes - 2] == (byte) 0xFF &&
172185
data[totalBytes - 1] == (byte) 0xD9);
173186
}
187+
188+
private static int getJPEGSize(byte[] data, int maxLength) {
189+
if (data == null || maxLength < 4) {
190+
return -1; // Invalid or too small to be a JPEG
191+
}
192+
193+
// Check for SOI marker
194+
if (data[0] != (byte) 0xFF || data[1] != (byte) 0xD8) {
195+
return -1; // Not a JPEG
196+
}
197+
198+
int pos = 2; // Start after SOI
199+
200+
while (pos < maxLength - 2) {
201+
// Look for the next marker (0xFF xx)
202+
if (data[pos] == (byte) 0xFF) {
203+
byte marker = data[pos + 1];
204+
205+
// End of Image (EOI) found
206+
if (marker == (byte) 0xD9) {
207+
return pos + 2; // JPEG size
208+
}
209+
210+
// Skip padding bytes (some JPEGs use 0xFF 0x00)
211+
if (marker == (byte) 0x00) {
212+
pos++;
213+
continue;
214+
}
215+
216+
// Most markers have a 2-byte length field
217+
if ((marker >= (byte) 0xC0 && marker <= (byte) 0xFE) && marker != (byte) 0xD9) {
218+
if (pos + 3 >= maxLength) {
219+
return -1; // Incomplete JPEG
220+
}
221+
222+
// Read segment length (big-endian)
223+
int segmentLength = ((data[pos + 2] & 0xFF) << 8) | (data[pos + 3] & 0xFF);
224+
225+
if (segmentLength < 2 || pos + segmentLength >= maxLength) {
226+
return -1; // Corrupt or incomplete JPEG
227+
}
228+
229+
pos += segmentLength; // Move to next marker
230+
} else {
231+
pos++; // Skip unknown byte
232+
}
233+
} else {
234+
pos++; // Continue searching
235+
}
236+
}
237+
238+
return -1; // No valid JPEG end found
239+
}
174240
}

0 commit comments

Comments
 (0)
Please sign in to comment.