emotion: add v4l2:// uri scheme for webcam.
[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 # include <linux/videodev2.h>
10
11 # include <Ecore.h>
12 # include <Eeze.h>
13 #endif
14
15 EAPI int EMOTION_WEBCAM_UPDATE = 0;
16
17 struct ext_match_s
18 {
19    unsigned int length;
20    const char *extension;
21 };
22
23 #define MATCHING(Ext)                           \
24   { sizeof (Ext), Ext }
25
26 static const struct ext_match_s matchs[] =
27 { /* map extensions to know if it's a emotion playable content for good first-guess tries */
28    MATCHING(".264"),
29    MATCHING(".3g2"),
30    MATCHING(".3gp"),
31    MATCHING(".3gp2"),
32    MATCHING(".3gpp"),
33    MATCHING(".3gpp2"),
34    MATCHING(".3p2"),
35    MATCHING(".asf"),
36    MATCHING(".avi"),
37    MATCHING(".bdm"),
38    MATCHING(".bdmv"),
39    MATCHING(".clpi"),
40    MATCHING(".clp"),
41    MATCHING(".fla"),
42    MATCHING(".flv"),
43    MATCHING(".m1v"),
44    MATCHING(".m2v"),
45    MATCHING(".m2t"),
46    MATCHING(".m4v"),
47    MATCHING(".mkv"),
48    MATCHING(".mov"),
49    MATCHING(".mp2"),
50    MATCHING(".mp2ts"),
51    MATCHING(".mp4"),
52    MATCHING(".mpe"),
53    MATCHING(".mpeg"),
54    MATCHING(".mpg"),
55    MATCHING(".mpl"),
56    MATCHING(".mpls"),
57    MATCHING(".mts"),
58    MATCHING(".mxf"),
59    MATCHING(".nut"),
60    MATCHING(".nuv"),
61    MATCHING(".ogg"),
62    MATCHING(".ogm"),
63    MATCHING(".ogv"),
64    MATCHING(".rm"),
65    MATCHING(".rmj"),
66    MATCHING(".rmm"),
67    MATCHING(".rms"),
68    MATCHING(".rmx"),
69    MATCHING(".rmvb"),
70    MATCHING(".swf"),
71    MATCHING(".ts"),
72    MATCHING(".weba"),
73    MATCHING(".webm"),
74    MATCHING(".wmv")
75 };
76
77 Eina_Bool
78 _emotion_object_extension_can_play_generic_get(const void *data __UNUSED__, const char *file)
79 {
80    unsigned int length;
81    unsigned int i;
82
83    length = eina_stringshare_strlen(file) + 1;
84    if (length < 5) return EINA_FALSE;
85
86    for (i = 0; i < sizeof (matchs) / sizeof (struct ext_match_s); ++i)
87      {
88         if (matchs[i].length > length) continue;
89
90         if (!strcasecmp(matchs[i].extension,
91                         file + length - matchs[i].length))
92           return EINA_TRUE;
93      }
94
95    return EINA_FALSE;
96 }
97
98 EAPI Eina_Bool
99 emotion_object_extension_may_play_fast_get(const char *file)
100 {
101    if (!file) return EINA_FALSE;
102    return _emotion_object_extension_can_play_generic_get(NULL, file);
103 }
104
105 EAPI Eina_Bool
106 emotion_object_extension_may_play_get(const char *file)
107 {
108    const char *tmp;
109    Eina_Bool result;
110
111    if (!file) return EINA_FALSE;
112    tmp = eina_stringshare_add(file);
113    result = emotion_object_extension_may_play_fast_get(tmp);
114    eina_stringshare_del(tmp);
115
116    return result;
117 }
118
119 #ifdef EMOTION_HAVE_EEZE
120 struct _Emotion_Webcam
121 {
122    EINA_REFCOUNT;
123
124    const char *syspath;
125    const char *device;
126    const char *name;
127 };
128
129 static int _emotion_webcams_count = 0;
130 static Eina_List *_emotion_webcams = NULL;
131 static Eeze_Udev_Watch *eeze_watcher = NULL;
132
133 static void
134 emotion_webcam_destroy(Emotion_Webcam *ew)
135 {
136    eina_stringshare_del(ew->syspath);
137    eina_stringshare_del(ew->device);
138    eina_stringshare_del(ew->name);
139    free(ew);
140 }
141
142 static void
143 _emotion_check_device(Emotion_Webcam *ew)
144 {
145    Emotion_Webcam *check;
146    Eina_List *l;
147    struct v4l2_capability caps;
148    int fd;
149
150    if (!ew) return ;
151    if (!ew->device) goto on_error;
152
153    fd = open(ew->device, O_RDONLY);
154    if (!fd) goto on_error;
155
156    if (ioctl(fd, VIDIOC_QUERYCAP, &caps) == -1) goto on_error;
157
158    /* Likely not a webcam */
159    if (!caps.capabilities & V4L2_CAP_VIDEO_CAPTURE) goto on_error;
160    if (caps.capabilities & V4L2_CAP_TUNER
161        || caps.capabilities & V4L2_CAP_RADIO
162        || caps.capabilities & V4L2_CAP_MODULATOR)
163      goto on_error;
164
165    EINA_LIST_FOREACH(_emotion_webcams, l, check)
166      if (check->device == ew->device)
167        goto on_error;
168
169    _emotion_webcams = eina_list_append(_emotion_webcams, ew);
170
171    EINA_REFCOUNT_INIT(ew);
172
173    return ;
174
175  on_error:
176    fprintf(stderr, "'%s' is not a webcam\n", ew->name);
177    eina_stringshare_del(ew->syspath);
178    eina_stringshare_del(ew->device);
179    eina_stringshare_del(ew->name);
180    free(ew);
181 }
182
183 static Emotion_Webcam *
184 _emotion_webcam_new(const char *syspath)
185 {
186    Emotion_Webcam *test;
187    const char *device;
188    char *local;
189
190    test = malloc(sizeof (Emotion_Webcam));
191    if (!test) return NULL;
192
193    test->syspath = eina_stringshare_ref(syspath);
194    test->name = eeze_udev_syspath_get_sysattr(syspath, "name");
195
196    device = eeze_udev_syspath_get_property(syspath, "DEVNAME");
197    local = alloca(eina_stringshare_strlen(device) + 8);
198    snprintf(local, eina_stringshare_strlen(device) + 8, "v4l2://%s", device);
199    test->device = eina_stringshare_add(local);
200    eina_stringshare_del(device);
201
202    return test;
203 }
204
205 static void
206 _emotion_enumerate_all_webcams(void)
207 {
208    Eina_List *devices;
209    const char *syspath;
210
211    devices = eeze_udev_find_by_type(EEZE_UDEV_TYPE_V4L, NULL);
212
213    EINA_LIST_FREE(devices, syspath)
214      {
215         Emotion_Webcam *test;
216
217         test = _emotion_webcam_new(syspath);
218         if (test) _emotion_check_device(test);
219
220         eina_stringshare_del(syspath);
221      }
222 }
223
224 static void
225 _emotion_eeze_events(const char *syspath,
226                      Eeze_Udev_Event ev,
227                      void *data,
228                      Eeze_Udev_Watch *watcher)
229 {
230    if (ev == EEZE_UDEV_EVENT_REMOVE)
231      {
232         Emotion_Webcam *check;
233         Eina_List *l;
234
235         EINA_LIST_FOREACH(_emotion_webcams, l, check)
236           if (check->syspath == syspath)
237             {
238                _emotion_webcams = eina_list_remove_list(_emotion_webcams, l);
239                EINA_REFCOUNT_UNREF(check)
240                  emotion_webcam_destroy(check);
241                break ;
242             }
243      }
244    else if (ev == EEZE_UDEV_EVENT_ADD)
245      {
246         Emotion_Webcam *test;
247
248         test = _emotion_webcam_new(syspath);
249         if (test) _emotion_check_device(test);
250      }
251    ecore_event_add(EMOTION_WEBCAM_UPDATE, NULL, NULL, NULL);
252 }
253
254 #endif
255
256 EAPI Eina_Bool
257 emotion_init(void)
258 {
259 #ifdef EMOTION_HAVE_EEZE
260    if (_emotion_webcams_count++) return EINA_TRUE;
261
262    EMOTION_WEBCAM_UPDATE = ecore_event_type_new();
263
264    eeze_init();
265
266    _emotion_enumerate_all_webcams();
267
268    eeze_watcher = eeze_udev_watch_add(EEZE_UDEV_TYPE_V4L,
269                                       (EEZE_UDEV_EVENT_ADD | EEZE_UDEV_EVENT_REMOVE),
270                                       _emotion_eeze_events, NULL);
271
272    return EINA_TRUE;
273 #else
274    return EINA_FALSE;
275 #endif
276 }
277
278 EAPI Eina_Bool
279 emotion_shutdown(void)
280 {
281 #ifdef EMOTION_HAVE_EEZE
282    if (--_emotion_webcams_count) return EINA_TRUE;
283
284    eeze_udev_watch_del(eeze_watcher);
285    eeze_watcher = NULL;
286
287    eeze_shutdown();
288
289    return EINA_TRUE;
290 #else
291    return EINA_FALSE;
292 #endif
293 }
294
295 EAPI const Eina_List *
296 emotion_webcams_get(void)
297 {
298 #ifdef EMOTION_HAVE_EEZE
299    return _emotion_webcams;
300 #else
301    return NULL;
302 #endif
303 }
304
305 EAPI const char *
306 emotion_webcam_name_get(Emotion_Webcam *ew)
307 {
308    if (!ew) return NULL;
309
310 #ifdef EMOTION_HAVE_EEZE
311    return ew->name;
312 #else
313    return NULL;
314 #endif
315 }
316
317 EAPI const char *
318 emotion_webcam_device_get(Emotion_Webcam *ew)
319 {
320    if (!ew) return NULL;
321
322 #ifdef EMOTION_HAVE_EEZE
323    return ew->device;
324 #else
325    return NULL;
326 #endif
327 }