54748f0026b3b65c06903de1bb4ff90eea8e9663
[profile/ivi/emotion.git] / src / lib / emotion_main.c
1 #include "emotion_private.h"
2 #include "Emotion.h"
3
4 #ifdef EMOTION_HAVE_EEZE
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <fcntl.h>
8 # include <sys/ioctl.h>
9 # ifdef HAVE_V4L2
10 #  include <linux/videodev2.h>
11 # endif
12
13 # include <Ecore.h>
14 # include <Eeze.h>
15 #endif
16
17 #include <Eet.h>
18
19 EAPI int EMOTION_WEBCAM_UPDATE = 0;
20
21 struct ext_match_s
22 {
23    unsigned int length;
24    const char *extension;
25 };
26
27 #define MATCHING(Ext)                           \
28   { sizeof (Ext), Ext }
29
30 static const struct ext_match_s matchs[] =
31 { /* map extensions to know if it's a emotion playable content for good first-guess tries */
32    MATCHING(".264"),
33    MATCHING(".3g2"),
34    MATCHING(".3gp"),
35    MATCHING(".3gp2"),
36    MATCHING(".3gpp"),
37    MATCHING(".3gpp2"),
38    MATCHING(".3p2"),
39    MATCHING(".asf"),
40    MATCHING(".avi"),
41    MATCHING(".bdm"),
42    MATCHING(".bdmv"),
43    MATCHING(".clpi"),
44    MATCHING(".clp"),
45    MATCHING(".fla"),
46    MATCHING(".flv"),
47    MATCHING(".m1v"),
48    MATCHING(".m2v"),
49    MATCHING(".m2t"),
50    MATCHING(".m4v"),
51    MATCHING(".mkv"),
52    MATCHING(".mov"),
53    MATCHING(".mp2"),
54    MATCHING(".mp2ts"),
55    MATCHING(".mp4"),
56    MATCHING(".mpe"),
57    MATCHING(".mpeg"),
58    MATCHING(".mpg"),
59    MATCHING(".mpl"),
60    MATCHING(".mpls"),
61    MATCHING(".mts"),
62    MATCHING(".mxf"),
63    MATCHING(".nut"),
64    MATCHING(".nuv"),
65    MATCHING(".ogg"),
66    MATCHING(".ogm"),
67    MATCHING(".ogv"),
68    MATCHING(".rm"),
69    MATCHING(".rmj"),
70    MATCHING(".rmm"),
71    MATCHING(".rms"),
72    MATCHING(".rmx"),
73    MATCHING(".rmvb"),
74    MATCHING(".swf"),
75    MATCHING(".ts"),
76    MATCHING(".weba"),
77    MATCHING(".webm"),
78    MATCHING(".wmv")
79 };
80
81 Eina_Bool
82 _emotion_object_extension_can_play_generic_get(const void *data __UNUSED__, const char *file)
83 {
84    unsigned int length;
85    unsigned int i;
86
87    length = eina_stringshare_strlen(file) + 1;
88    if (length < 5) return EINA_FALSE;
89
90    for (i = 0; i < sizeof (matchs) / sizeof (struct ext_match_s); ++i)
91      {
92         if (matchs[i].length > length) continue;
93
94         if (!strcasecmp(matchs[i].extension,
95                         file + length - matchs[i].length))
96           return EINA_TRUE;
97      }
98
99    return EINA_FALSE;
100 }
101
102 EAPI Eina_Bool
103 emotion_object_extension_may_play_fast_get(const char *file)
104 {
105    if (!file) return EINA_FALSE;
106    return _emotion_object_extension_can_play_generic_get(NULL, file);
107 }
108
109 EAPI Eina_Bool
110 emotion_object_extension_may_play_get(const char *file)
111 {
112    const char *tmp;
113    Eina_Bool result;
114
115    if (!file) return EINA_FALSE;
116    tmp = eina_stringshare_add(file);
117    result = emotion_object_extension_may_play_fast_get(tmp);
118    eina_stringshare_del(tmp);
119
120    return result;
121 }
122
123 typedef struct _Emotion_Webcams Emotion_Webcams;
124
125 struct _Emotion_Webcams
126 {
127    Eina_List *webcams;
128 };
129
130 struct _Emotion_Webcam
131 {
132    EINA_REFCOUNT;
133
134    const char *syspath;
135    const char *device;
136    const char *name;
137
138    const char *custom;
139
140    const char *filename;
141 };
142
143 static int _emotion_webcams_count = 0;
144 static Eet_Data_Descriptor *_webcam_edd;
145 static Eet_Data_Descriptor *_webcams_edd;
146
147 static Emotion_Webcams *_emotion_webcams = NULL;
148 static Eet_File *_emotion_webcams_file = NULL;
149
150 static Eet_Data_Descriptor *
151 _emotion_webcams_data(void)
152 {
153    Eet_Data_Descriptor_Class eddc;
154
155    EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Emotion_Webcam);
156    _webcam_edd = eet_data_descriptor_file_new(&eddc);
157    EET_DATA_DESCRIPTOR_ADD_BASIC(_webcam_edd, Emotion_Webcam, "device", device, EET_T_STRING);
158    EET_DATA_DESCRIPTOR_ADD_BASIC(_webcam_edd, Emotion_Webcam, "name", name, EET_T_STRING);
159    EET_DATA_DESCRIPTOR_ADD_BASIC(_webcam_edd, Emotion_Webcam, "custom", custom, EET_T_STRING);
160    EET_DATA_DESCRIPTOR_ADD_BASIC(_webcam_edd, Emotion_Webcam, "filename", filename, EET_T_STRING);
161
162    EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Emotion_Webcams);
163    _webcams_edd = eet_data_descriptor_file_new(&eddc);
164    EET_DATA_DESCRIPTOR_ADD_LIST(_webcams_edd, Emotion_Webcams, "webcams", webcams, _webcam_edd);
165
166    return _webcams_edd;
167 }
168
169 #ifdef EMOTION_HAVE_EEZE
170 static Eeze_Udev_Watch *eeze_watcher = NULL;
171
172 static void
173 emotion_webcam_destroy(Emotion_Webcam *ew)
174 {
175    if (!ew->custom)
176      {
177         eina_stringshare_del(ew->syspath);
178         eina_stringshare_del(ew->device);
179         eina_stringshare_del(ew->name);
180      }
181    free(ew);
182 }
183
184 static void
185 _emotion_check_device(Emotion_Webcam *ew)
186 {
187 #ifdef HAVE_V4L2
188    Emotion_Webcam *check;
189    Eina_List *l;
190    struct v4l2_capability caps;
191    int fd;
192 #endif
193
194    if (!ew) return ;
195 #ifdef HAVE_V4L2
196    if (!ew->device) goto on_error;
197
198    fd = open(ew->filename, O_RDONLY);
199    if (fd < 0) goto on_error;
200
201    if (ioctl(fd, VIDIOC_QUERYCAP, &caps) == -1) goto on_error;
202
203    /* Likely not a webcam */
204    if (!caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) goto on_error;
205    if (caps.capabilities & V4L2_CAP_TUNER
206        || caps.capabilities & V4L2_CAP_RADIO
207        || caps.capabilities & V4L2_CAP_MODULATOR)
208      goto on_error;
209
210    EINA_LIST_FOREACH(_emotion_webcams->webcams, l, check)
211      if (check->device == ew->device)
212        goto on_error;
213
214    _emotion_webcams->webcams = eina_list_append(_emotion_webcams->webcams, ew);
215
216    EINA_REFCOUNT_INIT(ew);
217
218    return ;
219
220  on_error:
221 #endif
222    fprintf(stderr, "'%s' is not a webcam ['%s']\n", ew->name, strerror(errno));
223    eina_stringshare_del(ew->syspath);
224    eina_stringshare_del(ew->device);
225    eina_stringshare_del(ew->name);
226    free(ew);
227 }
228
229 static Emotion_Webcam *
230 _emotion_webcam_new(const char *syspath)
231 {
232    Emotion_Webcam *test;
233    const char *device;
234    char *local;
235
236    test = malloc(sizeof (Emotion_Webcam));
237    if (!test) return NULL;
238
239    test->custom = NULL;
240    test->syspath = eina_stringshare_ref(syspath);
241    test->name = eeze_udev_syspath_get_sysattr(syspath, "name");
242
243    device = eeze_udev_syspath_get_property(syspath, "DEVNAME");
244    local = alloca(eina_stringshare_strlen(device) + 8);
245    snprintf(local, eina_stringshare_strlen(device) + 8, "v4l2://%s", device);
246    test->device = eina_stringshare_add(local);
247    eina_stringshare_del(device);
248    test->filename = test->device + 7;
249
250    return test;
251 }
252
253 static void
254 _emotion_enumerate_all_webcams(void)
255 {
256    Eina_List *devices;
257    const char *syspath;
258
259    devices = eeze_udev_find_by_type(EEZE_UDEV_TYPE_V4L, NULL);
260
261    EINA_LIST_FREE(devices, syspath)
262      {
263         Emotion_Webcam *test;
264
265         test = _emotion_webcam_new(syspath);
266         if (test) _emotion_check_device(test);
267
268         eina_stringshare_del(syspath);
269      }
270 }
271
272 static void
273 _emotion_eeze_events(const char *syspath,
274                      Eeze_Udev_Event ev,
275                      void *data __UNUSED__,
276                      Eeze_Udev_Watch *watcher __UNUSED__)
277 {
278    if (ev == EEZE_UDEV_EVENT_REMOVE)
279      {
280         Emotion_Webcam *check;
281         Eina_List *l;
282
283         EINA_LIST_FOREACH(_emotion_webcams->webcams, l, check)
284           if (check->syspath == syspath)
285             {
286                _emotion_webcams->webcams = eina_list_remove_list(_emotion_webcams->webcams, l);
287                EINA_REFCOUNT_UNREF(check)
288                  emotion_webcam_destroy(check);
289                break ;
290             }
291      }
292    else if (ev == EEZE_UDEV_EVENT_ADD)
293      {
294         Emotion_Webcam *test;
295
296         test = _emotion_webcam_new(syspath);
297         if (test) _emotion_check_device(test);
298      }
299    ecore_event_add(EMOTION_WEBCAM_UPDATE, NULL, NULL, NULL);
300 }
301
302 #endif
303
304 EAPI Eina_Bool
305 emotion_init(void)
306 {
307    char buffer[4096];
308
309    if (_emotion_webcams_count++) return EINA_TRUE;
310
311    snprintf(buffer, 4096, "%s/emotion.cfg", PACKAGE_DATA_DIR);
312    _emotion_webcams_file = eet_open(buffer, EET_FILE_MODE_READ);
313    if (_emotion_webcams_file)
314      {
315         Eet_Data_Descriptor *edd;
316
317         edd = _emotion_webcams_data();
318
319         _emotion_webcams = eet_data_read(_emotion_webcams_file, edd, "config");
320
321         eet_data_descriptor_free(_webcams_edd); _webcams_edd = NULL;
322         eet_data_descriptor_free(_webcam_edd); _webcam_edd = NULL;
323      }
324
325    if (!_emotion_webcams)
326      {
327         _emotion_webcams = calloc(1, sizeof (Emotion_Webcams));
328         if (!_emotion_webcams) return EINA_FALSE;
329      }
330
331 #ifdef EMOTION_HAVE_EEZE
332    EMOTION_WEBCAM_UPDATE = ecore_event_type_new();
333
334    eeze_init();
335
336    _emotion_enumerate_all_webcams();
337
338    eeze_watcher = eeze_udev_watch_add(EEZE_UDEV_TYPE_V4L,
339                                       (EEZE_UDEV_EVENT_ADD | EEZE_UDEV_EVENT_REMOVE),
340                                       _emotion_eeze_events, NULL);
341 #endif
342
343    return EINA_TRUE;
344 }
345
346 EAPI Eina_Bool
347 emotion_shutdown(void)
348 {
349    Emotion_Webcam *ew;
350
351    if (--_emotion_webcams_count) return EINA_TRUE;
352
353    EINA_LIST_FREE(_emotion_webcams->webcams, ew)
354      {
355 #ifdef EMOTION_HAVE_EEZE
356         /* There is currently no way to refcount from the outside, this help, but could lead to some issue */
357         EINA_REFCOUNT_UNREF(ew)
358           emotion_webcam_destroy(ew);
359 #endif
360      }
361    free(_emotion_webcams);
362    _emotion_webcams = NULL;
363
364    if (_emotion_webcams_file)
365      {
366         /* As long as there is no one reference any pointer, you are safe */
367         eet_close(_emotion_webcams_file);
368         _emotion_webcams_file = NULL;
369      }
370
371 #ifdef EMOTION_HAVE_EEZE
372    eeze_udev_watch_del(eeze_watcher);
373    eeze_watcher = NULL;
374
375    eeze_shutdown();
376 #endif
377
378    return EINA_TRUE;
379 }
380
381 EAPI const Eina_List *
382 emotion_webcams_get(void)
383 {
384    return _emotion_webcams->webcams;
385 }
386
387 EAPI const char *
388 emotion_webcam_name_get(const Emotion_Webcam *ew)
389 {
390    if (!ew) return NULL;
391
392    return ew->name;
393 }
394
395 EAPI const char *
396 emotion_webcam_device_get(const Emotion_Webcam *ew)
397 {
398    if (!ew) return NULL;
399
400    return ew->device;
401 }
402
403 EAPI const char *
404 emotion_webcam_custom_get(const char *device)
405 {
406    const Emotion_Webcam *ew;
407    const Eina_List *l;
408
409    EINA_LIST_FOREACH(_emotion_webcams->webcams, l, ew)
410      if (ew->device && strcmp(device, ew->device) == 0)
411        return ew->custom;
412
413    return NULL;
414 }