Small updates to avimux and the v4l plugins for usability in general
[platform/upstream/gstreamer.git] / sys / v4l / gstv4lelement.c
1 /* G-Streamer generic V4L element - generic V4L calls handling
2  * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "v4l_calls.h"
21
22 static GstElementDetails gst_v4lelement_details = {
23   "Generic video4linux Element",
24   "None/Video",
25   "Generic plugin for handling common video4linux calls",
26   VERSION,
27   "Ronald Bultje <rbultje@ronald.bitfreak.net>",
28   "(C) 2001",
29 };
30
31 /* V4lElement signals and args */
32 enum {
33   /* FILL ME */
34   LAST_SIGNAL
35 };
36
37 enum {
38   ARG_0,
39   ARG_CHANNEL,
40   ARG_CHANNEL_NAMES,
41   ARG_NORM,
42   ARG_NORM_NAMES,
43   ARG_HAS_TUNER,
44   ARG_FREQUENCY,
45   ARG_HAS_AUDIO,
46   ARG_MUTE,
47   ARG_MODE,
48   ARG_VOLUME,
49   ARG_HUE,
50   ARG_BRIGHTNESS,
51   ARG_CONTRAST,
52   ARG_SATURATION,
53   ARG_DEVICE,
54   ARG_DEVICE_NAME,
55   ARG_DEVICE_IS_CAPTURE,
56   ARG_DEVICE_IS_OVERLAY,
57   ARG_DEVICE_IS_MJPEG_CAPTURE,
58   ARG_DEVICE_IS_MJPEG_PLAYBACK,
59   ARG_DEVICE_IS_MPEG_CAPTURE,
60   ARG_DEVICE_IS_MPEG_PLAYBACK
61 };
62
63
64 static void                  gst_v4lelement_class_init   (GstV4lElementClass *klass);
65 static void                  gst_v4lelement_init         (GstV4lElement      *v4lelement);
66 static void                  gst_v4lelement_set_property (GObject            *object,
67                                                           guint              prop_id,
68                                                           const GValue       *value,
69                                                           GParamSpec         *pspec);
70 static void                  gst_v4lelement_get_property (GObject            *object,
71                                                           guint              prop_id,
72                                                           GValue             *value,
73                                                           GParamSpec         *pspec);
74 static GstElementStateReturn gst_v4lelement_change_state (GstElement         *element);
75 static gboolean              plugin_init                 (GModule            *module,
76                                                           GstPlugin          *plugin);
77
78
79 static GstElementClass *parent_class = NULL;
80 //static guint gst_v4lelement_signals[LAST_SIGNAL] = { 0 };
81
82
83 GType
84 gst_v4lelement_get_type (void)
85 {
86   static GType v4lelement_type = 0;
87
88   if (!v4lelement_type) {
89     static const GTypeInfo v4lelement_info = {
90       sizeof(GstV4lElementClass),
91       NULL,
92       NULL,
93       (GClassInitFunc)gst_v4lelement_class_init,
94       NULL,
95       NULL,
96       sizeof(GstV4lElement),
97       0,
98       (GInstanceInitFunc)gst_v4lelement_init,
99       NULL
100     };
101     v4lelement_type = g_type_register_static(GST_TYPE_ELEMENT, "GstV4lElement", &v4lelement_info, 0);
102   }
103   return v4lelement_type;
104 }
105
106
107
108 static void
109 gst_v4lelement_class_init (GstV4lElementClass *klass)
110 {
111   GObjectClass *gobject_class;
112   GstElementClass *gstelement_class;
113
114   gobject_class = (GObjectClass*)klass;
115   gstelement_class = (GstElementClass*)klass;
116
117   parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
118
119   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNEL,
120     g_param_spec_int("channel","channel","channel",
121     G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
122   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNEL_NAMES,
123     g_param_spec_pointer("channel_names","channel_names","channel_names",
124     G_PARAM_READABLE));
125   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM,
126     g_param_spec_int("norm","norm","norm",
127     G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
128   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM_NAMES,
129     g_param_spec_pointer("norm_names","norm_names","norm_names",
130     G_PARAM_READABLE));
131
132   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_TUNER,
133     g_param_spec_boolean("has_tuner","has_tuner","has_tuner",
134     0,G_PARAM_READABLE));
135   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQUENCY,
136     g_param_spec_ulong("frequency","frequency","frequency",
137     0,G_MAXULONG,0,G_PARAM_READWRITE));
138
139   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_AUDIO,
140     g_param_spec_boolean("has_audio","has_audio","has_audio",
141     0,G_PARAM_READABLE));
142   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUTE,
143     g_param_spec_boolean("mute","mute","mute",
144     0,G_PARAM_READWRITE));
145   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VOLUME,
146     g_param_spec_int("volume","volume","volume",
147     G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
148   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MODE,
149     g_param_spec_int("mode","mode","mode",
150     G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
151
152   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HUE,
153     g_param_spec_int("hue","hue","hue",
154     G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
155   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BRIGHTNESS,
156     g_param_spec_int("brightness","brightness","brightness",
157     G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
158   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CONTRAST,
159     g_param_spec_int("contrast","contrast","contrast",
160     G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
161   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SATURATION,
162     g_param_spec_int("saturation","saturation","saturation",
163     G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
164
165   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
166     g_param_spec_string("device","device","device",
167     NULL, G_PARAM_READWRITE));
168   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_NAME,
169     g_param_spec_string("device_name","device_name","device_name",
170     NULL, G_PARAM_READABLE));
171
172   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_IS_CAPTURE,
173     g_param_spec_boolean("can_capture","can_capture","can_capture",
174     0,G_PARAM_READABLE));
175   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_IS_OVERLAY,
176     g_param_spec_boolean("has_overlay","has_overlay","has_overlay",
177     0,G_PARAM_READABLE));
178
179   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_IS_MJPEG_CAPTURE,
180     g_param_spec_boolean("can_capture_mjpeg","can_capture_mjpeg","can_capture_mjpeg",
181     0,G_PARAM_READABLE));
182   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_IS_MJPEG_PLAYBACK,
183     g_param_spec_boolean("can_playback_mjpeg","can_playback_mjpeg","can_playback_mjpeg",
184     0,G_PARAM_READABLE));
185
186   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_IS_MPEG_CAPTURE,
187     g_param_spec_boolean("can_capture_mpeg","can_capture_mpeg","can_capture_mpeg",
188     0,G_PARAM_READABLE));
189   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE_IS_MPEG_PLAYBACK,
190     g_param_spec_boolean("can_playback_mpeg","can_playback_mpeg","can_playback_mpeg",
191     0,G_PARAM_READABLE));
192
193   gobject_class->set_property = gst_v4lelement_set_property;
194   gobject_class->get_property = gst_v4lelement_get_property;
195
196   gstelement_class->change_state = gst_v4lelement_change_state;
197 }
198
199
200 static void
201 gst_v4lelement_init (GstV4lElement *v4lelement)
202 {
203   /* some default values */
204   v4lelement->video_fd = -1;
205   v4lelement->buffer = NULL;
206   v4lelement->videodev = NULL;
207
208   v4lelement->norm = -1;
209   v4lelement->channel = -1; /* the first channel */
210
211   v4lelement->frequency = 0;
212
213   v4lelement->mute = FALSE;
214   v4lelement->volume = -1;
215   v4lelement->mode = -1;
216
217   v4lelement->brightness = -1;
218   v4lelement->hue = -1;
219   v4lelement->contrast = -1;
220   v4lelement->saturation = -1;
221 }
222
223
224 static void
225 gst_v4lelement_set_property (GObject      *object,
226                              guint        prop_id,
227                              const GValue *value,
228                              GParamSpec   *pspec)
229 {
230   GstV4lElement *v4lelement;
231
232   /* it's not null if we got it, but it might not be ours */
233   g_return_if_fail(GST_IS_V4LELEMENT(object));
234   v4lelement = GST_V4LELEMENT(object);
235
236   switch (prop_id)
237   {
238     case ARG_CHANNEL:
239       v4lelement->channel = g_value_get_int(value);
240       if (GST_V4L_IS_OPEN(v4lelement) && !GST_V4L_IS_ACTIVE(v4lelement))
241       {
242         if (v4lelement->norm >= VIDEO_MODE_PAL &&
243             v4lelement->norm < VIDEO_MODE_AUTO &&
244             v4lelement->channel >= 0)
245           if (!gst_v4l_set_chan_norm(v4lelement, v4lelement->channel, v4lelement->norm))
246             return;
247       }
248       break;
249     case ARG_NORM:
250       v4lelement->norm = g_value_get_int(value);
251       if (GST_V4L_IS_OPEN(v4lelement) && !GST_V4L_IS_ACTIVE(v4lelement))
252       {
253         if (v4lelement->norm >= VIDEO_MODE_PAL &&
254             v4lelement->norm < VIDEO_MODE_AUTO &&
255             v4lelement->channel >= 0)
256           if (!gst_v4l_set_chan_norm(v4lelement, v4lelement->channel, v4lelement->norm))
257             return;
258       }
259       break;
260     case ARG_FREQUENCY:
261       v4lelement->frequency = g_value_get_ulong(value);
262       if (GST_V4L_IS_OPEN(v4lelement) && !GST_V4L_IS_ACTIVE(v4lelement))
263       {
264         if (gst_v4l_has_tuner(v4lelement))
265           if (!gst_v4l_set_frequency(v4lelement, v4lelement->frequency))
266             return;
267       }
268       break;
269     case ARG_MUTE:
270       v4lelement->mute = g_value_get_boolean(value);
271       if (GST_V4L_IS_OPEN(v4lelement))
272       {
273         if (gst_v4l_has_audio(v4lelement))
274           if (!gst_v4l_set_audio(v4lelement, V4L_AUDIO_MUTE, v4lelement->mute))
275             return;
276       }
277       break;
278     case ARG_MODE:
279       v4lelement->mode = g_value_get_int(value);
280       if (GST_V4L_IS_OPEN(v4lelement))
281       {
282         if (!gst_v4l_set_audio(v4lelement, V4L_AUDIO_MODE, v4lelement->mute))
283           return;
284       }
285       break;
286     case ARG_VOLUME:
287       v4lelement->volume = g_value_get_int(value);
288       if (GST_V4L_IS_OPEN(v4lelement))
289       {
290         if (!gst_v4l_set_audio(v4lelement, V4L_AUDIO_VOLUME, v4lelement->volume))
291           return;
292       }
293       break;
294     case ARG_HUE:
295       v4lelement->hue = g_value_get_int(value);
296       if (GST_V4L_IS_OPEN(v4lelement))
297       {
298         if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_HUE, v4lelement->hue))
299           return;
300       }
301       break;
302     case ARG_BRIGHTNESS:
303       v4lelement->brightness = g_value_get_int(value);
304       if (GST_V4L_IS_OPEN(v4lelement))
305       {
306         if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_BRIGHTNESS, v4lelement->brightness))
307           return;
308       }
309       break;
310     case ARG_CONTRAST:
311       v4lelement->contrast = g_value_get_int(value);
312       if (GST_V4L_IS_OPEN(v4lelement))
313       {
314         if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_CONTRAST, v4lelement->contrast))
315           return;
316       }
317       break;
318     case ARG_SATURATION:
319       v4lelement->saturation = g_value_get_int(value);
320       if (GST_V4L_IS_OPEN(v4lelement))
321       {
322         if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_SATURATION, v4lelement->saturation))
323           return;
324       }
325       break;
326     case ARG_DEVICE:
327       if (GST_V4L_IS_OPEN(v4lelement))
328         break; /* only set when *not* open */
329       if (v4lelement->videodev)
330         g_free(v4lelement->videodev);
331       v4lelement->videodev = g_strdup(g_value_get_string(value));
332       break;
333     default:
334       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
335       break;
336   }
337 }
338
339
340 static void
341 gst_v4lelement_get_property (GObject    *object,
342                              guint      prop_id,
343                              GValue     *value,
344                              GParamSpec *pspec)
345 {
346   GstV4lElement *v4lelement;
347   gint temp_i = 0;
348   gulong temp_ul = 0;
349   GList *list = NULL;
350
351   /* it's not null if we got it, but it might not be ours */
352   g_return_if_fail(GST_IS_V4LELEMENT(object));
353   v4lelement = GST_V4LELEMENT(object);
354
355   switch (prop_id)
356   {
357     case ARG_CHANNEL:
358       if (GST_V4L_IS_OPEN(v4lelement))
359         gst_v4l_get_chan_norm(v4lelement, &temp_i, NULL);
360       g_value_set_int(value, temp_i);
361       break;
362     case ARG_CHANNEL_NAMES:
363       if (GST_V4L_IS_OPEN(v4lelement))
364         list = gst_v4l_get_chan_names(v4lelement);
365       g_value_set_pointer(value, (gpointer)list);
366       break;
367     case ARG_NORM:
368       if (GST_V4L_IS_OPEN(v4lelement))
369         gst_v4l_get_chan_norm(v4lelement, NULL, &temp_i);
370       g_value_set_int(value, temp_i);
371       break;
372     case ARG_NORM_NAMES:
373       for (temp_i=0;norm_name[temp_i]!=NULL;temp_i++)
374         list = g_list_append(list, (gpointer)g_strdup(norm_name[temp_i]));
375       g_value_set_pointer(value, (gpointer)list);
376       break;
377     case ARG_HAS_TUNER:
378       g_value_set_boolean(value, FALSE);
379       if (GST_V4L_IS_OPEN(v4lelement))
380         if (gst_v4l_has_tuner(v4lelement))
381           g_value_set_boolean(value, TRUE);
382       break;
383     case ARG_FREQUENCY:
384       if (GST_V4L_IS_OPEN(v4lelement))
385         if (gst_v4l_has_tuner(v4lelement))
386           gst_v4l_get_frequency(v4lelement, &temp_ul);
387       g_value_set_ulong(value, temp_ul);
388       break;
389     case ARG_HAS_AUDIO:
390       g_value_set_boolean(value, FALSE);
391       if (GST_V4L_IS_OPEN(v4lelement))
392         if (gst_v4l_has_audio(v4lelement))
393           g_value_set_boolean(value, TRUE);
394       break;
395     case ARG_MUTE:
396       if (GST_V4L_IS_OPEN(v4lelement))
397         if (gst_v4l_has_audio(v4lelement))
398           gst_v4l_get_audio(v4lelement, V4L_AUDIO_MUTE, &temp_i);
399       g_value_set_boolean(value, temp_i?TRUE:FALSE);
400       break;
401     case ARG_MODE:
402       if (GST_V4L_IS_OPEN(v4lelement))
403         if (gst_v4l_has_tuner(v4lelement))
404           gst_v4l_get_audio(v4lelement, V4L_AUDIO_MODE, &temp_i);
405       g_value_set_int(value, temp_i);
406       break;
407     case ARG_VOLUME:
408       if (GST_V4L_IS_OPEN(v4lelement))
409         if (gst_v4l_has_tuner(v4lelement))
410           gst_v4l_get_audio(v4lelement, V4L_AUDIO_VOLUME, &temp_i);
411       g_value_set_int(value, temp_i);
412       break;
413     case ARG_HUE:
414       if (GST_V4L_IS_OPEN(v4lelement))
415         gst_v4l_get_picture(v4lelement, V4L_PICTURE_HUE, &temp_i);
416       g_value_set_int(value, temp_i);
417       break;
418     case ARG_BRIGHTNESS:
419       if (GST_V4L_IS_OPEN(v4lelement))
420         gst_v4l_get_picture(v4lelement, V4L_PICTURE_BRIGHTNESS, &temp_i);
421       g_value_set_int(value, temp_i);
422       break;
423     case ARG_CONTRAST:
424       if (GST_V4L_IS_OPEN(v4lelement))
425         gst_v4l_get_picture(v4lelement, V4L_PICTURE_CONTRAST, &temp_i);
426       g_value_set_int(value, temp_i);
427       break;
428     case ARG_SATURATION:
429       if (GST_V4L_IS_OPEN(v4lelement))
430         gst_v4l_get_picture(v4lelement, V4L_PICTURE_SATURATION, &temp_i);
431       g_value_set_int(value, temp_i);
432       break;
433     case ARG_DEVICE:
434       g_value_set_string(value, g_strdup(v4lelement->videodev?v4lelement->videodev:"/dev/video"));
435       break;
436     case ARG_DEVICE_NAME:
437       if (GST_V4L_IS_OPEN(v4lelement))
438         g_value_set_string(value, g_strdup(v4lelement->vcap.name));
439       else
440         g_value_set_string(value, g_strdup("None"));
441       break;
442     case ARG_DEVICE_IS_CAPTURE:
443       g_value_set_boolean(value, FALSE);
444       if (GST_V4L_IS_OPEN(v4lelement))
445         g_value_set_boolean(value, v4lelement->vcap.type & VID_TYPE_CAPTURE);
446       break;
447     case ARG_DEVICE_IS_OVERLAY:
448       g_value_set_boolean(value, FALSE);
449       if (GST_V4L_IS_OPEN(v4lelement))
450         g_value_set_boolean(value, v4lelement->vcap.type & VID_TYPE_OVERLAY);
451       break;
452     case ARG_DEVICE_IS_MJPEG_CAPTURE:
453       g_value_set_boolean(value, FALSE);
454       if (GST_V4L_IS_OPEN(v4lelement))
455         g_value_set_boolean(value, v4lelement->vcap.type & VID_TYPE_MJPEG_ENCODER);
456       break;
457     case ARG_DEVICE_IS_MJPEG_PLAYBACK:
458       g_value_set_boolean(value, FALSE);
459       if (GST_V4L_IS_OPEN(v4lelement))
460         g_value_set_boolean(value, v4lelement->vcap.type & VID_TYPE_MJPEG_DECODER);
461       break;
462     case ARG_DEVICE_IS_MPEG_CAPTURE:
463       g_value_set_boolean(value, FALSE);
464       if (GST_V4L_IS_OPEN(v4lelement))
465         g_value_set_boolean(value, v4lelement->vcap.type & VID_TYPE_MPEG_ENCODER);
466       break;
467     case ARG_DEVICE_IS_MPEG_PLAYBACK:
468       g_value_set_boolean(value, FALSE);
469       if (GST_V4L_IS_OPEN(v4lelement))
470         g_value_set_boolean(value, v4lelement->vcap.type & VID_TYPE_MPEG_DECODER);
471       break;
472     default:
473       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
474       break;
475   }
476 }
477
478
479 static GstElementStateReturn
480 gst_v4lelement_change_state (GstElement *element)
481 {
482   GstV4lElement *v4lelement;
483   
484   g_return_val_if_fail(GST_IS_V4LELEMENT(element), GST_STATE_FAILURE);
485   
486   v4lelement = GST_V4LELEMENT(element);
487
488   /* if going down into NULL state, close the device if it's open
489    * if going to READY, open the device (and set some options)
490    */
491   switch (GST_STATE_TRANSITION(element))
492   {
493     case GST_STATE_NULL_TO_READY:
494     {
495       int n, temp;
496
497       if (!gst_v4l_open(v4lelement))
498         return GST_STATE_FAILURE;
499
500       /* now, sync options */
501       if (v4lelement->norm >= VIDEO_MODE_PAL &&
502           v4lelement->norm < VIDEO_MODE_AUTO &&
503           v4lelement->channel >= 0)
504       {
505         if (!gst_v4l_set_chan_norm(v4lelement, v4lelement->channel, v4lelement->norm))
506           return GST_STATE_FAILURE;
507       }
508       if (v4lelement->frequency > 0 && gst_v4l_has_tuner(v4lelement))
509       {
510         if (!gst_v4l_set_frequency(v4lelement, v4lelement->frequency))
511           return GST_STATE_FAILURE;
512       }
513       for (n=V4L_AUDIO_VOLUME;n<=V4L_AUDIO_MODE;n++)
514       {
515         switch (n)
516         {
517           case V4L_AUDIO_MUTE:   temp = v4lelement->mute;   break;
518           case V4L_AUDIO_VOLUME: temp = v4lelement->volume; break;
519           case V4L_AUDIO_MODE:   temp = v4lelement->mode;   break;
520         }
521         if (temp >= 0 && gst_v4l_has_audio(v4lelement))
522         {
523           if (!gst_v4l_set_audio(v4lelement, n, temp))
524             return GST_STATE_FAILURE;
525         }
526       }
527       for (n=V4L_PICTURE_HUE;n<=V4L_PICTURE_SATURATION;n++)
528       {
529         switch (n)
530         {
531           case V4L_PICTURE_HUE:        temp = v4lelement->hue;        break;
532           case V4L_PICTURE_BRIGHTNESS: temp = v4lelement->brightness; break;
533           case V4L_PICTURE_SATURATION: temp = v4lelement->saturation; break;
534           case V4L_PICTURE_CONTRAST:   temp = v4lelement->contrast;   break;
535         }
536         if (temp >= 0)
537         {
538           if (!gst_v4l_set_picture(v4lelement, n, temp))
539             return GST_STATE_FAILURE;
540         }
541       }
542     }
543       break;
544     case GST_STATE_READY_TO_NULL:
545       if (!gst_v4l_close(v4lelement))
546         return GST_STATE_FAILURE;
547       break;
548   }
549
550   if (GST_ELEMENT_CLASS(parent_class)->change_state)
551     return GST_ELEMENT_CLASS(parent_class)->change_state(element);
552
553   return GST_STATE_SUCCESS;
554 }
555
556
557 static gboolean
558 plugin_init (GModule   *module,
559              GstPlugin *plugin)
560 {
561   GstElementFactory *factory;
562
563   /* create an elementfactory for the v4lelement */
564   factory = gst_elementfactory_new("v4lelement", GST_TYPE_V4LELEMENT,
565                                    &gst_v4lelement_details);
566   g_return_val_if_fail(factory != NULL, FALSE);
567   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
568
569   return TRUE;
570 }
571
572
573 GstPluginDesc plugin_desc = {
574   GST_VERSION_MAJOR,
575   GST_VERSION_MINOR,
576   "v4lelement",
577   plugin_init
578 };