Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / sys / v4l / gstv4lmjpegsink.c
1 /* GStreamer
2  *
3  * gstv4lmjpegsink.c: hardware MJPEG video sink plugin
4  *
5  * Copyright (C) 2001-2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <string.h>
28 #include "v4lmjpegsink_calls.h"
29
30 GST_DEBUG_CATEGORY_STATIC (v4lmjpegsink_debug);
31 #define GST_CAT_DEFAULT v4lmjpegsink_debug
32
33 /* v4lmjpegsink signals and args */
34 enum
35 {
36   SIGNAL_FRAME_DISPLAYED,
37   LAST_SIGNAL
38 };
39
40 enum
41 {
42   ARG_0,
43   ARG_NUMBUFS,
44   ARG_BUFSIZE,
45   ARG_X_OFFSET,
46   ARG_Y_OFFSET,
47   ARG_FRAMES_DISPLAYED,
48   ARG_FRAME_TIME
49 };
50
51
52 /* init functions */
53 static void gst_v4lmjpegsink_base_init (gpointer g_class);
54 static void gst_v4lmjpegsink_class_init (GstV4lMjpegSinkClass * klass);
55 static void gst_v4lmjpegsink_init (GstV4lMjpegSink * v4lmjpegsink);
56
57 /* the chain of buffers */
58 static GstPadLinkReturn gst_v4lmjpegsink_sinkconnect (GstPad * pad,
59     const GstCaps * vscapslist);
60 static void gst_v4lmjpegsink_chain (GstPad * pad, GstData * _data);
61
62 /* get/set gst object functions */
63 static void gst_v4lmjpegsink_set_property (GObject * object,
64     guint prop_id, const GValue * value, GParamSpec * pspec);
65 static void gst_v4lmjpegsink_get_property (GObject * object,
66     guint prop_id, GValue * value, GParamSpec * pspec);
67 static GstStateChangeReturn gst_v4lmjpegsink_change_state (GstElement *
68     element);
69 static void gst_v4lmjpegsink_set_clock (GstElement * element, GstClock * clock);
70
71
72 static GstElementClass *parent_class = NULL;
73 static guint gst_v4lmjpegsink_signals[LAST_SIGNAL] = { 0 };
74
75
76 GType
77 gst_v4lmjpegsink_get_type (void)
78 {
79   static GType v4lmjpegsink_type = 0;
80
81   if (!v4lmjpegsink_type) {
82     static const GTypeInfo v4lmjpegsink_info = {
83       sizeof (GstV4lMjpegSinkClass),
84       gst_v4lmjpegsink_base_init,
85       NULL,
86       (GClassInitFunc) gst_v4lmjpegsink_class_init,
87       NULL,
88       NULL,
89       sizeof (GstV4lMjpegSink),
90       0,
91       (GInstanceInitFunc) gst_v4lmjpegsink_init,
92     };
93
94     v4lmjpegsink_type =
95         g_type_register_static (GST_TYPE_V4LELEMENT, "GstV4lMjpegSink",
96         &v4lmjpegsink_info, 0);
97   }
98   return v4lmjpegsink_type;
99 }
100
101 static void
102 gst_v4lmjpegsink_base_init (gpointer g_class)
103 {
104   static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
105       GST_PAD_SINK,
106       GST_PAD_ALWAYS,
107       GST_STATIC_CAPS ("image/jpeg, "
108           "width = (int) [ 1, MAX ], "
109           "height = (int) [ 1, MAX ], " "framerate = (fraction) [ 0, MAX ]")
110       );
111   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
112
113   gst_element_class_set_details_simple (gstelement_class,
114       "Video (video4linux/MJPEG) sink", "Sink/Video",
115       "Writes MJPEG-encoded frames to a zoran MJPEG/video4linux device",
116       "GStreamer maintainers <gstreamer-devel@lists.sourceforge.net>");
117
118   gst_element_class_add_pad_template (gstelement_class,
119       gst_static_pad_template_get (&sink_template));
120 }
121
122 static void
123 gst_v4lmjpegsink_class_init (GstV4lMjpegSinkClass * klass)
124 {
125   GObjectClass *gobject_class;
126   GstElementClass *gstelement_class;
127
128   gobject_class = (GObjectClass *) klass;
129   gstelement_class = (GstElementClass *) klass;
130
131   parent_class = g_type_class_peek_parent (klass);
132
133   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUMBUFS,
134       g_param_spec_int ("num-buffers", "num-buffers", "num-buffers",
135           G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
136   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BUFSIZE,
137       g_param_spec_int ("buffer-size", "buffer-size", "buffer-size",
138           G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
139
140   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_X_OFFSET,
141       g_param_spec_int ("x-offset", "x-offset", "x-offset",
142           G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
143   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_Y_OFFSET,
144       g_param_spec_int ("y-offset", "y-offset", "y-offset",
145           G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
146
147   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAMES_DISPLAYED,
148       g_param_spec_int ("frames-displayed", "frames-displayed",
149           "frames-displayed", G_MININT, G_MAXINT, 0,
150           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
151   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FRAME_TIME,
152       g_param_spec_int ("frame-time", "frame-time", "frame-time", G_MININT,
153           G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
154
155   GST_DEBUG_CATEGORY_INIT (v4lmjpegsink_debug, "v4lmjpegsink", 0,
156       "V4L MJPEG sink element");
157   gobject_class->set_property = gst_v4lmjpegsink_set_property;
158   gobject_class->get_property = gst_v4lmjpegsink_get_property;
159
160   gst_v4lmjpegsink_signals[SIGNAL_FRAME_DISPLAYED] =
161       g_signal_new ("frame-displayed", G_TYPE_FROM_CLASS (klass),
162       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstV4lMjpegSinkClass,
163           frame_displayed), NULL, NULL, g_cclosure_marshal_VOID__VOID,
164       G_TYPE_NONE, 0);
165
166   gstelement_class->change_state = gst_v4lmjpegsink_change_state;
167   gstelement_class->set_clock = gst_v4lmjpegsink_set_clock;
168 }
169
170
171 static void
172 gst_v4lmjpegsink_init (GstV4lMjpegSink * v4lmjpegsink)
173 {
174   GstElementClass *klass = GST_ELEMENT_GET_CLASS (v4lmjpegsink);
175
176   v4lmjpegsink->sinkpad =
177       gst_pad_new_from_template (gst_element_class_get_pad_template (klass,
178           "sink"), "sink");
179   gst_element_add_pad (GST_ELEMENT (v4lmjpegsink), v4lmjpegsink->sinkpad);
180
181   gst_pad_set_chain_function (v4lmjpegsink->sinkpad, gst_v4lmjpegsink_chain);
182   gst_pad_set_link_function (v4lmjpegsink->sinkpad,
183       gst_v4lmjpegsink_sinkconnect);
184
185   v4lmjpegsink->clock = NULL;
186
187   v4lmjpegsink->width = -1;
188   v4lmjpegsink->height = -1;
189
190   v4lmjpegsink->x_offset = -1;
191   v4lmjpegsink->y_offset = -1;
192
193   v4lmjpegsink->numbufs = 64;
194   v4lmjpegsink->bufsize = 256;
195
196   GST_OBJECT_FLAG_SET (v4lmjpegsink, GST_ELEMENT_THREAD_SUGGESTED);
197 }
198
199
200 static GstPadLinkReturn
201 gst_v4lmjpegsink_sinkconnect (GstPad * pad, const GstCaps * vscapslist)
202 {
203   GstV4lMjpegSink *v4lmjpegsink;
204   GstStructure *structure;
205
206   v4lmjpegsink = GST_V4LMJPEGSINK (gst_pad_get_parent (pad));
207
208   /* in case the buffers are active (which means that we already
209    * did capsnego before and didn't clean up), clean up anyways */
210   if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)))
211     if (!gst_v4lmjpegsink_playback_deinit (v4lmjpegsink))
212       return GST_PAD_LINK_REFUSED;
213
214   structure = gst_caps_get_structure (vscapslist, 0);
215
216   gst_structure_get_int (structure, "width", &v4lmjpegsink->width);
217   gst_structure_get_int (structure, "height", &v4lmjpegsink->height);
218
219   if (!gst_v4lmjpegsink_set_playback (v4lmjpegsink, v4lmjpegsink->width, v4lmjpegsink->height, v4lmjpegsink->x_offset, v4lmjpegsink->y_offset, GST_V4LELEMENT (v4lmjpegsink)->vchan.norm, 0))   /* TODO: interlacing */
220     return GST_PAD_LINK_REFUSED;
221
222   /* set buffer info */
223   if (!gst_v4lmjpegsink_set_buffer (v4lmjpegsink,
224           v4lmjpegsink->numbufs, v4lmjpegsink->bufsize))
225     return GST_PAD_LINK_REFUSED;
226   if (!gst_v4lmjpegsink_playback_init (v4lmjpegsink))
227     return GST_PAD_LINK_REFUSED;
228
229   return GST_PAD_LINK_OK;
230
231 }
232
233
234 static void
235 gst_v4lmjpegsink_set_clock (GstElement * element, GstClock * clock)
236 {
237   GstV4lMjpegSink *v4mjpegsink = GST_V4LMJPEGSINK (element);
238
239   v4mjpegsink->clock = clock;
240 }
241
242
243 static void
244 gst_v4lmjpegsink_chain (GstPad * pad, GstData * _data)
245 {
246   GstBuffer *buf = GST_BUFFER (_data);
247   GstV4lMjpegSink *v4lmjpegsink;
248   gint num;
249
250   g_return_if_fail (pad != NULL);
251   g_return_if_fail (GST_IS_PAD (pad));
252   g_return_if_fail (buf != NULL);
253
254   v4lmjpegsink = GST_V4LMJPEGSINK (gst_pad_get_parent (pad));
255
256   if (v4lmjpegsink->clock) {
257     GST_DEBUG ("videosink: clock wait: %" G_GUINT64_FORMAT,
258         GST_BUFFER_TIMESTAMP (buf));
259
260     gst_element_wait (GST_ELEMENT (v4lmjpegsink), GST_BUFFER_TIMESTAMP (buf));
261   }
262 #if 0
263   if (GST_BUFFER_POOL (buf) == v4lmjpegsink->bufferpool) {
264     num = GPOINTER_TO_INT (GST_BUFFER_POOL_PRIVATE (buf));
265     gst_v4lmjpegsink_play_frame (v4lmjpegsink, num);
266   } else {
267 #endif
268     /* check size */
269     if (GST_BUFFER_SIZE (buf) > v4lmjpegsink->breq.size) {
270       GST_ELEMENT_ERROR (v4lmjpegsink, RESOURCE, WRITE, (NULL),
271           ("Buffer too big (%d KB), max. buffersize is %ld KB",
272               GST_BUFFER_SIZE (buf) / 1024, v4lmjpegsink->breq.size / 1024));
273       return;
274     }
275
276     /* put JPEG data to the device */
277     gst_v4lmjpegsink_wait_frame (v4lmjpegsink, &num);
278     memcpy (gst_v4lmjpegsink_get_buffer (v4lmjpegsink, num),
279         GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
280     gst_v4lmjpegsink_play_frame (v4lmjpegsink, num);
281 #if 0
282   }
283 #endif
284
285   g_signal_emit (G_OBJECT (v4lmjpegsink),
286       gst_v4lmjpegsink_signals[SIGNAL_FRAME_DISPLAYED], 0);
287
288   gst_buffer_unref (buf);
289 }
290
291
292 #if 0
293 static GstBuffer *
294 gst_v4lmjpegsink_buffer_new (GstBufferPool * pool,
295     guint64 offset, guint size, gpointer user_data)
296 {
297   GstV4lMjpegSink *v4lmjpegsink = GST_V4LMJPEGSINK (user_data);
298   GstBuffer *buffer = NULL;
299   guint8 *data;
300   gint num;
301
302   if (!GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lmjpegsink)))
303     return NULL;
304   if (v4lmjpegsink->breq.size < size) {
305     GST_DEBUG ("Requested buffer size is too large (%d > %ld)",
306         size, v4lmjpegsink->breq.size);
307     return NULL;
308   }
309   if (!gst_v4lmjpegsink_wait_frame (v4lmjpegsink, &num))
310     return NULL;
311   data = gst_v4lmjpegsink_get_buffer (v4lmjpegsink, num);
312   if (!data)
313     return NULL;
314   buffer = gst_buffer_new ();
315   GST_BUFFER_DATA (buffer) = data;
316   GST_BUFFER_MAXSIZE (buffer) = v4lmjpegsink->breq.size;
317   GST_BUFFER_SIZE (buffer) = size;
318   GST_BUFFER_POOL (buffer) = pool;
319   GST_BUFFER_POOL_PRIVATE (buffer) = GINT_TO_POINTER (num);
320
321   /* with this flag set, we don't need our own buffer_free() function */
322   GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_DONTFREE);
323
324   return buffer;
325 }
326 #endif
327
328
329 static void
330 gst_v4lmjpegsink_set_property (GObject * object,
331     guint prop_id, const GValue * value, GParamSpec * pspec)
332 {
333   GstV4lMjpegSink *v4lmjpegsink;
334
335   g_return_if_fail (GST_IS_V4LMJPEGSINK (object));
336
337   v4lmjpegsink = GST_V4LMJPEGSINK (object);
338
339   switch (prop_id) {
340     case ARG_NUMBUFS:
341       v4lmjpegsink->numbufs = g_value_get_int (value);
342       break;
343     case ARG_BUFSIZE:
344       v4lmjpegsink->bufsize = g_value_get_int (value);
345       break;
346     case ARG_X_OFFSET:
347       v4lmjpegsink->x_offset = g_value_get_int (value);
348       break;
349     case ARG_Y_OFFSET:
350       v4lmjpegsink->y_offset = g_value_get_int (value);
351       break;
352     default:
353       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
354       break;
355   }
356 }
357
358
359 static void
360 gst_v4lmjpegsink_get_property (GObject * object,
361     guint prop_id, GValue * value, GParamSpec * pspec)
362 {
363   GstV4lMjpegSink *v4lmjpegsink;
364
365   v4lmjpegsink = GST_V4LMJPEGSINK (object);
366
367   switch (prop_id) {
368     case ARG_FRAMES_DISPLAYED:
369       g_value_set_int (value, v4lmjpegsink->frames_displayed);
370       break;
371     case ARG_FRAME_TIME:
372       g_value_set_int (value, v4lmjpegsink->frame_time / 1000000);
373       break;
374     case ARG_NUMBUFS:
375       g_value_set_int (value, v4lmjpegsink->numbufs);
376       break;
377     case ARG_BUFSIZE:
378       g_value_set_int (value, v4lmjpegsink->bufsize);
379       break;
380     default:
381       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
382       break;
383   }
384 }
385
386
387 static GstStateChangeReturn
388 gst_v4lmjpegsink_change_state (GstElement * element, GstStateChange transition)
389 {
390   GstV4lMjpegSink *v4lmjpegsink;
391   GstStateChangeReturn parent_value;
392
393   g_return_val_if_fail (GST_IS_V4LMJPEGSINK (element),
394       GST_STATE_CHANGE_FAILURE);
395   v4lmjpegsink = GST_V4LMJPEGSINK (element);
396
397   /* set up change state */
398   switch (transition) {
399     case GST_STATE_CHANGE_READY_TO_PAUSED:
400       /* we used to do buffer setup here, but that's now done
401        * right after capsnego */
402       break;
403     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
404       /* start */
405       if (!gst_v4lmjpegsink_playback_start (v4lmjpegsink))
406         return GST_STATE_CHANGE_FAILURE;
407       break;
408     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
409       /* de-queue all queued buffers */
410       if (!gst_v4lmjpegsink_playback_stop (v4lmjpegsink))
411         return GST_STATE_CHANGE_FAILURE;
412       break;
413     case GST_STATE_CHANGE_PAUSED_TO_READY:
414       /* stop playback, unmap all buffers */
415       if (!gst_v4lmjpegsink_playback_deinit (v4lmjpegsink))
416         return GST_STATE_CHANGE_FAILURE;
417       break;
418   }
419
420   if (GST_ELEMENT_CLASS (parent_class)->change_state) {
421     parent_value =
422         GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
423   } else {
424     parent_value = GST_STATE_CHANGE_FAILURE;
425   }
426
427   if (GST_ELEMENT_CLASS (parent_class)->change_state)
428     return parent_value;
429
430   return GST_STATE_CHANGE_SUCCESS;
431 }