1 /* G-Streamer Video4linux2 video-capture plugin
2 * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
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.
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.
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.
22 #include "v4l2src_calls.h"
24 /* elementfactory details */
25 static GstElementDetails gst_v4l2src_details = {
26 "Video (video4linux2) Source",
29 "Reads frames (compressed or uncompressed) from a video4linux2 device",
31 "Ronald Bultje <rbultje@ronald.bitfreak.net>",
35 /* V4l2Src signals and args */
54 static void gst_v4l2src_class_init (GstV4l2SrcClass *klass);
55 static void gst_v4l2src_init (GstV4l2Src *v4l2src);
57 /* signal functions */
58 static void gst_v4l2src_open (GstElement *element,
60 static void gst_v4l2src_close (GstElement *element,
63 /* pad/buffer functions */
64 static gboolean gst_v4l2src_srcconvert (GstPad *pad,
67 GstFormat *dest_format,
69 static GstPadLinkReturn gst_v4l2src_srcconnect (GstPad *pad,
71 static GstCaps * gst_v4l2src_getcaps (GstPad *pad,
73 static GstBuffer * gst_v4l2src_get (GstPad *pad);
76 static void gst_v4l2src_set_property (GObject *object,
80 static void gst_v4l2src_get_property (GObject *object,
86 static GstElementStateReturn gst_v4l2src_change_state (GstElement *element);
88 /* set_clock function for A/V sync */
89 static void gst_v4l2src_set_clock (GstElement *element,
93 /* bufferpool functions */
94 static GstBuffer * gst_v4l2src_buffer_new (GstBufferPool *pool,
98 static void gst_v4l2src_buffer_free (GstBufferPool *pool,
103 static GstPadTemplate *src_template;
105 static GstElementClass *parent_class = NULL;
106 static guint gst_v4l2src_signals[LAST_SIGNAL] = { 0 };
110 gst_v4l2src_get_type (void)
112 static GType v4l2src_type = 0;
115 static const GTypeInfo v4l2src_info = {
116 sizeof(GstV4l2SrcClass),
119 (GClassInitFunc) gst_v4l2src_class_init,
124 (GInstanceInitFunc) gst_v4l2src_init,
127 v4l2src_type = g_type_register_static(GST_TYPE_V4L2ELEMENT,
128 "GstV4l2Src", &v4l2src_info, 0);
135 gst_v4l2src_class_init (GstV4l2SrcClass *klass)
137 GObjectClass *gobject_class;
138 GstElementClass *gstelement_class;
139 GstV4l2ElementClass *v4l2_class;
141 gobject_class = (GObjectClass*)klass;
142 gstelement_class = (GstElementClass*)klass;
143 v4l2_class = (GstV4l2ElementClass*)klass;
145 parent_class = g_type_class_ref(GST_TYPE_V4L2ELEMENT);
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));
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));
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,
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,
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,
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);
183 gobject_class->set_property = gst_v4l2src_set_property;
184 gobject_class->get_property = gst_v4l2src_get_property;
186 gstelement_class->change_state = gst_v4l2src_change_state;
188 v4l2_class->open = gst_v4l2src_open;
189 v4l2_class->close = gst_v4l2src_close;
191 gstelement_class->set_clock = gst_v4l2src_set_clock;
196 gst_v4l2src_init (GstV4l2Src *v4l2src)
198 GST_FLAG_SET(GST_ELEMENT(v4l2src), GST_ELEMENT_THREAD_SUGGESTED);
200 v4l2src->srcpad = gst_pad_new_from_template(src_template, "src");
201 gst_element_add_pad(GST_ELEMENT(v4l2src), v4l2src->srcpad);
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);
208 v4l2src->bufferpool = gst_buffer_pool_new(NULL, NULL,
209 gst_v4l2src_buffer_new,
211 gst_v4l2src_buffer_free,
214 v4l2src->breq.count = 0;
216 v4l2src->formats = NULL;
217 v4l2src->format_list = NULL;
220 v4l2src->clock = NULL;
223 v4l2src->use_fixed_fps = TRUE;
228 gst_v4l2src_open (GstElement *element,
231 gst_v4l2src_fill_format_list(GST_V4L2SRC(element));
236 gst_v4l2src_close (GstElement *element,
239 gst_v4l2src_empty_format_list(GST_V4L2SRC(element));
244 gst_v4l2src_get_fps (GstV4l2Src *v4l2src)
247 struct v4l2_standard *std;
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;
259 /* if that failed ... */
261 if (!GST_V4L2_IS_OPEN(GST_V4L2ELEMENT(v4l2src)))
264 if (!gst_v4l2_get_norm(GST_V4L2ELEMENT(v4l2src), &norm))
267 std = ((struct v4l2_standard *) g_list_nth_data(GST_V4L2ELEMENT(v4l2src)->norms, norm));
268 fps = (1. * std->frameperiod.denominator) / std->frameperiod.numerator;
275 gst_v4l2src_srcconvert (GstPad *pad,
276 GstFormat src_format,
278 GstFormat *dest_format,
284 v4l2src = GST_V4L2SRC (gst_pad_get_parent (pad));
286 if ((fps = gst_v4l2src_get_fps(v4l2src)) == 0)
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;
300 case GST_FORMAT_DEFAULT:
301 switch (*dest_format) {
302 case GST_FORMAT_TIME:
303 *dest_value = src_value * GST_SECOND / fps;
319 gst_v4l2src_v4l2fourcc_to_caps (guint32 fourcc,
320 GstPropsEntry *width,
321 GstPropsEntry *height,
324 GstCaps *caps = NULL;
327 case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */
328 case V4L2_PIX_FMT_JPEG: /* JFIF JPEG */
329 caps = GST_CAPS_NEW("v4l2src_caps",
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;
344 guint32 r_mask = 0, b_mask = 0, g_mask = 0;
345 guint32 fcc = GST_MAKE_FOURCC('R','G','B',' ');
348 case V4L2_PIX_FMT_RGB332:
350 endianness = G_BYTE_ORDER; /* 'like, whatever' */
351 r_mask = 0xe0; g_mask = 0x1c; b_mask = 0x03;
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;
360 case V4L2_PIX_FMT_RGB565:
361 case V4L2_PIX_FMT_RGB565X:
363 endianness = (fourcc == V4L2_PIX_FMT_RGB565) ?
364 G_LITTLE_ENDIAN : G_BIG_ENDIAN;
365 r_mask = 0xf800; g_mask = 0x07e0; b_mask = 0x001f;
367 case V4L2_PIX_FMT_RGB24:
368 case V4L2_PIX_FMT_BGR24:
370 endianness = (fourcc == V4L2_PIX_FMT_BGR24) ?
371 G_LITTLE_ENDIAN : G_BIG_ENDIAN;
372 r_mask = 0xff0000; g_mask = 0x00ff00; b_mask = 0x0000ff;
374 case V4L2_PIX_FMT_RGB32:
375 case V4L2_PIX_FMT_BGR32:
377 endianness = (fourcc == V4L2_PIX_FMT_BGR32) ?
378 G_LITTLE_ENDIAN : G_BIG_ENDIAN;
379 r_mask = 0x00ff0000; g_mask = 0x0000ff00; b_mask = 0x000000ff;
382 g_assert_not_reached();
386 caps = GST_CAPS_NEW("v4l2src_caps",
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),
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: {
406 case V4L2_PIX_FMT_YUV420:
407 fcc = GST_MAKE_FOURCC('I','4','2','0');
409 case V4L2_PIX_FMT_YUYV:
410 fcc = GST_MAKE_FOURCC('Y','U','Y','2');
412 case V4L2_PIX_FMT_YVU420:
413 fcc = GST_MAKE_FOURCC('Y','V','1','2');
415 case V4L2_PIX_FMT_UYVY:
416 fcc = GST_MAKE_FOURCC('U','Y','V','Y');
418 case V4L2_PIX_FMT_Y41P:
419 fcc = GST_MAKE_FOURCC('Y','4','1','P');
422 g_assert_not_reached();
426 caps = GST_CAPS_NEW("v4l2src_caps",
428 "format", GST_PROPS_FOURCC(fcc),
434 "Unknown fourcc 0x%08x " GST_FOURCC_FORMAT ", trying default",
435 fourcc, GST_FOURCC_ARGS(fourcc));
437 /* add the standard one */
439 guint32 print_format = GUINT32_FROM_LE(fourcc);
440 gchar *print_format_str = (gchar *) &print_format, *string_format;
444 print_format_str[i] =
445 g_ascii_tolower(print_format_str[i]);
447 string_format = g_strdup_printf("video/%4.4s",
449 caps = GST_CAPS_NEW("v4l2src_caps",
452 g_free(string_format);
454 caps = GST_CAPS_NEW("v4l2src_caps",
456 "format",GST_PROPS_FOURCC(fourcc),
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);
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)), \
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)), \
486 static struct v4l2_fmtdesc *
487 gst_v4l2_caps_to_v4l2fourcc (GstV4l2Src *v4l2src,
492 struct v4l2_fmtdesc *end_fmt = NULL;
493 const gchar *format = gst_caps_get_mime(caps);
495 if (!strcmp(format, "video/raw")) {
497 gst_caps_get_fourcc_int(caps, "format", &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;
504 case GST_MAKE_FOURCC('Y','U','Y','2'):
505 fourcc = V4L2_PIX_FMT_YUYV;
507 case GST_MAKE_FOURCC('Y','4','1','P'):
508 fourcc = V4L2_PIX_FMT_Y41P;
510 case GST_MAKE_FOURCC('U','Y','V','Y'):
511 fourcc = V4L2_PIX_FMT_UYVY;
513 case GST_MAKE_FOURCC('Y','V','1','2'):
514 fourcc = V4L2_PIX_FMT_YVU420;
516 case GST_MAKE_FOURCC('R','G','B',' '): {
517 gint depth, endianness;
519 gst_caps_get_int(caps, "depth", &depth);
520 gst_caps_get_int(caps, "endianness", &endianness);
524 fourcc = V4L2_PIX_FMT_RGB332;
527 fourcc = (endianness == G_LITTLE_ENDIAN) ?
528 V4L2_PIX_FMT_RGB555 :
529 V4L2_PIX_FMT_RGB555X;
532 fourcc = (endianness == G_LITTLE_ENDIAN) ?
533 V4L2_PIX_FMT_RGB565 :
534 V4L2_PIX_FMT_RGB565X;
537 fourcc = (endianness == G_LITTLE_ENDIAN) ?
542 fourcc = (endianness == G_LITTLE_ENDIAN) ?
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) {
562 if (strncmp(format, "video/", 6))
565 if (strlen(format) != 4)
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]));
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) {
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) {
603 #define gst_caps_get_int_range(caps, name, min, max) \
604 gst_props_entry_get_int_range(gst_props_get_entry((caps)->properties, \
610 static GstPadLinkReturn
611 gst_v4l2src_srcconnect (GstPad *pad,
615 GstV4l2Element *v4l2element;
617 struct v4l2_fmtdesc *format;
620 v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
621 v4l2element = GST_V4L2ELEMENT(v4l2src);
623 /* clean up if we still haven't cleaned up our previous
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;
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))) {
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);
642 gst_caps_get_int_range(caps, "width", &max, &w);
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);
650 gst_caps_get_int_range(caps, "height", &max, &h);
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 */
660 GstPadLinkReturn ret_val;
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);
667 ret_val = gst_pad_try_set_caps(v4l2src->srcpad,
671 if (gst_v4l2src_capture_init(v4l2src)) {
672 return GST_PAD_LINK_DONE;
674 } else if (ret_val == GST_PAD_LINK_DELAYED) {
675 return GST_PAD_LINK_DELAYED;
680 return GST_PAD_LINK_REFUSED;
685 gst_v4l2src_getcaps (GstPad *pad,
688 GstV4l2Src *v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
689 GstCaps *list = NULL;
691 struct v4l2_fmtdesc *format;
692 int min_w, max_w, min_h, max_h;
694 if (!GST_V4L2_IS_OPEN(GST_V4L2ELEMENT(v4l2src))) {
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);
702 /* get size delimiters */
703 if (!gst_v4l2src_get_size_limits(v4l2src, format,
710 caps = gst_v4l2src_v4l2fourcc_to_caps_range(format->pixelformat,
713 format->flags & V4L2_FMT_FLAG_COMPRESSED);
715 list = gst_caps_append(list, caps);
723 gst_v4l2src_get (GstPad *pad)
730 g_return_val_if_fail (pad != NULL, NULL);
732 v4l2src = GST_V4L2SRC(gst_pad_get_parent (pad));
734 if (v4l2src->use_fixed_fps &&
735 (fps = gst_v4l2src_get_fps(v4l2src)) == 0)
738 buf = gst_buffer_new_from_pool(v4l2src->bufferpool, 0, 0);
740 gst_element_error(GST_ELEMENT(v4l2src),
741 "Failed to create a new GstBuffer");
745 if (v4l2src->need_writes > 0) {
747 num = v4l2src->last_frame;
748 v4l2src->need_writes--;
749 } else if (v4l2src->clock && v4l2src->use_fixed_fps) {
751 gboolean have_frame = FALSE;
754 /* by default, we use the frame once */
755 v4l2src->need_writes = 1;
757 /* grab a frame from the device */
758 if (!gst_v4l2src_grab_frame(v4l2src, &num))
761 v4l2src->last_frame = num;
762 time = GST_TIMEVAL_TO_TIME(v4l2src->bufsettings.timestamp) -
763 v4l2src->substract_time;
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 -
770 g_signal_emit(G_OBJECT(v4l2src),
771 gst_v4l2src_signals[SIGNAL_FRAME_LOST],
773 v4l2src->bufsettings.sequence -
774 v4l2src->last_seq - 1);
777 v4l2src->last_seq = v4l2src->bufsettings.sequence;
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.
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);
803 if (v4l2src->need_writes > 0) {
805 v4l2src->use_num_times[num] = v4l2src->need_writes;
806 v4l2src->need_writes--;
808 gst_v4l2src_requeue_frame(v4l2src, num);
810 } while (!have_frame);
812 /* grab a frame from the device */
813 if (!gst_v4l2src_grab_frame(v4l2src, &num))
816 v4l2src->use_num_times[num] = 1;
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;
828 g_signal_emit(G_OBJECT(v4l2src),
829 gst_v4l2src_signals[SIGNAL_FRAME_CAPTURE], 0);
836 gst_v4l2src_set_property (GObject *object,
843 g_return_if_fail(GST_IS_V4L2SRC(object));
844 v4l2src = GST_V4L2SRC(object);
848 if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src))) {
849 v4l2src->breq.count = g_value_get_int(value);
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);
860 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
867 gst_v4l2src_get_property (GObject *object,
874 g_return_if_fail(GST_IS_V4L2SRC(object));
875 v4l2src = GST_V4L2SRC(object);
879 g_value_set_int(value, v4l2src->breq.count);
883 g_value_set_int(value, v4l2src->format.fmt.pix.sizeimage);
886 case ARG_USE_FIXED_FPS:
887 g_value_set_boolean(value, v4l2src->use_fixed_fps);
891 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
897 static GstElementStateReturn
898 gst_v4l2src_change_state (GstElement *element)
901 gint transition = GST_STATE_TRANSITION (element);
902 GstElementStateReturn parent_return;
905 g_return_val_if_fail(GST_IS_V4L2SRC(element), GST_STATE_FAILURE);
906 v4l2src = GST_V4L2SRC(element);
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;
914 switch (transition) {
915 case GST_STATE_NULL_TO_READY:
916 if (!gst_v4l2src_get_capture(v4l2src))
917 return GST_STATE_FAILURE;
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 */
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;
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;
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;
948 case GST_STATE_READY_TO_NULL:
952 return GST_STATE_SUCCESS;
957 gst_v4l2src_set_clock (GstElement *element,
960 GST_V4L2SRC(element)->clock = clock;
965 gst_v4l2src_buffer_new (GstBufferPool *pool,
971 GstV4l2Src *v4l2src = GST_V4L2SRC(user_data);
973 if (!GST_V4L2_IS_ACTIVE(GST_V4L2ELEMENT(v4l2src)))
976 buffer = gst_buffer_new();
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);
990 gst_v4l2src_buffer_free (GstBufferPool *pool,
994 GstV4l2Src *v4l2src = GST_V4L2SRC(user_data);
997 if (gst_element_get_state(GST_ELEMENT(v4l2src)) != GST_STATE_PLAYING)
998 return; /* we've already cleaned up ourselves */
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);
1009 if (n == v4l2src->breq.count)
1010 gst_element_error(GST_ELEMENT(v4l2src),
1011 "Couldn\'t find the buffer");
1013 /* free the buffer itself */
1014 gst_buffer_default_free(buf);
1019 plugin_init (GModule *module,
1022 GstElementFactory *factory;
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);
1029 src_template = gst_pad_template_new("src",
1034 gst_element_factory_add_pad_template(factory, src_template);
1036 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE(factory));
1042 GstPluginDesc plugin_desc = {