mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2026-09-10 21:06:51 +00:00
secugen: Do image processing inside GTask threads
Do not block the main loop to process image data
This commit is contained in:
+318
-120
@@ -185,7 +185,7 @@ G_DEFINE_TYPE (FpiDeviceSecugen,
|
|||||||
* correction, middle range scales linearly. Identical to the table
|
* correction, middle range scales linearly. Identical to the table
|
||||||
* stored in the device's firmware data block.
|
* stored in the device's firmware data block.
|
||||||
*/
|
*/
|
||||||
static const guint8 g_blend_curve[256] = {
|
static const guint8 SECUGEN_BLEND_CURVE[256] = {
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||||
16, 17, 19, 21, 23, 25, 27, 29, 31, 32, 34, 36, 38, 40, 42, 44,
|
16, 17, 19, 21, 23, 25, 27, 29, 31, 32, 34, 36, 38, 40, 42, 44,
|
||||||
@@ -1449,6 +1449,184 @@ secugen_sharpen (const guint8 *src,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
guint8 *raw_frame;
|
||||||
|
gboolean has_blc_offsets;
|
||||||
|
gint16 blc_offsets[16];
|
||||||
|
gboolean has_ref_image;
|
||||||
|
guint8 *ref_image;
|
||||||
|
guint16 cal_value;
|
||||||
|
gboolean sharpen_enabled;
|
||||||
|
guint8 sharpen_threshold;
|
||||||
|
guint8 sharpen_amount;
|
||||||
|
guint8 sharpen_limit;
|
||||||
|
} SecugenCaptureTaskData;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
guint8 *frame;
|
||||||
|
guint8 *cal_raw;
|
||||||
|
} SecugenDetectTaskData;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
guint mean;
|
||||||
|
gboolean finger_present;
|
||||||
|
gboolean update_calibration;
|
||||||
|
guint8 *new_cal_raw;
|
||||||
|
} SecugenDetectTaskResult;
|
||||||
|
|
||||||
|
static void
|
||||||
|
secugen_capture_task_data_free (SecugenCaptureTaskData *data)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&data->raw_frame, g_free);
|
||||||
|
g_clear_pointer (&data->ref_image, g_free);
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
secugen_detect_task_data_free (SecugenDetectTaskData *data)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&data->frame, g_free);
|
||||||
|
g_clear_pointer (&data->cal_raw, g_free);
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
secugen_detect_task_result_free (SecugenDetectTaskResult *result)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&result->new_cal_raw, g_free);
|
||||||
|
g_free (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecugenCaptureTaskData, secugen_capture_task_data_free)
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecugenDetectTaskData, secugen_detect_task_data_free)
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC (SecugenDetectTaskResult, secugen_detect_task_result_free)
|
||||||
|
|
||||||
|
static void
|
||||||
|
secugen_capture_process_thread (GTask *task,
|
||||||
|
gpointer source_object G_GNUC_UNUSED,
|
||||||
|
gpointer task_data,
|
||||||
|
GCancellable *cancellable G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
SecugenCaptureTaskData *data = task_data;
|
||||||
|
g_autofree guint8 *image = g_malloc (SECUGEN_IMG_SIZE);
|
||||||
|
|
||||||
|
if (g_task_return_error_if_cancelled (task))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Image processing pipeline:
|
||||||
|
* 1. Band compensation at 956x688
|
||||||
|
* 2. Edge-aware unsharp mask at 956x688
|
||||||
|
* 3. Bilinear downsample 956x688 → 300x400
|
||||||
|
* 4. Flat-field blend at 300x400
|
||||||
|
* 5. Directional sharpening at 300x400 (conditional)
|
||||||
|
* 6. Bitwise NOT invert
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Step 1: BLC band compensation */
|
||||||
|
if (data->has_blc_offsets)
|
||||||
|
secugen_blc_compensate (data->raw_frame, SECUGEN_RAW_WIDTH,
|
||||||
|
SECUGEN_RAW_HEIGHT, data->blc_offsets);
|
||||||
|
|
||||||
|
/* Step 2: Edge-aware unsharp mask */
|
||||||
|
secugen_unsharp_mask (data->raw_frame, SECUGEN_RAW_WIDTH, SECUGEN_RAW_HEIGHT);
|
||||||
|
|
||||||
|
/* Step 3: Bilinear downsample to 300x400 */
|
||||||
|
secugen_resize_bilinear (data->raw_frame,
|
||||||
|
SECUGEN_RAW_WIDTH, SECUGEN_RAW_HEIGHT,
|
||||||
|
image,
|
||||||
|
SECUGEN_IMG_WIDTH, SECUGEN_IMG_HEIGHT);
|
||||||
|
|
||||||
|
if (g_task_return_error_if_cancelled (task))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Step 4: Blend flat-field correction */
|
||||||
|
if (data->has_ref_image)
|
||||||
|
{
|
||||||
|
secugen_blend (image,
|
||||||
|
SECUGEN_IMG_WIDTH, SECUGEN_IMG_HEIGHT,
|
||||||
|
data->ref_image,
|
||||||
|
data->cal_value,
|
||||||
|
SECUGEN_BLEND_CURVE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_task_return_error_if_cancelled (task))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Step 5: Directional sharpening (conditional) */
|
||||||
|
if (data->sharpen_enabled)
|
||||||
|
{
|
||||||
|
g_autofree guint8 *sharpened = g_malloc (SECUGEN_IMG_SIZE);
|
||||||
|
|
||||||
|
secugen_sharpen (image, sharpened,
|
||||||
|
SECUGEN_IMG_WIDTH, SECUGEN_IMG_HEIGHT,
|
||||||
|
data->sharpen_threshold,
|
||||||
|
data->sharpen_amount,
|
||||||
|
data->sharpen_limit);
|
||||||
|
memcpy (image, sharpened, SECUGEN_IMG_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Step 6: Invert (bitwise NOT) */
|
||||||
|
for (int i = 0; i < SECUGEN_IMG_SIZE; i++)
|
||||||
|
image[i] = ~image[i];
|
||||||
|
|
||||||
|
if (g_task_return_error_if_cancelled (task))
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_task_return_pointer (task, g_steal_pointer (&image), g_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
secugen_detect_analyze_thread (GTask *task,
|
||||||
|
gpointer source_object G_GNUC_UNUSED,
|
||||||
|
gpointer task_data,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
SecugenDetectTaskData *data = task_data;
|
||||||
|
|
||||||
|
g_autoptr(SecugenDetectTaskResult) result = g_new0 (SecugenDetectTaskResult, 1);
|
||||||
|
guint64 sum = 0;
|
||||||
|
int count = 0;
|
||||||
|
int start_row = SECUGEN_RAW_HEIGHT / 4;
|
||||||
|
int end_row = 3 * SECUGEN_RAW_HEIGHT / 4;
|
||||||
|
int start_col = SECUGEN_RAW_WIDTH / 4;
|
||||||
|
int end_col = 3 * SECUGEN_RAW_WIDTH / 4;
|
||||||
|
|
||||||
|
if (g_task_return_error_if_cancelled (task))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Compute mean brightness of central 50% region */
|
||||||
|
for (int y = start_row; y < end_row; y++)
|
||||||
|
{
|
||||||
|
for (int x = start_col; x < end_col; x++)
|
||||||
|
{
|
||||||
|
int idx = y * SECUGEN_RAW_WIDTH + x;
|
||||||
|
int val = (int) data->frame[idx] - (int) data->cal_raw[idx];
|
||||||
|
|
||||||
|
if (val < 0)
|
||||||
|
val = 0;
|
||||||
|
sum += val;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_task_return_error_if_cancelled (task))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->mean = count > 0 ? (guint) (sum / count) : 0;
|
||||||
|
result->finger_present = (result->mean >= SECUGEN_FINGER_THRESHOLD);
|
||||||
|
result->update_calibration = (!result->finger_present && result->mean <= 5);
|
||||||
|
if (result->update_calibration)
|
||||||
|
result->new_cal_raw = g_memdup2 (data->frame, SECUGEN_BULK_BUF_SIZE);
|
||||||
|
|
||||||
|
g_task_return_pointer (task,
|
||||||
|
g_steal_pointer (&result),
|
||||||
|
(GDestroyNotify) secugen_detect_task_result_free);
|
||||||
|
}
|
||||||
|
|
||||||
/* ================================================================
|
/* ================================================================
|
||||||
* Capture State Machine
|
* Capture State Machine
|
||||||
*
|
*
|
||||||
@@ -1470,6 +1648,47 @@ enum capture_states {
|
|||||||
CAPTURE_NUM_STATES,
|
CAPTURE_NUM_STATES,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
capture_process_done (GObject *source_object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
g_autoptr(FpImage) img = NULL;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autofree guint8 *processed = NULL;
|
||||||
|
FpDevice *dev = FP_DEVICE (source_object);
|
||||||
|
FpiDeviceSecugen *self = FPI_DEVICE_SECUGEN (dev);
|
||||||
|
FpiSsm *ssm = user_data;
|
||||||
|
|
||||||
|
processed = g_task_propagate_pointer (G_TASK (result), &error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (self->deactivating &&
|
||||||
|
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_ssm_mark_failed (ssm, g_steal_pointer (&error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->deactivating)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
img = fp_image_new (SECUGEN_IMG_WIDTH, SECUGEN_IMG_HEIGHT);
|
||||||
|
img->ppmm = SECUGEN_PPMM;
|
||||||
|
img->flags = FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
|
||||||
|
memcpy (img->data, processed, SECUGEN_IMG_SIZE);
|
||||||
|
|
||||||
|
fpi_image_device_image_captured (FP_IMAGE_DEVICE (dev), g_steal_pointer (&img));
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
capture_status_cb (FpiUsbTransfer *transfer,
|
capture_status_cb (FpiUsbTransfer *transfer,
|
||||||
FpDevice *dev,
|
FpDevice *dev,
|
||||||
@@ -1533,76 +1752,38 @@ capture_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||||||
|
|
||||||
case CAPTURE_DONE:
|
case CAPTURE_DONE:
|
||||||
{
|
{
|
||||||
g_autoptr(FpImage) img = NULL;
|
g_autoptr(GTask) task = NULL;
|
||||||
g_autofree guint8 *raw = NULL;
|
g_autoptr(SecugenCaptureTaskData) task_data = NULL;
|
||||||
int i;
|
|
||||||
|
|
||||||
img = fp_image_new (SECUGEN_IMG_WIDTH, SECUGEN_IMG_HEIGHT);
|
/* Snapshot frame + calibration parameters for worker-thread processing.
|
||||||
img->ppmm = SECUGEN_PPMM;
|
* The shared driver buffers remain owned by the main thread. */
|
||||||
img->flags = FPI_IMAGE_V_FLIPPED | FPI_IMAGE_H_FLIPPED;
|
task_data = g_new0 (SecugenCaptureTaskData, 1);
|
||||||
|
task_data->raw_frame = g_memdup2 (self->bulk_buffer, SECUGEN_RAW_SIZE);
|
||||||
|
task_data->has_blc_offsets = self->has_blc_offsets;
|
||||||
|
memcpy (task_data->blc_offsets, self->blc_offsets, sizeof (task_data->blc_offsets));
|
||||||
|
task_data->has_ref_image = self->has_ref_image;
|
||||||
|
|
||||||
/* Work on a copy of the raw 956x688 sensor data */
|
|
||||||
raw = g_malloc (SECUGEN_RAW_SIZE);
|
|
||||||
memcpy (raw, self->bulk_buffer, SECUGEN_RAW_SIZE);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Image processing pipeline:
|
|
||||||
* 1. Band compensation at 956x688
|
|
||||||
* 2. Edge-aware unsharp mask at 956x688
|
|
||||||
* 3. Bilinear downsample 956x688 → 300x400
|
|
||||||
* 4. Flat-field blend at 300x400
|
|
||||||
* 5. Directional sharpening at 300x400 (conditional)
|
|
||||||
* 6. Bitwise NOT invert
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Step 1: BLC band compensation */
|
|
||||||
if (self->has_blc_offsets)
|
|
||||||
{
|
|
||||||
secugen_blc_compensate (raw, SECUGEN_RAW_WIDTH,
|
|
||||||
SECUGEN_RAW_HEIGHT,
|
|
||||||
self->blc_offsets);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step 2: Edge-aware unsharp mask */
|
|
||||||
secugen_unsharp_mask (raw, SECUGEN_RAW_WIDTH, SECUGEN_RAW_HEIGHT);
|
|
||||||
|
|
||||||
/* Step 3: Bilinear downsample to 300x400 */
|
|
||||||
secugen_resize_bilinear (raw,
|
|
||||||
SECUGEN_RAW_WIDTH, SECUGEN_RAW_HEIGHT,
|
|
||||||
img->data,
|
|
||||||
SECUGEN_IMG_WIDTH, SECUGEN_IMG_HEIGHT);
|
|
||||||
|
|
||||||
/* Step 4: Blend flat-field correction */
|
|
||||||
if (self->has_ref_image)
|
if (self->has_ref_image)
|
||||||
{
|
task_data->ref_image = g_memdup2 (self->ref_image, SECUGEN_IMG_SIZE);
|
||||||
secugen_blend (img->data,
|
|
||||||
SECUGEN_IMG_WIDTH, SECUGEN_IMG_HEIGHT,
|
|
||||||
self->ref_image, self->cal_value,
|
|
||||||
g_blend_curve);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Step 5: Directional sharpening (conditional) */
|
task_data->cal_value = self->cal_value;
|
||||||
if (self->sharpen_enabled)
|
task_data->sharpen_enabled = self->sharpen_enabled;
|
||||||
{
|
task_data->sharpen_threshold = self->sharpen_threshold;
|
||||||
g_autofree guint8 *sharpened = g_malloc (SECUGEN_IMG_SIZE);
|
task_data->sharpen_amount = self->sharpen_amount;
|
||||||
|
task_data->sharpen_limit = self->sharpen_limit;
|
||||||
|
|
||||||
secugen_sharpen (img->data, sharpened,
|
task = g_task_new (FP_DEVICE (dev),
|
||||||
SECUGEN_IMG_WIDTH, SECUGEN_IMG_HEIGHT,
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
self->sharpen_threshold,
|
capture_process_done,
|
||||||
self->sharpen_amount,
|
ssm);
|
||||||
self->sharpen_limit);
|
g_task_set_source_tag (task, secugen_capture_process_thread);
|
||||||
memcpy (img->data, sharpened, SECUGEN_IMG_SIZE);
|
g_task_set_check_cancellable (task, TRUE);
|
||||||
}
|
g_task_set_task_data (task, g_steal_pointer (&task_data),
|
||||||
|
(GDestroyNotify) secugen_capture_task_data_free);
|
||||||
/* Step 6: Invert (bitwise NOT) */
|
g_task_run_in_thread (task, secugen_capture_process_thread);
|
||||||
for (i = 0; i < SECUGEN_IMG_SIZE; i++)
|
|
||||||
img->data[i] = ~img->data[i];
|
|
||||||
|
|
||||||
fpi_image_device_image_captured (dev, g_steal_pointer (&img));
|
|
||||||
fpi_ssm_mark_completed (ssm);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void secugen_finish_deactivate (FpImageDevice *dev);
|
static void secugen_finish_deactivate (FpImageDevice *dev);
|
||||||
@@ -1671,6 +1852,64 @@ enum detect_states {
|
|||||||
static void detect_start (FpImageDevice *dev);
|
static void detect_start (FpImageDevice *dev);
|
||||||
static void detect_retry_timeout (FpDevice *dev,
|
static void detect_retry_timeout (FpDevice *dev,
|
||||||
gpointer user_data G_GNUC_UNUSED);
|
gpointer user_data G_GNUC_UNUSED);
|
||||||
|
static void detect_analyze_done (GObject *source_object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
static void
|
||||||
|
detect_analyze_done (GObject *source_object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
FpDevice *dev = FP_DEVICE (source_object);
|
||||||
|
FpiDeviceSecugen *self = FPI_DEVICE_SECUGEN (dev);
|
||||||
|
FpiSsm *ssm = user_data;
|
||||||
|
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
g_autoptr(SecugenDetectTaskResult) analysis = NULL;
|
||||||
|
|
||||||
|
analysis = g_task_propagate_pointer (G_TASK (result), &error);
|
||||||
|
if (error)
|
||||||
|
{
|
||||||
|
if (self->deactivating &&
|
||||||
|
g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fpi_ssm_mark_failed (ssm, g_steal_pointer (&error));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->deactivating)
|
||||||
|
{
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp_dbg ("Finger detect: mean brightness = %u (threshold %d)",
|
||||||
|
analysis->mean, SECUGEN_FINGER_THRESHOLD);
|
||||||
|
|
||||||
|
if (analysis->finger_present)
|
||||||
|
{
|
||||||
|
fp_dbg ("Finger detected!");
|
||||||
|
fpi_image_device_report_finger_status (FP_IMAGE_DEVICE (dev), TRUE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (analysis->update_calibration && analysis->new_cal_raw)
|
||||||
|
memcpy (self->cal_raw, analysis->new_cal_raw, SECUGEN_BULK_BUF_SIZE);
|
||||||
|
|
||||||
|
self->finger_poll_source =
|
||||||
|
fpi_device_add_timeout (FP_DEVICE (dev),
|
||||||
|
SECUGEN_FINGER_POLL_MS,
|
||||||
|
detect_retry_timeout,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
fpi_ssm_mark_completed (ssm);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
detect_run_state (FpiSsm *ssm, FpDevice *_dev)
|
detect_run_state (FpiSsm *ssm, FpDevice *_dev)
|
||||||
@@ -1706,15 +1945,8 @@ detect_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||||||
|
|
||||||
case DETECT_ANALYZE:
|
case DETECT_ANALYZE:
|
||||||
{
|
{
|
||||||
guint64 sum = 0;
|
g_autoptr(GTask) task = NULL;
|
||||||
/* Use central 50% of the 956x688 raw sensor area */
|
g_autoptr(SecugenDetectTaskData) task_data = NULL;
|
||||||
int start_row = SECUGEN_RAW_HEIGHT / 4;
|
|
||||||
int end_row = 3 * SECUGEN_RAW_HEIGHT / 4;
|
|
||||||
int start_col = SECUGEN_RAW_WIDTH / 4;
|
|
||||||
int end_col = 3 * SECUGEN_RAW_WIDTH / 4;
|
|
||||||
int count = 0;
|
|
||||||
guint mean;
|
|
||||||
int y, x;
|
|
||||||
|
|
||||||
/* If a deactivate arrived while this detect cycle ran, do not report
|
/* If a deactivate arrived while this detect cycle ran, do not report
|
||||||
* finger state or arm another poll - just unwind the SSM so the
|
* finger state or arm another poll - just unwind the SSM so the
|
||||||
@@ -1725,54 +1957,20 @@ detect_run_state (FpiSsm *ssm, FpDevice *_dev)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute mean brightness of central 50% region */
|
/* Snapshot current frame/calibration for worker-thread analysis. */
|
||||||
for (y = start_row; y < end_row; y++)
|
task_data = g_new0 (SecugenDetectTaskData, 1);
|
||||||
for (x = start_col; x < end_col; x++)
|
task_data->frame = g_memdup2 (self->bulk_buffer, SECUGEN_BULK_BUF_SIZE);
|
||||||
{
|
task_data->cal_raw = g_memdup2 (self->cal_raw, SECUGEN_BULK_BUF_SIZE);
|
||||||
int idx = y * SECUGEN_RAW_WIDTH + x;
|
|
||||||
|
|
||||||
if (idx < SECUGEN_BULK_BUF_SIZE)
|
task = g_task_new (FP_DEVICE (dev),
|
||||||
{
|
fpi_device_get_cancellable (FP_DEVICE (dev)),
|
||||||
int val = (int) self->bulk_buffer[idx] -
|
detect_analyze_done,
|
||||||
(int) self->cal_raw[idx];
|
ssm);
|
||||||
|
g_task_set_source_tag (task, secugen_detect_analyze_thread);
|
||||||
if (val < 0)
|
g_task_set_check_cancellable (task, TRUE);
|
||||||
val = 0;
|
g_task_set_task_data (task, g_steal_pointer (&task_data),
|
||||||
sum += val;
|
(GDestroyNotify) secugen_detect_task_data_free);
|
||||||
count++;
|
g_task_run_in_thread (task, secugen_detect_analyze_thread);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mean = count > 0 ? (guint) (sum / count) : 0;
|
|
||||||
fp_dbg ("Finger detect: mean brightness = %u (threshold %d)",
|
|
||||||
mean, SECUGEN_FINGER_THRESHOLD);
|
|
||||||
|
|
||||||
if (mean >= SECUGEN_FINGER_THRESHOLD)
|
|
||||||
{
|
|
||||||
fp_dbg ("Finger detected!");
|
|
||||||
fpi_image_device_report_finger_status (dev, TRUE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* No finger - update calibration reference from this frame
|
|
||||||
* only if truly empty (mean < 5). This avoids contaminating
|
|
||||||
* the reference with partial finger touches.
|
|
||||||
*/
|
|
||||||
if (mean <= 5)
|
|
||||||
memcpy (self->cal_raw, self->bulk_buffer,
|
|
||||||
SECUGEN_BULK_BUF_SIZE);
|
|
||||||
|
|
||||||
/* Schedule another poll */
|
|
||||||
self->finger_poll_source =
|
|
||||||
fpi_device_add_timeout (FP_DEVICE (dev),
|
|
||||||
SECUGEN_FINGER_POLL_MS,
|
|
||||||
detect_retry_timeout,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
fpi_ssm_mark_completed (ssm);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user