Skip to content

Commit 6d70d24

Browse files
committed
bumped API version to 34, fixed some bugs that crept up from that
1 parent 5dafc9e commit 6d70d24

File tree

10 files changed

+146
-30
lines changed

10 files changed

+146
-30
lines changed

app/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ android {
88
defaultConfig {
99
applicationId "be.ntmn.inficam"
1010
minSdkVersion 21
11-
versionCode 2
12-
versionName "1.0.1"
11+
versionCode 3
12+
versionName "1.0.2"
1313
vectorDrawables.useSupportLibrary true // To support older minSdk
1414

1515
/* We need targetSdkVersion <= 27 for some Android 10 devices to work:
1616
* https://issuetracker.google.com/issues/145082934
1717
* https://issuetracker.google.com/issues/139087809
1818
*/
1919
//noinspection ExpiredTargetSdkVersion
20-
targetSdkVersion 27
20+
targetSdkVersion 34
2121
}
2222

2323
buildTypes {

app/src/main/java/be/ntmn/inficam/MainActivity.java

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,37 @@ public void onDisplayRemoved(int displayId) { /* Empty. */ }
298298
private final Runnable handleFrameRunnable = () -> handleFrame();
299299
Overlay.MinMaxAvg mma = new Overlay.MinMaxAvg();
300300

301+
private boolean isFinite(float v) {
302+
return !isNaN(v) && !isInfinite(v);
303+
}
304+
305+
private void mmaDownsample(Overlay.MinMaxAvg out, float[] temp, int w, int h, int step) {
306+
out.min = out.max = NaN;
307+
out.avg = 0.0f;
308+
out.min_x = out.min_y = out.max_x = out.max_y = 0;
309+
int n = 0;
310+
for (int y = 0; y < h; y += step) {
311+
int row = y * w;
312+
for (int x = 0; x < w; x += step) {
313+
float t = temp[row + x];
314+
if (t < out.min || isNaN(out.min)) {
315+
out.min = t;
316+
out.min_x = x;
317+
out.min_y = y;
318+
}
319+
if (t > out.max || isNaN(out.max)) {
320+
out.max = t;
321+
out.max_x = x;
322+
out.max_y = y;
323+
}
324+
out.avg += t;
325+
++n;
326+
}
327+
}
328+
if (n > 0)
329+
out.avg /= n;
330+
}
331+
301332
@Override
302333
public void onFrame(InfiCam.FrameInfo fi, float[] temp) {
303334
synchronized (frameLock) { /* Note this is called from another thread. */
@@ -360,6 +391,48 @@ public void onFrame(InfiCam.FrameInfo fi, float[] temp) {
360391
}
361392
}
362393

394+
/*
395+
* avoid passing NaN to native and fall back to computing min/max from the buffer when
396+
* the camera-provided range looks invalid (e.g. clamps everything to the minimum).
397+
*/
398+
final boolean autoMin = isNaN(overlayData.rangeMin) || isInfinite(overlayData.rangeMin);
399+
final boolean autoMax = isNaN(overlayData.rangeMax) || isInfinite(overlayData.rangeMax);
400+
if (autoMin && !isFinite(rangeMin))
401+
rangeMin = fi.min;
402+
if (autoMax && !isFinite(rangeMax))
403+
rangeMax = fi.max;
404+
405+
boolean suspectRange = !isFinite(rangeMin) || !isFinite(rangeMax) || rangeMax <= rangeMin;
406+
if (!suspectRange && (autoMin || autoMax) && temp != null && temp.length >= fi.width * fi.height
407+
&& fi.width > 0 && fi.height > 0) {
408+
int centerIdx = (fi.height / 2) * fi.width + (fi.width / 2);
409+
float s0 = temp[0];
410+
float sc = temp[centerIdx];
411+
float s1 = temp[temp.length - 1];
412+
float sampleMin = java.lang.Math.min(s0, java.lang.Math.min(sc, s1));
413+
float sampleMax = java.lang.Math.max(s0, java.lang.Math.max(sc, s1));
414+
/* If even a few samples fall entirely outside the palette range, it's likely wrong. */
415+
if (rangeMin > sampleMax || rangeMax < sampleMin)
416+
suspectRange = true;
417+
}
418+
419+
if (suspectRange && (autoMin || autoMax) && temp != null && fi.width > 0 && fi.height > 0) {
420+
/* Downsample to keep this cheap; good enough for palette scaling. */
421+
mmaDownsample(mma, temp, fi.width, fi.height, 4);
422+
if (isFinite(mma.min) && isFinite(mma.max) && mma.max > mma.min) {
423+
fi.min = mma.min;
424+
fi.min_x = mma.min_x;
425+
fi.min_y = mma.min_y;
426+
fi.max = mma.max;
427+
fi.max_x = mma.max_x;
428+
fi.max_y = mma.max_y;
429+
if (autoMin)
430+
rangeMin = mma.min;
431+
if (autoMax)
432+
rangeMax = mma.max;
433+
}
434+
}
435+
363436

364437
infiCam.applyPalette(rangeMin, rangeMax);
365438
handler.post(handleFrameRunnable);
@@ -670,7 +743,16 @@ protected void onStart() {
670743
DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
671744
displayManager.registerDisplayListener(displayListener, handler);
672745
IntentFilter batIFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
673-
Intent batteryStatus = registerReceiver(batteryRecevier, batIFilter);
746+
Intent batteryStatus;
747+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
748+
batteryStatus = registerReceiver(
749+
batteryRecevier,
750+
batIFilter,
751+
Context.RECEIVER_NOT_EXPORTED
752+
);
753+
} else {
754+
batteryStatus = registerReceiver(batteryRecevier, batIFilter);
755+
}
674756
updateBatLevel(batteryStatus);
675757

676758
/* Beware that we can't call these in onResume as they'll ask permission with dialogs and

app/src/main/java/be/ntmn/inficam/SurfaceMuxer.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ public static class InputSurface {
104104
public float scale_x = 1.0f, scale_y = 1.0f;
105105
public float translate_x = 0.0f, translate_y = 0.0f;
106106
public float sharpening = 0.0f;
107+
private volatile boolean frameAvailable = false;
107108

108109
public InputSurface(SurfaceMuxer muxer) {
109110
this.muxer = muxer;
@@ -136,13 +137,15 @@ private void init() {
136137
GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
137138
GLES20.GL_LINEAR);
138139
if (surfaceTexture == null) {
139-
surfaceTexture = new SurfaceTexture(textures[0]);
140-
surface = new Surface(surfaceTexture);
141-
} else surfaceTexture.attachToGLContext(textures[0]);
142-
/* After attaching to a new context we must call updateTexImage() or the
143-
* OnFrameAvailableListener may stop being called for some reason.
144-
*/
145-
surfaceTexture.updateTexImage();
140+
surfaceTexture = new SurfaceTexture(textures[0]);
141+
surfaceTexture.setOnFrameAvailableListener(
142+
st -> frameAvailable = true
143+
);
144+
surface = new Surface(surfaceTexture);
145+
} else {
146+
surfaceTexture.attachToGLContext(textures[0]);
147+
frameAvailable = true; // force first frame latch after reattach
148+
}
146149
initialized = true;
147150
}
148151

@@ -174,7 +177,10 @@ public void draw(OutputSurface os, int drawMode, int x, int y, int w, int h) {
174177
if (muxer.eglContext == EGL14.EGL_NO_CONTEXT)
175178
return;
176179
os.makeCurrent(); /* We need the context to be current before updateTexImage(). */
177-
surfaceTexture.updateTexImage(); /* Call might be redundant, probably don't care. */
180+
if (frameAvailable) {
181+
surfaceTexture.updateTexImage();
182+
frameAvailable = false;
183+
}
178184
GLES20.glViewport(x, y, w, h);
179185
int program = muxer.drawModes[drawMode].program;
180186
GLES20.glUseProgram(program);

app/src/main/java/be/ntmn/inficam/USBMonitor.java

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,26 @@ public interface ConnectCallback {
2727
private final HashMap<UsbDevice, ConnectCallback> callbacks = new HashMap<>();
2828

2929
public void start(Context ctx) { /* Recommended use is in onCreate()/onStart(). */
30-
this.ctx = ctx;
31-
if (!registered) {
32-
manager = (UsbManager) ctx.getSystemService(Context.USB_SERVICE);
33-
IntentFilter filter = new IntentFilter();
34-
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
35-
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
36-
filter.addAction(ACTION_USB_PERMISSION);
37-
ctx.registerReceiver(this, filter);
38-
registered = true;
39-
}
30+
this.ctx = ctx;
31+
if (!registered) {
32+
manager = (UsbManager) ctx.getSystemService(Context.USB_SERVICE);
33+
IntentFilter filter = new IntentFilter();
34+
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
35+
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
36+
filter.addAction(ACTION_USB_PERMISSION);
37+
38+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
39+
ctx.registerReceiver(
40+
this,
41+
filter,
42+
Context.RECEIVER_NOT_EXPORTED
43+
);
44+
} else {
45+
ctx.registerReceiver(this, filter);
46+
}
47+
48+
registered = true;
49+
}
4050
}
4151

4252
public void stop() { /* Call this in onDestroy()/onStop(), matching start() call. */
@@ -66,6 +76,10 @@ private void _connect(UsbDevice dev, ConnectCallback cb) {
6676
public void connect(UsbDevice dev, ConnectCallback cb) {
6777
if (!manager.hasPermission(dev)) {
6878
Intent intent = new Intent(ACTION_USB_PERMISSION);
79+
// Targeting Android 14+ (targetSdk 34) forbids FLAG_MUTABLE PendingIntents with
80+
// implicit Intents. UsbManager.requestPermission requires a mutable PendingIntent
81+
// so the system can add extras; restricting the Intent to our app satisfies both.
82+
intent.setPackage(ctx.getPackageName());
6983
int flags = PendingIntent.FLAG_ONE_SHOT;
7084
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
7185
flags |= PendingIntent.FLAG_MUTABLE;

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
plugins {
2-
id 'com.android.application' version '8.8.0' apply false
3-
id 'com.android.library' version '8.8.0' apply false
2+
id 'com.android.application' version '8.8.2' apply false
3+
id 'com.android.library' version '8.8.2' apply false
44
}
55

66
task clean(type: Delete) {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
APP_PLATFORM := android-16
22
APP_ABI := armeabi-v7a arm64-v8a x86_64 x86
3+
# APP_OPTIM := debug
34
APP_OPTIM := release
45
APP_STL := c++_static
56
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true

libinficam/src/main/jni/InfiCam/Android.mk

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,15 @@ LOCAL_C_INCLUDES :=$(LOCAL_PATH)/../libusb/libusb $(LOCAL_PATH)/../libuvc_build
77

88
LOCAL_CFLAGS := $(LOCAL_C_INCLUDES:%=-I%)
99
LOCAL_CFLAGS += -DANDROID_NDK
10-
LOCAL_CFLAGS += -DLOG_NDEBUG
1110
LOCAL_CFLAGS += -DACCESS_RAW_DESCRIPTORS
12-
LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays
11+
12+
# Debug vs Release
13+
ifeq ($(APP_OPTIM),debug)
14+
LOCAL_CFLAGS += -O0 -g -fno-inline -fno-omit-frame-pointer
15+
else
16+
LOCAL_CFLAGS += -O3 -fstrict-aliasing -fprefetch-loop-arrays
17+
LOCAL_CFLAGS += -DLOG_NDEBUG
18+
endif
1319

1420
LOCAL_LDLIBS := -ldl -llog -landroid
1521

libinficam/src/main/jni/InfiCam/InfiCam.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ int InfiCam::connect(int fd) {
182182
*/
183183
if (pthread_mutex_init(&frame_callback_mutex, NULL))
184184
return 1;
185+
if (pthread_cond_init(&calibration_cond, NULL)) {
186+
pthread_mutex_destroy(&frame_callback_mutex);
187+
return 1;
188+
}
185189
if (dev.connect(fd, p2_pro)) {
186190
pthread_mutex_destroy(&frame_callback_mutex);
187191
return 2;
@@ -202,6 +206,7 @@ void InfiCam::disconnect() {
202206
stream_stop();
203207
dev.disconnect();
204208
pthread_mutex_destroy(&frame_callback_mutex);
209+
pthread_cond_destroy(&calibration_cond);
205210
connected = 0;
206211
}
207212
}

libinficam/src/main/jni/InfiCam/InfiCam.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class InfiCam {
2525
float *frame_temp = NULL;
2626
pthread_mutex_t frame_callback_mutex;
2727
pthread_cond_t calibration_cond;
28-
int connected = 0, streaming = 0, table_invalid;
28+
int connected = 0, streaming = 0, table_invalid = 1;
2929
bool raw_sensor = false;
30-
bool p2_pro;
30+
bool p2_pro = false;
3131
bool calibrating = false;
3232
bool calibrated = false;
3333
bool* dead_pixel_mask = nullptr;

libinficam/src/main/jni/InfiCam/InfiFrame.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,8 @@ float InfiFrame::temp_single(uint16_t x) {
206206
float n = sqrtf(((float) (x - table_offset) * cal_d + cal_c) / cal_01 + cal_b);
207207
float wtot = powf((isfinite(n) ? n : 0.0) - cal_a + zeroc, 4);
208208
float ttot = powf((wtot - numerator_sub) / denominator, 0.25) - zeroc;
209-
return ttot + (distance_adjusted * 0.85 - 1.125) * (ttot - temp_air) / 100.0 + correction;
209+
float temp_single = ttot + (distance_adjusted * 0.85 - 1.125) * (ttot - temp_air) / 100.0 + correction;
210+
return temp_single;
210211
}
211212
}
212213

@@ -222,7 +223,8 @@ void InfiFrame::temp(uint16_t *input, float *output) {
222223

223224
void InfiFrame::temp(uint16_t *input, float *output, size_t len) {
224225
for (size_t i = 0; i < len; ++i)
225-
output[i] = temp(input[i]>>2);
226+
// output[i] = temp(input[i] & table_mask);
227+
output[i] = temp(input[i]);
226228
}
227229

228230
void InfiFrame::read_params(uint16_t *frame) {

0 commit comments

Comments
 (0)