GstPadTemplate <-> gst_pad_template <-> GST_PAD_TEMPLATE same with *factory and typefind.
[platform/upstream/gstreamer.git] / sys / v4l / gstv4lmjpegsrc.c
1 /* G-Streamer hardware MJPEG video source plugin
2  * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 #include <string.h>
21 #include "v4lmjpegsrc_calls.h"
22
23 static GstElementDetails gst_v4lmjpegsrc_details = {
24   "Video (video4linux/MJPEG) Source",
25   "Source/Video",
26   "Reads MJPEG-encoded frames from a zoran MJPEG/video4linux device",
27   VERSION,
28   "Ronald Bultje <rbultje@ronald.bitfreak.net>",
29   "(C) 2001",
30 };
31
32 /* V4lMjpegSrc signals and args */
33 enum {
34   /* FILL ME */
35   LAST_SIGNAL
36 };
37
38 /* arguments */
39 enum {
40   ARG_0,
41   ARG_X_OFFSET,
42   ARG_Y_OFFSET,
43   ARG_F_WIDTH,
44   ARG_F_HEIGHT,
45   ARG_H_DECIMATION,
46   ARG_V_DECIMATION,
47   ARG_WIDTH,
48   ARG_HEIGHT,
49   ARG_QUALITY,
50   ARG_NUMBUFS,
51   ARG_BUFSIZE
52 };
53
54
55 /* init functions */
56 static void                  gst_v4lmjpegsrc_class_init   (GstV4lMjpegSrcClass *klass);
57 static void                  gst_v4lmjpegsrc_init         (GstV4lMjpegSrc *v4lmjpegsrc);
58
59 /* pad/buffer functions */
60 static GstPadConnectReturn   gst_v4lmjpegsrc_srcconnect   (GstPad         *pad,
61                                                            GstCaps        *caps);
62 static GstBuffer*            gst_v4lmjpegsrc_get          (GstPad         *pad);
63
64 /* get/set params */
65 static void                  gst_v4lmjpegsrc_set_property (GObject        *object,
66                                                            guint          prop_id,
67                                                            const GValue   *value,
68                                                            GParamSpec     *pspec);
69 static void                  gst_v4lmjpegsrc_get_property (GObject        *object,
70                                                            guint          prop_id,
71                                                            GValue         *value,
72                                                            GParamSpec     *pspec);
73
74 /* state handling */
75 static GstElementStateReturn gst_v4lmjpegsrc_change_state (GstElement     *element);
76
77 /* bufferpool functions */
78 static GstBuffer*            gst_v4lmjpegsrc_buffer_new   (GstBufferPool  *pool,
79                                                            gint64         location,
80                                                            gint           size,
81                                                            gpointer       user_data);
82 static GstBuffer*            gst_v4lmjpegsrc_buffer_copy  (GstBuffer      *srcbuf);
83 static void                  gst_v4lmjpegsrc_buffer_free  (GstBuffer      *buf);
84
85
86 static GstCaps *capslist = NULL;
87 static GstPadTemplate *src_template;
88
89 static GstElementClass *parent_class = NULL;
90 /*static guint gst_v4lmjpegsrc_signals[LAST_SIGNAL] = { 0 }; */
91
92
93 GType
94 gst_v4lmjpegsrc_get_type (void)
95 {
96   static GType v4lmjpegsrc_type = 0;
97
98   if (!v4lmjpegsrc_type) {
99     static const GTypeInfo v4lmjpegsrc_info = {
100       sizeof(GstV4lMjpegSrcClass),
101       NULL,
102       NULL,
103       (GClassInitFunc)gst_v4lmjpegsrc_class_init,
104       NULL,
105       NULL,
106       sizeof(GstV4lMjpegSrc),
107       0,
108       (GInstanceInitFunc)gst_v4lmjpegsrc_init,
109       NULL
110     };
111     v4lmjpegsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lMjpegSrc", &v4lmjpegsrc_info, 0);
112   }
113   return v4lmjpegsrc_type;
114 }
115
116
117 static void
118 gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass *klass)
119 {
120   GObjectClass *gobject_class;
121   GstElementClass *gstelement_class;
122
123   gobject_class = (GObjectClass*)klass;
124   gstelement_class = (GstElementClass*)klass;
125
126   parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
127
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));
140
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));
147
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));
154
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));
158
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));
165
166   gobject_class->set_property = gst_v4lmjpegsrc_set_property;
167   gobject_class->get_property = gst_v4lmjpegsrc_get_property;
168
169   gstelement_class->change_state = gst_v4lmjpegsrc_change_state;
170 }
171
172
173 static void
174 gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc)
175 {
176   v4lmjpegsrc->srcpad = gst_pad_new_from_template (src_template, "src");
177   gst_element_add_pad(GST_ELEMENT(v4lmjpegsrc), v4lmjpegsrc->srcpad);
178
179   gst_pad_set_get_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get);
180   gst_pad_set_connect_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_srcconnect);
181
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);
187
188   v4lmjpegsrc->frame_width = 0;
189   v4lmjpegsrc->frame_height = 0;
190   v4lmjpegsrc->x_offset = -1;
191   v4lmjpegsrc->y_offset = -1;
192
193   v4lmjpegsrc->horizontal_decimation = 4;
194   v4lmjpegsrc->vertical_decimation = 4;
195
196   v4lmjpegsrc->end_width = 0;
197   v4lmjpegsrc->end_height = 0;
198
199   v4lmjpegsrc->quality = 50;
200
201   v4lmjpegsrc->numbufs = 64;
202   v4lmjpegsrc->bufsize = 256;
203
204   v4lmjpegsrc->capslist = capslist;
205 }
206
207
208 static GstPadConnectReturn
209 gst_v4lmjpegsrc_srcconnect (GstPad  *pad,
210                             GstCaps *caps)
211 {
212   GstV4lMjpegSrc *v4lmjpegsrc;
213
214   v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
215
216   /* we will try_set_caps() with the actual size (wxh) when we know it */
217
218   return GST_PAD_CONNECT_OK;
219 }
220
221
222 static GstBuffer*
223 gst_v4lmjpegsrc_get (GstPad *pad)
224 {
225   GstV4lMjpegSrc *v4lmjpegsrc;
226   GstBuffer *buf;
227   gint num;
228
229   g_return_val_if_fail (pad != NULL, NULL);
230
231   v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
232
233   buf = gst_buffer_new_from_pool(v4lmjpegsrc->bufferpool, 0, 0);
234   if (!buf)
235   {
236     gst_element_error(GST_ELEMENT(v4lmjpegsrc),
237       "Failed to create a new GstBuffer");
238     return NULL;
239   }
240
241   /* grab a frame from the device */
242   if (!gst_v4lmjpegsrc_grab_frame(v4lmjpegsrc, &num, &(GST_BUFFER_SIZE(buf))))
243     return NULL;
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;
247
248   return buf;
249 }
250
251
252 static void
253 gst_v4lmjpegsrc_set_property (GObject      *object,
254                               guint        prop_id,
255                               const GValue *value,
256                               GParamSpec   *pspec)
257 {
258   GstV4lMjpegSrc *v4lmjpegsrc;
259
260   g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
261   v4lmjpegsrc = GST_V4LMJPEGSRC(object);
262
263   switch (prop_id) {
264     case ARG_X_OFFSET:
265       v4lmjpegsrc->x_offset = g_value_get_int(value);
266       break;
267     case ARG_Y_OFFSET:
268       v4lmjpegsrc->y_offset = g_value_get_int(value);
269       break;
270     case ARG_F_WIDTH:
271       v4lmjpegsrc->frame_width = g_value_get_int(value);
272       break;
273     case ARG_F_HEIGHT:
274       v4lmjpegsrc->frame_height = g_value_get_int(value);
275       break;
276     case ARG_H_DECIMATION:
277       v4lmjpegsrc->horizontal_decimation = g_value_get_int(value);
278       break;
279     case ARG_V_DECIMATION:
280       v4lmjpegsrc->vertical_decimation = g_value_get_int(value);
281       break;
282     case ARG_QUALITY:
283       v4lmjpegsrc->quality = g_value_get_int(value);
284       break;
285     case ARG_NUMBUFS:
286       v4lmjpegsrc->numbufs = g_value_get_int(value);
287       break;
288     case ARG_BUFSIZE:
289       v4lmjpegsrc->bufsize = g_value_get_int(value);
290       break;
291     default:
292       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
293       break;
294   }
295 }
296
297
298 static void
299 gst_v4lmjpegsrc_get_property (GObject    *object,
300                               guint      prop_id,
301                               GValue     *value,
302                               GParamSpec *pspec)
303 {
304   GstV4lMjpegSrc *v4lmjpegsrc;
305
306   g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
307   v4lmjpegsrc = GST_V4LMJPEGSRC(object);
308
309   switch (prop_id) {
310     case ARG_WIDTH:
311       g_value_set_int(value, v4lmjpegsrc->end_width);
312       break;
313     case ARG_HEIGHT:
314       g_value_set_int(value, v4lmjpegsrc->end_height);
315       break;
316     case ARG_X_OFFSET:
317       g_value_set_int(value, v4lmjpegsrc->x_offset);
318       break;
319     case ARG_Y_OFFSET:
320       g_value_set_int(value, v4lmjpegsrc->y_offset);
321       break;
322     case ARG_F_WIDTH:
323       g_value_set_int(value, v4lmjpegsrc->frame_width);
324       break;
325     case ARG_F_HEIGHT:
326       g_value_set_int(value, v4lmjpegsrc->frame_height);
327       break;
328     case ARG_H_DECIMATION:
329       g_value_set_int(value, v4lmjpegsrc->horizontal_decimation);
330       break;
331     case ARG_V_DECIMATION:
332       g_value_set_int(value, v4lmjpegsrc->vertical_decimation);
333       break;
334     case ARG_QUALITY:
335       g_value_set_int(value, v4lmjpegsrc->quality);
336       break;
337     case ARG_NUMBUFS:
338       g_value_set_int(value, v4lmjpegsrc->breq.count);
339       break;
340     case ARG_BUFSIZE:
341       g_value_set_int(value, v4lmjpegsrc->breq.size);
342       break;
343     default:
344       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
345       break;
346   }
347 }
348
349
350 static GstElementStateReturn
351 gst_v4lmjpegsrc_change_state (GstElement *element)
352 {
353   GstV4lMjpegSrc *v4lmjpegsrc;
354   GstElementStateReturn parent_value;
355   GstCaps *caps;
356
357   g_return_val_if_fail(GST_IS_V4LMJPEGSRC(element), GST_STATE_FAILURE);
358   
359   v4lmjpegsrc = GST_V4LMJPEGSRC(element);
360
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)
370       {
371         if (!gst_v4lmjpegsrc_set_capture(v4lmjpegsrc,
372             v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->quality))
373           return GST_STATE_FAILURE;
374       }
375       else
376       {
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;
383       }
384       /* we now have an actual width/height - *set it* */
385       caps = gst_caps_new("v4lmjpegsrc_caps",
386                           "video/jpeg",
387                           gst_props_new(
388                             "width",  GST_PROPS_INT(v4lmjpegsrc->end_width),
389                             "height", GST_PROPS_INT(v4lmjpegsrc->end_height),
390                             NULL       ) );
391       if (!gst_pad_try_set_caps(v4lmjpegsrc->srcpad, caps))
392       {
393         gst_element_error(GST_ELEMENT(v4lmjpegsrc),
394           "Failed to set new caps");
395         return GST_STATE_FAILURE;
396       }
397       if (!gst_v4lmjpegsrc_capture_init(v4lmjpegsrc))
398         return GST_STATE_FAILURE;
399       break;
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;
404       break;
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;
409       break;
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;
414       break;
415   }
416
417   if (GST_ELEMENT_CLASS (parent_class)->change_state) {
418     parent_value = GST_ELEMENT_CLASS (parent_class)->change_state (element);
419   } else {
420     parent_value = GST_STATE_FAILURE;
421   }
422
423   if (GST_STATE_TRANSITION(element) == GST_STATE_NULL_TO_READY)
424   {
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))
430     {
431       gint norm, input;
432
433       if (GST_V4LELEMENT(v4lmjpegsrc)->norm < 0)
434         norm = VIDEO_MODE_AUTO;
435       else
436         norm = GST_V4LELEMENT(v4lmjpegsrc)->norm;
437
438       if (GST_V4LELEMENT(v4lmjpegsrc)->channel < 0)
439         input = V4L_MJPEG_INPUT_AUTO;
440       else
441         input = GST_V4LELEMENT(v4lmjpegsrc)->channel;
442
443       if (!gst_v4lmjpegsrc_set_input_norm(v4lmjpegsrc, input, norm))
444         return GST_STATE_FAILURE;
445     }
446   }
447
448   if (GST_ELEMENT_CLASS (parent_class)->change_state)
449     return parent_value;
450
451   return GST_STATE_SUCCESS;
452 }
453
454
455 static GstBuffer*
456 gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
457                             gint64        location,
458                             gint          size,
459                             gpointer      user_data)
460 {
461   GstBuffer *buffer;
462
463   buffer = gst_buffer_new();
464   if (!buffer) return NULL;
465   buffer->pool_private = user_data;
466
467   /* TODO: add interlacing info to buffer as metadata */
468
469   return buffer;
470 }
471
472
473 static GstBuffer*
474 gst_v4lmjpegsrc_buffer_copy (GstBuffer *srcbuf)
475 {
476   GstBuffer *buffer;
477
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);
485
486   return buffer;
487 }
488
489
490 static void
491 gst_v4lmjpegsrc_buffer_free (GstBuffer *buf)
492 {
493   GstV4lMjpegSrc *v4lmjpegsrc = buf->pool_private;
494   int n;
495
496   for (n=0;n<v4lmjpegsrc->breq.count;n++)
497     if (GST_BUFFER_DATA(buf) == gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, n))
498     {
499       gst_v4lmjpegsrc_requeue_frame(v4lmjpegsrc, n);
500       return;
501     }
502
503   gst_element_error(GST_ELEMENT(v4lmjpegsrc),
504     "Couldn't find the buffer");
505 }
506
507
508 static gboolean
509 plugin_init (GModule *module, GstPlugin *plugin)
510 {
511   GstElementFactory *factory;
512   GstCaps *caps;
513
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);
518
519   caps = gst_caps_new ("v4lmjpegsrc_caps",
520                        "video/jpeg",
521                        gst_props_new (
522                           "width",  GST_PROPS_INT_RANGE (0, G_MAXINT),
523                           "height", GST_PROPS_INT_RANGE (0, G_MAXINT),
524                           NULL       )
525                       );
526   capslist = gst_caps_append(capslist, caps);
527
528   src_template = gst_pad_template_new (
529                   "src",
530                   GST_PAD_SRC,
531                   GST_PAD_ALWAYS,
532                   capslist, NULL);
533
534   gst_element_factory_add_pad_template (factory, src_template);
535
536   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
537
538   return TRUE;
539 }
540
541
542 GstPluginDesc plugin_desc = {
543   GST_VERSION_MAJOR,
544   GST_VERSION_MINOR,
545   "v4lmjpegsrc",
546   plugin_init
547 };