change NULL to (NULL) for GST_ELEMENT_ERROR
[platform/upstream/gst-plugins-base.git] / sys / v4l / gstv4lsrc.c
1 /* G-Streamer BT8x8/V4L frame grabber plugin
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 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <string.h>
25 #include <sys/time.h>
26 #include "v4lsrc_calls.h"
27
28 /* elementfactory information */
29 static GstElementDetails gst_v4lsrc_details = GST_ELEMENT_DETAILS (
30   "Video (video4linux/raw) Source",
31   "Source/Video",
32   "Reads raw frames from a video4linux (BT8x8) device",
33   "Ronald Bultje <rbultje@ronald.bitfreak.net>"
34 );
35
36 /* V4lSrc signals and args */
37 enum {
38   /* FILL ME */
39   SIGNAL_FRAME_CAPTURE,
40   SIGNAL_FRAME_DROP,
41   SIGNAL_FRAME_INSERT,
42   LAST_SIGNAL
43 };
44
45 /* arguments */
46 enum {
47   ARG_0,
48   ARG_NUMBUFS,
49   ARG_BUFSIZE,
50   ARG_USE_FIXED_FPS
51 };
52
53 GST_FORMATS_FUNCTION (GstPad *, gst_v4lsrc_get_formats,
54                       GST_FORMAT_TIME, GST_FORMAT_DEFAULT);
55 GST_QUERY_TYPE_FUNCTION (GstPad *, gst_v4lsrc_get_query_types,
56                          GST_QUERY_POSITION);
57
58 /* init functions */
59 static void                  gst_v4lsrc_base_init    (gpointer g_class);
60 static void                  gst_v4lsrc_class_init   (GstV4lSrcClass *klass);
61 static void                  gst_v4lsrc_init         (GstV4lSrc      *v4lsrc);
62
63 /* parent class virtual functions */
64 static void                  gst_v4lsrc_open         (GstElement     *element,
65                                                       const gchar    *device);
66 static void                  gst_v4lsrc_close        (GstElement     *element,
67                                                       const gchar    *device);
68
69 /* pad/info functions */
70 static gboolean              gst_v4lsrc_src_convert  (GstPad         *pad,
71                                                       GstFormat      src_format,
72                                                       gint64         src_value,
73                                                       GstFormat      *dest_format,
74                                                       gint64         *dest_value);
75 static gboolean              gst_v4lsrc_src_query    (GstPad         *pad,
76                                                       GstQueryType   type, 
77                                                       GstFormat      *format,
78                                                       gint64         *value);
79
80 /* buffer functions */
81 static GstPadLinkReturn      gst_v4lsrc_srcconnect   (GstPad         *pad,
82                                                       const GstCaps        *caps);
83 static GstCaps*              gst_v4lsrc_getcaps      (GstPad         *pad);
84 static GstData*            gst_v4lsrc_get          (GstPad         *pad);
85
86 /* get/set params */
87 static void                  gst_v4lsrc_set_property (GObject        *object,
88                                                       guint          prop_id,
89                                                       const GValue   *value,
90                                                       GParamSpec     *pspec);
91 static void                  gst_v4lsrc_get_property (GObject        *object,
92                                                       guint          prop_id,
93                                                       GValue         *value,
94                                                       GParamSpec     *pspec);
95
96 /* state handling */
97 static GstElementStateReturn gst_v4lsrc_change_state (GstElement     *element);
98
99 /* set_clock function for a/V sync */
100 static void                  gst_v4lsrc_set_clock    (GstElement     *element,
101                                                       GstClock       *clock);
102
103 /* requeue buffer if it's back available */
104 static void                  gst_v4lsrc_buffer_free  (GstBuffer      *buffer);
105
106 static GstElementClass *parent_class = NULL;
107 static guint gst_v4lsrc_signals[LAST_SIGNAL] = { 0 };
108
109
110 GType
111 gst_v4lsrc_get_type (void)
112 {
113   static GType v4lsrc_type = 0;
114
115   if (!v4lsrc_type) {
116     static const GTypeInfo v4lsrc_info = {
117       sizeof(GstV4lSrcClass),
118       gst_v4lsrc_base_init,
119       NULL,
120       (GClassInitFunc)gst_v4lsrc_class_init,
121       NULL,
122       NULL,
123       sizeof(GstV4lSrc),
124       0,
125       (GInstanceInitFunc)gst_v4lsrc_init,
126       NULL
127     };
128     v4lsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lSrc", &v4lsrc_info, 0);
129   }
130   return v4lsrc_type;
131 }
132
133 static void
134 gst_v4lsrc_base_init (gpointer g_class)
135 {
136   GstPadTemplate *src_template;
137   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
138   
139   gst_element_class_set_details (gstelement_class, &gst_v4lsrc_details);
140
141   src_template = gst_pad_template_new (
142                   "src",
143                   GST_PAD_SRC,
144                   GST_PAD_ALWAYS,
145                   NULL);
146
147   gst_element_class_add_pad_template (gstelement_class, src_template);
148 }
149
150 static void
151 gst_v4lsrc_class_init (GstV4lSrcClass *klass)
152 {
153   GObjectClass *gobject_class;
154   GstElementClass *gstelement_class;
155   GstV4lElementClass *v4lelement_class;
156
157   gobject_class = (GObjectClass*)klass;
158   gstelement_class = (GstElementClass*)klass;
159   v4lelement_class = (GstV4lElementClass *) klass;
160
161   parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
162
163   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS,
164     g_param_spec_int("num_buffers","Num Buffers","Number of buffers",
165                      G_MININT,G_MAXINT,0,G_PARAM_READABLE));
166   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
167     g_param_spec_int("buffer_size","Buffer Size","Size of buffers",
168                      G_MININT,G_MAXINT,0,G_PARAM_READABLE));
169   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_USE_FIXED_FPS,
170     g_param_spec_boolean("use_fixed_fps", "Use Fixed FPS",
171                          "Drop/Insert frames to reach a certain FPS (TRUE) "
172                          "or adapt FPS to suit the number of frabbed frames",
173                          TRUE, G_PARAM_READWRITE));
174
175   /* signals */
176   gst_v4lsrc_signals[SIGNAL_FRAME_CAPTURE] =
177     g_signal_new("frame_capture", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
178                  G_STRUCT_OFFSET(GstV4lSrcClass, frame_capture),
179                  NULL, NULL, g_cclosure_marshal_VOID__VOID,
180                  G_TYPE_NONE, 0);
181   gst_v4lsrc_signals[SIGNAL_FRAME_DROP] =
182     g_signal_new("frame_drop", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
183                  G_STRUCT_OFFSET(GstV4lSrcClass, frame_drop),
184                  NULL, NULL, g_cclosure_marshal_VOID__VOID,
185                  G_TYPE_NONE, 0);
186   gst_v4lsrc_signals[SIGNAL_FRAME_INSERT] =
187     g_signal_new("frame_insert", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
188                  G_STRUCT_OFFSET(GstV4lSrcClass, frame_insert),
189                  NULL, NULL, g_cclosure_marshal_VOID__VOID,
190                  G_TYPE_NONE, 0);
191
192   gobject_class->set_property = gst_v4lsrc_set_property;
193   gobject_class->get_property = gst_v4lsrc_get_property;
194
195   gstelement_class->change_state = gst_v4lsrc_change_state;
196
197   gstelement_class->set_clock = gst_v4lsrc_set_clock;
198
199   v4lelement_class->open  = gst_v4lsrc_open;
200   v4lelement_class->close = gst_v4lsrc_close;
201 }
202
203
204 static void
205 gst_v4lsrc_init (GstV4lSrc *v4lsrc)
206 {
207   GstElementClass *klass = GST_ELEMENT_GET_CLASS (v4lsrc);
208
209   GST_FLAG_SET(GST_ELEMENT(v4lsrc), GST_ELEMENT_THREAD_SUGGESTED);
210
211   v4lsrc->srcpad = gst_pad_new_from_template (
212         gst_element_class_get_pad_template (klass, "src"), "src");
213   gst_element_add_pad(GST_ELEMENT(v4lsrc), v4lsrc->srcpad);
214
215   gst_pad_set_get_function (v4lsrc->srcpad, gst_v4lsrc_get);
216   gst_pad_set_getcaps_function (v4lsrc->srcpad, gst_v4lsrc_getcaps);
217   gst_pad_set_link_function (v4lsrc->srcpad, gst_v4lsrc_srcconnect);
218   gst_pad_set_convert_function (v4lsrc->srcpad, gst_v4lsrc_src_convert);
219   gst_pad_set_formats_function (v4lsrc->srcpad, gst_v4lsrc_get_formats);
220   gst_pad_set_query_function (v4lsrc->srcpad, gst_v4lsrc_src_query);
221   gst_pad_set_query_type_function (v4lsrc->srcpad, gst_v4lsrc_get_query_types);
222
223   v4lsrc->buffer_size = 0;
224
225   /* no clock */
226   v4lsrc->clock = NULL;
227
228   /* no colourspaces */
229   v4lsrc->colourspaces = NULL;
230
231   /* fps */
232   v4lsrc->use_fixed_fps = TRUE;
233
234   v4lsrc->is_capturing = FALSE;
235 }
236
237 static void
238 gst_v4lsrc_open (GstElement  *element,
239                  const gchar *device)
240 {
241   GstV4lSrc *v4lsrc = GST_V4LSRC (element);
242   int palette[] = {
243     VIDEO_PALETTE_YUV422,
244     VIDEO_PALETTE_YUV420P,
245     VIDEO_PALETTE_UYVY,
246     VIDEO_PALETTE_YUV411P,
247     VIDEO_PALETTE_YUV422P,
248     VIDEO_PALETTE_YUV410P,
249     VIDEO_PALETTE_YUV411,
250     VIDEO_PALETTE_RGB555,
251     VIDEO_PALETTE_RGB565,
252     VIDEO_PALETTE_RGB24,
253     VIDEO_PALETTE_RGB32,
254     -1
255   }, i;
256
257   for (i = 0; palette[i] != -1; i++) {
258     /* try palette out */
259     if (!gst_v4lsrc_try_palette(v4lsrc, palette[i]))
260       continue;
261     v4lsrc->colourspaces = g_list_append (v4lsrc->colourspaces,
262                                           GINT_TO_POINTER (palette[i]));
263   }
264 }
265
266 static void
267 gst_v4lsrc_close (GstElement  *element,
268                   const gchar *device)
269 {
270   GstV4lSrc *v4lsrc = GST_V4LSRC (element);
271
272   g_list_free (v4lsrc->colourspaces);
273   v4lsrc->colourspaces = NULL;
274 }
275
276 static gfloat
277 gst_v4lsrc_get_fps (GstV4lSrc *v4lsrc)
278 {
279   gint norm;
280   gfloat fps;
281
282   if (!v4lsrc->use_fixed_fps &&
283       v4lsrc->clock != NULL &&
284       v4lsrc->handled > 0) {
285     /* try to get time from clock master and calculate fps */
286     GstClockTime time = gst_clock_get_time(v4lsrc->clock) - v4lsrc->substract_time;
287     return v4lsrc->handled * GST_SECOND / time;
288   }
289
290   /* if that failed ... */
291
292   if (!GST_V4L_IS_OPEN(GST_V4LELEMENT(v4lsrc)))
293     return 0.;
294
295   if (!gst_v4l_get_chan_norm(GST_V4LELEMENT(v4lsrc), NULL, &norm))
296     return 0.;
297
298   if (norm == VIDEO_MODE_NTSC)
299     fps = 30000/1001;
300   else
301     fps = 25.;
302
303   return fps;
304 }
305
306 static gboolean
307 gst_v4lsrc_src_convert (GstPad    *pad,
308                         GstFormat  src_format,
309                         gint64     src_value,
310                         GstFormat *dest_format,
311                         gint64    *dest_value)
312 {
313   GstV4lSrc *v4lsrc;
314   gdouble fps;
315
316   v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
317
318   if ((fps = gst_v4lsrc_get_fps(v4lsrc)) == 0)
319     return FALSE;
320
321   switch (src_format) {
322     case GST_FORMAT_TIME:
323       switch (*dest_format) {
324         case GST_FORMAT_DEFAULT:
325           *dest_value = src_value * fps / GST_SECOND;
326           break;
327         default:
328           return FALSE;
329       }
330       break;
331
332     case GST_FORMAT_DEFAULT:
333       switch (*dest_format) {
334         case GST_FORMAT_TIME:
335           *dest_value = src_value * GST_SECOND / fps;
336           break;
337         default:
338           return FALSE;
339       }
340       break;
341
342     default:
343       return FALSE;
344   }
345
346   return TRUE;
347 }
348
349 static gboolean
350 gst_v4lsrc_src_query (GstPad      *pad,
351                       GstQueryType type, 
352                       GstFormat   *format,
353                       gint64      *value)
354 {
355   GstV4lSrc *v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
356   gboolean res = TRUE;
357   gdouble fps;
358
359   if ((fps = gst_v4lsrc_get_fps(v4lsrc)) == 0)
360     return FALSE;
361
362   switch (type) {
363     case GST_QUERY_POSITION:
364       switch (*format) {
365         case GST_FORMAT_TIME:
366           *value = v4lsrc->handled * GST_SECOND / fps;
367           break;
368         case GST_FORMAT_DEFAULT:
369           *value = v4lsrc->handled;
370           break;
371         default:
372           res = FALSE;
373           break;
374       }
375       break;
376     default:
377       res = FALSE;
378       break;
379   }
380
381   return res;
382 }
383
384 static GstCaps *
385 gst_v4lsrc_palette_to_caps (int palette)
386 {
387   guint32 fourcc;
388   GstCaps *caps;
389
390   switch (palette) {
391     case VIDEO_PALETTE_YUV422:
392     case VIDEO_PALETTE_YUYV:
393       fourcc = GST_MAKE_FOURCC('Y','U','Y','2');
394       break;
395     case VIDEO_PALETTE_YUV420P:
396       fourcc = GST_MAKE_FOURCC('I','4','2','0');
397       break;
398     case VIDEO_PALETTE_UYVY:
399       fourcc = GST_MAKE_FOURCC('U','Y','V','Y');
400       break;
401     case VIDEO_PALETTE_YUV411P:
402       fourcc = GST_MAKE_FOURCC('Y','4','1','B');
403       break;
404     case VIDEO_PALETTE_YUV411:
405       fourcc = GST_MAKE_FOURCC('Y','4','1','P');
406       break;
407     case VIDEO_PALETTE_YUV422P:
408       fourcc = GST_MAKE_FOURCC('Y','4','2','B');
409       break;
410     case VIDEO_PALETTE_YUV410P:
411       fourcc = GST_MAKE_FOURCC('Y','U','V','9');
412       break;
413     case VIDEO_PALETTE_RGB555:
414     case VIDEO_PALETTE_RGB565:
415     case VIDEO_PALETTE_RGB24:
416     case VIDEO_PALETTE_RGB32:
417       fourcc = GST_MAKE_FOURCC('R','G','B',' ');
418       break;
419     default:
420       return NULL;
421   }
422
423   if (fourcc == GST_MAKE_FOURCC('R','G','B',' ')) {
424     switch (palette) {
425       case VIDEO_PALETTE_RGB555:
426         caps = gst_caps_from_string ("video/x-raw-rgb, "
427             "bpp = (int) 16, "
428             "depth = (int) 15, "
429             "endianness = (int) BYTE_ORDER, "
430             "red_mask = 0x7c00, "
431             "green_mask = 0x03e0, "
432             "blue_mask = 0x001f");
433         break;
434       case VIDEO_PALETTE_RGB565:
435         caps = gst_caps_from_string ("video/x-raw-rgb, "
436             "bpp = (int) 16, "
437             "depth = (int) 16, "
438             "endianness = (int) BYTE_ORDER, "
439             "red_mask = 0xf800, "
440             "green_mask = 0x07f0, "
441             "blue_mask = 0x001f");
442         break;
443       case VIDEO_PALETTE_RGB24:
444         caps = gst_caps_from_string ("video/x-raw-rgb, "
445             "bpp = (int) 24, "
446             "depth = (int) 24, "
447             "endianness = (int) BIG_ENDIAN, "
448             "red_mask = 0xFF0000, "
449             "green_mask = 0x00FF00, "
450             "blue_mask = 0x0000FF");
451         break;
452       case VIDEO_PALETTE_RGB32:
453         caps = gst_caps_from_string ("video/x-raw-rgb, "
454             "bpp = (int) 24, "
455             "depth = (int) 32, "
456             "endianness = (int) BIG_ENDIAN, "
457             "red_mask = 0xFF000000, "
458             "green_mask = 0x00FF0000, "
459             "blue_mask = 0x0000FF00");
460         break;
461       default:
462         g_assert_not_reached();
463         return NULL;
464     }
465   } else {
466     caps = gst_caps_new_simple ("video/x-raw-yuv",
467         "format", GST_TYPE_FOURCC, fourcc, NULL);
468   }
469
470   return caps;
471 }
472
473
474 static GstPadLinkReturn
475 gst_v4lsrc_srcconnect (GstPad  *pad, const GstCaps *vscapslist)
476 {
477   GstV4lSrc *v4lsrc;
478   guint32 fourcc;
479   gint bpp, depth, w, h, palette = -1;
480   gdouble fps;
481   GstStructure *structure;
482   gboolean was_capturing;
483
484   v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
485   was_capturing = v4lsrc->is_capturing;
486
487   /* in case the buffers are active (which means that we already
488    * did capsnego before and didn't clean up), clean up anyways */
489   if (GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc)))
490   {
491     if (was_capturing) {
492       if (!gst_v4lsrc_capture_stop(v4lsrc))
493         return GST_PAD_LINK_REFUSED;
494     }
495     if (!gst_v4lsrc_capture_deinit(v4lsrc))
496       return GST_PAD_LINK_REFUSED;
497   } else if (!GST_V4L_IS_OPEN(GST_V4LELEMENT(v4lsrc))) {
498     return GST_PAD_LINK_DELAYED;
499   }
500
501   structure = gst_caps_get_structure (vscapslist, 0);
502
503   if (!strcmp(gst_structure_get_name (structure), "video/x-raw-yuv"))
504     gst_structure_get_fourcc (structure, "format", &fourcc);
505   else
506     fourcc = GST_MAKE_FOURCC('R','G','B',' ');
507
508   gst_structure_get_int (structure, "width", &w);
509   gst_structure_get_int (structure, "height", &h);
510   gst_structure_get_double (structure, "framerate", &fps);
511
512   switch (fourcc)
513   {
514     case GST_MAKE_FOURCC('I','4','2','0'):
515       palette = VIDEO_PALETTE_YUV420P;
516       v4lsrc->buffer_size = ((w+1)&~1) * ((h+1)&~1) * 1.5;
517       break;
518     case GST_MAKE_FOURCC('Y','U','Y','2'):
519       palette = VIDEO_PALETTE_YUV422;
520       v4lsrc->buffer_size = ((w+1)&~1) * h * 2;
521       break;
522     case GST_MAKE_FOURCC('U','Y','V','Y'):
523       palette = VIDEO_PALETTE_UYVY;
524       v4lsrc->buffer_size = ((w+1)&~1) * h * 2;
525       break;
526     case GST_MAKE_FOURCC('Y','4','1','B'):
527       palette = VIDEO_PALETTE_YUV411P;
528       v4lsrc->buffer_size = ((w+3)&~3) * h * 1.5;
529       break;
530     case GST_MAKE_FOURCC('Y','4','1','P'):
531       palette = VIDEO_PALETTE_YUV411;
532       v4lsrc->buffer_size = ((w+3)&~3) * h * 1.5;
533       break;
534     case GST_MAKE_FOURCC('Y','U','V','9'):
535       palette = VIDEO_PALETTE_YUV410P;
536       v4lsrc->buffer_size = ((w+3)&~3) * ((h+3)&~3) * 1.125;
537       break;
538     case GST_MAKE_FOURCC('Y','4','2','B'):
539       palette = VIDEO_PALETTE_YUV422P;
540       v4lsrc->buffer_size = ((w+1)&~1) * h * 2;
541       break;
542     case GST_MAKE_FOURCC('R','G','B',' '):
543       gst_structure_get_int (structure, "depth", &depth);
544       switch (depth)
545       {
546         case 15:
547           palette = VIDEO_PALETTE_RGB555;
548           v4lsrc->buffer_size = w * h * 2;
549           break;
550         case 16:
551           palette = VIDEO_PALETTE_RGB565;
552           v4lsrc->buffer_size = w * h * 2;
553           break;
554         case 24:
555           gst_structure_get_int (structure, "bpp", &bpp);
556           switch (bpp) {
557             case 24:
558               palette = VIDEO_PALETTE_RGB24;
559               v4lsrc->buffer_size = w * h * 3;
560               break;
561             case 32:
562               palette = VIDEO_PALETTE_RGB32;
563               v4lsrc->buffer_size = w * h * 4;
564               break;
565             default:
566               break;
567           }
568           break;
569         default:
570           break;
571       }
572       break;
573     default:
574       break;
575   }
576
577   if (palette == -1)
578     return GST_PAD_LINK_REFUSED;
579
580   if (!gst_v4lsrc_set_capture(v4lsrc, w, h, palette))
581     return GST_PAD_LINK_REFUSED;
582
583   if (!gst_v4lsrc_capture_init(v4lsrc))
584     return GST_PAD_LINK_REFUSED;
585
586   if (was_capturing) {
587     if (!gst_v4lsrc_capture_start(v4lsrc))
588       return GST_PAD_LINK_REFUSED;
589   }
590
591   return GST_PAD_LINK_OK;
592 }
593
594
595 static GstCaps *
596 gst_v4lsrc_getcaps (GstPad  *pad)
597 {
598   GstCaps *list;
599   GstV4lSrc *v4lsrc = GST_V4LSRC(gst_pad_get_parent(pad));
600   struct video_capability *vcap = &GST_V4LELEMENT(v4lsrc)->vcap;
601   GList *item;
602
603   if (!GST_V4L_IS_OPEN(GST_V4LELEMENT(v4lsrc))) {
604     return gst_caps_new_any ();
605   }
606
607   list = gst_caps_new_empty();
608   for (item = v4lsrc->colourspaces; item != NULL; item = item->next) {
609     GstCaps *one;
610
611     one = gst_v4lsrc_palette_to_caps(GPOINTER_TO_INT (item->data));
612     if (!one)
613       g_print ("Palette %d gave no caps\n",
614                GPOINTER_TO_INT (item->data));
615     gst_caps_set_simple (one,
616         "width", GST_TYPE_INT_RANGE, vcap->minwidth,  vcap->maxwidth,
617         "height", GST_TYPE_INT_RANGE, vcap->minheight, vcap->maxheight,
618         "framerate", G_TYPE_DOUBLE, gst_v4lsrc_get_fps(v4lsrc),
619         NULL);
620     gst_caps_append(list, one);
621   }
622
623   return list;
624 }
625
626
627 static GstData *
628 gst_v4lsrc_get (GstPad *pad)
629 {
630   GstV4lSrc *v4lsrc;
631   GstBuffer *buf;
632   gint num;
633   gdouble fps = 0.;
634
635   g_return_val_if_fail (pad != NULL, NULL);
636
637   v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
638
639   if (v4lsrc->use_fixed_fps &&
640       (fps = gst_v4lsrc_get_fps(v4lsrc)) == 0)
641     return NULL;
642
643   if (v4lsrc->need_writes > 0) {
644     /* use last frame */
645     num = v4lsrc->last_frame;
646     v4lsrc->need_writes--;
647   } else if (v4lsrc->clock && v4lsrc->use_fixed_fps) {
648     GstClockTime time;
649     gboolean have_frame = FALSE;
650
651     do {
652       /* by default, we use the frame once */
653       v4lsrc->need_writes = 1;
654
655       /* grab a frame from the device */
656       if (!gst_v4lsrc_grab_frame(v4lsrc, &num))
657         return NULL;
658
659       v4lsrc->last_frame = num;
660       time = v4lsrc->timestamp_sync - v4lsrc->substract_time;
661
662       /* decide how often we're going to write the frame - set
663        * v4lsrc->need_writes to (that-1) and have_frame to TRUE
664        * if we're going to write it - else, just continue.
665        * 
666        * time is generally the system or audio clock. Let's
667        * say that we've written one second of audio, then we want
668        * to have written one second of video too, within the same
669        * timeframe. This means that if time - begin_time = X sec,
670        * we want to have written X*fps frames. If we've written
671        * more - drop, if we've written less - dup... */
672       if (v4lsrc->handled * (GST_SECOND/fps) - time > 1.5 * (GST_SECOND/fps)) {
673         /* yo dude, we've got too many frames here! Drop! DROP! */
674         v4lsrc->need_writes--; /* -= (v4lsrc->handled - (time / fps)); */
675         g_signal_emit(G_OBJECT(v4lsrc),
676                       gst_v4lsrc_signals[SIGNAL_FRAME_DROP], 0);
677       } else if (v4lsrc->handled * (GST_SECOND/fps) - time < - 1.5 * (GST_SECOND/fps)) {
678         /* this means we're lagging far behind */
679         v4lsrc->need_writes++; /* += ((time / fps) - v4lsrc->handled); */
680         g_signal_emit(G_OBJECT(v4lsrc),
681                       gst_v4lsrc_signals[SIGNAL_FRAME_INSERT], 0);
682       }
683
684       if (v4lsrc->need_writes > 0) {
685         have_frame = TRUE;
686         v4lsrc->use_num_times[num] = v4lsrc->need_writes;
687         v4lsrc->need_writes--;
688       } else {
689         gst_v4lsrc_requeue_frame(v4lsrc, num);
690       }
691     } while (!have_frame);
692   } else {
693     /* grab a frame from the device */
694     if (!gst_v4lsrc_grab_frame(v4lsrc, &num))
695       return NULL;
696
697     v4lsrc->use_num_times[num] = 1;
698   }
699
700   buf = gst_buffer_new ();
701   GST_BUFFER_FREE_DATA_FUNC (buf) = gst_v4lsrc_buffer_free;
702   GST_BUFFER_PRIVATE (buf) = v4lsrc; /* hack to re-queue buffer on free */
703   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY | GST_BUFFER_DONTFREE);
704   GST_BUFFER_DATA(buf) = gst_v4lsrc_get_buffer(v4lsrc, num);
705   GST_BUFFER_MAXSIZE (buf) = v4lsrc->mbuf.size / v4lsrc->mbuf.frames;
706   GST_BUFFER_SIZE(buf) = v4lsrc->buffer_size;
707   if (v4lsrc->use_fixed_fps)
708     GST_BUFFER_TIMESTAMP(buf) = v4lsrc->handled * GST_SECOND / fps;
709   else /* calculate time based on our own clock */
710     GST_BUFFER_TIMESTAMP(buf) = v4lsrc->timestamp_sync - v4lsrc->substract_time;
711
712   v4lsrc->handled++;
713   g_signal_emit(G_OBJECT(v4lsrc),
714                 gst_v4lsrc_signals[SIGNAL_FRAME_CAPTURE], 0);
715
716   return GST_DATA (buf);
717 }
718
719
720 static void
721 gst_v4lsrc_set_property (GObject      *object,
722                          guint        prop_id,
723                          const GValue *value,
724                          GParamSpec   *pspec)
725 {
726   GstV4lSrc *v4lsrc;
727
728   g_return_if_fail(GST_IS_V4LSRC(object));
729   v4lsrc = GST_V4LSRC(object);
730
731   switch (prop_id) {
732     case ARG_USE_FIXED_FPS:
733       if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc))) {
734         v4lsrc->use_fixed_fps = g_value_get_boolean(value);
735       }
736       break;
737
738     default:
739       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
740       break;
741   }
742 }
743
744
745 static void
746 gst_v4lsrc_get_property (GObject    *object,
747                          guint      prop_id,
748                          GValue     *value,
749                          GParamSpec *pspec)
750 {
751   GstV4lSrc *v4lsrc;
752
753   g_return_if_fail(GST_IS_V4LSRC(object));
754   v4lsrc = GST_V4LSRC(object);
755
756   switch (prop_id) {
757     case ARG_NUMBUFS:
758       g_value_set_int(value, v4lsrc->mbuf.frames);
759       break;
760
761     case ARG_BUFSIZE:
762       if (v4lsrc->mbuf.frames == 0)
763         g_value_set_int(value, 0);
764       else
765         g_value_set_int(value, v4lsrc->mbuf.size/(v4lsrc->mbuf.frames*1024));
766       break;
767
768     case ARG_USE_FIXED_FPS:
769       g_value_set_boolean(value, v4lsrc->use_fixed_fps);
770       break;
771
772     default:
773       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
774       break;
775   }
776 }
777
778
779 static GstElementStateReturn
780 gst_v4lsrc_change_state (GstElement *element)
781 {
782   GstV4lSrc *v4lsrc;
783   GTimeVal time;
784   gint transition = GST_STATE_TRANSITION (element);
785
786   g_return_val_if_fail(GST_IS_V4LSRC(element), GST_STATE_FAILURE);
787   
788   v4lsrc = GST_V4LSRC(element);
789
790   switch (transition) {
791     case GST_STATE_NULL_TO_READY:
792       break;
793     case GST_STATE_READY_TO_PAUSED:
794       v4lsrc->handled = 0;
795       v4lsrc->need_writes = 0;
796       v4lsrc->last_frame = 0;
797       v4lsrc->substract_time = 0;
798       /* buffer setup used to be done here, but I moved it to
799        * capsnego */
800       break;
801     case GST_STATE_PAUSED_TO_PLAYING:
802       /* queue all buffer, start streaming capture */
803       if (!gst_v4lsrc_capture_start(v4lsrc))
804         return GST_STATE_FAILURE;
805       g_get_current_time(&time);
806       v4lsrc->substract_time = GST_TIMEVAL_TO_TIME(time) - v4lsrc->substract_time;
807       break;
808     case GST_STATE_PLAYING_TO_PAUSED:
809       /* de-queue all queued buffers */
810       if (!gst_v4lsrc_capture_stop(v4lsrc))
811         return GST_STATE_FAILURE;
812       g_get_current_time(&time);
813       v4lsrc->substract_time = GST_TIMEVAL_TO_TIME(time) - v4lsrc->substract_time;
814       break;
815     case GST_STATE_PAUSED_TO_READY:
816       /* stop capturing, unmap all buffers */
817       if (!gst_v4lsrc_capture_deinit(v4lsrc))
818         return GST_STATE_FAILURE;
819       break;
820     case GST_STATE_READY_TO_NULL:
821       break;
822   }
823
824   if (GST_ELEMENT_CLASS (parent_class)->change_state)
825     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
826
827   return GST_STATE_SUCCESS;
828 }
829
830
831 #if 0
832 static GstBuffer*
833 gst_v4lsrc_buffer_new (GstBufferPool *pool,
834                        guint64       offset,
835                        guint         size,
836                        gpointer      user_data)
837 {
838   GstBuffer *buffer;
839   GstV4lSrc *v4lsrc = GST_V4LSRC(user_data);
840
841   if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc)))
842     return NULL;
843
844   buffer = gst_buffer_new();
845   if (!buffer)
846     return NULL;
847
848   /* TODO: add interlacing info to buffer as metadata
849    * (height>288 or 240 = topfieldfirst, else noninterlaced) */
850   GST_BUFFER_MAXSIZE(buffer) = v4lsrc->mbuf.size / v4lsrc->mbuf.frames;
851   GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
852
853   return buffer;
854 }
855 #endif
856
857 static void
858 gst_v4lsrc_buffer_free (GstBuffer *buf)
859 {
860   GstV4lSrc *v4lsrc = GST_V4LSRC (GST_BUFFER_PRIVATE (buf));
861   int n;
862
863   if (gst_element_get_state(GST_ELEMENT(v4lsrc)) != GST_STATE_PLAYING)
864     return; /* we've already cleaned up ourselves */
865
866   for (n=0;n<v4lsrc->mbuf.frames;n++)
867     if (GST_BUFFER_DATA(buf) == gst_v4lsrc_get_buffer(v4lsrc, n))
868     {
869       v4lsrc->use_num_times[n]--;
870       if (v4lsrc->use_num_times[n] <= 0) {
871         gst_v4lsrc_requeue_frame(v4lsrc, n);
872       }
873       break;
874     }
875
876   if (n == v4lsrc->mbuf.frames)
877     GST_ELEMENT_ERROR (v4lsrc, RESOURCE, TOO_LAZY, (NULL),
878       ("Couldn\'t find the buffer"));
879 }
880
881
882 static void
883 gst_v4lsrc_set_clock (GstElement *element,
884                       GstClock   *clock)
885 {
886   GST_V4LSRC(element)->clock = clock;
887 }