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.
21 #include "v4lmjpegsrc_calls.h"
23 static GstElementDetails gst_v4lmjpegsrc_details = {
24 "Video (video4linux/MJPEG) Source",
26 "Reads MJPEG-encoded frames from a zoran MJPEG/video4linux device",
28 "Ronald Bultje <rbultje@ronald.bitfreak.net>",
32 /* V4lMjpegSrc signals and args */
56 static void gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass *klass);
57 static void gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc);
59 /* pad/buffer functions */
60 static GstPadConnectReturn gst_v4lmjpegsrc_srcconnect (GstPad *pad,
62 static GstBuffer* gst_v4lmjpegsrc_get (GstPad *pad);
65 static void gst_v4lmjpegsrc_set_property (GObject *object,
69 static void gst_v4lmjpegsrc_get_property (GObject *object,
75 static GstElementStateReturn gst_v4lmjpegsrc_change_state (GstElement *element);
77 /* bufferpool functions */
78 static GstBuffer* gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
82 static GstBuffer* gst_v4lmjpegsrc_buffer_copy (GstBuffer *srcbuf);
83 static void gst_v4lmjpegsrc_buffer_free (GstBuffer *buf);
86 static GstCaps *capslist = NULL;
87 static GstPadTemplate *src_template;
89 static GstElementClass *parent_class = NULL;
90 /*static guint gst_v4lmjpegsrc_signals[LAST_SIGNAL] = { 0 }; */
94 gst_v4lmjpegsrc_get_type (void)
96 static GType v4lmjpegsrc_type = 0;
98 if (!v4lmjpegsrc_type) {
99 static const GTypeInfo v4lmjpegsrc_info = {
100 sizeof(GstV4lMjpegSrcClass),
103 (GClassInitFunc)gst_v4lmjpegsrc_class_init,
106 sizeof(GstV4lMjpegSrc),
108 (GInstanceInitFunc)gst_v4lmjpegsrc_init,
111 v4lmjpegsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lMjpegSrc", &v4lmjpegsrc_info, 0);
113 return v4lmjpegsrc_type;
118 gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass *klass)
120 GObjectClass *gobject_class;
121 GstElementClass *gstelement_class;
123 gobject_class = (GObjectClass*)klass;
124 gstelement_class = (GstElementClass*)klass;
126 parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
128 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_X_OFFSET,
129 g_param_spec_int("x_offset","x_offset","x_offset",
130 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
131 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_Y_OFFSET,
132 g_param_spec_int("y_offset","y_offset","y_offset",
133 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
134 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_WIDTH,
135 g_param_spec_int("frame_width","frame_width","frame_width",
136 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
137 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_HEIGHT,
138 g_param_spec_int("frame_height","frame_height","frame_height",
139 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
141 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_H_DECIMATION,
142 g_param_spec_int("h_decimation","h_decimation","h_decimation",
143 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
144 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_V_DECIMATION,
145 g_param_spec_int("v_decimation","v_decimation","v_decimation",
146 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
148 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH,
149 g_param_spec_int("width","width","width",
150 G_MININT,G_MAXINT,0,G_PARAM_READABLE));
151 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HEIGHT,
152 g_param_spec_int("height","height","height",
153 G_MININT,G_MAXINT,0,G_PARAM_READABLE));
155 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_QUALITY,
156 g_param_spec_int("quality","quality","quality",
157 G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
159 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS,
160 g_param_spec_int("num_buffers","num_buffers","num_buffers",
161 G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
162 g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
163 g_param_spec_int("buffer_size","buffer_size","buffer_size",
164 G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
166 gobject_class->set_property = gst_v4lmjpegsrc_set_property;
167 gobject_class->get_property = gst_v4lmjpegsrc_get_property;
169 gstelement_class->change_state = gst_v4lmjpegsrc_change_state;
174 gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc)
176 v4lmjpegsrc->srcpad = gst_pad_new_from_template (src_template, "src");
177 gst_element_add_pad(GST_ELEMENT(v4lmjpegsrc), v4lmjpegsrc->srcpad);
179 gst_pad_set_get_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get);
180 gst_pad_set_connect_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_srcconnect);
182 v4lmjpegsrc->bufferpool = gst_buffer_pool_new();
183 gst_buffer_pool_set_buffer_new_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_new);
184 gst_buffer_pool_set_buffer_copy_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_copy);
185 gst_buffer_pool_set_buffer_free_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_free);
186 gst_buffer_pool_set_user_data(v4lmjpegsrc->bufferpool, v4lmjpegsrc);
188 v4lmjpegsrc->frame_width = 0;
189 v4lmjpegsrc->frame_height = 0;
190 v4lmjpegsrc->x_offset = -1;
191 v4lmjpegsrc->y_offset = -1;
193 v4lmjpegsrc->horizontal_decimation = 4;
194 v4lmjpegsrc->vertical_decimation = 4;
196 v4lmjpegsrc->end_width = 0;
197 v4lmjpegsrc->end_height = 0;
199 v4lmjpegsrc->quality = 50;
201 v4lmjpegsrc->numbufs = 64;
202 v4lmjpegsrc->bufsize = 256;
204 v4lmjpegsrc->capslist = capslist;
208 static GstPadConnectReturn
209 gst_v4lmjpegsrc_srcconnect (GstPad *pad,
212 GstV4lMjpegSrc *v4lmjpegsrc;
214 v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
216 /* we will try_set_caps() with the actual size (wxh) when we know it */
218 return GST_PAD_CONNECT_OK;
223 gst_v4lmjpegsrc_get (GstPad *pad)
225 GstV4lMjpegSrc *v4lmjpegsrc;
229 g_return_val_if_fail (pad != NULL, NULL);
231 v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
233 buf = gst_buffer_new_from_pool(v4lmjpegsrc->bufferpool, 0, 0);
236 gst_element_error(GST_ELEMENT(v4lmjpegsrc),
237 "Failed to create a new GstBuffer");
241 /* grab a frame from the device */
242 if (!gst_v4lmjpegsrc_grab_frame(v4lmjpegsrc, &num, &(GST_BUFFER_SIZE(buf))))
244 GST_BUFFER_DATA(buf) = gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, num);
245 buf->timestamp = v4lmjpegsrc->bsync.timestamp.tv_sec * 1000000000 +
246 v4lmjpegsrc->bsync.timestamp.tv_usec * 1000;
253 gst_v4lmjpegsrc_set_property (GObject *object,
258 GstV4lMjpegSrc *v4lmjpegsrc;
260 g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
261 v4lmjpegsrc = GST_V4LMJPEGSRC(object);
265 v4lmjpegsrc->x_offset = g_value_get_int(value);
268 v4lmjpegsrc->y_offset = g_value_get_int(value);
271 v4lmjpegsrc->frame_width = g_value_get_int(value);
274 v4lmjpegsrc->frame_height = g_value_get_int(value);
276 case ARG_H_DECIMATION:
277 v4lmjpegsrc->horizontal_decimation = g_value_get_int(value);
279 case ARG_V_DECIMATION:
280 v4lmjpegsrc->vertical_decimation = g_value_get_int(value);
283 v4lmjpegsrc->quality = g_value_get_int(value);
286 v4lmjpegsrc->numbufs = g_value_get_int(value);
289 v4lmjpegsrc->bufsize = g_value_get_int(value);
292 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
299 gst_v4lmjpegsrc_get_property (GObject *object,
304 GstV4lMjpegSrc *v4lmjpegsrc;
306 g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
307 v4lmjpegsrc = GST_V4LMJPEGSRC(object);
311 g_value_set_int(value, v4lmjpegsrc->end_width);
314 g_value_set_int(value, v4lmjpegsrc->end_height);
317 g_value_set_int(value, v4lmjpegsrc->x_offset);
320 g_value_set_int(value, v4lmjpegsrc->y_offset);
323 g_value_set_int(value, v4lmjpegsrc->frame_width);
326 g_value_set_int(value, v4lmjpegsrc->frame_height);
328 case ARG_H_DECIMATION:
329 g_value_set_int(value, v4lmjpegsrc->horizontal_decimation);
331 case ARG_V_DECIMATION:
332 g_value_set_int(value, v4lmjpegsrc->vertical_decimation);
335 g_value_set_int(value, v4lmjpegsrc->quality);
338 g_value_set_int(value, v4lmjpegsrc->breq.count);
341 g_value_set_int(value, v4lmjpegsrc->breq.size);
344 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
350 static GstElementStateReturn
351 gst_v4lmjpegsrc_change_state (GstElement *element)
353 GstV4lMjpegSrc *v4lmjpegsrc;
354 GstElementStateReturn parent_value;
357 g_return_val_if_fail(GST_IS_V4LMJPEGSRC(element), GST_STATE_FAILURE);
359 v4lmjpegsrc = GST_V4LMJPEGSRC(element);
361 switch (GST_STATE_TRANSITION(element)) {
362 case GST_STATE_READY_TO_PAUSED:
363 /* set buffer info */
364 if (!gst_v4lmjpegsrc_set_buffer(v4lmjpegsrc, v4lmjpegsrc->numbufs, v4lmjpegsrc->bufsize))
365 return GST_STATE_FAILURE;
366 /* set capture parameters and mmap the buffers */
367 if (!v4lmjpegsrc->frame_width && !v4lmjpegsrc->frame_height &&
368 v4lmjpegsrc->x_offset < 0 && v4lmjpegsrc->y_offset < 0 &&
369 v4lmjpegsrc->horizontal_decimation == v4lmjpegsrc->vertical_decimation)
371 if (!gst_v4lmjpegsrc_set_capture(v4lmjpegsrc,
372 v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->quality))
373 return GST_STATE_FAILURE;
377 if (!gst_v4lmjpegsrc_set_capture_m(v4lmjpegsrc,
378 v4lmjpegsrc->x_offset, v4lmjpegsrc->y_offset,
379 v4lmjpegsrc->frame_width, v4lmjpegsrc->frame_height,
380 v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->vertical_decimation,
381 v4lmjpegsrc->quality))
382 return GST_STATE_FAILURE;
384 /* we now have an actual width/height - *set it* */
385 caps = gst_caps_new("v4lmjpegsrc_caps",
388 "width", GST_PROPS_INT(v4lmjpegsrc->end_width),
389 "height", GST_PROPS_INT(v4lmjpegsrc->end_height),
391 if (!gst_pad_try_set_caps(v4lmjpegsrc->srcpad, caps))
393 gst_element_error(GST_ELEMENT(v4lmjpegsrc),
394 "Failed to set new caps");
395 return GST_STATE_FAILURE;
397 if (!gst_v4lmjpegsrc_capture_init(v4lmjpegsrc))
398 return GST_STATE_FAILURE;
400 case GST_STATE_PAUSED_TO_PLAYING:
401 /* queue all buffer, start streaming capture */
402 if (!gst_v4lmjpegsrc_capture_start(v4lmjpegsrc))
403 return GST_STATE_FAILURE;
405 case GST_STATE_PLAYING_TO_PAUSED:
406 /* de-queue all queued buffers */
407 if (!gst_v4lmjpegsrc_capture_stop(v4lmjpegsrc))
408 return GST_STATE_FAILURE;
410 case GST_STATE_PAUSED_TO_READY:
411 /* stop capturing, unmap all buffers */
412 if (!gst_v4lmjpegsrc_capture_deinit(v4lmjpegsrc))
413 return GST_STATE_FAILURE;
417 if (GST_ELEMENT_CLASS (parent_class)->change_state) {
418 parent_value = GST_ELEMENT_CLASS (parent_class)->change_state (element);
420 parent_value = GST_STATE_FAILURE;
423 if (GST_STATE_TRANSITION(element) == GST_STATE_NULL_TO_READY)
425 /* do autodetection if no input/norm is selected yet */
426 if ((GST_V4LELEMENT(v4lmjpegsrc)->norm < VIDEO_MODE_PAL ||
427 GST_V4LELEMENT(v4lmjpegsrc)->norm == VIDEO_MODE_AUTO) ||
428 (GST_V4LELEMENT(v4lmjpegsrc)->channel < 0 ||
429 GST_V4LELEMENT(v4lmjpegsrc)->channel == V4L_MJPEG_INPUT_AUTO))
433 if (GST_V4LELEMENT(v4lmjpegsrc)->norm < 0)
434 norm = VIDEO_MODE_AUTO;
436 norm = GST_V4LELEMENT(v4lmjpegsrc)->norm;
438 if (GST_V4LELEMENT(v4lmjpegsrc)->channel < 0)
439 input = V4L_MJPEG_INPUT_AUTO;
441 input = GST_V4LELEMENT(v4lmjpegsrc)->channel;
443 if (!gst_v4lmjpegsrc_set_input_norm(v4lmjpegsrc, input, norm))
444 return GST_STATE_FAILURE;
448 if (GST_ELEMENT_CLASS (parent_class)->change_state)
451 return GST_STATE_SUCCESS;
456 gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
463 buffer = gst_buffer_new();
464 if (!buffer) return NULL;
465 buffer->pool_private = user_data;
467 /* TODO: add interlacing info to buffer as metadata */
474 gst_v4lmjpegsrc_buffer_copy (GstBuffer *srcbuf)
478 buffer = gst_buffer_new();
479 if (!buffer) return NULL;
480 GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(srcbuf));
481 if (!GST_BUFFER_DATA(buffer)) return NULL;
482 GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
483 memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(srcbuf), GST_BUFFER_SIZE(srcbuf));
484 GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP(srcbuf);
491 gst_v4lmjpegsrc_buffer_free (GstBuffer *buf)
493 GstV4lMjpegSrc *v4lmjpegsrc = buf->pool_private;
496 for (n=0;n<v4lmjpegsrc->breq.count;n++)
497 if (GST_BUFFER_DATA(buf) == gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, n))
499 gst_v4lmjpegsrc_requeue_frame(v4lmjpegsrc, n);
503 gst_element_error(GST_ELEMENT(v4lmjpegsrc),
504 "Couldn't find the buffer");
509 plugin_init (GModule *module, GstPlugin *plugin)
511 GstElementFactory *factory;
514 /* create an elementfactory for the v4lmjpegsrcparse element */
515 factory = gst_element_factory_new("v4lmjpegsrc",GST_TYPE_V4LMJPEGSRC,
516 &gst_v4lmjpegsrc_details);
517 g_return_val_if_fail(factory != NULL, FALSE);
519 caps = gst_caps_new ("v4lmjpegsrc_caps",
522 "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
523 "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
526 capslist = gst_caps_append(capslist, caps);
528 src_template = gst_pad_template_new (
534 gst_element_factory_add_pad_template (factory, src_template);
536 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
542 GstPluginDesc plugin_desc = {