3 * gstv4lsrc.c: BT8x8/V4L source element
5 * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
29 #include "v4lsrc_calls.h"
30 #include <sys/ioctl.h>
33 GST_DEBUG_CATEGORY_STATIC (v4lsrc_debug);
34 #define GST_CAT_DEFAULT v4lsrc_debug
47 GST_BOILERPLATE (GstV4lSrc, gst_v4lsrc, GstV4lElement, GST_TYPE_V4LELEMENT);
49 static GstStaticPadTemplate v4l_src_template = GST_STATIC_PAD_TEMPLATE ("src",
52 GST_STATIC_CAPS ("ANY")
56 static gboolean gst_v4lsrc_start (GstBaseSrc * src);
57 static gboolean gst_v4lsrc_stop (GstBaseSrc * src);
58 static gboolean gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps);
59 static GstCaps *gst_v4lsrc_get_caps (GstBaseSrc * src);
60 static GstFlowReturn gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** out);
61 static gboolean gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query);
62 static void gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps);
64 static void gst_v4lsrc_set_property (GObject * object,
65 guint prop_id, const GValue * value, GParamSpec * pspec);
66 static void gst_v4lsrc_get_property (GObject * object,
67 guint prop_id, GValue * value, GParamSpec * pspec);
71 gst_v4lsrc_base_init (gpointer g_class)
73 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
75 gst_element_class_set_details_simple (gstelement_class,
76 "Video (video4linux/raw) Source", "Source/Video",
77 "Reads raw frames from a video4linux device",
78 "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
80 gst_element_class_add_pad_template (gstelement_class,
81 gst_static_pad_template_get (&v4l_src_template));
85 gst_v4lsrc_class_init (GstV4lSrcClass * klass)
87 GObjectClass *gobject_class;
88 GstBaseSrcClass *basesrc_class;
89 GstPushSrcClass *pushsrc_class;
91 gobject_class = (GObjectClass *) klass;
92 basesrc_class = (GstBaseSrcClass *) klass;
93 pushsrc_class = (GstPushSrcClass *) klass;
95 gobject_class->set_property = gst_v4lsrc_set_property;
96 gobject_class->get_property = gst_v4lsrc_get_property;
98 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE,
99 g_param_spec_boolean ("autoprobe", "Autoprobe",
100 "Whether the device should be probed for all possible features",
101 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
102 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_AUTOPROBE_FPS,
103 g_param_spec_boolean ("autoprobe-fps", "Autoprobe FPS",
104 "Whether the device should be probed for framerates",
105 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
106 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_COPY_MODE,
107 g_param_spec_boolean ("copy-mode", "Copy mode",
108 "Whether to send out copies of buffers, or direct pointers to the mmap region",
109 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
110 g_object_class_install_property (G_OBJECT_CLASS (klass),
111 PROP_TIMESTAMP_OFFSET, g_param_spec_int64 ("timestamp-offset",
113 "A time offset subtracted from timestamps set on buffers (in ns)",
114 G_MININT64, G_MAXINT64, 0,
115 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
117 GST_DEBUG_CATEGORY_INIT (v4lsrc_debug, "v4lsrc", 0, "V4L source element");
119 basesrc_class->get_caps = gst_v4lsrc_get_caps;
120 basesrc_class->set_caps = gst_v4lsrc_set_caps;
121 basesrc_class->start = gst_v4lsrc_start;
122 basesrc_class->stop = gst_v4lsrc_stop;
123 basesrc_class->fixate = gst_v4lsrc_fixate;
124 basesrc_class->query = gst_v4lsrc_query;
126 pushsrc_class->create = gst_v4lsrc_create;
130 gst_v4lsrc_init (GstV4lSrc * v4lsrc, GstV4lSrcClass * klass)
132 v4lsrc->buffer_size = 0;
135 v4lsrc->colorspaces = NULL;
137 v4lsrc->is_capturing = FALSE;
138 v4lsrc->autoprobe = TRUE;
139 v4lsrc->autoprobe_fps = TRUE;
140 v4lsrc->copy_mode = TRUE;
142 v4lsrc->timestamp_offset = 0;
144 v4lsrc->fps_list = NULL;
146 gst_base_src_set_format (GST_BASE_SRC (v4lsrc), GST_FORMAT_TIME);
147 gst_base_src_set_live (GST_BASE_SRC (v4lsrc), TRUE);
151 gst_v4lsrc_set_property (GObject * object,
152 guint prop_id, const GValue * value, GParamSpec * pspec)
154 GstV4lSrc *v4lsrc = GST_V4LSRC (object);
158 g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)));
159 v4lsrc->autoprobe = g_value_get_boolean (value);
161 case PROP_AUTOPROBE_FPS:
162 g_return_if_fail (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc)));
163 v4lsrc->autoprobe_fps = g_value_get_boolean (value);
166 v4lsrc->copy_mode = g_value_get_boolean (value);
168 case PROP_TIMESTAMP_OFFSET:
169 v4lsrc->timestamp_offset = g_value_get_int64 (value);
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
179 gst_v4lsrc_get_property (GObject * object,
180 guint prop_id, GValue * value, GParamSpec * pspec)
182 GstV4lSrc *v4lsrc = GST_V4LSRC (object);
186 g_value_set_boolean (value, v4lsrc->autoprobe);
188 case PROP_AUTOPROBE_FPS:
189 g_value_set_boolean (value, v4lsrc->autoprobe_fps);
192 g_value_set_boolean (value, v4lsrc->copy_mode);
194 case PROP_TIMESTAMP_OFFSET:
195 g_value_set_int64 (value, v4lsrc->timestamp_offset);
198 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
203 /* this function is a bit of a last resort */
205 gst_v4lsrc_fixate (GstBaseSrc * bsrc, GstCaps * caps)
207 GstStructure *structure;
209 int targetwidth, targetheight;
210 GstV4lSrc *v4lsrc = GST_V4LSRC (bsrc);
211 struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
212 struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
214 if (GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
215 GST_DEBUG_OBJECT (v4lsrc, "device reported w: %d-%d, h: %d-%d",
216 vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight);
217 targetwidth = vcap->minwidth;
218 targetheight = vcap->minheight;
219 /* if we can get the current vwin settings, we use those to fixate */
220 if (!gst_v4l_get_capabilities (GST_V4LELEMENT (v4lsrc)))
221 GST_DEBUG_OBJECT (v4lsrc, "failed getting capabilities");
223 targetwidth = vwin->width;
224 targetheight = vwin->height;
227 GST_DEBUG_OBJECT (v4lsrc, "device closed, guessing");
232 GST_DEBUG_OBJECT (v4lsrc, "targetting %dx%d", targetwidth, targetheight);
234 for (i = 0; i < gst_caps_get_size (caps); ++i) {
237 structure = gst_caps_get_structure (caps, i);
238 gst_structure_fixate_field_nearest_int (structure, "width", targetwidth);
239 gst_structure_fixate_field_nearest_int (structure, "height", targetheight);
240 gst_structure_fixate_field_nearest_fraction (structure, "framerate", 15, 2);
242 v = gst_structure_get_value (structure, "format");
243 if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
246 g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST);
248 fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0));
249 gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
254 static gint all_palettes[] = {
255 VIDEO_PALETTE_YUV422,
256 VIDEO_PALETTE_YUV420P,
258 VIDEO_PALETTE_YUV411P,
259 VIDEO_PALETTE_YUV422P,
260 VIDEO_PALETTE_YUV410P,
261 VIDEO_PALETTE_YUV411,
262 VIDEO_PALETTE_RGB555,
263 VIDEO_PALETTE_RGB565,
270 gst_v4lsrc_palette_to_caps (int palette)
276 case VIDEO_PALETTE_YUV422:
277 case VIDEO_PALETTE_YUYV:
278 fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
280 case VIDEO_PALETTE_YUV420P:
281 fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
283 case VIDEO_PALETTE_UYVY:
284 fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
286 case VIDEO_PALETTE_YUV411P:
287 fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
289 case VIDEO_PALETTE_YUV411:
290 fourcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P');
292 case VIDEO_PALETTE_YUV422P:
293 fourcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
295 case VIDEO_PALETTE_YUV410P:
296 fourcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9');
298 case VIDEO_PALETTE_RGB555:
299 case VIDEO_PALETTE_RGB565:
300 case VIDEO_PALETTE_RGB24:
301 case VIDEO_PALETTE_RGB32:
302 fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' ');
308 if (fourcc == GST_MAKE_FOURCC ('R', 'G', 'B', ' ')) {
310 case VIDEO_PALETTE_RGB555:
311 caps = gst_caps_from_string ("video/x-raw-rgb, "
314 "endianness = (int) BYTE_ORDER, "
315 "red_mask = 0x7c00, " "green_mask = 0x03e0, " "blue_mask = 0x001f");
317 case VIDEO_PALETTE_RGB565:
318 caps = gst_caps_from_string ("video/x-raw-rgb, "
321 "endianness = (int) BYTE_ORDER, "
322 "red_mask = 0xf800, " "green_mask = 0x07f0, " "blue_mask = 0x001f");
324 case VIDEO_PALETTE_RGB24:
325 caps = gst_caps_from_string ("video/x-raw-rgb, "
328 "endianness = (int) BIG_ENDIAN, "
329 "red_mask = 0xFF0000, "
330 "green_mask = 0x00FF00, " "blue_mask = 0x0000FF");
332 case VIDEO_PALETTE_RGB32:
333 caps = gst_caps_from_string ("video/x-raw-rgb, "
336 "endianness = (int) BIG_ENDIAN, "
337 "red_mask = 0xFF000000, "
338 "green_mask = 0x00FF0000, " "blue_mask = 0x0000FF00");
341 g_assert_not_reached ();
345 caps = gst_caps_new_simple ("video/x-raw-yuv",
346 "format", GST_TYPE_FOURCC, fourcc, NULL);
353 gst_v4lsrc_get_any_caps (void)
356 GstCaps *caps = gst_caps_new_empty (), *one;
358 for (i = 0; all_palettes[i] != -1; i++) {
359 one = gst_v4lsrc_palette_to_caps (all_palettes[i]);
360 gst_caps_append (caps, one);
367 gst_v4lsrc_get_caps (GstBaseSrc * src)
370 GstV4lSrc *v4lsrc = GST_V4LSRC (src);
371 struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
372 gint width = GST_V4LELEMENT (src)->vcap.minwidth;
373 gint height = GST_V4LELEMENT (src)->vcap.minheight;
378 if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
379 return gst_v4lsrc_get_any_caps ();
382 if (!v4lsrc->autoprobe) {
383 /* FIXME: query current caps and return those, with _any appended */
384 return gst_v4lsrc_get_any_caps ();
387 if (!v4lsrc->colorspaces) {
388 GST_DEBUG_OBJECT (v4lsrc, "Checking supported palettes");
389 for (i = 0; all_palettes[i] != -1; i++) {
390 /* try palette out */
391 if (!gst_v4lsrc_try_capture (v4lsrc, width, height, all_palettes[i]))
393 GST_DEBUG_OBJECT (v4lsrc, "Added palette %d (%s) to supported list",
394 all_palettes[i], gst_v4lsrc_palette_name (all_palettes[i]));
395 v4lsrc->colorspaces = g_list_append (v4lsrc->colorspaces,
396 GINT_TO_POINTER (all_palettes[i]));
398 GST_DEBUG_OBJECT (v4lsrc, "%d palette(s) supported",
399 g_list_length (v4lsrc->colorspaces));
400 if (v4lsrc->autoprobe_fps) {
401 GST_DEBUG_OBJECT (v4lsrc, "autoprobing framerates");
402 v4lsrc->fps_list = gst_v4lsrc_get_fps_list (v4lsrc);
407 if (!gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)) {
412 list = gst_caps_new_empty ();
413 for (item = v4lsrc->colorspaces; item != NULL; item = item->next) {
416 one = gst_v4lsrc_palette_to_caps (GPOINTER_TO_INT (item->data));
418 GST_WARNING_OBJECT (v4lsrc, "Palette %d gave no caps\n",
419 GPOINTER_TO_INT (item->data));
423 GST_DEBUG_OBJECT (v4lsrc,
424 "Device reports w: %d-%d, h: %d-%d, fps: %d/%d for palette %d",
425 vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight,
426 fps_n, fps_d, GPOINTER_TO_INT (item->data));
428 if (vcap->minwidth < vcap->maxwidth) {
429 gst_caps_set_simple (one, "width", GST_TYPE_INT_RANGE, vcap->minwidth,
430 vcap->maxwidth, NULL);
432 gst_caps_set_simple (one, "width", G_TYPE_INT, vcap->minwidth, NULL);
434 if (vcap->minheight < vcap->maxheight) {
435 gst_caps_set_simple (one, "height", GST_TYPE_INT_RANGE, vcap->minheight,
436 vcap->maxheight, NULL);
438 gst_caps_set_simple (one, "height", G_TYPE_INT, vcap->minheight, NULL);
441 if (v4lsrc->autoprobe_fps) {
442 GstStructure *structure = gst_caps_get_structure (one, 0);
444 if (v4lsrc->fps_list) {
445 gst_structure_set_value (structure, "framerate", v4lsrc->fps_list);
447 gst_structure_set (structure, "framerate", GST_TYPE_FRACTION,
451 gst_caps_set_simple (one, "framerate", GST_TYPE_FRACTION_RANGE,
455 GST_DEBUG_OBJECT (v4lsrc, "caps: %" GST_PTR_FORMAT, one);
456 gst_caps_append (list, one);
463 gst_v4lsrc_set_caps (GstBaseSrc * src, GstCaps * caps)
467 gint bpp, depth, w, h, palette = -1;
468 const GValue *new_fps;
469 gint cur_fps_n, cur_fps_d;
470 GstStructure *structure;
471 struct video_window *vwin;
473 v4lsrc = GST_V4LSRC (src);
474 vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
476 /* if we're not open, punt -- we'll get setcaps'd later via negotiate */
477 if (!GST_V4L_IS_OPEN (v4lsrc))
480 /* make sure we stop capturing and dealloc buffers */
481 if (GST_V4L_IS_ACTIVE (v4lsrc)) {
482 if (!gst_v4lsrc_capture_stop (v4lsrc))
484 if (!gst_v4lsrc_capture_deinit (v4lsrc))
488 /* it's fixed, one struct */
489 structure = gst_caps_get_structure (caps, 0);
491 if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0)
492 gst_structure_get_fourcc (structure, "format", &fourcc);
494 fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', ' ');
496 gst_structure_get_int (structure, "width", &w);
497 gst_structure_get_int (structure, "height", &h);
498 new_fps = gst_structure_get_value (structure, "framerate");
500 /* set framerate if it's not already correct */
501 if (!gst_v4lsrc_get_fps (v4lsrc, &cur_fps_n, &cur_fps_d))
505 GST_DEBUG_OBJECT (v4lsrc, "linking with %dx%d at %d/%d fps", w, h,
506 gst_value_get_fraction_numerator (new_fps),
507 gst_value_get_fraction_denominator (new_fps));
509 if (gst_value_get_fraction_numerator (new_fps) != cur_fps_n ||
510 gst_value_get_fraction_denominator (new_fps) != cur_fps_d) {
511 int fps_index = (gst_value_get_fraction_numerator (new_fps) * 16) /
512 (gst_value_get_fraction_denominator (new_fps) * 15);
514 GST_DEBUG_OBJECT (v4lsrc, "Trying to set fps index %d", fps_index);
515 /* set bits 16 to 21 to 0 */
516 vwin->flags &= (0x3F00 - 1);
517 /* set bits 16 to 21 to the index */
518 vwin->flags |= fps_index << 16;
519 if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) {
526 case GST_MAKE_FOURCC ('I', '4', '2', '0'):
527 palette = VIDEO_PALETTE_YUV420P;
528 v4lsrc->buffer_size = ((w + 1) & ~1) * ((h + 1) & ~1) * 1.5;
530 case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
531 palette = VIDEO_PALETTE_YUV422;
532 v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
534 case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
535 palette = VIDEO_PALETTE_UYVY;
536 v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
538 case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
539 palette = VIDEO_PALETTE_YUV411P;
540 v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5;
542 case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
543 palette = VIDEO_PALETTE_YUV411;
544 v4lsrc->buffer_size = ((w + 3) & ~3) * h * 1.5;
546 case GST_MAKE_FOURCC ('Y', 'U', 'V', '9'):
547 palette = VIDEO_PALETTE_YUV410P;
548 v4lsrc->buffer_size = ((w + 3) & ~3) * ((h + 3) & ~3) * 1.125;
550 case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
551 palette = VIDEO_PALETTE_YUV422P;
552 v4lsrc->buffer_size = ((w + 1) & ~1) * h * 2;
554 case GST_MAKE_FOURCC ('R', 'G', 'B', ' '):
555 gst_structure_get_int (structure, "depth", &depth);
558 palette = VIDEO_PALETTE_RGB555;
559 v4lsrc->buffer_size = w * h * 2;
562 palette = VIDEO_PALETTE_RGB565;
563 v4lsrc->buffer_size = w * h * 2;
566 gst_structure_get_int (structure, "bpp", &bpp);
569 palette = VIDEO_PALETTE_RGB24;
570 v4lsrc->buffer_size = w * h * 3;
573 palette = VIDEO_PALETTE_RGB32;
574 v4lsrc->buffer_size = w * h * 4;
589 GST_WARNING_OBJECT (v4lsrc, "palette for fourcc %" GST_FOURCC_FORMAT
590 " is -1, refusing link", GST_FOURCC_ARGS (fourcc));
594 GST_DEBUG_OBJECT (v4lsrc, "trying to set_capture %dx%d, palette %d",
596 /* this only fills in v4lsrc->mmap values */
597 if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) {
598 GST_WARNING_OBJECT (v4lsrc, "could not set_capture %dx%d, palette %d",
603 /* first try the negotiated settings using try_capture */
604 if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) {
605 GST_DEBUG_OBJECT (v4lsrc, "failed trying palette %d for %dx%d", palette,
610 if (!gst_v4lsrc_capture_init (v4lsrc))
613 if (!gst_v4lsrc_capture_start (v4lsrc))
620 gst_v4lsrc_query (GstBaseSrc * bsrc, GstQuery * query)
623 gboolean res = FALSE;
625 v4lsrc = GST_V4LSRC (bsrc);
627 switch (GST_QUERY_TYPE (query)) {
628 case GST_QUERY_LATENCY:
630 GstClockTime min_latency, max_latency;
633 /* device must be open */
634 if (!GST_V4L_IS_OPEN (v4lsrc))
637 /* we must have a framerate */
638 if (!(res = gst_v4lsrc_get_fps (v4lsrc, &fps_n, &fps_d)))
641 /* min latency is the time to capture one frame */
642 min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
644 /* max latency is total duration of the frame buffer */
645 max_latency = v4lsrc->mbuf.frames * min_latency;
647 GST_DEBUG_OBJECT (bsrc,
648 "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
649 GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
651 /* we are always live, the min latency is 1 frame and the max latency is
652 * the complete buffer of frames. */
653 gst_query_set_latency (query, TRUE, min_latency, max_latency);
659 res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
666 /* start and stop are not symmetric -- start will open the device, but not start
667 capture. it's setcaps that will start capture, which is called via basesrc's
668 negotiate method. stop will both stop capture and close the device.
671 gst_v4lsrc_start (GstBaseSrc * src)
673 GstV4lSrc *v4lsrc = GST_V4LSRC (src);
681 gst_v4lsrc_stop (GstBaseSrc * src)
683 GstV4lSrc *v4lsrc = GST_V4LSRC (src);
685 if (GST_V4L_IS_ACTIVE (v4lsrc) && !gst_v4lsrc_capture_stop (v4lsrc))
688 if (GST_V4LELEMENT (v4lsrc)->buffer != NULL) {
689 if (!gst_v4lsrc_capture_deinit (v4lsrc))
693 g_list_free (v4lsrc->colorspaces);
694 v4lsrc->colorspaces = NULL;
696 if (v4lsrc->fps_list) {
697 g_value_unset (v4lsrc->fps_list);
698 g_free (v4lsrc->fps_list);
699 v4lsrc->fps_list = NULL;
706 gst_v4lsrc_create (GstPushSrc * src, GstBuffer ** buf)
711 v4lsrc = GST_V4LSRC (src);
713 /* grab a frame from the device */
714 if (!gst_v4lsrc_grab_frame (v4lsrc, &num))
715 return GST_FLOW_ERROR;
717 *buf = gst_v4lsrc_buffer_new (v4lsrc, num);
719 if (v4lsrc->copy_mode) {
720 GstBuffer *copy = gst_buffer_copy (*buf);
722 gst_buffer_unref (*buf);