1 /* G-Streamer hardware MJPEG video source plugin
2 * Copyright (C) 2001-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.
25 #include "v4lmjpegsrc_calls.h"
27 /* elementfactory information */
28 static GstElementDetails gst_v4lmjpegsrc_details = {
29 "Video (video4linux/MJPEG) Source",
31 "Reads MJPEG-encoded frames from a zoran MJPEG/video4linux device",
32 "Ronald Bultje <rbultje@ronald.bitfreak.net>"
35 /* 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,
75 GstFormat *dest_format,
77 static gboolean gst_v4lmjpegsrc_src_query (GstPad *pad,
82 /* buffer functions */
83 static GstPadLinkReturn gst_v4lmjpegsrc_srcconnect (GstPad *pad,
85 static GstData* gst_v4lmjpegsrc_get (GstPad *pad);
86 static GstCaps* gst_v4lmjpegsrc_getcaps (GstPad *pad);
89 static void gst_v4lmjpegsrc_set_property (GObject *object,
93 static void gst_v4lmjpegsrc_get_property (GObject *object,
98 /* set_clock function for A/V sync */
99 static void gst_v4lmjpegsrc_set_clock (GstElement *element,
103 static GstElementStateReturn gst_v4lmjpegsrc_change_state (GstElement *element);
105 /* requeue buffer after use */
106 static void gst_v4lmjpegsrc_buffer_free (GstBuffer *buffer);
108 static GstElementClass *parent_class = NULL;
109 static guint gst_v4lmjpegsrc_signals[LAST_SIGNAL] = { 0 };
113 gst_v4lmjpegsrc_get_type (void)
115 static GType v4lmjpegsrc_type = 0;
117 if (!v4lmjpegsrc_type) {
118 static const GTypeInfo v4lmjpegsrc_info = {
119 sizeof(GstV4lMjpegSrcClass),
120 gst_v4lmjpegsrc_base_init,
122 (GClassInitFunc)gst_v4lmjpegsrc_class_init,
125 sizeof(GstV4lMjpegSrc),
127 (GInstanceInitFunc)gst_v4lmjpegsrc_init,
130 v4lmjpegsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lMjpegSrc", &v4lmjpegsrc_info, 0);
132 return v4lmjpegsrc_type;
137 gst_v4lmjpegsrc_base_init (gpointer g_class)
139 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE (
143 GST_STATIC_CAPS ("video/x-jpeg, "
144 "width = (int) [ 0, MAX ], "
145 "height = (int) [ 0, MAX ], "
146 "framerate = (double) [ 0, MAX ]"
149 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
151 gst_element_class_set_details (gstelement_class, &gst_v4lmjpegsrc_details);
153 gst_element_class_add_pad_template (gstelement_class,
154 gst_static_pad_template_get (&src_template));
157 gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass *klass)
159 GObjectClass *gobject_class;
160 GstElementClass *gstelement_class;
162 gobject_class = (GObjectClass*)klass;
163 gstelement_class = (GstElementClass*)klass;
165 parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
168 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_X_OFFSET,
169 g_param_spec_int("x_offset","x_offset","x_offset",
170 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
171 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_Y_OFFSET,
172 g_param_spec_int("y_offset","y_offset","y_offset",
173 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
174 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_WIDTH,
175 g_param_spec_int("frame_width","frame_width","frame_width",
176 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
177 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_HEIGHT,
178 g_param_spec_int("frame_height","frame_height","frame_height",
179 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
182 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_QUALITY,
183 g_param_spec_int("quality","Quality","JPEG frame quality",
184 1,100,50,G_PARAM_READWRITE));
186 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS,
187 g_param_spec_int("num_buffers","Num Buffers","Number of Buffers",
188 1,256,64,G_PARAM_READWRITE));
189 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
190 g_param_spec_int("buffer_size", "Buffer Size", "Size of buffers",
191 0, 512*1024, 128*1024, G_PARAM_READABLE));
193 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_USE_FIXED_FPS,
194 g_param_spec_boolean("use_fixed_fps", "Use Fixed FPS",
195 "Drop/Insert frames to reach a certain FPS (TRUE) "
196 "or adapt FPS to suit the number of frabbed frames",
197 TRUE, G_PARAM_READWRITE));
200 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_CAPTURE] =
201 g_signal_new("frame_capture", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
202 G_STRUCT_OFFSET(GstV4lMjpegSrcClass, frame_capture),
203 NULL, NULL, g_cclosure_marshal_VOID__VOID,
205 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_DROP] =
206 g_signal_new("frame_drop", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
207 G_STRUCT_OFFSET(GstV4lMjpegSrcClass, frame_drop),
208 NULL, NULL, g_cclosure_marshal_VOID__VOID,
210 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_INSERT] =
211 g_signal_new("frame_insert", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
212 G_STRUCT_OFFSET(GstV4lMjpegSrcClass, frame_insert),
213 NULL, NULL, g_cclosure_marshal_VOID__VOID,
215 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_LOST] =
216 g_signal_new("frame_lost", G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
217 G_STRUCT_OFFSET(GstV4lMjpegSrcClass, frame_lost),
218 NULL, NULL, g_cclosure_marshal_VOID__INT,
219 G_TYPE_NONE, 1, G_TYPE_INT);
221 gobject_class->set_property = gst_v4lmjpegsrc_set_property;
222 gobject_class->get_property = gst_v4lmjpegsrc_get_property;
224 gstelement_class->change_state = gst_v4lmjpegsrc_change_state;
226 gstelement_class->set_clock = gst_v4lmjpegsrc_set_clock;
231 gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc)
233 GstElementClass *klass = GST_ELEMENT_GET_CLASS (v4lmjpegsrc);
235 GST_FLAG_SET(GST_ELEMENT(v4lmjpegsrc), GST_ELEMENT_THREAD_SUGGESTED);
237 v4lmjpegsrc->srcpad = gst_pad_new_from_template (
238 gst_element_class_get_pad_template (klass, "src"), "src");
239 gst_element_add_pad(GST_ELEMENT(v4lmjpegsrc), v4lmjpegsrc->srcpad);
241 gst_pad_set_get_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get);
242 gst_pad_set_getcaps_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_getcaps);
243 gst_pad_set_link_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_srcconnect);
244 gst_pad_set_convert_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_src_convert);
245 gst_pad_set_formats_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get_formats);
246 gst_pad_set_query_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_src_query);
247 gst_pad_set_query_type_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get_query_types);
250 v4lmjpegsrc->frame_width = 0;
251 v4lmjpegsrc->frame_height = 0;
252 v4lmjpegsrc->x_offset = -1;
253 v4lmjpegsrc->y_offset = -1;
256 v4lmjpegsrc->quality = 50;
258 v4lmjpegsrc->numbufs = 64;
261 v4lmjpegsrc->clock = NULL;
264 v4lmjpegsrc->use_fixed_fps = TRUE;
269 gst_v4lmjpegsrc_get_fps (GstV4lMjpegSrc *v4lmjpegsrc)
274 if (!v4lmjpegsrc->use_fixed_fps &&
275 v4lmjpegsrc->clock != NULL &&
276 v4lmjpegsrc->handled > 0) {
277 /* try to get time from clock master and calculate fps */
278 GstClockTime time = gst_clock_get_time(v4lmjpegsrc->clock) - v4lmjpegsrc->substract_time;
279 return v4lmjpegsrc->handled * GST_SECOND / time;
282 /* if that failed ... */
284 if (!GST_V4L_IS_OPEN(GST_V4LELEMENT(v4lmjpegsrc)))
287 if (!gst_v4l_get_chan_norm(GST_V4LELEMENT(v4lmjpegsrc), NULL, &norm))
290 if (norm == VIDEO_MODE_NTSC)
299 gst_v4lmjpegsrc_src_convert (GstPad *pad,
300 GstFormat src_format,
302 GstFormat *dest_format,
305 GstV4lMjpegSrc *v4lmjpegsrc;
308 v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
310 if ((fps = gst_v4lmjpegsrc_get_fps(v4lmjpegsrc)) == 0)
313 switch (src_format) {
314 case GST_FORMAT_TIME:
315 switch (*dest_format) {
316 case GST_FORMAT_DEFAULT:
317 *dest_value = src_value * fps / GST_SECOND;
324 case GST_FORMAT_DEFAULT:
325 switch (*dest_format) {
326 case GST_FORMAT_TIME:
327 *dest_value = src_value * GST_SECOND / fps;
342 gst_v4lmjpegsrc_src_query (GstPad *pad,
347 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
351 if ((fps = gst_v4lmjpegsrc_get_fps(v4lmjpegsrc)) == 0)
355 case GST_QUERY_POSITION:
357 case GST_FORMAT_TIME:
358 *value = v4lmjpegsrc->handled * GST_SECOND / fps;
360 case GST_FORMAT_DEFAULT:
361 *value = v4lmjpegsrc->handled;
377 calc_bufsize (int hor_dec,
380 guint8 div = hor_dec * ver_dec;
381 guint32 num = (1024 * 512) / (div);
390 if (result > (512 * 1024))
397 static GstPadLinkReturn
398 gst_v4lmjpegsrc_srcconnect (GstPad *pad,
401 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC(gst_pad_get_parent(pad));
402 gint hor_dec, ver_dec;
404 gint max_w = GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth,
405 max_h = GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxheight;
407 GstStructure *structure;
409 /* in case the buffers are active (which means that we already
410 * did capsnego before and didn't clean up), clean up anyways */
411 if (GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
413 if (!gst_v4lmjpegsrc_capture_deinit(v4lmjpegsrc))
414 return GST_PAD_LINK_REFUSED;
416 else if (!GST_V4L_IS_OPEN(GST_V4LELEMENT(v4lmjpegsrc)))
418 return GST_PAD_LINK_DELAYED;
421 /* Note: basically, we don't give a damn about the opposite caps here.
422 * that might seem odd, but it isn't. we know that the opposite caps is
423 * either NULL or has mime type video/x-jpeg, and in both cases, we'll set
424 * our own mime type back and it'll work. Other properties are to be set
425 * by the src, not by the opposite caps */
427 structure = gst_caps_get_structure (caps, 0);
428 gst_structure_get_int (structure, "width", &w);
429 gst_structure_get_int (structure, "height", &h);
431 /* figure out decimation */
434 } else if (w*2 >= max_w) {
441 } else if (h*2 >= max_h) {
447 /* calculate bufsize */
448 bufsize = calc_bufsize(hor_dec, ver_dec);
450 /* set buffer info */
451 if (!gst_v4lmjpegsrc_set_buffer(v4lmjpegsrc,
452 v4lmjpegsrc->numbufs, bufsize)) {
453 return GST_PAD_LINK_REFUSED;
456 /* set capture parameters and mmap the buffers */
457 if (hor_dec == ver_dec) {
458 if (!gst_v4lmjpegsrc_set_capture(v4lmjpegsrc,
460 v4lmjpegsrc->quality)) {
461 return GST_PAD_LINK_REFUSED;
464 if (!gst_v4lmjpegsrc_set_capture_m(v4lmjpegsrc,
467 v4lmjpegsrc->quality)) {
468 return GST_PAD_LINK_REFUSED;
472 if (!v4lmjpegsrc->frame_width && !v4lmjpegsrc->frame_height &&
473 v4lmjpegsrc->x_offset < 0 && v4lmjpegsrc->y_offset < 0 &&
474 v4lmjpegsrc->horizontal_decimation == v4lmjpegsrc->vertical_decimation)
476 if (!gst_v4lmjpegsrc_set_capture(v4lmjpegsrc,
477 v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->quality))
478 return GST_PAD_LINK_REFUSED;
482 if (!gst_v4lmjpegsrc_set_capture_m(v4lmjpegsrc,
483 v4lmjpegsrc->x_offset, v4lmjpegsrc->y_offset,
484 v4lmjpegsrc->frame_width, v4lmjpegsrc->frame_height,
485 v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->vertical_decimation,
486 v4lmjpegsrc->quality))
487 return GST_PAD_LINK_REFUSED;
491 return GST_PAD_LINK_OK;
496 gst_v4lmjpegsrc_get (GstPad *pad)
498 GstV4lMjpegSrc *v4lmjpegsrc;
503 g_return_val_if_fail (pad != NULL, NULL);
505 v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
507 if (v4lmjpegsrc->use_fixed_fps &&
508 (fps = gst_v4lmjpegsrc_get_fps(v4lmjpegsrc)) == 0)
511 if (v4lmjpegsrc->need_writes > 0) {
513 num = v4lmjpegsrc->last_frame;
514 v4lmjpegsrc->need_writes--;
515 } else if (v4lmjpegsrc->clock && v4lmjpegsrc->use_fixed_fps) {
517 gboolean have_frame = FALSE;
520 /* by default, we use the frame once */
521 v4lmjpegsrc->need_writes = 1;
523 /* grab a frame from the device */
524 if (!gst_v4lmjpegsrc_grab_frame(v4lmjpegsrc, &num, &v4lmjpegsrc->last_size))
527 v4lmjpegsrc->last_frame = num;
528 time = GST_TIMEVAL_TO_TIME(v4lmjpegsrc->bsync.timestamp) -
529 v4lmjpegsrc->substract_time;
531 /* first check whether we lost any frames according to the device */
532 if (v4lmjpegsrc->last_seq != 0) {
533 if (v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq > 1) {
534 v4lmjpegsrc->need_writes = v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq;
535 g_signal_emit(G_OBJECT(v4lmjpegsrc),
536 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_LOST], 0,
537 v4lmjpegsrc->bsync.seq - v4lmjpegsrc->last_seq - 1);
540 v4lmjpegsrc->last_seq = v4lmjpegsrc->bsync.seq;
542 /* decide how often we're going to write the frame - set
543 * v4lmjpegsrc->need_writes to (that-1) and have_frame to TRUE
544 * if we're going to write it - else, just continue.
546 * time is generally the system or audio clock. Let's
547 * say that we've written one second of audio, then we want
548 * to have written one second of video too, within the same
549 * timeframe. This means that if time - begin_time = X sec,
550 * we want to have written X*fps frames. If we've written
551 * more - drop, if we've written less - dup... */
552 if (v4lmjpegsrc->handled * (GST_SECOND/fps) - time > 1.5 * (GST_SECOND/fps)) {
553 /* yo dude, we've got too many frames here! Drop! DROP! */
554 v4lmjpegsrc->need_writes--; /* -= (v4lmjpegsrc->handled - (time / fps)); */
555 g_signal_emit(G_OBJECT(v4lmjpegsrc),
556 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_DROP], 0);
557 } else if (v4lmjpegsrc->handled * (GST_SECOND/fps) - time < - 1.5 * (GST_SECOND/fps)) {
558 /* this means we're lagging far behind */
559 v4lmjpegsrc->need_writes++; /* += ((time / fps) - v4lmjpegsrc->handled); */
560 g_signal_emit(G_OBJECT(v4lmjpegsrc),
561 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_INSERT], 0);
564 if (v4lmjpegsrc->need_writes > 0) {
566 v4lmjpegsrc->use_num_times[num] = v4lmjpegsrc->need_writes;
567 v4lmjpegsrc->need_writes--;
569 gst_v4lmjpegsrc_requeue_frame(v4lmjpegsrc, num);
571 } while (!have_frame);
573 /* grab a frame from the device */
574 if (!gst_v4lmjpegsrc_grab_frame(v4lmjpegsrc, &num, &v4lmjpegsrc->last_size))
577 v4lmjpegsrc->use_num_times[num] = 1;
580 buf = gst_buffer_new ();
581 GST_BUFFER_FREE_DATA_FUNC (buf) = gst_v4lmjpegsrc_buffer_free;
582 GST_BUFFER_PRIVATE (buf) = v4lmjpegsrc;
583 GST_BUFFER_DATA(buf) = gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, num);
584 GST_BUFFER_SIZE(buf) = v4lmjpegsrc->last_size;
585 GST_BUFFER_MAXSIZE(buf) = v4lmjpegsrc->breq.size;
586 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_READONLY | GST_BUFFER_DONTFREE);
587 if (v4lmjpegsrc->use_fixed_fps)
588 GST_BUFFER_TIMESTAMP(buf) = v4lmjpegsrc->handled * GST_SECOND / fps;
589 else /* calculate time based on our own clock */
590 GST_BUFFER_TIMESTAMP(buf) = GST_TIMEVAL_TO_TIME(v4lmjpegsrc->bsync.timestamp) -
591 v4lmjpegsrc->substract_time;
593 v4lmjpegsrc->handled++;
594 g_signal_emit(G_OBJECT(v4lmjpegsrc),
595 gst_v4lmjpegsrc_signals[SIGNAL_FRAME_CAPTURE], 0);
597 return GST_DATA (buf);
602 gst_v4lmjpegsrc_getcaps (GstPad *pad)
604 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC(gst_pad_get_parent(pad));
605 struct video_capability *vcap = &GST_V4LELEMENT(v4lmjpegsrc)->vcap;
607 if (!GST_V4L_IS_OPEN(GST_V4LELEMENT(v4lmjpegsrc))) {
611 return gst_caps_new_simple ("video/x-jpeg",
612 "width", GST_TYPE_INT_RANGE, vcap->maxwidth/4, vcap->maxwidth,
613 "height", GST_TYPE_INT_RANGE, vcap->maxheight/4, vcap->maxheight,
614 "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE,
620 gst_v4lmjpegsrc_set_property (GObject *object,
625 GstV4lMjpegSrc *v4lmjpegsrc;
627 g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
628 v4lmjpegsrc = GST_V4LMJPEGSRC(object);
633 v4lmjpegsrc->x_offset = g_value_get_int(value);
636 v4lmjpegsrc->y_offset = g_value_get_int(value);
639 v4lmjpegsrc->frame_width = g_value_get_int(value);
642 v4lmjpegsrc->frame_height = g_value_get_int(value);
646 v4lmjpegsrc->quality = g_value_get_int(value);
649 v4lmjpegsrc->numbufs = g_value_get_int(value);
651 case ARG_USE_FIXED_FPS:
652 if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc))) {
653 v4lmjpegsrc->use_fixed_fps = g_value_get_boolean(value);
657 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
664 gst_v4lmjpegsrc_get_property (GObject *object,
669 GstV4lMjpegSrc *v4lmjpegsrc;
671 g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
672 v4lmjpegsrc = GST_V4LMJPEGSRC(object);
677 g_value_set_int(value, v4lmjpegsrc->x_offset);
680 g_value_set_int(value, v4lmjpegsrc->y_offset);
683 g_value_set_int(value, v4lmjpegsrc->frame_width);
686 g_value_set_int(value, v4lmjpegsrc->frame_height);
690 g_value_set_int(value, v4lmjpegsrc->quality);
693 if (GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
694 g_value_set_int(value, v4lmjpegsrc->breq.count);
696 g_value_set_int(value, v4lmjpegsrc->numbufs);
699 g_value_set_int(value, v4lmjpegsrc->breq.size);
701 case ARG_USE_FIXED_FPS:
702 g_value_set_boolean(value, v4lmjpegsrc->use_fixed_fps);
705 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
711 static GstElementStateReturn
712 gst_v4lmjpegsrc_change_state (GstElement *element)
714 GstV4lMjpegSrc *v4lmjpegsrc;
717 g_return_val_if_fail(GST_IS_V4LMJPEGSRC(element), GST_STATE_FAILURE);
719 v4lmjpegsrc = GST_V4LMJPEGSRC(element);
721 switch (GST_STATE_TRANSITION(element)) {
722 case GST_STATE_READY_TO_PAUSED:
723 /* actual buffer set-up used to be done here - but I moved
724 * it to capsnego itself */
725 v4lmjpegsrc->handled = 0;
726 v4lmjpegsrc->need_writes = 0;
727 v4lmjpegsrc->last_frame = 0;
728 v4lmjpegsrc->substract_time = 0;
730 case GST_STATE_PAUSED_TO_PLAYING:
731 /* queue all buffer, start streaming capture */
732 if (!gst_v4lmjpegsrc_capture_start(v4lmjpegsrc))
733 return GST_STATE_FAILURE;
734 g_get_current_time(&time);
735 v4lmjpegsrc->substract_time = GST_TIMEVAL_TO_TIME(time) -
736 v4lmjpegsrc->substract_time;
737 v4lmjpegsrc->last_seq = 0;
739 case GST_STATE_PLAYING_TO_PAUSED:
740 g_get_current_time(&time);
741 v4lmjpegsrc->substract_time = GST_TIMEVAL_TO_TIME(time) -
742 v4lmjpegsrc->substract_time;
743 /* de-queue all queued buffers */
744 if (!gst_v4lmjpegsrc_capture_stop(v4lmjpegsrc))
745 return GST_STATE_FAILURE;
747 case GST_STATE_PAUSED_TO_READY:
748 /* stop capturing, unmap all buffers */
749 if (!gst_v4lmjpegsrc_capture_deinit(v4lmjpegsrc))
750 return GST_STATE_FAILURE;
754 if (GST_ELEMENT_CLASS (parent_class)->change_state)
755 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
757 return GST_STATE_SUCCESS;
762 gst_v4lmjpegsrc_set_clock (GstElement *element,
765 GST_V4LMJPEGSRC(element)->clock = clock;
771 gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
777 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC(user_data);
779 if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
782 buffer = gst_buffer_new();
786 /* TODO: add interlacing info to buffer as metadata */
787 GST_BUFFER_MAXSIZE(buffer) = v4lmjpegsrc->breq.size;
788 GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
795 gst_v4lmjpegsrc_buffer_free (GstBuffer *buf)
797 GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (GST_BUFFER_PRIVATE (buf));
800 if (gst_element_get_state(GST_ELEMENT(v4lmjpegsrc)) != GST_STATE_PLAYING)
801 return; /* we've already cleaned up ourselves */
803 for (n=0;n<v4lmjpegsrc->breq.count;n++)
804 if (GST_BUFFER_DATA(buf) == gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, n))
806 v4lmjpegsrc->use_num_times[n]--;
807 if (v4lmjpegsrc->use_num_times[n] <= 0) {
808 gst_v4lmjpegsrc_requeue_frame(v4lmjpegsrc, n);
813 if (n == v4lmjpegsrc->breq.count)
814 GST_ELEMENT_ERROR (v4lmjpegsrc, RESOURCE, TOO_LAZY, (NULL),
815 ("Couldn't find the buffer"));