change NULL to (NULL) for GST_ELEMENT_ERROR
[platform/upstream/gst-plugins-base.git] / sys / v4l / gstv4lmjpegsrc.c
1 /* G-Streamer hardware MJPEG video source 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 "v4lmjpegsrc_calls.h"
26
27 /* elementfactory information */
28 static GstElementDetails gst_v4lmjpegsrc_details = {
29   "Video (video4linux/MJPEG) Source",
30   "Source/Video",
31   "Reads MJPEG-encoded frames from a zoran MJPEG/video4linux device",
32   "Ronald Bultje <rbultje@ronald.bitfreak.net>"
33 };
34
35 /* V4lMjpegSrc signals and args */
36 enum {
37   SIGNAL_FRAME_CAPTURE,
38   SIGNAL_FRAME_DROP,
39   SIGNAL_FRAME_INSERT,
40   SIGNAL_FRAME_LOST,
41   LAST_SIGNAL
42 };
43
44 /* arguments */
45 enum {
46   ARG_0,
47 #if 0
48   ARG_X_OFFSET,
49   ARG_Y_OFFSET,
50   ARG_F_WIDTH,
51   ARG_F_HEIGHT,
52   /* normally, we would want to use subframe capture, however,
53    * for the time being it's easier if we disable it first */
54 #endif
55   ARG_QUALITY,
56   ARG_NUMBUFS,
57   ARG_BUFSIZE,
58   ARG_USE_FIXED_FPS
59 };
60
61 GST_FORMATS_FUNCTION (GstPad *, gst_v4lmjpegsrc_get_formats,
62                       GST_FORMAT_TIME, GST_FORMAT_DEFAULT);
63 GST_QUERY_TYPE_FUNCTION (GstPad *, gst_v4lmjpegsrc_get_query_types,
64                          GST_QUERY_POSITION);
65
66 /* init functions */
67 static void                  gst_v4lmjpegsrc_base_init    (gpointer g_class);
68 static void                  gst_v4lmjpegsrc_class_init   (GstV4lMjpegSrcClass *klass);
69 static void                  gst_v4lmjpegsrc_init         (GstV4lMjpegSrc *v4lmjpegsrc);
70
71 /* pad/info functions */
72 static gboolean              gst_v4lmjpegsrc_src_convert  (GstPad         *pad,
73                                                            GstFormat      src_format,
74                                                            gint64         src_value,
75                                                            GstFormat      *dest_format,
76                                                            gint64         *dest_value);
77 static gboolean              gst_v4lmjpegsrc_src_query    (GstPad         *pad,
78                                                            GstQueryType   type, 
79                                                            GstFormat      *format,
80                                                            gint64         *value);
81
82 /* buffer functions */
83 static GstPadLinkReturn      gst_v4lmjpegsrc_srcconnect   (GstPad         *pad,
84                                                            const GstCaps        *caps);
85 static GstData*            gst_v4lmjpegsrc_get          (GstPad         *pad);
86 static GstCaps*              gst_v4lmjpegsrc_getcaps      (GstPad         *pad);
87
88 /* get/set params */
89 static void                  gst_v4lmjpegsrc_set_property (GObject        *object,
90                                                            guint          prop_id,
91                                                            const GValue   *value,
92                                                            GParamSpec     *pspec);
93 static void                  gst_v4lmjpegsrc_get_property (GObject        *object,
94                                                            guint          prop_id,
95                                                            GValue         *value,
96                                                            GParamSpec     *pspec);
97
98 /* set_clock function for A/V sync */
99 static void                  gst_v4lmjpegsrc_set_clock    (GstElement     *element,
100                                                            GstClock       *clock);
101
102 /* state handling */
103 static GstElementStateReturn gst_v4lmjpegsrc_change_state (GstElement     *element);
104
105 /* requeue buffer after use */
106 static void                  gst_v4lmjpegsrc_buffer_free  (GstBuffer      *buffer);
107
108 static GstElementClass *parent_class = NULL;
109 static guint gst_v4lmjpegsrc_signals[LAST_SIGNAL] = { 0 };
110
111
112 GType
113 gst_v4lmjpegsrc_get_type (void)
114 {
115   static GType v4lmjpegsrc_type = 0;
116
117   if (!v4lmjpegsrc_type) {
118     static const GTypeInfo v4lmjpegsrc_info = {
119       sizeof(GstV4lMjpegSrcClass),
120       gst_v4lmjpegsrc_base_init,
121       NULL,
122       (GClassInitFunc)gst_v4lmjpegsrc_class_init,
123       NULL,
124       NULL,
125       sizeof(GstV4lMjpegSrc),
126       0,
127       (GInstanceInitFunc)gst_v4lmjpegsrc_init,
128       NULL
129     };
130     v4lmjpegsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lMjpegSrc", &v4lmjpegsrc_info, 0);
131   }
132   return v4lmjpegsrc_type;
133 }
134
135
136 static void
137 gst_v4lmjpegsrc_base_init (gpointer g_class)
138 {
139   static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE (
140       "src",
141       GST_PAD_SRC,
142       GST_PAD_ALWAYS,
143       GST_STATIC_CAPS ("video/x-jpeg, "
144         "width = (int) [ 0, MAX ], "
145         "height = (int) [ 0, MAX ], "
146         "framerate = (double) [ 0, MAX ]"
147       )
148   );
149   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
150   
151   gst_element_class_set_details (gstelement_class, &gst_v4lmjpegsrc_details);
152
153   gst_element_class_add_pad_template (gstelement_class,
154       gst_static_pad_template_get (&src_template));
155 }
156 static void
157 gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass *klass)
158 {
159   GObjectClass *gobject_class;
160   GstElementClass *gstelement_class;
161
162   gobject_class = (GObjectClass*)klass;
163   gstelement_class = (GstElementClass*)klass;
164
165   parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
166
167 #if 0
168   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_X_OFFSET,
169     g_param_spec_int("x_offset","x_offset","x_offset",
170                      G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
171   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_Y_OFFSET,
172     g_param_spec_int("y_offset","y_offset","y_offset",
173                      G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
174   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_WIDTH,
175     g_param_spec_int("frame_width","frame_width","frame_width",
176                      G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
177   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_HEIGHT,
178     g_param_spec_int("frame_height","frame_height","frame_height",
179                      G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
180 #endif
181
182   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_QUALITY,
183     g_param_spec_int("quality","Quality","JPEG frame quality",
184                      1,100,50,G_PARAM_READWRITE));
185
186   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS,
187     g_param_spec_int("num_buffers","Num Buffers","Number of Buffers",
188                      1,256,64,G_PARAM_READWRITE));
189   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
190     g_param_spec_int("buffer_size", "Buffer Size", "Size of buffers",
191                      0, 512*1024, 128*1024, G_PARAM_READABLE));
192
193   g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_USE_FIXED_FPS,
194     g_param_spec_boolean("use_fixed_fps", "Use Fixed FPS",
195                          "Drop/Insert frames to reach a certain FPS (TRUE) "
196                          "or adapt FPS to suit the number of frabbed frames",
197                          TRUE, G_PARAM_READWRITE));
198
199   /* signals */
200   gst_v4lmjpegsrc_signals[SIGNAL_FRAME_CAPTURE] =
201     g_signal_new("frame_capture", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
202                  G_STRUCT_OFFSET(GstV4lMjpegSrcClass, frame_capture),
203                  NULL, NULL, g_cclosure_marshal_VOID__VOID,
204                  G_TYPE_NONE, 0);
205   gst_v4lmjpegsrc_signals[SIGNAL_FRAME_DROP] =
206     g_signal_new("frame_drop", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
207                  G_STRUCT_OFFSET(GstV4lMjpegSrcClass, frame_drop),
208                  NULL, NULL, g_cclosure_marshal_VOID__VOID,
209                  G_TYPE_NONE, 0);
210   gst_v4lmjpegsrc_signals[SIGNAL_FRAME_INSERT] =
211     g_signal_new("frame_insert", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
212                  G_STRUCT_OFFSET(GstV4lMjpegSrcClass, frame_insert),
213                  NULL, NULL, g_cclosure_marshal_VOID__VOID,
214                  G_TYPE_NONE, 0);
215   gst_v4lmjpegsrc_signals[SIGNAL_FRAME_LOST] =
216     g_signal_new("frame_lost", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
217                  G_STRUCT_OFFSET(GstV4lMjpegSrcClass, frame_lost),
218                  NULL, NULL, g_cclosure_marshal_VOID__INT,
219                  G_TYPE_NONE, 1, G_TYPE_INT);
220
221   gobject_class->set_property = gst_v4lmjpegsrc_set_property;
222   gobject_class->get_property = gst_v4lmjpegsrc_get_property;
223
224   gstelement_class->change_state = gst_v4lmjpegsrc_change_state;
225
226   gstelement_class->set_clock = gst_v4lmjpegsrc_set_clock;
227 }
228
229
230 static void
231 gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc)
232 {
233   GstElementClass *klass = GST_ELEMENT_GET_CLASS (v4lmjpegsrc);
234
235   GST_FLAG_SET(GST_ELEMENT(v4lmjpegsrc), GST_ELEMENT_THREAD_SUGGESTED);
236
237   v4lmjpegsrc->srcpad = gst_pad_new_from_template (
238         gst_element_class_get_pad_template (klass, "src"), "src");
239   gst_element_add_pad(GST_ELEMENT(v4lmjpegsrc), v4lmjpegsrc->srcpad);
240
241   gst_pad_set_get_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get);
242   gst_pad_set_getcaps_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_getcaps);
243   gst_pad_set_link_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_srcconnect);
244   gst_pad_set_convert_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_src_convert);
245   gst_pad_set_formats_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get_formats);
246   gst_pad_set_query_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_src_query);
247   gst_pad_set_query_type_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get_query_types);
248
249 #if 0
250   v4lmjpegsrc->frame_width = 0;
251   v4lmjpegsrc->frame_height = 0;
252   v4lmjpegsrc->x_offset = -1;
253   v4lmjpegsrc->y_offset = -1;
254 #endif
255
256   v4lmjpegsrc->quality = 50;
257
258   v4lmjpegsrc->numbufs = 64;
259
260   /* no clock */
261   v4lmjpegsrc->clock = NULL;
262
263   /* fps */
264   v4lmjpegsrc->use_fixed_fps = TRUE;
265 }
266
267
268 static gfloat
269 gst_v4lmjpegsrc_get_fps (GstV4lMjpegSrc *v4lmjpegsrc)
270 {
271   gint norm;
272   gfloat fps;
273  
274   if (!v4lmjpegsrc->use_fixed_fps &&
275       v4lmjpegsrc->clock != NULL &&
276       v4lmjpegsrc->handled > 0) {
277     /* try to get time from clock master and calculate fps */
278     GstClockTime time = gst_clock_get_time(v4lmjpegsrc->clock) - v4lmjpegsrc->substract_time;
279     return v4lmjpegsrc->handled * GST_SECOND / time;
280   }
281
282   /* if that failed ... */
283
284   if (!GST_V4L_IS_OPEN(GST_V4LELEMENT(v4lmjpegsrc)))
285     return 0.;
286
287   if (!gst_v4l_get_chan_norm(GST_V4LELEMENT(v4lmjpegsrc), NULL, &norm))
288     return 0.;
289
290   if (norm == VIDEO_MODE_NTSC)
291     fps = 30000/1001;
292   else
293     fps = 25.;
294
295   return fps;
296 }
297
298 static gboolean
299 gst_v4lmjpegsrc_src_convert (GstPad    *pad,
300                              GstFormat  src_format,
301                              gint64     src_value,
302                              GstFormat *dest_format,
303                              gint64    *dest_value)
304 {
305   GstV4lMjpegSrc *v4lmjpegsrc;
306   gdouble fps;
307
308   v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
309
310   if ((fps = gst_v4lmjpegsrc_get_fps(v4lmjpegsrc)) == 0)
311     return FALSE;
312
313   switch (src_format) {
314     case GST_FORMAT_TIME:
315       switch (*dest_format) {
316         case GST_FORMAT_DEFAULT:
317           *dest_value = src_value * fps / GST_SECOND;
318           break;
319         default:
320           return FALSE;
321       }
322       break;
323
324     case GST_FORMAT_DEFAULT:
325       switch (*dest_format) {
326         case GST_FORMAT_TIME:
327           *dest_value = src_value * GST_SECOND / fps;
328           break;
329         default:
330           return FALSE;
331       }
332       break;
333
334     default:
335       return FALSE;
336   }
337
338   return TRUE;
339 }
340
341 static gboolean
342 gst_v4lmjpegsrc_src_query (GstPad      *pad,
343                            GstQueryType type, 
344                           GstFormat   *format,
345                            gint64      *value)
346 {
347   GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
348   gboolean res = TRUE;
349   gdouble fps;
350
351   if ((fps = gst_v4lmjpegsrc_get_fps(v4lmjpegsrc)) == 0)
352     return FALSE;
353
354   switch (type) {
355     case GST_QUERY_POSITION:
356       switch (*format) {
357         case GST_FORMAT_TIME:
358           *value = v4lmjpegsrc->handled * GST_SECOND / fps;
359           break;
360         case GST_FORMAT_DEFAULT:
361           *value = v4lmjpegsrc->handled;
362           break;
363         default:
364           res = FALSE;
365           break;
366       }
367       break;
368     default:
369       res = FALSE;
370       break;
371   }
372
373   return res;
374 }
375
376 static inline gulong
377 calc_bufsize (int hor_dec,
378               int ver_dec)
379 {
380         guint8 div = hor_dec * ver_dec;
381         guint32 num = (1024 * 512) / (div);
382         guint32 result = 2;
383                                                                                 
384         num--;
385         while (num) {
386                 num >>= 1;
387                 result <<= 1;
388         }
389                                                                                 
390         if (result > (512 * 1024))
391                 return (512 * 1024);
392         if (result < 8192)
393                 return 8192;
394         return result;
395 }
396
397 static GstPadLinkReturn
398 gst_v4lmjpegsrc_srcconnect (GstPad  *pad,
399                             const GstCaps *caps)
400 {
401   GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC(gst_pad_get_parent(pad));
402   gint hor_dec, ver_dec;
403   gint w, h;
404   gint max_w = GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth,
405        max_h = GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxheight;
406   gulong bufsize;
407   GstStructure *structure;
408
409   /* in case the buffers are active (which means that we already
410    * did capsnego before and didn't clean up), clean up anyways */
411   if (GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
412   {
413     if (!gst_v4lmjpegsrc_capture_deinit(v4lmjpegsrc))
414       return GST_PAD_LINK_REFUSED;
415   }
416   else if (!GST_V4L_IS_OPEN(GST_V4LELEMENT(v4lmjpegsrc)))
417   {
418     return GST_PAD_LINK_DELAYED;
419   }
420
421   /* Note: basically, we don't give a damn about the opposite caps here.
422    * that might seem odd, but it isn't. we know that the opposite caps is
423    * either NULL or has mime type video/x-jpeg, and in both cases, we'll set
424    * our own mime type back and it'll work. Other properties are to be set
425    * by the src, not by the opposite caps */
426
427   structure = gst_caps_get_structure (caps, 0);
428   gst_structure_get_int (structure, "width", &w);
429   gst_structure_get_int (structure, "height", &h);
430
431   /* figure out decimation */
432   if (w >= max_w) {
433     hor_dec = 1;
434   } else if (w*2 >= max_w) {
435     hor_dec = 2;
436   } else {
437     hor_dec = 4;
438   }
439   if (h >= max_h) {
440     ver_dec = 1;
441   } else if (h*2 >= max_h) {
442     ver_dec = 2;
443   } else {
444     ver_dec = 4;
445   }
446
447   /* calculate bufsize */
448   bufsize = calc_bufsize(hor_dec, ver_dec);
449
450   /* set buffer info */
451   if (!gst_v4lmjpegsrc_set_buffer(v4lmjpegsrc,
452                                   v4lmjpegsrc->numbufs, bufsize)) {
453     return GST_PAD_LINK_REFUSED;
454   }
455
456   /* set capture parameters and mmap the buffers */
457   if (hor_dec == ver_dec) {
458     if (!gst_v4lmjpegsrc_set_capture(v4lmjpegsrc,
459                                      hor_dec,
460                                      v4lmjpegsrc->quality)) {
461       return GST_PAD_LINK_REFUSED;
462     }
463   } else {
464     if (!gst_v4lmjpegsrc_set_capture_m(v4lmjpegsrc,
465                                        0, 0, max_w, max_h,
466                                        hor_dec, ver_dec,
467                                        v4lmjpegsrc->quality)) {
468       return GST_PAD_LINK_REFUSED;
469     }
470   }
471 #if 0
472   if (!v4lmjpegsrc->frame_width && !v4lmjpegsrc->frame_height &&
473        v4lmjpegsrc->x_offset < 0 && v4lmjpegsrc->y_offset < 0 &&
474        v4lmjpegsrc->horizontal_decimation == v4lmjpegsrc->vertical_decimation)
475   {
476     if (!gst_v4lmjpegsrc_set_capture(v4lmjpegsrc,
477         v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->quality))
478       return GST_PAD_LINK_REFUSED;
479   }
480   else
481   {
482     if (!gst_v4lmjpegsrc_set_capture_m(v4lmjpegsrc,
483          v4lmjpegsrc->x_offset, v4lmjpegsrc->y_offset,
484          v4lmjpegsrc->frame_width, v4lmjpegsrc->frame_height,
485          v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->vertical_decimation,
486          v4lmjpegsrc->quality))
487       return GST_PAD_LINK_REFUSED;
488   }
489 #endif
490
491   return GST_PAD_LINK_OK;
492 }
493
494
495 static GstData*
496 gst_v4lmjpegsrc_get (GstPad *pad)
497 {
498   GstV4lMjpegSrc *v4lmjpegsrc;
499   GstBuffer *buf;
500   gint num;
501   gdouble fps = 0;
502
503   g_return_val_if_fail (pad != NULL, NULL);
504
505   v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
506
507   if (v4lmjpegsrc->use_fixed_fps &&
508       (fps = gst_v4lmjpegsrc_get_fps(v4lmjpegsrc)) == 0)
509     return NULL;
510
511   if (v4lmjpegsrc->need_writes > 0) {
512     /* use last frame */
513     num = v4lmjpegsrc->last_frame;
514     v4lmjpegsrc->need_writes--;
515   } else if (v4lmjpegsrc->clock && v4lmjpegsrc->use_fixed_fps) {
516     GstClockTime time;
517     gboolean have_frame = FALSE;
518
519     do {
520       /* by default, we use the frame once */
521       v4lmjpegsrc->need_writes = 1;
522
523       /* grab a frame from the device */
524       if (!gst_v4lmjpegsrc_grab_frame(v4lmjpegsrc, &num, &v4lmjpegsrc->last_size))
525         return NULL;
526
527       v4lmjpegsrc->last_frame = num;
528       time = GST_TIMEVAL_TO_TIME(v4lmjpegsrc->bsync.timestamp) -
529                v4lmjpegsrc->substract_time;
530
531       /* first check whether we lost any frames according to the device */
532       if (v4lmjpegsrc->last_seq != 0) {
533         if (v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq > 1) {
534           v4lmjpegsrc->need_writes = v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq;
535           g_signal_emit(G_OBJECT(v4lmjpegsrc),
536                         gst_v4lmjpegsrc_signals[SIGNAL_FRAME_LOST], 0,
537                         v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq - 1);
538         }
539       }
540       v4lmjpegsrc->last_seq = v4lmjpegsrc->bsync.seq;
541
542       /* decide how often we're going to write the frame - set
543        * v4lmjpegsrc->need_writes to (that-1) and have_frame to TRUE
544        * if we're going to write it - else, just continue.
545        * 
546        * time is generally the system or audio clock. Let's
547        * say that we've written one second of audio, then we want
548        * to have written one second of video too, within the same
549        * timeframe. This means that if time - begin_time = X sec,
550        * we want to have written X*fps frames. If we've written
551        * more - drop, if we've written less - dup... */
552       if (v4lmjpegsrc->handled * (GST_SECOND/fps) - time > 1.5 * (GST_SECOND/fps)) {
553         /* yo dude, we've got too many frames here! Drop! DROP! */
554         v4lmjpegsrc->need_writes--; /* -= (v4lmjpegsrc->handled - (time / fps)); */
555         g_signal_emit(G_OBJECT(v4lmjpegsrc),
556                       gst_v4lmjpegsrc_signals[SIGNAL_FRAME_DROP], 0);
557       } else if (v4lmjpegsrc->handled * (GST_SECOND/fps) - time < - 1.5 * (GST_SECOND/fps)) {
558         /* this means we're lagging far behind */
559         v4lmjpegsrc->need_writes++; /* += ((time / fps) - v4lmjpegsrc->handled); */
560         g_signal_emit(G_OBJECT(v4lmjpegsrc),
561                       gst_v4lmjpegsrc_signals[SIGNAL_FRAME_INSERT], 0);
562       }
563
564       if (v4lmjpegsrc->need_writes > 0) {
565         have_frame = TRUE;
566         v4lmjpegsrc->use_num_times[num] = v4lmjpegsrc->need_writes;
567         v4lmjpegsrc->need_writes--;
568       } else {
569         gst_v4lmjpegsrc_requeue_frame(v4lmjpegsrc, num);
570       }
571     } while (!have_frame);
572   } else {
573     /* grab a frame from the device */
574     if (!gst_v4lmjpegsrc_grab_frame(v4lmjpegsrc, &num, &v4lmjpegsrc->last_size))
575       return NULL;
576
577     v4lmjpegsrc->use_num_times[num] = 1;
578   }
579
580   buf = gst_buffer_new ();
581   GST_BUFFER_FREE_DATA_FUNC (buf) = gst_v4lmjpegsrc_buffer_free;
582   GST_BUFFER_PRIVATE (buf) = v4lmjpegsrc;
583   GST_BUFFER_DATA(buf) = gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, num);
584   GST_BUFFER_SIZE(buf) = v4lmjpegsrc->last_size;
585   GST_BUFFER_MAXSIZE(buf) = v4lmjpegsrc->breq.size;
586   GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY | GST_BUFFER_DONTFREE);
587   if (v4lmjpegsrc->use_fixed_fps)
588     GST_BUFFER_TIMESTAMP(buf) = v4lmjpegsrc->handled * GST_SECOND / fps;
589   else /* calculate time based on our own clock */
590     GST_BUFFER_TIMESTAMP(buf) = GST_TIMEVAL_TO_TIME(v4lmjpegsrc->bsync.timestamp) -
591                                   v4lmjpegsrc->substract_time;
592
593   v4lmjpegsrc->handled++;
594   g_signal_emit(G_OBJECT(v4lmjpegsrc),
595                 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_CAPTURE], 0);
596
597   return GST_DATA (buf);
598 }
599
600
601 static GstCaps*
602 gst_v4lmjpegsrc_getcaps (GstPad  *pad)
603 {
604   GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC(gst_pad_get_parent(pad));
605   struct video_capability *vcap = &GST_V4LELEMENT(v4lmjpegsrc)->vcap;
606
607   if (!GST_V4L_IS_OPEN(GST_V4LELEMENT(v4lmjpegsrc))) {
608     return NULL;
609   }
610
611   return gst_caps_new_simple ("video/x-jpeg",
612       "width", GST_TYPE_INT_RANGE, vcap->maxwidth/4, vcap->maxwidth,
613       "height", GST_TYPE_INT_RANGE, vcap->maxheight/4, vcap->maxheight,
614       "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE,
615       NULL);
616 }
617
618
619 static void
620 gst_v4lmjpegsrc_set_property (GObject      *object,
621                               guint        prop_id,
622                               const GValue *value,
623                               GParamSpec   *pspec)
624 {
625   GstV4lMjpegSrc *v4lmjpegsrc;
626
627   g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
628   v4lmjpegsrc = GST_V4LMJPEGSRC(object);
629
630   switch (prop_id) {
631 #if 0
632     case ARG_X_OFFSET:
633       v4lmjpegsrc->x_offset = g_value_get_int(value);
634       break;
635     case ARG_Y_OFFSET:
636       v4lmjpegsrc->y_offset = g_value_get_int(value);
637       break;
638     case ARG_F_WIDTH:
639       v4lmjpegsrc->frame_width = g_value_get_int(value);
640       break;
641     case ARG_F_HEIGHT:
642       v4lmjpegsrc->frame_height = g_value_get_int(value);
643       break;
644 #endif
645     case ARG_QUALITY:
646       v4lmjpegsrc->quality = g_value_get_int(value);
647       break;
648     case ARG_NUMBUFS:
649       v4lmjpegsrc->numbufs = g_value_get_int(value);
650       break;
651     case ARG_USE_FIXED_FPS:
652       if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc))) {
653         v4lmjpegsrc->use_fixed_fps = g_value_get_boolean(value);
654       }
655       break;
656     default:
657       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
658       break;
659   }
660 }
661
662
663 static void
664 gst_v4lmjpegsrc_get_property (GObject    *object,
665                               guint      prop_id,
666                               GValue     *value,
667                               GParamSpec *pspec)
668 {
669   GstV4lMjpegSrc *v4lmjpegsrc;
670
671   g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
672   v4lmjpegsrc = GST_V4LMJPEGSRC(object);
673
674   switch (prop_id) {
675 #if 0
676     case ARG_X_OFFSET:
677       g_value_set_int(value, v4lmjpegsrc->x_offset);
678       break;
679     case ARG_Y_OFFSET:
680       g_value_set_int(value, v4lmjpegsrc->y_offset);
681       break;
682     case ARG_F_WIDTH:
683       g_value_set_int(value, v4lmjpegsrc->frame_width);
684       break;
685     case ARG_F_HEIGHT:
686       g_value_set_int(value, v4lmjpegsrc->frame_height);
687       break;
688 #endif
689     case ARG_QUALITY:
690       g_value_set_int(value, v4lmjpegsrc->quality);
691       break;
692     case ARG_NUMBUFS:
693       if (GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
694         g_value_set_int(value, v4lmjpegsrc->breq.count);
695       else
696         g_value_set_int(value, v4lmjpegsrc->numbufs);
697       break;
698     case ARG_BUFSIZE:
699       g_value_set_int(value, v4lmjpegsrc->breq.size);
700       break;
701     case ARG_USE_FIXED_FPS:
702       g_value_set_boolean(value, v4lmjpegsrc->use_fixed_fps);
703       break;
704     default:
705       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
706       break;
707   }
708 }
709
710
711 static GstElementStateReturn
712 gst_v4lmjpegsrc_change_state (GstElement *element)
713 {
714   GstV4lMjpegSrc *v4lmjpegsrc;
715   GTimeVal time;
716
717   g_return_val_if_fail(GST_IS_V4LMJPEGSRC(element), GST_STATE_FAILURE);
718   
719   v4lmjpegsrc = GST_V4LMJPEGSRC(element);
720
721   switch (GST_STATE_TRANSITION(element)) {
722     case GST_STATE_READY_TO_PAUSED:
723       /* actual buffer set-up used to be done here - but I moved
724        * it to capsnego itself */
725       v4lmjpegsrc->handled = 0;
726       v4lmjpegsrc->need_writes = 0;
727       v4lmjpegsrc->last_frame = 0;
728       v4lmjpegsrc->substract_time = 0;
729       break;
730     case GST_STATE_PAUSED_TO_PLAYING:
731       /* queue all buffer, start streaming capture */
732       if (!gst_v4lmjpegsrc_capture_start(v4lmjpegsrc))
733         return GST_STATE_FAILURE;
734       g_get_current_time(&time);
735       v4lmjpegsrc->substract_time = GST_TIMEVAL_TO_TIME(time) -
736                                       v4lmjpegsrc->substract_time;
737       v4lmjpegsrc->last_seq = 0;
738       break;
739     case GST_STATE_PLAYING_TO_PAUSED:
740       g_get_current_time(&time);
741       v4lmjpegsrc->substract_time = GST_TIMEVAL_TO_TIME(time) -
742                                       v4lmjpegsrc->substract_time;
743       /* de-queue all queued buffers */
744       if (!gst_v4lmjpegsrc_capture_stop(v4lmjpegsrc))
745         return GST_STATE_FAILURE;
746       break;
747     case GST_STATE_PAUSED_TO_READY:
748       /* stop capturing, unmap all buffers */
749       if (!gst_v4lmjpegsrc_capture_deinit(v4lmjpegsrc))
750         return GST_STATE_FAILURE;
751       break;
752   }
753
754   if (GST_ELEMENT_CLASS (parent_class)->change_state)
755     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
756
757   return GST_STATE_SUCCESS;
758 }
759
760
761 static void
762 gst_v4lmjpegsrc_set_clock (GstElement *element,
763                            GstClock   *clock)
764 {
765   GST_V4LMJPEGSRC(element)->clock = clock;
766 }
767
768
769 #if 0
770 static GstBuffer*
771 gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
772                             guint64       offset,
773                             guint         size,
774                             gpointer      user_data)
775 {
776   GstBuffer *buffer;
777   GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC(user_data);
778
779   if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
780     return NULL;
781
782   buffer = gst_buffer_new();
783   if (!buffer)
784     return NULL;
785
786   /* TODO: add interlacing info to buffer as metadata */
787   GST_BUFFER_MAXSIZE(buffer) = v4lmjpegsrc->breq.size;
788   GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
789
790   return buffer;
791 }
792 #endif
793
794 static void
795 gst_v4lmjpegsrc_buffer_free (GstBuffer *buf)
796 {
797   GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (GST_BUFFER_PRIVATE (buf));
798   int n;
799
800   if (gst_element_get_state(GST_ELEMENT(v4lmjpegsrc)) != GST_STATE_PLAYING)
801     return; /* we've already cleaned up ourselves */
802
803   for (n=0;n<v4lmjpegsrc->breq.count;n++)
804     if (GST_BUFFER_DATA(buf) == gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, n))
805     {
806       v4lmjpegsrc->use_num_times[n]--;
807       if (v4lmjpegsrc->use_num_times[n] <= 0) {
808         gst_v4lmjpegsrc_requeue_frame(v4lmjpegsrc, n);
809       }
810       break;
811     }
812
813   if (n == v4lmjpegsrc->breq.count)
814     GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL),
815       ("Couldn't find the buffer"));
816 }