f28c59a67c6834caa8f1327873230ea1b68805ea
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / gstv4l2src.c
1 /* G-Streamer Video4linux2 video-capture plugin
2  * Copyright (C) 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 <string.h>
21 #include <sys/time.h>
22 #include "v4l2src_calls.h"
23
24 /* elementfactory details */
25 static GstElementDetails gst_v4l2src_details = {
26         "Video (video4linux2) Source",
27         "Source/Video",
28         "LGPL",
29         "Reads frames (compressed or uncompressed) from a video4linux2 device",
30         VERSION,
31         "Ronald Bultje <rbultje@ronald.bitfreak.net>",
32         "(C) 2002",
33 };
34
35 /* V4l2Src 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         ARG_NUMBUFS,
48         ARG_BUFSIZE,
49         ARG_USE_FIXED_FPS
50 };
51
52
53 /* init functions */
54 static void                     gst_v4l2src_class_init          (GstV4l2SrcClass *klass);
55 static void                     gst_v4l2src_init                (GstV4l2Src      *v4l2src);
56
57 /* signal functions */
58 static void                     gst_v4l2src_open                (GstElement      *element,
59                                                                  const gchar     *device);
60 static void                     gst_v4l2src_close               (GstElement      *element,
61                                                                  const gchar     *device);
62
63 /* pad/buffer functions */
64 static gboolean                 gst_v4l2src_srcconvert          (GstPad          *pad,
65                                                                  GstFormat       src_format,
66                                                                  gint64          src_value,
67                                                                  GstFormat       *dest_format,
68                                                                  gint64          *dest_value);
69 static GstPadLinkReturn         gst_v4l2src_srcconnect          (GstPad          *pad,
70                                                                  GstCaps         *caps);
71 static GstCaps *                gst_v4l2src_getcaps             (GstPad          *pad,
72                                                                  GstCaps         *caps);
73 static GstBuffer *              gst_v4l2src_get                 (GstPad          *pad);
74
75 /* get/set params */
76 static void                     gst_v4l2src_set_property        (GObject         *object,
77                                                                  guint           prop_id,
78                                                                  const GValue    *value,
79                                                                  GParamSpec      *pspec);
80 static void                     gst_v4l2src_get_property        (GObject         *object,
81                                                                  guint           prop_id,
82                                                                  GValue          *value,
83                                                                  GParamSpec      *pspec);
84
85 /* state handling */
86 static GstElementStateReturn    gst_v4l2src_change_state        (GstElement      *element);
87
88 /* set_clock function for A/V sync */
89 static void                     gst_v4l2src_set_clock           (GstElement     *element,
90                                                                  GstClock       *clock);
91
92
93 /* bufferpool functions */
94 static GstBuffer *              gst_v4l2src_buffer_new          (GstBufferPool   *pool,
95                                                                  guint64         offset,
96                                                                  guint           size,
97                                                                  gpointer        user_data);
98 static void                     gst_v4l2src_buffer_free         (GstBufferPool   *pool,
99                                                                  GstBuffer       *buf,
100                                                                  gpointer        user_data);
101
102
103 static GstPadTemplate *src_template;
104
105 static GstElementClass *parent_class = NULL;
106 static guint gst_v4l2src_signals[LAST_SIGNAL] = { 0 };
107
108
109 GType
110 gst_v4l2src_get_type (void)
111 {
112         static GType v4l2src_type = 0;
113
114         if (!v4l2src_type) {
115                 static const GTypeInfo v4l2src_info = {
116                         sizeof(GstV4l2SrcClass),
117                         NULL,
118                         NULL,
119                         (GClassInitFunc) gst_v4l2src_class_init,
120                         NULL,
121                         NULL,
122                         sizeof(GstV4l2Src),
123                         0,
124                         (GInstanceInitFunc) gst_v4l2src_init,
125                         NULL
126                 };
127                 v4l2src_type = g_type_register_static(GST_TYPE_V4L2ELEMENT,
128                         "GstV4l2Src", &v4l2src_info, 0);
129         }
130         return v4l2src_type;
131 }
132
133
134 static void
135 gst_v4l2src_class_init (GstV4l2SrcClass *klass)
136 {
137         GObjectClass *gobject_class;
138         GstElementClass *gstelement_class;
139         GstV4l2ElementClass *v4l2_class;
140
141         gobject_class = (GObjectClass*)klass;
142         gstelement_class = (GstElementClass*)klass;
143         v4l2_class = (GstV4l2ElementClass*)klass;
144
145         parent_class = g_type_class_ref(GST_TYPE_V4L2ELEMENT);
146
147         g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS,
148                 g_param_spec_int("num_buffers","num_buffers","num_buffers",
149                                  G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
150         g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
151                 g_param_spec_int("buffer_size","buffer_size","buffer_size",
152                                  G_MININT,G_MAXINT,0,G_PARAM_READABLE));
153
154         g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_USE_FIXED_FPS,
155                 g_param_spec_boolean("use_fixed_fps", "Use Fixed FPS",
156                                      "Drop/Insert frames to reach a certain FPS (TRUE) "
157                                      "or adapt FPS to suit the number of frabbed frames",
158                                      TRUE, G_PARAM_READWRITE));
159
160         /* signals */
161         gst_v4l2src_signals[SIGNAL_FRAME_CAPTURE] =
162                 g_signal_new("frame_capture", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
163                              G_STRUCT_OFFSET(GstV4l2SrcClass, frame_capture),
164                              NULL, NULL, g_cclosure_marshal_VOID__VOID,
165                              G_TYPE_NONE, 0);
166         gst_v4l2src_signals[SIGNAL_FRAME_DROP] =
167                 g_signal_new("frame_drop", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
168                              G_STRUCT_OFFSET(GstV4l2SrcClass, frame_drop),
169                              NULL, NULL, g_cclosure_marshal_VOID__VOID,
170                              G_TYPE_NONE, 0);
171         gst_v4l2src_signals[SIGNAL_FRAME_INSERT] =
172                 g_signal_new("frame_insert", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
173                              G_STRUCT_OFFSET(GstV4l2SrcClass, frame_insert),
174                              NULL, NULL, g_cclosure_marshal_VOID__VOID,
175                              G_TYPE_NONE, 0);
176         gst_v4l2src_signals[SIGNAL_FRAME_LOST] =
177                 g_signal_new("frame_lost", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
178                              G_STRUCT_OFFSET(GstV4l2SrcClass, frame_lost),
179                              NULL, NULL, g_cclosure_marshal_VOID__INT,
180                              G_TYPE_NONE, 1, G_TYPE_INT);
181
182
183         gobject_class->set_property = gst_v4l2src_set_property;
184         gobject_class->get_property = gst_v4l2src_get_property;
185
186         gstelement_class->change_state = gst_v4l2src_change_state;
187
188         v4l2_class->open = gst_v4l2src_open;
189         v4l2_class->close = gst_v4l2src_close;
190
191         gstelement_class->set_clock = gst_v4l2src_set_clock;
192 }
193
194
195 static void
196 gst_v4l2src_init (GstV4l2Src *v4l2src)
197 {
198         GST_FLAG_SET(GST_ELEMENT(v4l2src), GST_ELEMENT_THREAD_SUGGESTED);
199
200         v4l2src->srcpad = gst_pad_new_from_template(src_template, "src");
201         gst_element_add_pad(GST_ELEMENT(v4l2src), v4l2src->srcpad);
202
203         gst_pad_set_get_function(v4l2src->srcpad, gst_v4l2src_get);
204         gst_pad_set_link_function(v4l2src->srcpad, gst_v4l2src_srcconnect);
205         gst_pad_set_convert_function (v4l2src->srcpad, gst_v4l2src_srcconvert);
206         gst_pad_set_getcaps_function (v4l2src->srcpad, gst_v4l2src_getcaps);
207
208         v4l2src->bufferpool = gst_buffer_pool_new(NULL, NULL,
209                                         gst_v4l2src_buffer_new,
210                                         NULL,
211                                         gst_v4l2src_buffer_free,
212                                         v4l2src);
213
214         v4l2src->breq.count = 0;
215
216         v4l2src->formats = NULL;
217         v4l2src->format_list = NULL;
218
219         /* no clock */
220         v4l2src->clock = NULL;
221
222         /* fps */
223         v4l2src->use_fixed_fps = TRUE;
224 }
225
226
227 static void
228 gst_v4l2src_open (GstElement  *element,
229                   const gchar *device)
230 {
231         gst_v4l2src_fill_format_list(GST_V4L2SRC(element));
232 }
233
234
235 static void
236 gst_v4l2src_close (GstElement  *element,
237                    const gchar *device)
238 {
239         gst_v4l2src_empty_format_list(GST_V4L2SRC(element));
240 }
241
242
243 static gdouble
244 gst_v4l2src_get_fps (GstV4l2Src *v4l2src)
245 {
246         gint norm;
247         struct v4l2_standard *std;
248         gdouble fps;
249
250         if (!v4l2src->use_fixed_fps &&
251             v4l2src->clock != NULL &&
252             v4l2src->handled > 0) {
253                 /* try to get time from clock master and calculate fps */
254                 GstClockTime time = gst_clock_get_time(v4l2src->clock) -
255                                       v4l2src->substract_time;
256                 return v4l2src->handled * GST_SECOND / time;
257         }
258
259         /* if that failed ... */
260  
261         if (!GST_V4L2_IS_OPEN(GST_V4L2ELEMENT(v4l2src)))
262                 return 0.;
263
264         if (!gst_v4l2_get_norm(GST_V4L2ELEMENT(v4l2src), &norm))
265                 return 0.;
266
267         std = ((struct v4l2_standard *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->norms, norm));
268         fps = (1. * std->frameperiod.denominator) / std->frameperiod.numerator;
269
270         return fps;
271 }
272
273
274 static gboolean
275 gst_v4l2src_srcconvert (GstPad    *pad,
276                         GstFormat  src_format,
277                         gint64     src_value,
278                         GstFormat *dest_format,
279                         gint64    *dest_value)
280 {
281         GstV4l2Src *v4l2src;
282         gdouble fps;
283
284         v4l2src = GST_V4L2SRC (gst_pad_get_parent (pad));
285
286         if ((fps = gst_v4l2src_get_fps(v4l2src)) == 0)
287                 return FALSE;
288
289         switch (src_format) {
290                 case GST_FORMAT_TIME:
291                         switch (*dest_format) {
292                                 case GST_FORMAT_DEFAULT:
293                                         *dest_value = src_value * fps / GST_SECOND;
294                                         break;
295                                 default:
296                                         return FALSE;
297                         }
298                         break;
299
300                 case GST_FORMAT_DEFAULT:
301                         switch (*dest_format) {
302                                 case GST_FORMAT_TIME:
303                                         *dest_value = src_value * GST_SECOND / fps;
304                                         break;
305                                 default:
306                                         return FALSE;
307                         }
308                         break;
309
310                 default:
311                         return FALSE;
312         }
313
314         return TRUE;
315 }
316
317
318 static GstCaps *
319 gst_v4l2src_v4l2fourcc_to_caps (guint32        fourcc,
320                                 GstPropsEntry *width,
321                                 GstPropsEntry *height,
322                                 gboolean       compressed)
323 {
324         GstCaps *caps = NULL;
325
326         switch (fourcc) {
327         case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */
328         case V4L2_PIX_FMT_JPEG:  /* JFIF JPEG */
329                 caps = GST_CAPS_NEW("v4l2src_caps",
330                                     "video/jpeg",
331                                       NULL);
332                         break;
333         case V4L2_PIX_FMT_RGB332:
334         case V4L2_PIX_FMT_RGB555:
335         case V4L2_PIX_FMT_RGB555X:
336         case V4L2_PIX_FMT_RGB565:
337         case V4L2_PIX_FMT_RGB565X:
338         case V4L2_PIX_FMT_RGB24:
339         case V4L2_PIX_FMT_BGR24:
340         case V4L2_PIX_FMT_RGB32:
341         case V4L2_PIX_FMT_BGR32: {
342                 guint depth=0, bpp=0;
343                 gint endianness = 0;
344                 guint32 r_mask = 0, b_mask = 0, g_mask = 0;
345                 guint32 fcc = GST_MAKE_FOURCC('R','G','B',' ');
346
347                 switch (fourcc) {
348                 case V4L2_PIX_FMT_RGB332:
349                         bpp = depth = 8;
350                         endianness = G_BYTE_ORDER; /* 'like, whatever' */
351                         r_mask = 0xe0; g_mask = 0x1c; b_mask = 0x03;
352                         break;
353                 case V4L2_PIX_FMT_RGB555:
354                 case V4L2_PIX_FMT_RGB555X:
355                         bpp = 16; depth = 15;
356                         endianness = (fourcc == V4L2_PIX_FMT_RGB332) ?
357                                      G_LITTLE_ENDIAN : G_BIG_ENDIAN;
358                         r_mask = 0x7c00; g_mask = 0x03e0; b_mask = 0x001f;
359                         break;
360                 case V4L2_PIX_FMT_RGB565:
361                 case V4L2_PIX_FMT_RGB565X:
362                         bpp = depth = 16;
363                         endianness = (fourcc == V4L2_PIX_FMT_RGB565) ?
364                                      G_LITTLE_ENDIAN : G_BIG_ENDIAN;
365                         r_mask = 0xf800; g_mask = 0x07e0; b_mask = 0x001f;
366                         break;
367                 case V4L2_PIX_FMT_RGB24:
368                 case V4L2_PIX_FMT_BGR24:
369                         bpp = depth = 24;
370                         endianness = (fourcc == V4L2_PIX_FMT_BGR24) ?
371                                      G_LITTLE_ENDIAN : G_BIG_ENDIAN;
372                         r_mask = 0xff0000; g_mask = 0x00ff00; b_mask = 0x0000ff;
373                         break;
374                 case V4L2_PIX_FMT_RGB32:
375                 case V4L2_PIX_FMT_BGR32:
376                         bpp = depth = 32;
377                         endianness = (fourcc == V4L2_PIX_FMT_BGR32) ?
378                                      G_LITTLE_ENDIAN : G_BIG_ENDIAN;
379                         r_mask = 0x00ff0000; g_mask = 0x0000ff00; b_mask = 0x000000ff;
380                         break;
381                 default:
382                         g_assert_not_reached();
383                         break;
384                 }
385
386                 caps = GST_CAPS_NEW("v4l2src_caps",
387                                     "video/raw",
388                                       "format",     GST_PROPS_FOURCC(fcc),
389                                       "bpp",        GST_PROPS_INT(bpp),
390                                       "depth",      GST_PROPS_INT(depth),
391                                       "red_mask",   GST_PROPS_INT(r_mask),
392                                       "green_mask", GST_PROPS_INT(g_mask),
393                                       "blue_mask",  GST_PROPS_INT(b_mask),
394                                       "endianness", GST_PROPS_INT(endianness),
395                                       NULL);
396                 break;
397         }
398         case V4L2_PIX_FMT_YUV420: /* I420/IYUV */
399         case V4L2_PIX_FMT_YUYV:
400         case V4L2_PIX_FMT_YVU420:
401         case V4L2_PIX_FMT_UYVY:
402         case V4L2_PIX_FMT_Y41P: {
403                 guint32 fcc = 0;
404
405                 switch (fourcc) {
406                 case V4L2_PIX_FMT_YUV420:
407                         fcc = GST_MAKE_FOURCC('I','4','2','0');
408                         break;
409                 case V4L2_PIX_FMT_YUYV:
410                         fcc = GST_MAKE_FOURCC('Y','U','Y','2');
411                         break;
412                 case V4L2_PIX_FMT_YVU420:
413                         fcc = GST_MAKE_FOURCC('Y','V','1','2');
414                         break;
415                 case V4L2_PIX_FMT_UYVY:
416                         fcc = GST_MAKE_FOURCC('U','Y','V','Y');
417                         break;
418                 case V4L2_PIX_FMT_Y41P:
419                         fcc = GST_MAKE_FOURCC('Y','4','1','P');
420                         break;
421                 default:
422                         g_assert_not_reached();
423                         break;
424                 }
425
426                 caps = GST_CAPS_NEW("v4l2src_caps",
427                                     "video/raw",
428                                       "format", GST_PROPS_FOURCC(fcc),
429                                       NULL);
430                 break;
431         }
432         default:
433                 GST_DEBUG (
434                           "Unknown fourcc 0x%08x " GST_FOURCC_FORMAT ", trying default",
435                           fourcc, GST_FOURCC_ARGS(fourcc));
436
437                 /* add the standard one */
438                 if (compressed) {
439                         guint32 print_format = GUINT32_FROM_LE(fourcc);
440                         gchar *print_format_str = (gchar *) &print_format, *string_format;
441                         gint i;
442
443                         for (i=0;i<4;i++) {
444                                 print_format_str[i] =
445                                         g_ascii_tolower(print_format_str[i]);
446                         }
447                         string_format = g_strdup_printf("video/%4.4s",
448                                                         print_format_str);
449                         caps = GST_CAPS_NEW("v4l2src_caps",
450                                             string_format,
451                                               NULL);
452                         g_free(string_format);
453                 } else {
454                         caps = GST_CAPS_NEW("v4l2src_caps",
455                                             "video/raw",
456                                               "format",GST_PROPS_FOURCC(fourcc),
457                                               NULL);
458                 }
459                 break;
460         }
461
462         if (!caps->properties)
463                 caps->properties = gst_props_empty_new();
464         gst_props_add_entry(caps->properties, width);
465         gst_props_add_entry(caps->properties, height);
466
467         return caps;
468 }
469
470 #define gst_v4l2src_v4l2fourcc_to_caps_fixed(f, width, height,c) \
471         gst_v4l2src_v4l2fourcc_to_caps(f, \
472                                        gst_props_entry_new("width", \
473                                                            GST_PROPS_INT(width)), \
474                                        gst_props_entry_new("height", \
475                                                            GST_PROPS_INT(height)), \
476                                        c)
477
478 #define gst_v4l2src_v4l2fourcc_to_caps_range(f, min_w, max_w, min_h, max_h, c) \
479         gst_v4l2src_v4l2fourcc_to_caps(f, \
480                                        gst_props_entry_new("width", \
481                                                            GST_PROPS_INT_RANGE(min_w, max_w)), \
482                                        gst_props_entry_new("height", \
483                                                            GST_PROPS_INT_RANGE(min_h, max_h)), \
484                                        c)
485
486 static struct v4l2_fmtdesc *
487 gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src *v4l2src,
488                              GstCaps    *caps)
489 {
490         gint i;
491         guint32 fourcc = 0;
492         struct v4l2_fmtdesc *end_fmt = NULL;
493         const gchar *format = gst_caps_get_mime(caps);
494
495         if (!strcmp(format, "video/raw")) {
496                 /* non-compressed */
497                 gst_caps_get_fourcc_int(caps, "format", &fourcc);
498
499                 switch (fourcc) {
500                 case GST_MAKE_FOURCC('I','4','2','0'):
501                 case GST_MAKE_FOURCC('I','Y','U','V'):
502                         fourcc = V4L2_PIX_FMT_YUV420;
503                         break;
504                 case GST_MAKE_FOURCC('Y','U','Y','2'):
505                         fourcc = V4L2_PIX_FMT_YUYV;
506                         break;
507                 case GST_MAKE_FOURCC('Y','4','1','P'):
508                         fourcc = V4L2_PIX_FMT_Y41P;
509                         break;
510                 case GST_MAKE_FOURCC('U','Y','V','Y'):
511                         fourcc = V4L2_PIX_FMT_UYVY;
512                         break;
513                 case GST_MAKE_FOURCC('Y','V','1','2'):
514                         fourcc = V4L2_PIX_FMT_YVU420;
515                         break;
516                 case GST_MAKE_FOURCC('R','G','B',' '): {
517                         gint depth, endianness;
518
519                         gst_caps_get_int(caps, "depth", &depth);
520                         gst_caps_get_int(caps, "endianness", &endianness);
521
522                         switch (depth) {
523                         case 8:
524                                 fourcc = V4L2_PIX_FMT_RGB332;
525                                 break;
526                         case 15:
527                                 fourcc = (endianness == G_LITTLE_ENDIAN) ?
528                                          V4L2_PIX_FMT_RGB555 :
529                                          V4L2_PIX_FMT_RGB555X;
530                                 break;
531                         case 16:
532                                 fourcc = (endianness == G_LITTLE_ENDIAN) ?
533                                          V4L2_PIX_FMT_RGB565 :
534                                          V4L2_PIX_FMT_RGB565X;
535                                 break;
536                         case 24:
537                                 fourcc = (endianness == G_LITTLE_ENDIAN) ?
538                                          V4L2_PIX_FMT_BGR24 :
539                                          V4L2_PIX_FMT_RGB24;
540                                 break;
541                         case 32:
542                                 fourcc = (endianness == G_LITTLE_ENDIAN) ?
543                                          V4L2_PIX_FMT_BGR32 :
544                                          V4L2_PIX_FMT_RGB32;
545                                 break;
546                         }
547                 }
548                 default:
549                         break;
550                 }
551                 for (i=0;i<g_list_length(v4l2src->formats);i++) {
552                         struct v4l2_fmtdesc *fmt;
553                         fmt = (struct v4l2_fmtdesc *)
554                                 g_list_nth_data(v4l2src->formats, i);
555                         if (fmt->pixelformat == fourcc) {
556                                 end_fmt = fmt;
557                                 break;
558                         }
559                 }
560         } else {
561                 /* compressed */
562                 if (strncmp(format, "video/", 6))
563                         return NULL;
564                 format = &format[6];
565                 if (strlen(format) != 4)
566                         return NULL;
567                 fourcc = GST_MAKE_FOURCC(g_ascii_toupper(format[0]),
568                                          g_ascii_toupper(format[1]),
569                                          g_ascii_toupper(format[2]),
570                                          g_ascii_toupper(format[3]));
571
572                 switch (fourcc) {
573                 case GST_MAKE_FOURCC('J','P','E','G'): {
574                         struct v4l2_fmtdesc *fmt;
575                         for (i=0;i<g_list_length(v4l2src->formats);i++) {
576                                 fmt = g_list_nth_data(v4l2src->formats, i);
577                                 if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG ||
578                                     fmt->pixelformat == V4L2_PIX_FMT_JPEG) {
579                                         end_fmt = fmt;
580                                         break;
581                                 }
582                         }
583                         break;
584                 }
585                 default: {
586                         /* FIXME: check for fourcc in list */
587                         struct v4l2_fmtdesc *fmt;
588                         for (i=0;i<g_list_length(v4l2src->formats);i++) {
589                                 fmt = g_list_nth_data(v4l2src->formats, i);
590                                 if (fourcc == fmt->pixelformat) {
591                                         end_fmt = fmt;
592                                         break;
593                                 }
594                         }
595                         break;
596                 }
597                 }
598         }
599
600         return end_fmt;
601 }
602
603 #define gst_caps_get_int_range(caps, name, min, max) \
604         gst_props_entry_get_int_range(gst_props_get_entry((caps)->properties, \
605                                                           name), \
606                                       min, max)
607
608
609
610 static GstPadLinkReturn
611 gst_v4l2src_srcconnect (GstPad  *pad,
612                         GstCaps *vscapslist)
613 {
614         GstV4l2Src *v4l2src;
615         GstV4l2Element *v4l2element;
616         GstCaps *caps;
617         struct v4l2_fmtdesc *format;
618         int w, h;
619
620         v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
621         v4l2element = GST_V4L2ELEMENT(v4l2src);
622
623         /* clean up if we still haven't cleaned up our previous
624          * capture session */
625         if (GST_V4L2_IS_ACTIVE(v4l2element)) {
626                 if (!gst_v4l2src_capture_deinit(v4l2src))
627                         return GST_PAD_LINK_REFUSED;
628         } else if (!GST_V4L2_IS_OPEN(v4l2element)) {
629                 return GST_PAD_LINK_DELAYED;
630         }
631
632         for (caps = vscapslist; caps != NULL; caps = caps->next) {
633                 /* we want our own v4l2 type of fourcc codes */
634                 if (!(format = gst_v4l2_caps_to_v4l2fourcc(v4l2src, caps))) {
635                         continue;
636                 }
637                 if (gst_caps_has_property(caps, "width")) {
638                         if (gst_caps_has_fixed_property(caps, "width")) {
639                                 gst_caps_get_int(caps, "width", &w);
640                         } else {
641                                 int max;
642                                 gst_caps_get_int_range(caps, "width", &max, &w);
643                         }
644                 }
645                 if (gst_caps_has_property(caps, "height")) {
646                         if (gst_caps_has_fixed_property(caps, "height")) {
647                                 gst_caps_get_int(caps, "height", &h);
648                         } else {
649                                 int max;
650                                 gst_caps_get_int_range(caps, "height", &max, &h);
651                         }
652                 }
653
654                 /* we found the pixelformat! - try it out */
655                 if (gst_v4l2src_set_capture(v4l2src, format, w, h)) {
656                         /* it fits! Now, get the proper counterpart and retry
657                          * it on the other side (again...) - if it works, we're
658                          * done -> GST_PAD_LINK_OK */
659                         GstCaps *lastcaps;
660                         GstPadLinkReturn ret_val;
661
662                         lastcaps = gst_v4l2src_v4l2fourcc_to_caps_fixed(format->pixelformat,
663                                                 v4l2src->format.fmt.pix.width,
664                                                 v4l2src->format.fmt.pix.height,
665                                                 format->flags & V4L2_FMT_FLAG_COMPRESSED);
666
667                         ret_val = gst_pad_try_set_caps(v4l2src->srcpad,
668                                                        lastcaps);
669
670                         if (ret_val > 0) {
671                                 if (gst_v4l2src_capture_init(v4l2src)) {
672                                         return GST_PAD_LINK_DONE;
673                                 }
674                         } else if (ret_val == GST_PAD_LINK_DELAYED) {
675                                 return GST_PAD_LINK_DELAYED;
676                         }
677                 }
678         }
679
680         return GST_PAD_LINK_REFUSED;
681 }
682
683
684 static GstCaps *
685 gst_v4l2src_getcaps (GstPad  *pad,
686                      GstCaps *caps)
687 {
688         GstV4l2Src *v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
689         GstCaps *list = NULL;
690         gint i;
691         struct v4l2_fmtdesc *format;
692         int min_w, max_w, min_h, max_h;
693
694         if (!GST_V4L2_IS_OPEN(GST_V4L2ELEMENT(v4l2src))) {
695                 return NULL;
696         }
697
698         /* build our own capslist */
699         for (i=0;i<g_list_length(v4l2src->formats);i++) {
700                 format = g_list_nth_data(v4l2src->formats, i);
701
702                 /* get size delimiters */
703                 if (!gst_v4l2src_get_size_limits(v4l2src, format,
704                                                  &min_w, &max_w,
705                                                  &min_h, &max_h)) {
706                         continue;
707                 }
708
709                 /* add to list */
710                 caps = gst_v4l2src_v4l2fourcc_to_caps_range(format->pixelformat,
711                                                             min_w, max_w,
712                                                             min_h, max_h,
713                                                             format->flags & V4L2_FMT_FLAG_COMPRESSED);
714
715                 list = gst_caps_append(list, caps);
716         }
717
718         return list;
719 }
720
721
722 static GstBuffer*
723 gst_v4l2src_get (GstPad *pad)
724 {
725         GstV4l2Src *v4l2src;
726         GstBuffer *buf;
727         gint num;
728         gdouble fps = 0;
729
730         g_return_val_if_fail (pad != NULL, NULL);
731
732         v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
733
734         if (v4l2src->use_fixed_fps &&
735             (fps = gst_v4l2src_get_fps(v4l2src)) == 0)
736                 return NULL;
737
738         buf = gst_buffer_new_from_pool(v4l2src->bufferpool, 0, 0);
739         if (!buf) {
740                 gst_element_error(GST_ELEMENT(v4l2src),
741                         "Failed to create a new GstBuffer");
742                 return NULL;
743         }
744
745         if (v4l2src->need_writes > 0) {
746                 /* use last frame */
747                 num = v4l2src->last_frame;
748                 v4l2src->need_writes--;
749         } else if (v4l2src->clock && v4l2src->use_fixed_fps) {
750                 GstClockTime time;
751                 gboolean have_frame = FALSE;
752
753                 do {
754                         /* by default, we use the frame once */
755                         v4l2src->need_writes = 1;
756
757                         /* grab a frame from the device */
758                         if (!gst_v4l2src_grab_frame(v4l2src, &num))
759                                 return NULL;
760
761                         v4l2src->last_frame = num;
762                         time = GST_TIMEVAL_TO_TIME(v4l2src->bufsettings.timestamp) -
763                                  v4l2src->substract_time;
764
765                         /* first check whether we lost any frames according to the device */
766                         if (v4l2src->last_seq != 0) {
767                                 if (v4l2src->bufsettings.sequence - v4l2src->last_seq > 1) {
768                                         v4l2src->need_writes = v4l2src->bufsettings.sequence -
769                                                                  v4l2src->last_seq;
770                                         g_signal_emit(G_OBJECT(v4l2src),
771                                                       gst_v4l2src_signals[SIGNAL_FRAME_LOST],
772                                                       0,
773                                                       v4l2src->bufsettings.sequence -
774                                                         v4l2src->last_seq - 1);
775                                 }
776                         }
777                         v4l2src->last_seq = v4l2src->bufsettings.sequence;
778
779                         /* decide how often we're going to write the frame - set
780                          * v4lmjpegsrc->need_writes to (that-1) and have_frame to TRUE
781                          * if we're going to write it - else, just continue.
782                          * 
783                          * time is generally the system or audio clock. Let's
784                          * say that we've written one second of audio, then we want
785                          * to have written one second of video too, within the same
786                          * timeframe. This means that if time - begin_time = X sec,
787                          * we want to have written X*fps frames. If we've written
788                          * more - drop, if we've written less - dup... */
789                         if (v4l2src->handled * (GST_SECOND/fps) - time >
790                             1.5 * (GST_SECOND/fps)) {
791                                 /* yo dude, we've got too many frames here! Drop! DROP! */
792                                 v4l2src->need_writes--; /* -= (v4l2src->handled - (time / fps)); */
793                                 g_signal_emit(G_OBJECT(v4l2src),
794                                               gst_v4l2src_signals[SIGNAL_FRAME_DROP], 0);
795                         } else if (v4l2src->handled * (GST_SECOND/fps) - time <
796                                      -1.5 * (GST_SECOND/fps)) {
797                                 /* this means we're lagging far behind */
798                                 v4l2src->need_writes++; /* += ((time / fps) - v4l2src->handled); */
799                                 g_signal_emit(G_OBJECT(v4l2src),
800                                               gst_v4l2src_signals[SIGNAL_FRAME_INSERT], 0);
801                         }
802
803                         if (v4l2src->need_writes > 0) {
804                                 have_frame = TRUE;
805                                 v4l2src->use_num_times[num] = v4l2src->need_writes;
806                                 v4l2src->need_writes--;
807                         } else {
808                                 gst_v4l2src_requeue_frame(v4l2src, num);
809                         }
810                 } while (!have_frame);
811         } else {
812                 /* grab a frame from the device */
813                 if (!gst_v4l2src_grab_frame(v4l2src, &num))
814                         return NULL;
815
816                 v4l2src->use_num_times[num] = 1;
817         }
818
819         GST_BUFFER_DATA(buf) = gst_v4l2src_get_buffer(v4l2src, num);
820         GST_BUFFER_SIZE(buf) = v4l2src->bufsettings.bytesused;
821         if (v4l2src->use_fixed_fps)
822                 GST_BUFFER_TIMESTAMP(buf) = v4l2src->handled * GST_SECOND / fps;
823         else /* calculate time based on our own clock */
824                 GST_BUFFER_TIMESTAMP(buf) = GST_TIMEVAL_TO_TIME(v4l2src->bufsettings.timestamp) -
825                                               v4l2src->substract_time;
826
827         v4l2src->handled++;
828         g_signal_emit(G_OBJECT(v4l2src),
829                       gst_v4l2src_signals[SIGNAL_FRAME_CAPTURE], 0);
830
831         return buf;
832 }
833
834
835 static void
836 gst_v4l2src_set_property (GObject      *object,
837                           guint        prop_id,
838                           const GValue *value,
839                           GParamSpec   *pspec)
840 {
841         GstV4l2Src *v4l2src;
842
843         g_return_if_fail(GST_IS_V4L2SRC(object));
844         v4l2src = GST_V4L2SRC(object);
845
846         switch (prop_id) {
847                 case ARG_NUMBUFS:
848                         if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
849                                 v4l2src->breq.count = g_value_get_int(value);
850                         }
851                         break;
852
853                 case ARG_USE_FIXED_FPS:
854                         if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
855                                 v4l2src->use_fixed_fps = g_value_get_boolean(value);
856                         }
857                         break;
858
859                 default:
860                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
861                         break;
862         }
863 }
864
865
866 static void
867 gst_v4l2src_get_property (GObject    *object,
868                           guint      prop_id,
869                           GValue     *value,
870                           GParamSpec *pspec)
871 {
872         GstV4l2Src *v4l2src;
873
874         g_return_if_fail(GST_IS_V4L2SRC(object));
875         v4l2src = GST_V4L2SRC(object);
876
877         switch (prop_id) {
878                 case ARG_NUMBUFS:
879                         g_value_set_int(value, v4l2src->breq.count);
880                         break;
881
882                 case ARG_BUFSIZE:
883                         g_value_set_int(value, v4l2src->format.fmt.pix.sizeimage);
884                         break;
885
886                 case ARG_USE_FIXED_FPS:
887                         g_value_set_boolean(value, v4l2src->use_fixed_fps);
888                         break;
889
890                 default:
891                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
892                         break;
893         }
894 }
895
896
897 static GstElementStateReturn
898 gst_v4l2src_change_state (GstElement *element)
899 {
900         GstV4l2Src *v4l2src;
901         gint transition = GST_STATE_TRANSITION (element);
902         GstElementStateReturn parent_return;
903         GTimeVal time;
904
905         g_return_val_if_fail(GST_IS_V4L2SRC(element), GST_STATE_FAILURE);
906         v4l2src = GST_V4L2SRC(element);
907
908         if (GST_ELEMENT_CLASS (parent_class)->change_state) {
909                 parent_return = GST_ELEMENT_CLASS (parent_class)->change_state (element);
910                 if (parent_return != GST_STATE_SUCCESS)
911                         return parent_return;
912         }
913
914         switch (transition) {
915                 case GST_STATE_NULL_TO_READY:
916                         if (!gst_v4l2src_get_capture(v4l2src))
917                                 return GST_STATE_FAILURE;
918                         break;
919                 case GST_STATE_READY_TO_PAUSED:
920                         v4l2src->handled = 0;
921                         v4l2src->need_writes = 0;
922                         v4l2src->last_frame = 0;
923                         v4l2src->substract_time = 0;
924                         /* buffer setup moved to capsnego */
925                         break;
926                 case GST_STATE_PAUSED_TO_PLAYING:
927                         /* queue all buffer, start streaming capture */
928                         if (!gst_v4l2src_capture_start(v4l2src))
929                                 return GST_STATE_FAILURE;
930                         g_get_current_time(&time);
931                         v4l2src->substract_time = GST_TIMEVAL_TO_TIME(time) -
932                                                     v4l2src->substract_time;
933                         v4l2src->last_seq = 0;
934                         break;
935                 case GST_STATE_PLAYING_TO_PAUSED:
936                         g_get_current_time(&time);
937                         v4l2src->substract_time = GST_TIMEVAL_TO_TIME(time) -
938                                                     v4l2src->substract_time;
939                         /* de-queue all queued buffers */
940                         if (!gst_v4l2src_capture_stop(v4l2src))
941                                 return GST_STATE_FAILURE;
942                         break;
943                 case GST_STATE_PAUSED_TO_READY:
944                         /* stop capturing, unmap all buffers */
945                         if (!gst_v4l2src_capture_deinit(v4l2src))
946                                 return GST_STATE_FAILURE;
947                         break;
948                 case GST_STATE_READY_TO_NULL:
949                         break;
950         }
951
952         return GST_STATE_SUCCESS;
953 }
954
955
956 static void
957 gst_v4l2src_set_clock (GstElement *element,
958                            GstClock   *clock)
959 {
960         GST_V4L2SRC(element)->clock = clock;
961 }
962
963
964 static GstBuffer*
965 gst_v4l2src_buffer_new (GstBufferPool *pool,
966                         guint64        offset,
967                         guint          size,
968                         gpointer       user_data)
969 {
970         GstBuffer *buffer;
971         GstV4l2Src *v4l2src = GST_V4L2SRC(user_data);
972
973         if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src)))
974                 return NULL;
975
976         buffer = gst_buffer_new();
977         if (!buffer)
978                 return NULL;
979
980         /* TODO: add interlacing info to buffer as metadata
981          * (height>288 or 240 = topfieldfirst, else noninterlaced) */
982         GST_BUFFER_MAXSIZE(buffer) = v4l2src->bufsettings.length;
983         GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
984
985         return buffer;
986 }
987
988
989 static void
990 gst_v4l2src_buffer_free (GstBufferPool *pool,
991                          GstBuffer     *buf,
992                          gpointer      user_data)
993 {
994         GstV4l2Src *v4l2src = GST_V4L2SRC(user_data);
995         int n;
996
997         if (gst_element_get_state(GST_ELEMENT(v4l2src)) != GST_STATE_PLAYING)
998                 return; /* we've already cleaned up ourselves */
999
1000         for (n=0;n<v4l2src->breq.count;n++)
1001                 if (GST_BUFFER_DATA(buf) == gst_v4l2src_get_buffer(v4l2src, n)) {
1002                         v4l2src->use_num_times[n]--;
1003                         if (v4l2src->use_num_times[n] <= 0) {
1004                                 gst_v4l2src_requeue_frame(v4l2src, n);
1005                         }
1006                         break;
1007                 }
1008
1009         if (n == v4l2src->breq.count)
1010                 gst_element_error(GST_ELEMENT(v4l2src),
1011                         "Couldn\'t find the buffer");
1012
1013         /* free the buffer itself */
1014         gst_buffer_default_free(buf);
1015 }
1016
1017
1018 static gboolean
1019 plugin_init (GModule   *module,
1020              GstPlugin *plugin)
1021 {
1022         GstElementFactory *factory;
1023
1024         /* create an elementfactory for the v4l2src */
1025         factory = gst_element_factory_new("v4l2src", GST_TYPE_V4L2SRC,
1026                                 &gst_v4l2src_details);
1027         g_return_val_if_fail(factory != NULL, FALSE);
1028
1029         src_template = gst_pad_template_new("src",
1030                                 GST_PAD_SRC,
1031                                 GST_PAD_ALWAYS,
1032                                 NULL);
1033
1034         gst_element_factory_add_pad_template(factory, src_template);
1035
1036         gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE(factory));
1037
1038         return TRUE;
1039 }
1040
1041
1042 GstPluginDesc plugin_desc = {
1043         GST_VERSION_MAJOR,
1044         GST_VERSION_MINOR,
1045         "v4l2src",
1046         plugin_init
1047 };