upload tizen1.0 source
[framework/multimedia/gst-plugins-good0.10.git] / gst / debugutils / gstnavseek.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2003> David Schleef <ds@schleef.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * This file was (probably) generated from gstnavseek.c,
23  * gstnavseek.c,v 1.7 2003/11/08 02:48:59 dschleef Exp 
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "gstnavseek.h"
31 #include <string.h>
32 #include <math.h>
33
34 enum
35 {
36   ARG_0,
37   ARG_SEEKOFFSET
38 };
39
40 GstStaticPadTemplate navseek_src_template = GST_STATIC_PAD_TEMPLATE ("src",
41     GST_PAD_SRC,
42     GST_PAD_ALWAYS,
43     GST_STATIC_CAPS_ANY);
44
45 GstStaticPadTemplate navseek_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
46     GST_PAD_SINK,
47     GST_PAD_ALWAYS,
48     GST_STATIC_CAPS_ANY);
49
50 static gboolean gst_navseek_event (GstBaseTransform * trans, GstEvent * event);
51 static GstFlowReturn gst_navseek_transform_ip (GstBaseTransform * basetrans,
52     GstBuffer * buf);
53 static gboolean gst_navseek_handle_src_event (GstPad * pad, GstEvent * event);
54 static gboolean gst_navseek_stop (GstBaseTransform * trans);
55 static gboolean gst_navseek_start (GstBaseTransform * trans);
56
57 static void gst_navseek_set_property (GObject * object, guint prop_id,
58     const GValue * value, GParamSpec * pspec);
59 static void gst_navseek_get_property (GObject * object, guint prop_id,
60     GValue * value, GParamSpec * pspec);
61
62 GType gst_navseek_get_type (void);
63 GST_BOILERPLATE (GstNavSeek, gst_navseek, GstBaseTransform,
64     GST_TYPE_BASE_TRANSFORM);
65
66 static void
67 gst_navseek_base_init (gpointer g_class)
68 {
69   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
70
71   gst_element_class_add_pad_template (element_class,
72       gst_static_pad_template_get (&navseek_sink_template));
73   gst_element_class_add_pad_template (element_class,
74       gst_static_pad_template_get (&navseek_src_template));
75
76   gst_element_class_set_details_simple (element_class,
77       "Seek based on left-right arrows", "Filter/Video",
78       "Seek based on navigation keys left-right",
79       "Jan Schmidt <thaytan@mad.scientist.com>");
80 }
81
82 static void
83 gst_navseek_class_init (GstNavSeekClass * klass)
84 {
85   GstBaseTransformClass *gstbasetrans_class;
86   GObjectClass *gobject_class;
87
88   gobject_class = G_OBJECT_CLASS (klass);
89   gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
90
91   gobject_class->set_property = gst_navseek_set_property;
92   gobject_class->get_property = gst_navseek_get_property;
93
94   g_object_class_install_property (gobject_class,
95       ARG_SEEKOFFSET, g_param_spec_double ("seek-offset", "Seek Offset",
96           "Time in seconds to seek by", 0.0, G_MAXDOUBLE, 5.0,
97           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
98
99   gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_navseek_event);
100   gstbasetrans_class->transform_ip =
101       GST_DEBUG_FUNCPTR (gst_navseek_transform_ip);
102   gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_navseek_start);
103   gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_navseek_stop);
104 }
105
106 static void
107 gst_navseek_init (GstNavSeek * navseek, GstNavSeekClass * g_class)
108 {
109   gst_pad_set_event_function (GST_BASE_TRANSFORM (navseek)->srcpad,
110       GST_DEBUG_FUNCPTR (gst_navseek_handle_src_event));
111
112   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (navseek), TRUE);
113
114   navseek->seek_offset = 5.0;
115   navseek->loop = FALSE;
116   navseek->grab_seg_start = FALSE;
117   navseek->grab_seg_end = FALSE;
118   navseek->segment_start = GST_CLOCK_TIME_NONE;
119   navseek->segment_end = GST_CLOCK_TIME_NONE;
120 }
121
122 static void
123 gst_navseek_seek (GstNavSeek * navseek, gint64 offset)
124 {
125   GstFormat peer_format = GST_FORMAT_TIME;
126   gboolean ret;
127   GstPad *peer_pad;
128   gint64 peer_value;
129
130   /* Query for the current time then attempt to set to time + offset */
131   peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
132   ret = gst_pad_query_position (peer_pad, &peer_format, &peer_value);
133
134   if (ret && peer_format == GST_FORMAT_TIME) {
135     GstEvent *event;
136
137     peer_value += offset;
138     if (peer_value < 0)
139       peer_value = 0;
140
141     event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
142         GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH,
143         GST_SEEK_TYPE_SET, peer_value, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
144
145     gst_pad_send_event (peer_pad, event);
146   }
147
148   gst_object_unref (peer_pad);
149 }
150
151 static void
152 gst_navseek_change_playback_rate (GstNavSeek * navseek, gdouble rate)
153 {
154   GstFormat peer_format = GST_FORMAT_TIME;
155   gboolean ret;
156   GstPad *peer_pad;
157   gint64 current_position;
158
159   peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
160   ret = gst_pad_query_position (peer_pad, &peer_format, &current_position);
161
162   if (ret && peer_format == GST_FORMAT_TIME) {
163     GstEvent *event;
164     gint64 start;
165     gint64 stop;
166
167     if (rate > 0.0) {
168       start = current_position;
169       stop = -1;
170     } else {
171       /* negative rate: we play from stop to start */
172       start = 0;
173       stop = current_position;
174     }
175
176     event = gst_event_new_seek (rate, GST_FORMAT_TIME,
177         GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SKIP,
178         GST_SEEK_TYPE_SET, start, GST_SEEK_TYPE_SET, stop);
179
180     gst_pad_send_event (peer_pad, event);
181   }
182 }
183
184 static void
185 gst_navseek_segseek (GstNavSeek * navseek)
186 {
187   GstEvent *event;
188   GstPad *peer_pad;
189
190   if ((navseek->segment_start == GST_CLOCK_TIME_NONE) ||
191       (navseek->segment_end == GST_CLOCK_TIME_NONE) ||
192       (!GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad))) {
193     return;
194   }
195
196   if (navseek->loop) {
197     event =
198         gst_event_new_seek (1.0, GST_FORMAT_TIME,
199         GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT,
200         GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
201         navseek->segment_end);
202   } else {
203     event =
204         gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE,
205         GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
206         navseek->segment_end);
207   }
208
209   peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
210   gst_pad_send_event (peer_pad, event);
211   gst_object_unref (peer_pad);
212 }
213
214 static gboolean
215 gst_navseek_handle_src_event (GstPad * pad, GstEvent * event)
216 {
217   GstNavSeek *navseek;
218   gboolean ret = TRUE;
219
220   navseek = GST_NAVSEEK (GST_PAD_PARENT (pad));
221
222   switch (GST_EVENT_TYPE (event)) {
223     case GST_EVENT_NAVIGATION:
224       /* Check for a keyup and convert left/right to a seek event */
225     {
226       const GstStructure *structure;
227       const gchar *event_type;
228
229       structure = gst_event_get_structure (event);
230       g_return_val_if_fail (structure != NULL, FALSE);
231
232       event_type = gst_structure_get_string (structure, "event");
233       g_return_val_if_fail (event_type != NULL, FALSE);
234
235       if (strcmp (event_type, "key-press") == 0) {
236         const gchar *key;
237
238         key = gst_structure_get_string (structure, "key");
239         g_return_val_if_fail (key != NULL, FALSE);
240
241         if (strcmp (key, "Left") == 0) {
242           /* Seek backward by 5 secs */
243           gst_navseek_seek (navseek, -1.0 * navseek->seek_offset * GST_SECOND);
244         } else if (strcmp (key, "Right") == 0) {
245           /* Seek forward */
246           gst_navseek_seek (navseek, navseek->seek_offset * GST_SECOND);
247         } else if (strcmp (key, "s") == 0) {
248           /* Grab the next frame as the start frame of a segment */
249           navseek->grab_seg_start = TRUE;
250         } else if (strcmp (key, "e") == 0) {
251           /* Grab the next frame as the end frame of a segment */
252           navseek->grab_seg_end = TRUE;
253         } else if (strcmp (key, "l") == 0) {
254           /* Toggle the loop flag. If we have both start and end segment times send a seek */
255           navseek->loop = !navseek->loop;
256           gst_navseek_segseek (navseek);
257         } else if (strcmp (key, "f") == 0) {
258           /* fast forward */
259           gst_navseek_change_playback_rate (navseek, 2.0);
260         } else if (strcmp (key, "r") == 0) {
261           /* rewind */
262           gst_navseek_change_playback_rate (navseek, -2.0);
263         } else if (strcmp (key, "n") == 0) {
264           /* normal speed */
265           gst_navseek_change_playback_rate (navseek, 1.0);
266         }
267       } else {
268         break;
269       }
270       gst_event_unref (event);
271       event = NULL;
272     }
273       break;
274     default:
275       break;
276   }
277
278   if (event && GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad)) {
279     GstPad *peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
280
281     ret = gst_pad_send_event (peer_pad, event);
282     gst_object_unref (peer_pad);
283   }
284
285   return ret;
286 }
287
288 static void
289 gst_navseek_set_property (GObject * object, guint prop_id,
290     const GValue * value, GParamSpec * pspec)
291 {
292   GstNavSeek *navseek = GST_NAVSEEK (object);
293
294   switch (prop_id) {
295     case ARG_SEEKOFFSET:
296       GST_OBJECT_LOCK (navseek);
297       navseek->seek_offset = g_value_get_double (value);
298       GST_OBJECT_UNLOCK (navseek);
299       break;
300     default:
301       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
302       break;
303   }
304 }
305
306 static void
307 gst_navseek_get_property (GObject * object, guint prop_id,
308     GValue * value, GParamSpec * pspec)
309 {
310   GstNavSeek *navseek = GST_NAVSEEK (object);
311
312   switch (prop_id) {
313     case ARG_SEEKOFFSET:
314       GST_OBJECT_LOCK (navseek);
315       g_value_set_double (value, navseek->seek_offset);
316       GST_OBJECT_UNLOCK (navseek);
317       break;
318     default:
319       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
320       break;
321   }
322 }
323
324 static gboolean
325 gst_navseek_event (GstBaseTransform * trans, GstEvent * event)
326 {
327   GstNavSeek *navseek = GST_NAVSEEK (trans);
328
329   switch (GST_EVENT_TYPE (event)) {
330     case GST_EVENT_EOS:
331       GST_OBJECT_LOCK (navseek);
332       if (navseek->loop)
333         gst_navseek_segseek (navseek);
334       GST_OBJECT_UNLOCK (navseek);
335       break;
336     default:
337       break;
338   }
339   return GST_BASE_TRANSFORM_CLASS (parent_class)->event (trans, event);
340 }
341
342 static GstFlowReturn
343 gst_navseek_transform_ip (GstBaseTransform * basetrans, GstBuffer * buf)
344 {
345   GstNavSeek *navseek = GST_NAVSEEK (basetrans);
346
347   GST_OBJECT_LOCK (navseek);
348
349   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
350     if (navseek->grab_seg_start) {
351       navseek->segment_start = GST_BUFFER_TIMESTAMP (buf);
352       navseek->segment_end = GST_CLOCK_TIME_NONE;
353       navseek->grab_seg_start = FALSE;
354     }
355
356     if (navseek->grab_seg_end) {
357       navseek->segment_end = GST_BUFFER_TIMESTAMP (buf);
358       navseek->grab_seg_end = FALSE;
359       gst_navseek_segseek (navseek);
360     }
361   }
362
363   GST_OBJECT_UNLOCK (navseek);
364
365   return GST_FLOW_OK;
366 }
367
368 static gboolean
369 gst_navseek_start (GstBaseTransform * trans)
370 {
371   /* anything we should be doing here? */
372   return TRUE;
373 }
374
375 static gboolean
376 gst_navseek_stop (GstBaseTransform * trans)
377 {
378   /* anything we should be doing here? */
379   return TRUE;
380 }