3 * gstv4lmjpegsrc.c: hardware MJPEG video source plugin
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.
28 #include "v4lmjpegsrc_calls.h"
30 GST_DEBUG_CATEGORY (v4lmjpegsrc_debug);
31 #define GST_CAT_DEFAULT v4lmjpegsrc_debug
33 /* V4lMjpegSrc signals and args */
52 /* normally, we would want to use subframe capture, however,
53 * for the time being it's easier if we disable it first */
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,
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);
71 /* pad/info functions */
72 static gboolean gst_v4lmjpegsrc_src_convert (GstPad * pad,
74 gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
75 static gboolean gst_v4lmjpegsrc_src_query (GstPad * pad,
76 GstQueryType type, GstFormat * format, gint64 * value);
78 /* buffer functions */
79 static GstPadLinkReturn gst_v4lmjpegsrc_srcconnect (GstPad * pad,
80 const GstCaps * caps);
81 static GstData *gst_v4lmjpegsrc_get (GstPad * pad);
82 static GstCaps *gst_v4lmjpegsrc_getcaps (GstPad * pad);
85 static void gst_v4lmjpegsrc_set_property (GObject * object,
86 guint prop_id, const GValue * value, GParamSpec * pspec);
87 static void gst_v4lmjpegsrc_get_property (GObject * object,
88 guint prop_id, GValue * value, GParamSpec * pspec);
90 /* set_clock function for A/V sync */
91 static void gst_v4lmjpegsrc_set_clock (GstElement * element, GstClock * clock);
94 static GstStateChangeReturn gst_v4lmjpegsrc_change_state (GstElement * element);
96 /* requeue buffer after use */
97 static void gst_v4lmjpegsrc_buffer_free (GstBuffer * buffer);
99 static GstElementClass *parent_class = NULL;
100 static guint gst_v4lmjpegsrc_signals[LAST_SIGNAL] = { 0 };
104 gst_v4lmjpegsrc_get_type (void)
106 static GType v4lmjpegsrc_type = 0;
108 if (!v4lmjpegsrc_type) {
109 static const GTypeInfo v4lmjpegsrc_info = {
110 sizeof (GstV4lMjpegSrcClass),
111 gst_v4lmjpegsrc_base_init,
113 (GClassInitFunc) gst_v4lmjpegsrc_class_init,
116 sizeof (GstV4lMjpegSrc),
118 (GInstanceInitFunc) gst_v4lmjpegsrc_init,
123 g_type_register_static (GST_TYPE_V4LELEMENT, "GstV4lMjpegSrc",
124 &v4lmjpegsrc_info, 0);
126 return v4lmjpegsrc_type;
131 gst_v4lmjpegsrc_base_init (gpointer g_class)
133 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
136 GST_STATIC_CAPS ("image/jpeg, "
137 "width = (int) [ 0, MAX ], "
138 "height = (int) [ 0, MAX ], " "framerate = (fraction) [ 0, MAX ]")
140 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
142 gst_element_class_set_details_sinmple (gstelement_class,
143 "Video (video4linux/MJPEG) Source", "Source/Video",
144 "Reads MJPEG-encoded frames from a zoran MJPEG/video4linux device",
145 "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
147 gst_element_class_add_pad_template (gstelement_class,
148 gst_static_pad_template_get (&src_template));
152 gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass * klass)
154 GObjectClass *gobject_class;
155 GstElementClass *gstelement_class;
157 gobject_class = (GObjectClass *) klass;
158 gstelement_class = (GstElementClass *) klass;
160 parent_class = g_type_class_peek_parent (klass);
163 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_X_OFFSET,
164 g_param_spec_int ("x-offset", "x_offset", "x_offset",
165 G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
166 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_Y_OFFSET,
167 g_param_spec_int ("y-offset", "y_offset", "y_offset",
168 G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
169 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_F_WIDTH,
170 g_param_spec_int ("frame-width", "frame_width", "frame_width",
171 G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
172 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_F_HEIGHT,
173 g_param_spec_int ("frame-height", "frame_height", "frame_height",
174 G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
177 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_QUALITY,
178 g_param_spec_int ("quality", "Quality", "JPEG frame quality",
179 1, 100, 50, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
181 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUMBUFS,
182 g_param_spec_int ("num-buffers", "Num Buffers", "Number of Buffers",
183 1, 256, 64, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
184 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFSIZE,
185 g_param_spec_int ("buffer-size", "Buffer Size", "Size of buffers",
186 0, 512 * 1024, 128 * 1024,
187 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
189 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_USE_FIXED_FPS,
190 g_param_spec_boolean ("use-fixed-fps", "Use Fixed FPS",
191 "Drop/Insert frames to reach a certain FPS (TRUE) "
192 "or adapt FPS to suit the number of grabbed frames",
193 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
196 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_CAPTURE] =
197 g_signal_new ("frame-capture", G_TYPE_FROM_CLASS (klass),
198 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstV4lMjpegSrcClass, frame_capture),
199 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
200 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_DROP] =
201 g_signal_new ("frame-drop", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
202 G_STRUCT_OFFSET (GstV4lMjpegSrcClass, frame_drop), NULL, NULL,
203 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
204 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_INSERT] =
205 g_signal_new ("frame-insert", G_TYPE_FROM_CLASS (klass),
206 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstV4lMjpegSrcClass, frame_insert),
207 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
208 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_LOST] =
209 g_signal_new ("frame-lost", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
210 G_STRUCT_OFFSET (GstV4lMjpegSrcClass, frame_lost), NULL, NULL,
211 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
213 GST_DEBUG_CATEGORY_INIT (v4lmjpegsrc_debug, "v4lmjpegsrc", 0,
214 "V4L MJPEG source element");
215 gobject_class->set_property = gst_v4lmjpegsrc_set_property;
216 gobject_class->get_property = gst_v4lmjpegsrc_get_property;
218 gstelement_class->change_state = gst_v4lmjpegsrc_change_state;
220 gstelement_class->set_clock = gst_v4lmjpegsrc_set_clock;
225 gst_v4lmjpegsrc_init (GstV4lMjpegSrc * v4lmjpegsrc)
227 GstElementClass *klass = GST_ELEMENT_GET_CLASS (v4lmjpegsrc);
229 GST_OBJECT_FLAG_SET (GST_ELEMENT (v4lmjpegsrc), GST_ELEMENT_THREAD_SUGGESTED);
231 v4lmjpegsrc->srcpad =
232 gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
234 gst_element_add_pad (GST_ELEMENT (v4lmjpegsrc), v4lmjpegsrc->srcpad);
236 gst_pad_set_get_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get);
237 gst_pad_set_getcaps_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_getcaps);
238 gst_pad_set_link_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_srcconnect);
239 gst_pad_set_convert_function (v4lmjpegsrc->srcpad,
240 gst_v4lmjpegsrc_src_convert);
241 gst_pad_set_formats_function (v4lmjpegsrc->srcpad,
242 gst_v4lmjpegsrc_get_formats);
243 gst_pad_set_query_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_src_query);
244 gst_pad_set_query_type_function (v4lmjpegsrc->srcpad,
245 gst_v4lmjpegsrc_get_query_types);
248 v4lmjpegsrc->frame_width = 0;
249 v4lmjpegsrc->frame_height = 0;
250 v4lmjpegsrc->x_offset = -1;
251 v4lmjpegsrc->y_offset = -1;
254 v4lmjpegsrc->quality = 50;
256 v4lmjpegsrc->numbufs = 64;
259 v4lmjpegsrc->clock = NULL;
262 v4lmjpegsrc->use_fixed_fps = TRUE;
264 v4lmjpegsrc->is_capturing = FALSE;
269 gst_v4lmjpegsrc_get_fps (GstV4lMjpegSrc * v4lmjpegsrc, GValue * fps)
273 g_return_val_if_fail (GST_VALUE_HOLDS_FRACTION (fps), FALSE);
275 if (!v4lmjpegsrc->use_fixed_fps &&
276 v4lmjpegsrc->clock != NULL && v4lmjpegsrc->handled > 0) {
277 /* try to get time from clock master and calculate fps */
279 gst_clock_get_time (v4lmjpegsrc->clock) - v4lmjpegsrc->substract_time;
280 return v4lmjpegsrc->handled * GST_SECOND / time;
283 /* if that failed ... */
285 if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsrc)))
288 if (!gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lmjpegsrc), NULL, &norm))
291 if (norm == VIDEO_MODE_NTSC)
292 gst_value_set_fraction (fps, 30000, 1001);
294 gst_value_set_fraction (fps, 25, 1);
300 gst_v4lmjpegsrc_src_convert (GstPad * pad,
301 GstFormat src_format,
302 gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
304 GstV4lMjpegSrc *v4lmjpegsrc;
306 gboolean result = TRUE;
308 v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
310 g_value_init (&fps, GST_VALUE_FRACTION);
311 if (!gst_v4lmjpegsrc_get_fps (v4lmjpegsrc, &fps))
314 switch (src_format) {
315 case GST_FORMAT_TIME:
316 switch (*dest_format) {
317 case GST_FORMAT_DEFAULT:
318 *dest_value = gst_util_uint64_scale (src_value,
319 gst_value_get_fraction_numerator (&fps),
320 gst_value_get_fraction_denominator (&fps) * GST_SECOND);
327 case GST_FORMAT_DEFAULT:
328 switch (*dest_format) {
329 case GST_FORMAT_TIME:
330 *dest_value = src_value * gst_util_uint64_scale_int (GST_SECOND,
331 gst_value_get_fraction_denominator (&fps),
332 gst_value_get_fraction_numerator (&fps));
343 g_value_unset (&fps);
348 gst_v4lmjpegsrc_src_query (GstPad * pad,
349 GstQueryType type, GstFormat * format, gint64 * value)
351 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
355 g_value_init (&fps, GST_VALUE_FRACTION);
356 if (!gst_v4lmjpegsrc_get_fps (v4lmjpegsrc, &fps))
360 case GST_QUERY_POSITION:
362 case GST_FORMAT_TIME:
363 *value = v4lmjpegsrc->handled * gst_util_uint64_scale_int (GST_SECOND,
364 gst_value_get_fraction_denominator (&fps),
365 gst_value_get_fraction_numerator (&fps));
367 case GST_FORMAT_DEFAULT:
368 *value = v4lmjpegsrc->handled;
380 g_value_unset (&fps);
385 calc_bufsize (int hor_dec, int ver_dec)
387 guint8 div = hor_dec * ver_dec;
388 guint32 num = (1024 * 512) / (div);
397 if (result > (512 * 1024))
404 static GstPadLinkReturn
405 gst_v4lmjpegsrc_srcconnect (GstPad * pad, const GstCaps * caps)
407 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
408 gint hor_dec, ver_dec;
410 gint max_w = GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxwidth,
411 max_h = GST_V4LELEMENT (v4lmjpegsrc)->vcap.maxheight;
413 GstStructure *structure;
414 gboolean was_capturing;
416 /* in case the buffers are active (which means that we already
417 * did capsnego before and didn't clean up), clean up anyways */
418 if ((was_capturing = v4lmjpegsrc->is_capturing)) {
419 if (!gst_v4lmjpegsrc_capture_stop (v4lmjpegsrc))
420 return GST_PAD_LINK_REFUSED;
422 if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc))) {
423 if (!gst_v4lmjpegsrc_capture_deinit (v4lmjpegsrc))
424 return GST_PAD_LINK_REFUSED;
425 } else if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsrc))) {
426 return GST_PAD_LINK_DELAYED;
429 /* Note: basically, we don't give a damn about the opposite caps here.
430 * that might seem odd, but it isn't. we know that the opposite caps is
431 * either NULL or has mime type image/jpeg, and in both cases, we'll set
432 * our own mime type back and it'll work. Other properties are to be set
433 * by the src, not by the opposite caps */
435 structure = gst_caps_get_structure (caps, 0);
436 gst_structure_get_int (structure, "width", &w);
437 gst_structure_get_int (structure, "height", &h);
439 /* figure out decimation */
442 } else if (w * 2 >= max_w) {
449 } else if (h * 2 >= max_h) {
455 /* calculate bufsize */
456 bufsize = calc_bufsize (hor_dec, ver_dec);
458 /* set buffer info */
459 if (!gst_v4lmjpegsrc_set_buffer (v4lmjpegsrc, v4lmjpegsrc->numbufs, bufsize)) {
460 return GST_PAD_LINK_REFUSED;
463 /* set capture parameters and mmap the buffers */
464 if (hor_dec == ver_dec) {
465 if (!gst_v4lmjpegsrc_set_capture (v4lmjpegsrc,
466 hor_dec, v4lmjpegsrc->quality)) {
467 return GST_PAD_LINK_REFUSED;
470 if (!gst_v4lmjpegsrc_set_capture_m (v4lmjpegsrc,
471 0, 0, max_w, max_h, hor_dec, ver_dec, v4lmjpegsrc->quality)) {
472 return GST_PAD_LINK_REFUSED;
476 if (!v4lmjpegsrc->frame_width && !v4lmjpegsrc->frame_height &&
477 v4lmjpegsrc->x_offset < 0 && v4lmjpegsrc->y_offset < 0 &&
478 v4lmjpegsrc->horizontal_decimation == v4lmjpegsrc->vertical_decimation) {
479 if (!gst_v4lmjpegsrc_set_capture (v4lmjpegsrc,
480 v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->quality))
481 return GST_PAD_LINK_REFUSED;
483 if (!gst_v4lmjpegsrc_set_capture_m (v4lmjpegsrc,
484 v4lmjpegsrc->x_offset, v4lmjpegsrc->y_offset,
485 v4lmjpegsrc->frame_width, v4lmjpegsrc->frame_height,
486 v4lmjpegsrc->horizontal_decimation,
487 v4lmjpegsrc->vertical_decimation, v4lmjpegsrc->quality))
488 return GST_PAD_LINK_REFUSED;
492 if (!gst_v4lmjpegsrc_capture_init (v4lmjpegsrc))
493 return GST_PAD_LINK_REFUSED;
495 if (was_capturing || GST_STATE (v4lmjpegsrc) == GST_STATE_PLAYING)
496 if (!gst_v4lmjpegsrc_capture_start (v4lmjpegsrc))
497 return GST_PAD_LINK_REFUSED;
499 return GST_PAD_LINK_OK;
504 gst_v4lmjpegsrc_get (GstPad * pad)
506 GstV4lMjpegSrc *v4lmjpegsrc;
510 GstClockTime duration;
511 GstClockTime cur_frame_time;
513 g_return_val_if_fail (pad != NULL, NULL);
515 v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
517 if (v4lmjpegsrc->use_fixed_fps) {
518 g_value_init (&fps, GST_VALUE_FRACTION);
519 duration = gst_util_uint64_scale_int (GST_SECOND,
520 gst_value_get_fraction_denominator (&fps),
521 gst_value_get_fraction_numerator (&fps));
523 gst_util_uint64_scale_int (v4lmjpegsrc->handled * GST_SECOND,
524 gst_value_get_fraction_denominator (&fps),
525 gst_value_get_fraction_numerator (&fps));
528 if (!gst_v4lmjpegsrc_get_fps (v4lmjpegsrc, &fps)) {
529 g_value_unset (&fps);
534 if (v4lmjpegsrc->need_writes > 0) {
536 num = v4lmjpegsrc->last_frame;
537 v4lmjpegsrc->need_writes--;
538 } else if (v4lmjpegsrc->clock && v4lmjpegsrc->use_fixed_fps) {
540 gboolean have_frame = FALSE;
543 /* by default, we use the frame once */
544 v4lmjpegsrc->need_writes = 1;
546 /* grab a frame from the device */
547 if (!gst_v4lmjpegsrc_grab_frame (v4lmjpegsrc, &num,
548 &v4lmjpegsrc->last_size))
551 v4lmjpegsrc->last_frame = num;
552 time = GST_TIMEVAL_TO_TIME (v4lmjpegsrc->bsync.timestamp) -
553 v4lmjpegsrc->substract_time;
555 /* first check whether we lost any frames according to the device */
556 if (v4lmjpegsrc->last_seq != 0) {
557 if (v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq > 1) {
558 v4lmjpegsrc->need_writes =
559 v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq;
560 g_signal_emit (G_OBJECT (v4lmjpegsrc),
561 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_LOST], 0,
562 v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq - 1);
565 v4lmjpegsrc->last_seq = v4lmjpegsrc->bsync.seq;
567 /* decide how often we're going to write the frame - set
568 * v4lmjpegsrc->need_writes to (that-1) and have_frame to TRUE
569 * if we're going to write it - else, just continue.
571 * time is generally the system or audio clock. Let's
572 * say that we've written one second of audio, then we want
573 * to have written one second of video too, within the same
574 * timeframe. This means that if time - begin_time = X sec,
575 * we want to have written X*fps frames. If we've written
576 * more - drop, if we've written less - dup... */
577 if (cur_frame_time - time > 1.5 * duration) {
578 /* yo dude, we've got too many frames here! Drop! DROP! */
579 v4lmjpegsrc->need_writes--; /* -= (v4lmjpegsrc->handled - (time / fps)); */
580 g_signal_emit (G_OBJECT (v4lmjpegsrc),
581 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_DROP], 0);
582 } else if (cur_frame_time - time < -1.5 * duration) {
583 /* this means we're lagging far behind */
584 v4lmjpegsrc->need_writes++; /* += ((time / fps) - v4lmjpegsrc->handled); */
585 g_signal_emit (G_OBJECT (v4lmjpegsrc),
586 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_INSERT], 0);
589 if (v4lmjpegsrc->need_writes > 0) {
591 v4lmjpegsrc->use_num_times[num] = v4lmjpegsrc->need_writes;
592 v4lmjpegsrc->need_writes--;
594 gst_v4lmjpegsrc_requeue_frame (v4lmjpegsrc, num);
596 } while (!have_frame);
598 /* grab a frame from the device */
599 if (!gst_v4lmjpegsrc_grab_frame (v4lmjpegsrc, &num,
600 &v4lmjpegsrc->last_size))
603 v4lmjpegsrc->use_num_times[num] = 1;
606 buf = gst_buffer_new ();
607 GST_BUFFER_FREE_DATA_FUNC (buf) = gst_v4lmjpegsrc_buffer_free;
608 GST_BUFFER_PRIVATE (buf) = v4lmjpegsrc;
609 GST_BUFFER_DATA (buf) = gst_v4lmjpegsrc_get_buffer (v4lmjpegsrc, num);
610 GST_BUFFER_SIZE (buf) = v4lmjpegsrc->last_size;
611 GST_BUFFER_MAXSIZE (buf) = v4lmjpegsrc->breq.size;
612 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY);
613 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_DONTFREE);
614 if (v4lmjpegsrc->use_fixed_fps)
615 GST_BUFFER_TIMESTAMP (buf) = cur_frame_time;
616 else /* calculate time based on our own clock */
617 GST_BUFFER_TIMESTAMP (buf) =
618 GST_TIMEVAL_TO_TIME (v4lmjpegsrc->bsync.timestamp) -
619 v4lmjpegsrc->substract_time;
621 v4lmjpegsrc->handled++;
622 g_signal_emit (G_OBJECT (v4lmjpegsrc),
623 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_CAPTURE], 0);
625 return GST_DATA (buf);
630 gst_v4lmjpegsrc_getcaps (GstPad * pad)
632 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
633 struct video_capability *vcap = &GST_V4LELEMENT (v4lmjpegsrc)->vcap;
637 GValue w = { 0 }, h = {
643 if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lmjpegsrc))) {
644 return gst_caps_copy (gst_pad_get_pad_template_caps (pad));
647 g_value_init (&fps, GST_TYPE_FRACTION);
648 gst_return_val_if_fail (gst_v4lmjpegsrc_get_fps (v4lmjpegsrc, &fps), NULL);
650 caps = gst_caps_new_simple ("image/jpeg", NULL);
651 str = gst_caps_get_structure (caps, 0);
652 gst_structure_set_value (str, "framerate", &fps);
653 g_value_unset (&fps);
655 g_value_init (&w, GST_TYPE_LIST);
656 g_value_init (&h, GST_TYPE_LIST);
657 g_value_init (&w1, G_TYPE_INT);
658 g_value_init (&h1, G_TYPE_INT);
659 for (i = 0; i <= 2; i++) {
660 g_value_set_int (&w1, vcap->maxwidth / (1 << i));
661 g_value_set_int (&h1, vcap->maxheight / (1 << i));
662 gst_value_list_append_value (&w, &w1);
663 gst_value_list_append_value (&h, &h1);
667 gst_structure_set_value (str, "width", &w);
668 gst_structure_set_value (str, "height", &h);
677 gst_v4lmjpegsrc_set_property (GObject * object,
678 guint prop_id, const GValue * value, GParamSpec * pspec)
680 GstV4lMjpegSrc *v4lmjpegsrc;
682 g_return_if_fail (GST_IS_V4LMJPEGSRC (object));
683 v4lmjpegsrc = GST_V4LMJPEGSRC (object);
688 v4lmjpegsrc->x_offset = g_value_get_int (value);
691 v4lmjpegsrc->y_offset = g_value_get_int (value);
694 v4lmjpegsrc->frame_width = g_value_get_int (value);
697 v4lmjpegsrc->frame_height = g_value_get_int (value);
701 v4lmjpegsrc->quality = g_value_get_int (value);
704 v4lmjpegsrc->numbufs = g_value_get_int (value);
706 case ARG_USE_FIXED_FPS:
707 if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc))) {
708 v4lmjpegsrc->use_fixed_fps = g_value_get_boolean (value);
712 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
719 gst_v4lmjpegsrc_get_property (GObject * object,
720 guint prop_id, GValue * value, GParamSpec * pspec)
722 GstV4lMjpegSrc *v4lmjpegsrc;
724 g_return_if_fail (GST_IS_V4LMJPEGSRC (object));
725 v4lmjpegsrc = GST_V4LMJPEGSRC (object);
730 g_value_set_int (value, v4lmjpegsrc->x_offset);
733 g_value_set_int (value, v4lmjpegsrc->y_offset);
736 g_value_set_int (value, v4lmjpegsrc->frame_width);
739 g_value_set_int (value, v4lmjpegsrc->frame_height);
743 g_value_set_int (value, v4lmjpegsrc->quality);
746 if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)))
747 g_value_set_int (value, v4lmjpegsrc->breq.count);
749 g_value_set_int (value, v4lmjpegsrc->numbufs);
752 g_value_set_int (value, v4lmjpegsrc->breq.size);
754 case ARG_USE_FIXED_FPS:
755 g_value_set_boolean (value, v4lmjpegsrc->use_fixed_fps);
758 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
764 static GstStateChangeReturn
765 gst_v4lmjpegsrc_change_state (GstElement * element, GstStateChange transition)
767 GstV4lMjpegSrc *v4lmjpegsrc;
770 g_return_val_if_fail (GST_IS_V4LMJPEGSRC (element), GST_STATE_CHANGE_FAILURE);
772 v4lmjpegsrc = GST_V4LMJPEGSRC (element);
774 switch (transition) {
775 case GST_STATE_CHANGE_READY_TO_PAUSED:
776 /* actual buffer set-up used to be done here - but I moved
777 * it to capsnego itself */
778 v4lmjpegsrc->handled = 0;
779 v4lmjpegsrc->need_writes = 0;
780 v4lmjpegsrc->last_frame = 0;
781 v4lmjpegsrc->substract_time = 0;
783 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
784 /* queue all buffer, start streaming capture */
785 if (GST_V4LELEMENT (v4lmjpegsrc)->buffer &&
786 !gst_v4lmjpegsrc_capture_start (v4lmjpegsrc))
787 return GST_STATE_CHANGE_FAILURE;
788 g_get_current_time (&time);
789 v4lmjpegsrc->substract_time = GST_TIMEVAL_TO_TIME (time) -
790 v4lmjpegsrc->substract_time;
791 v4lmjpegsrc->last_seq = 0;
793 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
794 g_get_current_time (&time);
795 v4lmjpegsrc->substract_time = GST_TIMEVAL_TO_TIME (time) -
796 v4lmjpegsrc->substract_time;
797 /* de-queue all queued buffers */
798 if (v4lmjpegsrc->is_capturing &&
799 !gst_v4lmjpegsrc_capture_stop (v4lmjpegsrc))
800 return GST_STATE_CHANGE_FAILURE;
802 case GST_STATE_CHANGE_PAUSED_TO_READY:
803 /* stop capturing, unmap all buffers */
804 if (GST_V4LELEMENT (v4lmjpegsrc)->buffer &&
805 !gst_v4lmjpegsrc_capture_deinit (v4lmjpegsrc))
806 return GST_STATE_CHANGE_FAILURE;
810 if (GST_ELEMENT_CLASS (parent_class)->change_state)
811 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
813 return GST_STATE_CHANGE_SUCCESS;
818 gst_v4lmjpegsrc_set_clock (GstElement * element, GstClock * clock)
820 GST_V4LMJPEGSRC (element)->clock = clock;
826 gst_v4lmjpegsrc_buffer_new (GstBufferPool * pool,
827 guint64 offset, guint size, gpointer user_data)
830 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (user_data);
832 if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsrc)))
835 buffer = gst_buffer_new ();
839 /* TODO: add interlacing info to buffer as metadata */
840 GST_BUFFER_MAXSIZE (buffer) = v4lmjpegsrc->breq.size;
841 GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTFREE);
848 gst_v4lmjpegsrc_buffer_free (GstBuffer * buf)
850 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (GST_BUFFER_PRIVATE (buf));
853 if (gst_element_get_state (GST_ELEMENT (v4lmjpegsrc)) != GST_STATE_PLAYING)
854 return; /* we've already cleaned up ourselves */
856 for (n = 0; n < v4lmjpegsrc->breq.count; n++)
857 if (GST_BUFFER_DATA (buf) == gst_v4lmjpegsrc_get_buffer (v4lmjpegsrc, n)) {
858 v4lmjpegsrc->use_num_times[n]--;
859 if (v4lmjpegsrc->use_num_times[n] <= 0) {
860 gst_v4lmjpegsrc_requeue_frame (v4lmjpegsrc, n);
865 if (n == v4lmjpegsrc->breq.count)
866 GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL),
867 ("Couldn't find the buffer"));