summaryrefslogtreecommitdiff
path: root/src/lib/emotion/emotion_webcam.c
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2020-03-25 16:46:27 +0000
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2020-03-25 17:11:28 +0000
commit030ef36c72b721de487ca3bb940d4f22a58e745c (patch)
tree0a2fc74d53716ca19ea0c96599a855ef6cec10ec /src/lib/emotion/emotion_webcam.c
parent6068cc9039243d493d001df7a35426cd7c5acfea (diff)
emotion - webcam - fix segv on webcam plug/unplug and clean
well hunting was fun... custom webcams i just cant see being used. no api to add them - have to hand craft a config file .. and udev/eeze provide info on webcam devices anyway at runtime with plug/unplug etc. ... so this should be the only ay (for now) and it keesp the code simpler and less bug-prone now issue was some nasty skipping unref as opposed to destroy. in chasing i simplified the code to help me narrow it down and not chase the same logic in multiple places. shorter cleaere, simpler and minux one bug. @fix
Diffstat (limited to '')
-rw-r--r--src/lib/emotion/emotion_webcam.c284
1 files changed, 95 insertions, 189 deletions
diff --git a/src/lib/emotion/emotion_webcam.c b/src/lib/emotion/emotion_webcam.c
index d29110aa23..8b46b9a724 100644
--- a/src/lib/emotion/emotion_webcam.c
+++ b/src/lib/emotion/emotion_webcam.c
@@ -27,11 +27,9 @@ typedef struct _Emotion_Webcams Emotion_Webcams;
27struct _Emotion_Webcams 27struct _Emotion_Webcams
28{ 28{
29 Eina_List *webcams; 29 Eina_List *webcams;
30
31 Ecore_Idler *idler; 30 Ecore_Idler *idler;
32 Eina_List *check_list; 31 Eina_List *check_list;
33 32 Eina_Bool init : 1;
34 Eina_Bool init;
35}; 33};
36 34
37struct _Emotion_Webcam 35struct _Emotion_Webcam
@@ -41,56 +39,18 @@ struct _Emotion_Webcam
41 const char *syspath; 39 const char *syspath;
42 const char *device; 40 const char *device;
43 const char *name; 41 const char *name;
44
45 const char *custom;
46
47 const char *filename; 42 const char *filename;
43 Eina_Bool in_list : 1;
48}; 44};
49 45
50static Eet_Data_Descriptor *_webcam_edd;
51static Eet_Data_Descriptor *_webcams_edd;
52
53static Emotion_Webcams *_emotion_webcams = NULL; 46static Emotion_Webcams *_emotion_webcams = NULL;
54 47
55static Eet_Data_Descriptor *
56_emotion_webcams_edds_new(void)
57{
58 Eet_Data_Descriptor_Class eddc;
59
60 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Emotion_Webcam);
61 _webcam_edd = eet_data_descriptor_file_new(&eddc);
62 EET_DATA_DESCRIPTOR_ADD_BASIC(_webcam_edd, Emotion_Webcam, "device", device, EET_T_STRING);
63 EET_DATA_DESCRIPTOR_ADD_BASIC(_webcam_edd, Emotion_Webcam, "name", name, EET_T_STRING);
64 EET_DATA_DESCRIPTOR_ADD_BASIC(_webcam_edd, Emotion_Webcam, "custom", custom, EET_T_STRING);
65 EET_DATA_DESCRIPTOR_ADD_BASIC(_webcam_edd, Emotion_Webcam, "filename", filename, EET_T_STRING);
66
67 EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Emotion_Webcams);
68 _webcams_edd = eet_data_descriptor_file_new(&eddc);
69 EET_DATA_DESCRIPTOR_ADD_LIST(_webcams_edd, Emotion_Webcams, "webcams", webcams, _webcam_edd);
70 EET_DATA_DESCRIPTOR_ADD_BASIC(_webcam_edd, Emotion_Webcams, "init", init, EET_T_CHAR);
71
72 return _webcams_edd;
73}
74
75static void
76_emotion_webcams_edds_free(void)
77{
78 eet_data_descriptor_free(_webcams_edd);
79 _webcams_edd = NULL;
80
81 eet_data_descriptor_free(_webcam_edd);
82 _webcam_edd = NULL;
83}
84
85static void 48static void
86emotion_webcam_destroy(Emotion_Webcam *ew) 49emotion_webcam_destroy(Emotion_Webcam *ew)
87{ 50{
88 if (!ew->custom) 51 eina_stringshare_del(ew->syspath);
89 { 52 eina_stringshare_del(ew->device);
90 eina_stringshare_del(ew->syspath); 53 eina_stringshare_del(ew->name);
91 eina_stringshare_del(ew->device);
92 eina_stringshare_del(ew->name);
93 }
94 free(ew); 54 free(ew);
95} 55}
96 56
@@ -116,33 +76,25 @@ _emotion_check_device(Emotion_Webcam *ew)
116 76
117 if (ioctl(fd, VIDIOC_QUERYCAP, &caps) == -1) goto on_error; 77 if (ioctl(fd, VIDIOC_QUERYCAP, &caps) == -1) goto on_error;
118 78
119 /* Likely not a webcam */ 79 // Likely not a webcam
120 if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE)) goto on_error; 80 if (!(caps.capabilities & V4L2_CAP_VIDEO_CAPTURE)) goto on_error;
121 if (caps.capabilities & V4L2_CAP_TUNER 81 if (caps.capabilities &
122 || caps.capabilities & V4L2_CAP_RADIO 82 (V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_MODULATOR))
123 || caps.capabilities & V4L2_CAP_MODULATOR)
124 goto on_error; 83 goto on_error;
125 84
126 EINA_LIST_FOREACH(_emotion_webcams->webcams, l, check) 85 EINA_LIST_FOREACH(_emotion_webcams->webcams, l, check)
127 if (check->device == ew->device) 86 {
128 goto on_error; 87 if (check->device == ew->device) goto on_error;
129 88 }
130 _emotion_webcams->webcams = eina_list_append(_emotion_webcams->webcams, ew); 89 _emotion_webcams->webcams = eina_list_append(_emotion_webcams->webcams, ew);
131 90 ew->in_list = EINA_TRUE;
132 EINA_REFCOUNT_INIT(ew);
133
134 if (fd >= 0) close(fd); 91 if (fd >= 0) close(fd);
135
136 return EINA_TRUE; 92 return EINA_TRUE;
137 93
138 on_error: 94 on_error:
139#endif 95#endif
140 INF("'%s' is not a webcam ['%s']", ew->name, strerror(errno)); 96 INF("'%s' is not a webcam ['%s']", ew->name, strerror(errno));
141 _emotion_webcams->webcams = eina_list_remove(_emotion_webcams->webcams, ew); 97 emotion_webcam_destroy(ew);
142 eina_stringshare_del(ew->syspath);
143 eina_stringshare_del(ew->device);
144 eina_stringshare_del(ew->name);
145 free(ew);
146#ifdef HAVE_V4L2 98#ifdef HAVE_V4L2
147 if (fd >= 0) close(fd); 99 if (fd >= 0) close(fd);
148#endif 100#endif
@@ -152,109 +104,113 @@ _emotion_check_device(Emotion_Webcam *ew)
152static Emotion_Webcam * 104static Emotion_Webcam *
153_emotion_webcam_new(const char *syspath) 105_emotion_webcam_new(const char *syspath)
154{ 106{
155 Emotion_Webcam *test; 107 Emotion_Webcam *ew;
156 const char *device; 108 const char *device;
157 char *local; 109 char *local;
158 110
159 test = malloc(sizeof (Emotion_Webcam)); 111 ew = calloc(1, sizeof(Emotion_Webcam));
160 if (!test) return NULL; 112 if (!ew) return NULL;
161 113
162 test->custom = NULL; 114 EINA_REFCOUNT_INIT(ew);
163 test->syspath = eina_stringshare_ref(syspath); 115 ew->syspath = eina_stringshare_ref(syspath);
164 test->name = eeze_udev_syspath_get_sysattr(syspath, "name"); 116 ew->name = eeze_udev_syspath_get_sysattr(syspath, "name");
165 117
166 device = eeze_udev_syspath_get_property(syspath, "DEVNAME"); 118 device = eeze_udev_syspath_get_property(syspath, "DEVNAME");
167 local = alloca(eina_stringshare_strlen(device) + 8); 119 local = alloca(eina_stringshare_strlen(device) + 8);
168 snprintf(local, eina_stringshare_strlen(device) + 8, "v4l2://%s", device); 120 snprintf(local, eina_stringshare_strlen(device) + 8, "v4l2://%s", device);
169 test->device = eina_stringshare_add(local); 121 ew->device = eina_stringshare_add(local);
170 eina_stringshare_del(device); 122 eina_stringshare_del(device);
171 test->filename = test->device + 7; 123 ew->filename = ew->device + 7;
172 124
173 return test; 125 return ew;
174} 126}
175 127
176static void 128static void
177_emotion_webcam_remove_cb(void *user_data, void *func_data EINA_UNUSED) 129_emotion_webcam_unref(Emotion_Webcam *ew)
178{ 130{
179 Emotion_Webcam *webcam; 131 EINA_REFCOUNT_UNREF(ew)
180
181 /* called at the end of EMOTION_WEBCAM_ADD event, to prevent the free */
182 if (!user_data)
183 return;
184
185 webcam = user_data;
186
187 EINA_REFCOUNT_UNREF(webcam)
188 { 132 {
189 if (_emotion_webcams) 133 if ((ew->in_list) && (_emotion_webcams))
190 _emotion_webcams->webcams = 134 {
191 eina_list_remove(_emotion_webcams->webcams, webcam); 135 _emotion_webcams->webcams =
192 emotion_webcam_destroy(webcam); 136 eina_list_remove(_emotion_webcams->webcams, ew);
137 ew->in_list = EINA_FALSE;
138 }
139 emotion_webcam_destroy(ew);
193 } 140 }
194} 141}
195 142
143static void
144_emotion_eeze_event_free(void *data EINA_UNUSED, void *ev)
145{
146 _emotion_webcam_unref(ev);
147}
148
149static void
150_emotion_webcam_ev_add(const char *syspath)
151{
152 Emotion_Webcam *ew = _emotion_webcam_new(syspath);
153 if (!ew) return;
154 if (!_emotion_check_device(ew)) return;
155 EINA_REFCOUNT_REF(ew);
156 ecore_event_add(EMOTION_WEBCAM_ADD, ew, _emotion_eeze_event_free, NULL);
157}
158
196static Eina_Bool 159static Eina_Bool
197_emotion_process_webcam(void *data) 160_emotion_process_webcam(void *data)
198{ 161{
199 Emotion_Webcams *webcams; 162 Emotion_Webcams *webcams = data;
200 Emotion_Webcam *test;
201 const char *syspath; 163 const char *syspath;
202 164
203 webcams = data;
204 syspath = eina_list_data_get(webcams->check_list); 165 syspath = eina_list_data_get(webcams->check_list);
205 if (!syspath) 166 if (!syspath)
206 { 167 {
207 webcams->idler = NULL; 168 webcams->idler = NULL;
208 webcams->init = EINA_TRUE; 169 webcams->init = EINA_TRUE;
209 return EINA_FALSE; 170 return EINA_FALSE;
210 } 171 }
211
212 webcams->check_list = eina_list_remove_list(webcams->check_list, 172 webcams->check_list = eina_list_remove_list(webcams->check_list,
213 webcams->check_list); 173 webcams->check_list);
214 174 _emotion_webcam_ev_add(syspath);
215 test = _emotion_webcam_new(syspath);
216 if (test)
217 {
218 if (_emotion_check_device(test))
219 ecore_event_add(EMOTION_WEBCAM_ADD, test, NULL, NULL);
220 }
221
222 eina_stringshare_del(syspath); 175 eina_stringshare_del(syspath);
223
224 return EINA_TRUE; 176 return EINA_TRUE;
225} 177}
226 178
227static void 179static void
228_emotion_eeze_events(const char *syspath, 180_emotion_webcam_remove_cb(void *data EINA_UNUSED, void *ev)
229 Eeze_Udev_Event ev, 181{
182 _emotion_webcam_unref(ev);
183}
184
185static void
186_emotion_eeze_events(const char *syspath, Eeze_Udev_Event ev,
230 void *data EINA_UNUSED, 187 void *data EINA_UNUSED,
231 Eeze_Udev_Watch *watcher EINA_UNUSED) 188 Eeze_Udev_Watch *watcher EINA_UNUSED)
232{ 189{
233 if (ev == EEZE_UDEV_EVENT_REMOVE) 190 if (ev == EEZE_UDEV_EVENT_REMOVE)
234 { 191 {
235 Emotion_Webcam *check; 192 Emotion_Webcam *ew;
236 Eina_List *l; 193 Eina_List *l;
237 194
238 EINA_LIST_FOREACH(_emotion_webcams->webcams, l, check) 195 EINA_LIST_FOREACH(_emotion_webcams->webcams, l, ew)
239 if (check->syspath == syspath) 196 {
240 { 197 if (ew->syspath == syspath)
241 _emotion_webcams->webcams = 198 {
242 eina_list_remove_list(_emotion_webcams->webcams, l); 199 if (ew->in_list)
243 ecore_event_add(EMOTION_WEBCAM_DEL, check, 200 {
244 _emotion_webcam_remove_cb, check); 201 _emotion_webcams->webcams =
245 break ; 202 eina_list_remove_list(_emotion_webcams->webcams, l);
246 } 203 ew->in_list = EINA_FALSE;
204 }
205 ecore_event_add(EMOTION_WEBCAM_DEL, ew,
206 _emotion_webcam_remove_cb, NULL);
207 break;
208 }
209 }
247 } 210 }
248 else if (ev == EEZE_UDEV_EVENT_ADD) 211 else if (ev == EEZE_UDEV_EVENT_ADD)
249 { 212 {
250 Emotion_Webcam *test; 213 _emotion_webcam_ev_add(syspath);
251
252 test = _emotion_webcam_new(syspath);
253 if (test)
254 {
255 if (_emotion_check_device(test))
256 ecore_event_add(EMOTION_WEBCAM_ADD, test, NULL, NULL);
257 }
258 } 214 }
259 ecore_event_add(EMOTION_WEBCAM_UPDATE, NULL, NULL, NULL); 215 ecore_event_add(EMOTION_WEBCAM_UPDATE, NULL, NULL, NULL);
260} 216}
@@ -266,12 +222,11 @@ _emotion_enumerate_all_webcams(void)
266{ 222{
267#ifdef HAVE_EEZE 223#ifdef HAVE_EEZE
268 Eina_List *devices; 224 Eina_List *devices;
269 if (_emotion_webcams->init) return ; 225 if (_emotion_webcams->init) return;
270 devices = eeze_udev_find_by_type(EEZE_UDEV_TYPE_V4L, NULL); 226 devices = eeze_udev_find_by_type(EEZE_UDEV_TYPE_V4L, NULL);
271
272 _emotion_webcams->check_list = devices; 227 _emotion_webcams->check_list = devices;
273 _emotion_webcams->idler = ecore_idler_add(_emotion_process_webcam, 228 _emotion_webcams->idler = ecore_idler_add(_emotion_process_webcam,
274 _emotion_webcams); 229 _emotion_webcams);
275#endif 230#endif
276} 231}
277 232
@@ -282,9 +237,6 @@ Eina_Bool emotion_webcam_init(void)
282 EMOTION_WEBCAM_ADD = ecore_event_type_new(); 237 EMOTION_WEBCAM_ADD = ecore_event_type_new();
283 EMOTION_WEBCAM_DEL = ecore_event_type_new(); 238 EMOTION_WEBCAM_DEL = ecore_event_type_new();
284 239
285 eet_init();
286 _emotion_webcams_edds_new();
287
288 if (!_emotion_webcams) 240 if (!_emotion_webcams)
289 { 241 {
290 _emotion_webcams = calloc(1, sizeof (Emotion_Webcams)); 242 _emotion_webcams = calloc(1, sizeof (Emotion_Webcams));
@@ -293,10 +245,9 @@ Eina_Bool emotion_webcam_init(void)
293 245
294#ifdef HAVE_EEZE 246#ifdef HAVE_EEZE
295 eeze_init(); 247 eeze_init();
296 248 eeze_watcher = eeze_udev_watch_add
297 eeze_watcher = eeze_udev_watch_add(EEZE_UDEV_TYPE_V4L, 249 (EEZE_UDEV_TYPE_V4L, (EEZE_UDEV_EVENT_ADD | EEZE_UDEV_EVENT_REMOVE),
298 (EEZE_UDEV_EVENT_ADD | EEZE_UDEV_EVENT_REMOVE), 250 _emotion_eeze_events, NULL);
299 _emotion_eeze_events, NULL);
300#endif 251#endif
301 252
302 return EINA_TRUE; 253 return EINA_TRUE;
@@ -308,8 +259,7 @@ emotion_webcam_shutdown(void)
308 Emotion_Webcam *ew; 259 Emotion_Webcam *ew;
309 const char *syspath; 260 const char *syspath;
310 261
311 ecore_event_type_flush(EMOTION_WEBCAM_UPDATE, 262 ecore_event_type_flush(EMOTION_WEBCAM_UPDATE, EMOTION_WEBCAM_ADD,
312 EMOTION_WEBCAM_ADD,
313 EMOTION_WEBCAM_DEL); 263 EMOTION_WEBCAM_DEL);
314 264
315 if (_emotion_webcams->idler) 265 if (_emotion_webcams->idler)
@@ -319,15 +269,21 @@ emotion_webcam_shutdown(void)
319 } 269 }
320 270
321 EINA_LIST_FREE(_emotion_webcams->check_list, syspath) 271 EINA_LIST_FREE(_emotion_webcams->check_list, syspath)
322 eina_stringshare_del(syspath); 272 {
273 eina_stringshare_del(syspath);
274 }
323 275
324 _emotion_webcams->init = EINA_FALSE; 276 _emotion_webcams->init = EINA_FALSE;
325 277
326 EINA_LIST_FREE(_emotion_webcams->webcams, ew) 278 EINA_LIST_FREE(_emotion_webcams->webcams, ew)
327 { 279 {
328 /* There is currently no way to refcount from the outside, this help, but could lead to some issue */ 280 ew->in_list = EINA_FALSE;
281 // There is currently no way to refcount from the outside, this helps
282 // but could lead to some issues
329 EINA_REFCOUNT_UNREF(ew) 283 EINA_REFCOUNT_UNREF(ew)
330 emotion_webcam_destroy(ew); 284 {
285 emotion_webcam_destroy(ew);
286 }
331 } 287 }
332 free(_emotion_webcams); 288 free(_emotion_webcams);
333 _emotion_webcams = NULL; 289 _emotion_webcams = NULL;
@@ -335,54 +291,15 @@ emotion_webcam_shutdown(void)
335#ifdef HAVE_EEZE 291#ifdef HAVE_EEZE
336 eeze_udev_watch_del(eeze_watcher); 292 eeze_udev_watch_del(eeze_watcher);
337 eeze_watcher = NULL; 293 eeze_watcher = NULL;
338
339 eeze_shutdown(); 294 eeze_shutdown();
340#endif 295#endif
341
342 _emotion_webcams_edds_free();
343 eet_shutdown();
344}
345
346Eina_Bool
347emotion_webcam_config_load(Eet_File *ef)
348{
349 Emotion_Webcams *emotion_webcams = NULL;
350
351 if (ef)
352 {
353 emotion_webcams = eet_data_read(ef, _webcams_edd, "config");
354 INF("Loaded config %p from eet %s", _emotion_webcams, eet_file_get(ef));
355 }
356
357 if (emotion_webcams)
358 {
359 if (_emotion_webcams)
360 {
361 emotion_webcam_shutdown();
362 _emotion_webcams = emotion_webcams;
363 emotion_webcam_init();
364 }
365 else
366 _emotion_webcams = emotion_webcams;
367 }
368
369 if (!_emotion_webcams)
370 {
371 DBG("No config, create empty");
372 _emotion_webcams = calloc(1, sizeof (Emotion_Webcams));
373 EINA_SAFETY_ON_NULL_RETURN_VAL(_emotion_webcams, EINA_FALSE);
374 }
375
376 return EINA_TRUE;
377} 296}
378 297
379EAPI const Eina_List * 298EAPI const Eina_List *
380emotion_webcams_get(void) 299emotion_webcams_get(void)
381{ 300{
382 EINA_SAFETY_ON_NULL_RETURN_VAL(_emotion_webcams, NULL); 301 EINA_SAFETY_ON_NULL_RETURN_VAL(_emotion_webcams, NULL);
383
384 _emotion_enumerate_all_webcams(); 302 _emotion_enumerate_all_webcams();
385
386 return _emotion_webcams->webcams; 303 return _emotion_webcams->webcams;
387} 304}
388 305
@@ -401,18 +318,7 @@ emotion_webcam_device_get(const Emotion_Webcam *ew)
401} 318}
402 319
403EAPI const char * 320EAPI const char *
404emotion_webcam_custom_get(const char *device) 321emotion_webcam_custom_get(const char *device EINA_UNUSED)
405{ 322{
406 const Emotion_Webcam *ew;
407 const Eina_List *l;
408
409 EINA_SAFETY_ON_NULL_RETURN_VAL(_emotion_webcams, NULL);
410
411 _emotion_enumerate_all_webcams();
412
413 EINA_LIST_FOREACH(_emotion_webcams->webcams, l, ew)
414 if (ew->device && strcmp(device, ew->device) == 0)
415 return ew->custom;
416
417 return NULL; 323 return NULL;
418} 324}