1 /* GStreamer |
|
2 * |
|
3 * gstv4lelement.c: base class for V4L elements |
|
4 * |
|
5 * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net> |
|
6 * |
|
7 * This library is free software; you can redistribute it and/or |
|
8 * modify it under the terms of the GNU Library General Public |
|
9 * License as published by the Free Software Foundation; either |
|
10 * version 2 of the License, or (at your option) any later version. |
|
11 * |
|
12 * This library is distributed in the hope that it will be useful, |
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
15 * Library General Public License for more details. |
|
16 * |
|
17 * You should have received a copy of the GNU Library General Public |
|
18 * License along with this library; if not, write to the |
|
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
20 * Boston, MA 02111-1307, USA. |
|
21 */ |
|
22 |
|
23 #ifdef HAVE_CONFIG_H |
|
24 #include <config.h> |
|
25 #endif |
|
26 |
|
27 #include <sys/stat.h> |
|
28 #include <fcntl.h> |
|
29 #include <errno.h> |
|
30 #include <unistd.h> |
|
31 #include <string.h> |
|
32 |
|
33 #include <gst/interfaces/propertyprobe.h> |
|
34 |
|
35 #include "v4l_calls.h" |
|
36 #include "gstv4ltuner.h" |
|
37 #ifdef HAVE_XVIDEO |
|
38 #include "gstv4lxoverlay.h" |
|
39 #endif |
|
40 #include "gstv4lcolorbalance.h" |
|
41 |
|
42 |
|
43 enum |
|
44 { |
|
45 PROP_0, |
|
46 PROP_DEVICE, |
|
47 PROP_DEVICE_NAME, |
|
48 PROP_FLAGS |
|
49 }; |
|
50 |
|
51 |
|
52 static void gst_v4lelement_init_interfaces (GType type); |
|
53 |
|
54 GST_BOILERPLATE_FULL (GstV4lElement, gst_v4lelement, GstPushSrc, |
|
55 GST_TYPE_PUSH_SRC, gst_v4lelement_init_interfaces); |
|
56 |
|
57 |
|
58 static void gst_v4lelement_dispose (GObject * object); |
|
59 static void gst_v4lelement_set_property (GObject * object, |
|
60 guint prop_id, const GValue * value, GParamSpec * pspec); |
|
61 static void gst_v4lelement_get_property (GObject * object, |
|
62 guint prop_id, GValue * value, GParamSpec * pspec); |
|
63 static gboolean gst_v4lelement_start (GstBaseSrc * src); |
|
64 static gboolean gst_v4lelement_stop (GstBaseSrc * src); |
|
65 |
|
66 |
|
67 static gboolean |
|
68 gst_v4l_iface_supported (GstImplementsInterface * iface, GType iface_type) |
|
69 { |
|
70 GstV4lElement *v4lelement = GST_V4LELEMENT (iface); |
|
71 |
|
72 #ifdef HAVE_XVIDEO |
|
73 g_assert (iface_type == GST_TYPE_TUNER || |
|
74 iface_type == GST_TYPE_X_OVERLAY || iface_type == GST_TYPE_COLOR_BALANCE); |
|
75 #else |
|
76 g_assert (iface_type == GST_TYPE_TUNER || |
|
77 iface_type == GST_TYPE_COLOR_BALANCE); |
|
78 #endif |
|
79 |
|
80 if (v4lelement->video_fd == -1) |
|
81 return FALSE; |
|
82 |
|
83 #ifdef HAVE_XVIDEO |
|
84 if (iface_type == GST_TYPE_X_OVERLAY && !GST_V4L_IS_OVERLAY (v4lelement)) |
|
85 return FALSE; |
|
86 #endif |
|
87 |
|
88 return TRUE; |
|
89 } |
|
90 |
|
91 static void |
|
92 gst_v4l_interface_init (GstImplementsInterfaceClass * klass) |
|
93 { |
|
94 /* default virtual functions */ |
|
95 klass->supported = gst_v4l_iface_supported; |
|
96 } |
|
97 |
|
98 static const GList * |
|
99 gst_v4l_probe_get_properties (GstPropertyProbe * probe) |
|
100 { |
|
101 GObjectClass *klass = G_OBJECT_GET_CLASS (probe); |
|
102 static GList *list = NULL; |
|
103 |
|
104 if (!list) { |
|
105 list = g_list_append (NULL, g_object_class_find_property (klass, "device")); |
|
106 } |
|
107 |
|
108 return list; |
|
109 } |
|
110 |
|
111 static gboolean |
|
112 gst_v4l_class_probe_devices (GstV4lElementClass * klass, gboolean check) |
|
113 { |
|
114 static gboolean init = FALSE; |
|
115 static GList *devices = NULL; |
|
116 |
|
117 if (!init && !check) { |
|
118 gchar *dev_base[] = { "/dev/video", "/dev/v4l/video", NULL }; |
|
119 gint base, n, fd; |
|
120 |
|
121 while (devices) { |
|
122 GList *item = devices; |
|
123 gchar *device = item->data; |
|
124 |
|
125 devices = g_list_remove (devices, item); |
|
126 g_free (device); |
|
127 } |
|
128 |
|
129 /* detect /dev entries */ |
|
130 for (n = 0; n < 64; n++) { |
|
131 for (base = 0; dev_base[base] != NULL; base++) { |
|
132 struct stat s; |
|
133 gchar *device = g_strdup_printf ("%s%d", dev_base[base], n); |
|
134 |
|
135 /* does the /dev/ entry exist at all? */ |
|
136 if (stat (device, &s) == 0) { |
|
137 /* yes: is a device attached? */ |
|
138 if ((fd = open (device, O_RDONLY)) > 0 || errno == EBUSY) { |
|
139 if (fd > 0) |
|
140 close (fd); |
|
141 |
|
142 devices = g_list_append (devices, device); |
|
143 break; |
|
144 } |
|
145 } |
|
146 g_free (device); |
|
147 } |
|
148 } |
|
149 |
|
150 init = TRUE; |
|
151 } |
|
152 |
|
153 klass->devices = devices; |
|
154 |
|
155 return init; |
|
156 } |
|
157 |
|
158 static void |
|
159 gst_v4l_probe_probe_property (GstPropertyProbe * probe, |
|
160 guint prop_id, const GParamSpec * pspec) |
|
161 { |
|
162 GstV4lElementClass *klass = GST_V4LELEMENT_GET_CLASS (probe); |
|
163 |
|
164 switch (prop_id) { |
|
165 case PROP_DEVICE: |
|
166 gst_v4l_class_probe_devices (klass, FALSE); |
|
167 break; |
|
168 default: |
|
169 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); |
|
170 break; |
|
171 } |
|
172 } |
|
173 |
|
174 static gboolean |
|
175 gst_v4l_probe_needs_probe (GstPropertyProbe * probe, |
|
176 guint prop_id, const GParamSpec * pspec) |
|
177 { |
|
178 GstV4lElementClass *klass = GST_V4LELEMENT_GET_CLASS (probe); |
|
179 gboolean ret = FALSE; |
|
180 |
|
181 switch (prop_id) { |
|
182 case PROP_DEVICE: |
|
183 ret = !gst_v4l_class_probe_devices (klass, TRUE); |
|
184 break; |
|
185 default: |
|
186 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); |
|
187 break; |
|
188 } |
|
189 |
|
190 return ret; |
|
191 } |
|
192 |
|
193 static GValueArray * |
|
194 gst_v4l_class_list_devices (GstV4lElementClass * klass) |
|
195 { |
|
196 GValueArray *array; |
|
197 GValue value = { 0 }; |
|
198 GList *item; |
|
199 |
|
200 if (!klass->devices) |
|
201 return NULL; |
|
202 |
|
203 array = g_value_array_new (g_list_length (klass->devices)); |
|
204 item = klass->devices; |
|
205 g_value_init (&value, G_TYPE_STRING); |
|
206 while (item) { |
|
207 gchar *device = item->data; |
|
208 |
|
209 g_value_set_string (&value, device); |
|
210 g_value_array_append (array, &value); |
|
211 |
|
212 item = item->next; |
|
213 } |
|
214 g_value_unset (&value); |
|
215 |
|
216 return array; |
|
217 } |
|
218 |
|
219 static GValueArray * |
|
220 gst_v4l_probe_get_values (GstPropertyProbe * probe, |
|
221 guint prop_id, const GParamSpec * pspec) |
|
222 { |
|
223 GstV4lElementClass *klass = GST_V4LELEMENT_GET_CLASS (probe); |
|
224 GValueArray *array = NULL; |
|
225 |
|
226 switch (prop_id) { |
|
227 case PROP_DEVICE: |
|
228 array = gst_v4l_class_list_devices (klass); |
|
229 break; |
|
230 default: |
|
231 G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); |
|
232 break; |
|
233 } |
|
234 |
|
235 return array; |
|
236 } |
|
237 |
|
238 static void |
|
239 gst_v4l_property_probe_interface_init (GstPropertyProbeInterface * iface) |
|
240 { |
|
241 iface->get_properties = gst_v4l_probe_get_properties; |
|
242 iface->probe_property = gst_v4l_probe_probe_property; |
|
243 iface->needs_probe = gst_v4l_probe_needs_probe; |
|
244 iface->get_values = gst_v4l_probe_get_values; |
|
245 } |
|
246 |
|
247 #define GST_TYPE_V4L_DEVICE_FLAGS (gst_v4l_device_get_type ()) |
|
248 static GType |
|
249 gst_v4l_device_get_type (void) |
|
250 { |
|
251 static GType v4l_device_type = 0; |
|
252 |
|
253 if (v4l_device_type == 0) { |
|
254 static const GFlagsValue values[] = { |
|
255 {VID_TYPE_CAPTURE, "CAPTURE", "Device can capture"}, |
|
256 {VID_TYPE_TUNER, "TUNER", "Device has a tuner"}, |
|
257 {VID_TYPE_OVERLAY, "OVERLAY", "Device can do overlay"}, |
|
258 {VID_TYPE_MPEG_DECODER, "MPEG_DECODER", "Device can decode MPEG"}, |
|
259 {VID_TYPE_MPEG_ENCODER, "MPEG_ENCODER", "Device can encode MPEG"}, |
|
260 {VID_TYPE_MJPEG_DECODER, "MJPEG_DECODER", "Device can decode MJPEG"}, |
|
261 {VID_TYPE_MJPEG_ENCODER, "MJPEG_ENCODER", "Device can encode MJPEG"}, |
|
262 {0x10000, "AUDIO", "Device handles audio"}, |
|
263 {0, NULL, NULL} |
|
264 }; |
|
265 |
|
266 v4l_device_type = g_flags_register_static ("GstV4lDeviceTypeFlags", values); |
|
267 } |
|
268 |
|
269 return v4l_device_type; |
|
270 } |
|
271 |
|
272 static void |
|
273 gst_v4lelement_init_interfaces (GType type) |
|
274 { |
|
275 static const GInterfaceInfo v4liface_info = { |
|
276 (GInterfaceInitFunc) gst_v4l_interface_init, |
|
277 NULL, |
|
278 NULL, |
|
279 }; |
|
280 static const GInterfaceInfo v4l_tuner_info = { |
|
281 (GInterfaceInitFunc) gst_v4l_tuner_interface_init, |
|
282 NULL, |
|
283 NULL, |
|
284 }; |
|
285 #ifdef HAVE_XVIDEO |
|
286 static const GInterfaceInfo v4l_xoverlay_info = { |
|
287 (GInterfaceInitFunc) gst_v4l_xoverlay_interface_init, |
|
288 NULL, |
|
289 NULL, |
|
290 }; |
|
291 #endif |
|
292 static const GInterfaceInfo v4l_colorbalance_info = { |
|
293 (GInterfaceInitFunc) gst_v4l_color_balance_interface_init, |
|
294 NULL, |
|
295 NULL, |
|
296 }; |
|
297 static const GInterfaceInfo v4l_propertyprobe_info = { |
|
298 (GInterfaceInitFunc) gst_v4l_property_probe_interface_init, |
|
299 NULL, |
|
300 NULL, |
|
301 }; |
|
302 |
|
303 g_type_add_interface_static (type, |
|
304 GST_TYPE_IMPLEMENTS_INTERFACE, &v4liface_info); |
|
305 g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l_tuner_info); |
|
306 #ifdef HAVE_XVIDEO |
|
307 g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l_xoverlay_info); |
|
308 #endif |
|
309 g_type_add_interface_static (type, |
|
310 GST_TYPE_COLOR_BALANCE, &v4l_colorbalance_info); |
|
311 g_type_add_interface_static (type, |
|
312 GST_TYPE_PROPERTY_PROBE, &v4l_propertyprobe_info); |
|
313 } |
|
314 |
|
315 |
|
316 static void |
|
317 gst_v4lelement_base_init (gpointer g_class) |
|
318 { |
|
319 GstV4lElementClass *klass = GST_V4LELEMENT_CLASS (g_class); |
|
320 |
|
321 klass->devices = NULL; |
|
322 } |
|
323 |
|
324 static void |
|
325 gst_v4lelement_class_init (GstV4lElementClass * klass) |
|
326 { |
|
327 GObjectClass *gobject_class; |
|
328 GstBaseSrcClass *basesrc_class; |
|
329 |
|
330 gobject_class = (GObjectClass *) klass; |
|
331 basesrc_class = (GstBaseSrcClass *) klass; |
|
332 |
|
333 gobject_class->set_property = gst_v4lelement_set_property; |
|
334 gobject_class->get_property = gst_v4lelement_get_property; |
|
335 |
|
336 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE, |
|
337 g_param_spec_string ("device", "Device", "Device location", |
|
338 NULL, G_PARAM_READWRITE)); |
|
339 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEVICE_NAME, |
|
340 g_param_spec_string ("device_name", "Device name", "Name of the device", |
|
341 NULL, G_PARAM_READABLE)); |
|
342 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FLAGS, |
|
343 g_param_spec_flags ("flags", "Flags", "Device type flags", |
|
344 GST_TYPE_V4L_DEVICE_FLAGS, 0, G_PARAM_READABLE)); |
|
345 |
|
346 basesrc_class->start = gst_v4lelement_start; |
|
347 basesrc_class->stop = gst_v4lelement_stop; |
|
348 |
|
349 gobject_class->dispose = gst_v4lelement_dispose; |
|
350 } |
|
351 |
|
352 |
|
353 static void |
|
354 gst_v4lelement_init (GstV4lElement * v4lelement, GstV4lElementClass * klass) |
|
355 { |
|
356 /* some default values */ |
|
357 v4lelement->video_fd = -1; |
|
358 v4lelement->buffer = NULL; |
|
359 v4lelement->videodev = g_strdup ("/dev/video0"); |
|
360 |
|
361 v4lelement->norms = NULL; |
|
362 v4lelement->channels = NULL; |
|
363 v4lelement->colors = NULL; |
|
364 |
|
365 v4lelement->xwindow_id = 0; |
|
366 } |
|
367 |
|
368 |
|
369 static void |
|
370 gst_v4lelement_dispose (GObject * object) |
|
371 { |
|
372 GstV4lElement *v4lelement = GST_V4LELEMENT (object); |
|
373 |
|
374 if (v4lelement->videodev) { |
|
375 g_free (v4lelement->videodev); |
|
376 v4lelement->videodev = NULL; |
|
377 } |
|
378 |
|
379 if (((GObjectClass *) parent_class)->dispose) |
|
380 ((GObjectClass *) parent_class)->dispose (object); |
|
381 } |
|
382 |
|
383 |
|
384 static void |
|
385 gst_v4lelement_set_property (GObject * object, |
|
386 guint prop_id, const GValue * value, GParamSpec * pspec) |
|
387 { |
|
388 GstV4lElement *v4lelement = GST_V4LELEMENT (object); |
|
389 |
|
390 switch (prop_id) { |
|
391 case PROP_DEVICE: |
|
392 if (v4lelement->videodev) |
|
393 g_free (v4lelement->videodev); |
|
394 v4lelement->videodev = g_strdup (g_value_get_string (value)); |
|
395 break; |
|
396 default: |
|
397 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
398 break; |
|
399 } |
|
400 } |
|
401 |
|
402 |
|
403 static void |
|
404 gst_v4lelement_get_property (GObject * object, |
|
405 guint prop_id, GValue * value, GParamSpec * pspec) |
|
406 { |
|
407 GstV4lElement *v4lelement = GST_V4LELEMENT (object); |
|
408 |
|
409 switch (prop_id) { |
|
410 case PROP_DEVICE: |
|
411 g_value_set_string (value, v4lelement->videodev); |
|
412 break; |
|
413 case PROP_DEVICE_NAME:{ |
|
414 gchar *new = NULL; |
|
415 |
|
416 if (GST_V4L_IS_OPEN (v4lelement)) { |
|
417 new = v4lelement->vcap.name; |
|
418 } else if (gst_v4l_open (v4lelement)) { |
|
419 new = v4lelement->vcap.name; |
|
420 gst_v4l_close (v4lelement); |
|
421 } |
|
422 g_value_set_string (value, new); |
|
423 break; |
|
424 } |
|
425 case PROP_FLAGS:{ |
|
426 guint flags = 0; |
|
427 |
|
428 if (GST_V4L_IS_OPEN (v4lelement)) { |
|
429 flags |= v4lelement->vcap.type & 0x3C0B; |
|
430 if (v4lelement->vcap.audios) |
|
431 flags |= 0x10000; |
|
432 } |
|
433 g_value_set_flags (value, flags); |
|
434 break; |
|
435 } |
|
436 default: |
|
437 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
|
438 break; |
|
439 } |
|
440 } |
|
441 |
|
442 static gboolean |
|
443 gst_v4lelement_start (GstBaseSrc * src) |
|
444 { |
|
445 GstV4lElement *v4lelement = GST_V4LELEMENT (src); |
|
446 |
|
447 if (!gst_v4l_open (v4lelement)) |
|
448 return FALSE; |
|
449 |
|
450 #ifdef HAVE_XVIDEO |
|
451 gst_v4l_xoverlay_start (v4lelement); |
|
452 #endif |
|
453 |
|
454 return TRUE; |
|
455 } |
|
456 |
|
457 static gboolean |
|
458 gst_v4lelement_stop (GstBaseSrc * src) |
|
459 { |
|
460 GstV4lElement *v4lelement = GST_V4LELEMENT (src); |
|
461 |
|
462 #ifdef HAVE_XVIDEO |
|
463 gst_v4l_xoverlay_stop (v4lelement); |
|
464 #endif |
|
465 |
|
466 if (!gst_v4l_close (v4lelement)) |
|
467 return FALSE; |
|
468 |
|
469 return TRUE; |
|
470 } |
|