aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheJackiMonster <thejackimonster@gmail.com>2022-08-12 03:43:54 +0200
committerTheJackiMonster <thejackimonster@gmail.com>2022-08-12 03:43:54 +0200
commit0fe98e7e4001f41b2e6d9520dcb5cde1c3e631e6 (patch)
tree1083a9bef5adc7052e4a780cbce9d461ce51896f
parent3271562e33a8f19416bff2ca122c75b98e85ed7d (diff)
downloadmessenger-gtk-0fe98e7e4001f41b2e6d9520dcb5cde1c3e631e6.tar.gz
messenger-gtk-0fe98e7e4001f41b2e6d9520dcb5cde1c3e631e6.zip
Replaced zbar dependency with gstreamer pipeline
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r--Makefile4
-rw-r--r--src/ui/new_contact.c374
-rw-r--r--src/ui/new_contact.h13
3 files changed, 245 insertions, 146 deletions
diff --git a/Makefile b/Makefile
index aa14fdf..41c8fa1 100644
--- a/Makefile
+++ b/Makefile
@@ -48,11 +48,11 @@ LIBRARIES = gnunetchat
48PACKAGES = gnunetutil\ 48PACKAGES = gnunetutil\
49 glib-2.0\ 49 glib-2.0\
50 gstreamer-1.0\ 50 gstreamer-1.0\
51 gstreamer-app-1.0\
51 gtk+-3.0\ 52 gtk+-3.0\
52 libhandy-1\ 53 libhandy-1\
53 libnotify\ 54 libnotify\
54 libqrencode\ 55 libqrencode
55 zbar
56 56
57INCLUDES = submodules/gnome-characters/lib 57INCLUDES = submodules/gnome-characters/lib
58 58
diff --git a/src/ui/new_contact.c b/src/ui/new_contact.c
index 094dd67..b4de414 100644
--- a/src/ui/new_contact.c
+++ b/src/ui/new_contact.c
@@ -24,6 +24,8 @@
24 24
25#include "new_contact.h" 25#include "new_contact.h"
26 26
27#include <gstreamer-1.0/gst/app/gstappsink.h>
28
27#include "../application.h" 29#include "../application.h"
28 30
29static void 31static void
@@ -89,61 +91,25 @@ handle_id_drawing_area_draw(GtkWidget* drawing_area,
89 91
90 gtk_render_background(context, cairo, 0, 0, width, height); 92 gtk_render_background(context, cairo, 0, 0, width, height);
91 93
92 GdkPixbuf *image = NULL;
93
94 if (!(handle->image)) 94 if (!(handle->image))
95 return FALSE; 95 return FALSE;
96 96
97 uint w, h; 97 uint w, h;
98 zbar_image_get_size(handle->image, &w, &h); 98 w = gdk_pixbuf_get_width(handle->image);
99 99 h = gdk_pixbuf_get_height(handle->image);
100 uint x, y, min_size;
101 min_size = (w < h? w : h);
102 x = (w - min_size) / 2;
103 y = (h - min_size) / 2;
104
105 const void* data = (const void*) (
106 (const char*) zbar_image_get_data(handle->image) +
107 (x + y * w) * 3
108 );
109
110 image = gdk_pixbuf_new_from_data(
111 data,
112 GDK_COLORSPACE_RGB,
113 FALSE,
114 8,
115 min_size,
116 min_size,
117 w * 3,
118 NULL,
119 NULL
120 );
121 100
122 GString *scan_result = (GString*) zbar_image_get_userdata(handle->image); 101 uint min_size = (w < h? w : h);
123 102
124 if (!scan_result) 103 double ratio_width = 1.0 * width / min_size;
125 goto render_image; 104 double ratio_height = 1.0 * height / min_size;
126
127 gtk_entry_set_text(handle->id_entry, scan_result->str);
128 g_string_free(scan_result, TRUE);
129
130render_image:
131 if (!image)
132 return FALSE;
133
134 int dwidth = gdk_pixbuf_get_width(image);
135 int dheight = gdk_pixbuf_get_height(image);
136
137 double ratio_width = 1.0 * width / dwidth;
138 double ratio_height = 1.0 * height / dheight;
139 105
140 const double ratio = ratio_width < ratio_height? ratio_width : ratio_height; 106 const double ratio = ratio_width < ratio_height? ratio_width : ratio_height;
141 107
142 dwidth = (int) (dwidth * ratio); 108 w = (uint) (min_size * ratio);
143 dheight = (int) (dheight * ratio); 109 h = (uint) (min_size * ratio);
144 110
145 double dx = (width - dwidth) * 0.5; 111 double dx = (width - w) * 0.5;
146 double dy = (height - dheight) * 0.5; 112 double dy = (height - h) * 0.5;
147 113
148 const int interp_type = (ratio >= 1.0? 114 const int interp_type = (ratio >= 1.0?
149 GDK_INTERP_NEAREST : 115 GDK_INTERP_NEAREST :
@@ -151,9 +117,9 @@ render_image:
151 ); 117 );
152 118
153 GdkPixbuf* scaled = gdk_pixbuf_scale_simple( 119 GdkPixbuf* scaled = gdk_pixbuf_scale_simple(
154 image, 120 handle->image,
155 dwidth, 121 w,
156 dheight, 122 h,
157 interp_type 123 interp_type
158 ); 124 );
159 125
@@ -162,36 +128,78 @@ render_image:
162 cairo_fill(cairo); 128 cairo_fill(cairo);
163 129
164 g_object_unref(scaled); 130 g_object_unref(scaled);
165 g_object_unref(image);
166
167 zbar_image_destroy(handle->image);
168 handle->image = NULL;
169
170 return FALSE; 131 return FALSE;
171} 132}
172 133
173static void 134static void
174_disable_video_processing(UI_NEW_CONTACT_Handle *handle) 135_disable_video_processing(UI_NEW_CONTACT_Handle *handle,
136 gboolean drop_pipeline)
175{ 137{
176 gtk_stack_set_visible_child(handle->preview_stack, handle->fail_box); 138 gtk_stack_set_visible_child(handle->preview_stack, handle->fail_box);
177 139
178 if (!(handle->video)) 140 if (0 != handle->idle_processing)
141 g_source_remove(handle->idle_processing);
142
143 handle->idle_processing = 0;
144
145 if ((!(handle->pipeline)) || (!drop_pipeline))
179 return; 146 return;
180 147
181 const zbar_error_t error_code = zbar_video_get_error_code(handle->video); 148 gst_element_set_state(handle->pipeline, GST_STATE_NULL);
149}
182 150
183 if (ZBAR_OK != error_code) 151static void
184 { 152_handle_video_sample(UI_NEW_CONTACT_Handle *handle,
185 const char *error_msg = zbar_video_error_string(handle->video, 0); 153 GstAppSink *appsink)
154{
155 GstSample *sample = gst_app_sink_try_pull_sample(appsink, 10);
186 156
187 if (error_msg) 157 if (!sample)
188 fprintf(stderr, "%s", error_msg); 158 return;
189 else
190 fprintf(stderr, "ERROR: Unknown error with zbar (%d)\n",
191 (int) error_code);
192 }
193 159
194 handle->idle_processing = 0; 160 GstCaps *caps = gst_sample_get_caps(sample);
161
162 GstStructure *s = gst_caps_get_structure(caps, 0);
163
164 gint width, height;
165 gst_structure_get_int(s, "width", &width);
166 gst_structure_get_int(s, "height", &height);
167
168 uint x, y, min_size;
169 min_size = (width < height? width : height);
170 x = (width - min_size) / 2;
171 y = (height - min_size) / 2;
172
173 GstBuffer *buffer = gst_sample_get_buffer(sample);
174 GstMapInfo map;
175
176 gst_buffer_map(buffer, &map, GST_MAP_READ);
177
178 if (handle->image)
179 g_object_unref(handle->image);
180
181 const void* data = (const void*) (
182 (const char*) (map.data) + (x + y * width) * 3
183 );
184
185 handle->image = gdk_pixbuf_new_from_data(
186 data,
187 GDK_COLORSPACE_RGB,
188 FALSE,
189 8,
190 min_size,
191 min_size,
192 width * 3,
193 NULL,
194 NULL
195 );
196
197 gst_buffer_unmap(buffer, &map);
198
199 if (handle->id_drawing_area)
200 gtk_widget_queue_draw(GTK_WIDGET(handle->id_drawing_area));
201
202 gst_sample_unref(sample);
195} 203}
196 204
197static gboolean 205static gboolean
@@ -202,72 +210,168 @@ idle_video_processing(gpointer user_data)
202 if (0 == handle->idle_processing) 210 if (0 == handle->idle_processing)
203 return FALSE; 211 return FALSE;
204 212
205 zbar_image_t *image = zbar_video_next_image(handle->video); 213 GstAppSink *appsink = GST_APP_SINK(handle->sink);
206 214
207 if (!image) 215 if (!appsink)
208 { 216 {
209 _disable_video_processing(handle); 217 _disable_video_processing(handle, TRUE);
210 return FALSE; 218 return FALSE;
211 } 219 }
212 220
213 GString *scan_result = NULL; 221 _handle_video_sample(handle, appsink);
222 return TRUE;
223}
214 224
215 zbar_image_t *y8 = zbar_image_convert( 225static void
216 image, 226msg_error_cb(UNUSED GstBus *bus,
217 zbar_fourcc('Y', '8', '0', '0') 227 GstMessage *msg,
218 ); 228 gpointer *data)
229{
230 UI_NEW_CONTACT_Handle *handle = (UI_NEW_CONTACT_Handle*) data;
231
232 GError* error;
233 gst_message_parse_error(msg, &error, NULL);
234
235 if (!error)
236 fprintf(stderr, "ERROR: Unknown error\n");
237 else if (error->message)
238 fprintf(stderr, "ERROR: %s (%d)", error->message, error->code);
239 else
240 fprintf(stderr, "ERROR: Unknown error (%d)\n", error->code);
219 241
220 if (zbar_scan_image(handle->scanner, y8) <= 0) 242 gst_element_set_state(handle->pipeline, GST_STATE_READY);
221 goto cleanup_scan; 243
244 if (!(handle->preview_stack))
245 return;
222 246
223 const zbar_symbol_set_t* set = zbar_image_scanner_get_results( 247 gtk_stack_set_visible_child(
224 handle->scanner 248 handle->preview_stack,
249 handle->fail_box
225 ); 250 );
251}
226 252
227 const zbar_symbol_t* symbol = zbar_symbol_set_first_symbol(set); 253static void
254msg_eos_cb(UNUSED GstBus *bus,
255 UNUSED GstMessage *msg,
256 gpointer *data)
257{
258 UI_NEW_CONTACT_Handle *handle = (UI_NEW_CONTACT_Handle*) data;
259
260 if (GST_MESSAGE_SRC(msg) == GST_OBJECT(handle->pipeline))
261 _disable_video_processing(handle, TRUE);
262}
263
264static void
265msg_state_changed_cb(UNUSED GstBus *bus,
266 GstMessage *msg,
267 gpointer *data)
268{
269 UI_NEW_CONTACT_Handle *handle = (UI_NEW_CONTACT_Handle*) data;
228 270
229 if (!symbol) 271 GstState old_state, new_state, pending_state;
230 goto cleanup_scan; 272 gst_message_parse_state_changed(msg, &old_state, &new_state, &pending_state);
231 273
232 uint data_len = 0; 274 if ((GST_MESSAGE_SRC(msg) != GST_OBJECT(handle->pipeline)) ||
233 const char *data = NULL; 275 (new_state == old_state) || (!(handle->preview_stack)))
276 return;
234 277
235 for (; symbol; symbol = zbar_symbol_next(symbol)) 278 if (GST_STATE_PLAYING == new_state)
236 { 279 {
237 if (zbar_symbol_get_count(symbol)) 280 gtk_stack_set_visible_child(
238 continue; 281 handle->preview_stack,
282 GTK_WIDGET(handle->id_drawing_area)
283 );
239 284
240 data_len = zbar_symbol_get_data_length(symbol); 285 if (0 == handle->idle_processing)
241 data = zbar_symbol_get_data(symbol); 286 handle->idle_processing = g_idle_add(idle_video_processing, handle);
242 } 287 }
288 else if (GST_STATE_PAUSED == new_state)
289 _disable_video_processing(handle, FALSE);
290}
243 291
244 if ((data_len > 0) && (data)) 292static void
245 scan_result = g_string_new_len(data, data_len); 293msg_barcode_cb(UNUSED GstBus *bus,
294 GstMessage *msg,
295 gpointer *data)
296{
297 UI_NEW_CONTACT_Handle *handle = (UI_NEW_CONTACT_Handle*) data;
298 GstMessageType msg_type = GST_MESSAGE_TYPE(msg);
299
300 if ((GST_MESSAGE_SRC(msg) != GST_OBJECT(handle->scanner)) ||
301 (GST_MESSAGE_ELEMENT != msg_type))
302 return;
303
304 const GstStructure *s = gst_message_get_structure(msg);
246 305
247cleanup_scan: 306 if (!s)
248 zbar_image_destroy(y8); 307 return;
308
309 const gchar *type = gst_structure_get_string(s, "type");
310 const gchar *symbol = gst_structure_get_string(s, "symbol");
311
312 if ((!type) || (!symbol) || (0 != g_strcmp0(type, "QR-Code")))
313 return;
249 314
250 zbar_image_t *rgb = zbar_image_convert( 315 if (handle->id_entry)
251 image, 316 gtk_entry_set_text(handle->id_entry, symbol);
252 zbar_fourcc('R', 'G', 'B', '3') 317}
318
319static void
320_setup_gst_pipeline(UI_NEW_CONTACT_Handle *handle)
321{
322 handle->pipeline = gst_parse_launch(
323 "v4l2src name=source ! videoconvert ! zbar name=scanner"
324 " ! videoconvert ! video/x-raw,format=RGB ! videoconvert ! appsink name=sink",
325 NULL
253 ); 326 );
254 327
255 if (!rgb) 328 handle->source = gst_bin_get_by_name(
256 goto cleanup_image; 329 GST_BIN(handle->pipeline), "source"
330 );
257 331
258 zbar_image_set_userdata(rgb, scan_result); 332 handle->scanner = gst_bin_get_by_name(
333 GST_BIN(handle->pipeline), "scanner"
334 );
259 335
260 if (handle->image) 336 handle->sink = gst_bin_get_by_name(
261 zbar_image_destroy(handle->image); 337 GST_BIN(handle->pipeline), "sink"
338 );
262 339
263 handle->image = rgb; 340 gst_app_sink_set_drop(GST_APP_SINK(handle->sink), TRUE);
264 341
265 if (handle->id_drawing_area) 342 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(handle->pipeline));
266 gtk_widget_queue_draw(GTK_WIDGET(handle->id_drawing_area));
267 343
268cleanup_image: 344 gst_bus_add_signal_watch(bus);
269 zbar_image_destroy(image); 345
270 return TRUE; 346 g_signal_connect(
347 G_OBJECT(bus),
348 "message::error",
349 (GCallback) msg_error_cb,
350 handle
351 );
352
353 g_signal_connect(
354 G_OBJECT(bus),
355 "message::eos",
356 (GCallback) msg_eos_cb,
357 handle
358 );
359
360 g_signal_connect(
361 G_OBJECT(bus),
362 "message::state-changed",
363 (GCallback) msg_state_changed_cb,
364 handle
365 );
366
367 g_signal_connect(
368 G_OBJECT(bus),
369 "message",
370 (GCallback) msg_barcode_cb,
371 handle
372 );
373
374 gst_object_unref(bus);
271} 375}
272 376
273static void* 377static void*
@@ -275,31 +379,17 @@ _ui_new_contact_video_thread(void *args)
275{ 379{
276 UI_NEW_CONTACT_Handle *handle = (UI_NEW_CONTACT_Handle*) args; 380 UI_NEW_CONTACT_Handle *handle = (UI_NEW_CONTACT_Handle*) args;
277 381
278 if (0 != zbar_video_open(handle->video, "")) 382 if (!(handle->pipeline))
279 {
280 _disable_video_processing(handle);
281 return NULL; 383 return NULL;
282 }
283
284 if (0 != zbar_video_enable(handle->video, 1))
285 {
286 _disable_video_processing(handle);
287 return NULL;
288 }
289 384
290 zbar_image_scanner_set_config( 385 GstStateChangeReturn ret = gst_element_set_state(
291 handle->scanner, 386 handle->pipeline,
292 ZBAR_QRCODE, 387 GST_STATE_PLAYING
293 ZBAR_CFG_ENABLE,
294 TRUE
295 ); 388 );
296 389
297 gtk_stack_set_visible_child( 390 if (GST_STATE_CHANGE_FAILURE == ret)
298 handle->preview_stack, 391 _disable_video_processing(handle, TRUE);
299 GTK_WIDGET(handle->id_drawing_area)
300 );
301 392
302 handle->idle_processing = g_idle_add(idle_video_processing, handle);
303 return NULL; 393 return NULL;
304} 394}
305 395
@@ -307,8 +397,16 @@ void
307ui_new_contact_dialog_init(MESSENGER_Application *app, 397ui_new_contact_dialog_init(MESSENGER_Application *app,
308 UI_NEW_CONTACT_Handle *handle) 398 UI_NEW_CONTACT_Handle *handle)
309{ 399{
310 handle->video = zbar_video_create(); 400 _setup_gst_pipeline(handle);
311 handle->scanner = zbar_image_scanner_create(); 401
402 handle->image = NULL;
403
404 pthread_create(
405 &(handle->video_tid),
406 NULL,
407 _ui_new_contact_video_thread,
408 handle
409 );
312 410
313 handle->builder = gtk_builder_new_from_resource( 411 handle->builder = gtk_builder_new_from_resource(
314 application_get_resource_path(app, "ui/new_contact.ui") 412 application_get_resource_path(app, "ui/new_contact.ui")
@@ -335,13 +433,6 @@ ui_new_contact_dialog_init(MESSENGER_Application *app,
335 gtk_builder_get_object(handle->builder, "id_drawing_area") 433 gtk_builder_get_object(handle->builder, "id_drawing_area")
336 ); 434 );
337 435
338 pthread_create(
339 &(handle->video_tid),
340 NULL,
341 _ui_new_contact_video_thread,
342 handle
343 );
344
345 handle->id_draw_signal = g_signal_connect( 436 handle->id_draw_signal = g_signal_connect(
346 handle->id_drawing_area, 437 handle->id_drawing_area,
347 "draw", 438 "draw",
@@ -398,13 +489,16 @@ ui_new_contact_dialog_cleanup(UI_NEW_CONTACT_Handle *handle)
398 handle->id_draw_signal 489 handle->id_draw_signal
399 ); 490 );
400 491
401 g_object_unref(handle->builder);
402
403 if (handle->image) 492 if (handle->image)
404 zbar_image_destroy(handle->image); 493 g_object_unref(handle->image);
405 494
406 zbar_image_scanner_destroy(handle->scanner); 495 g_object_unref(handle->builder);
407 zbar_video_destroy(handle->video); 496
497 if (handle->pipeline)
498 {
499 gst_element_set_state(handle->pipeline, GST_STATE_NULL);
500 gst_object_unref(GST_OBJECT(handle->pipeline));
501 }
408 502
409 memset(handle, 0, sizeof(*handle)); 503 memset(handle, 0, sizeof(*handle));
410} 504}
diff --git a/src/ui/new_contact.h b/src/ui/new_contact.h
index 7a7ff96..dd04cce 100644
--- a/src/ui/new_contact.h
+++ b/src/ui/new_contact.h
@@ -29,14 +29,19 @@
29 29
30#include <cairo/cairo.h> 30#include <cairo/cairo.h>
31#include <gdk/gdkpixbuf.h> 31#include <gdk/gdkpixbuf.h>
32#include <gstreamer-1.0/gst/gst.h>
32#include <pthread.h> 33#include <pthread.h>
33#include <zbar.h>
34 34
35typedef struct UI_NEW_CONTACT_Handle 35typedef struct UI_NEW_CONTACT_Handle
36{ 36{
37 zbar_video_t *video; 37 GstElement *pipeline;
38 zbar_image_t *image; 38 GstElement *source;
39 zbar_image_scanner_t *scanner; 39 GstElement *scanner;
40 GstElement *sink;
41
42 guint bus_watch;
43
44 GdkPixbuf *image;
40 45
41 GtkBuilder *builder; 46 GtkBuilder *builder;
42 GtkDialog *dialog; 47 GtkDialog *dialog;