tizen 2.0 init
[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_static_pad_template (element_class,
72       &navseek_sink_template);
73   gst_element_class_add_static_pad_template (element_class,
74       &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 void
215 gst_navseek_toggle_play_pause (GstNavSeek * navseek)
216 {
217   GstStateChangeReturn sret;
218   GstState current, pending, state;
219
220   sret = gst_element_get_state (GST_ELEMENT (navseek), &current, &pending, 0);
221   if (sret == GST_STATE_CHANGE_FAILURE)
222     return;
223
224   state = (pending != GST_STATE_VOID_PENDING) ? pending : current;
225
226   gst_element_post_message (GST_ELEMENT (navseek),
227       gst_message_new_request_state (GST_OBJECT (navseek),
228           (state == GST_STATE_PLAYING) ? GST_STATE_PAUSED : GST_STATE_PLAYING));
229 }
230
231 static gboolean
232 gst_navseek_handle_src_event (GstPad * pad, GstEvent * event)
233 {
234   GstNavSeek *navseek;
235   gboolean ret = TRUE;
236
237   navseek = GST_NAVSEEK (GST_PAD_PARENT (pad));
238
239   switch (GST_EVENT_TYPE (event)) {
240     case GST_EVENT_NAVIGATION:
241       /* Check for a keyup and convert left/right to a seek event */
242     {
243       const GstStructure *structure;
244       const gchar *event_type;
245
246       structure = gst_event_get_structure (event);
247       g_return_val_if_fail (structure != NULL, FALSE);
248
249       event_type = gst_structure_get_string (structure, "event");
250       g_return_val_if_fail (event_type != NULL, FALSE);
251
252       if (strcmp (event_type, "key-press") == 0) {
253         const gchar *key;
254
255         key = gst_structure_get_string (structure, "key");
256         g_return_val_if_fail (key != NULL, FALSE);
257
258         if (strcmp (key, "Left") == 0) {
259           /* Seek backward by 5 secs */
260           gst_navseek_seek (navseek, -1.0 * navseek->seek_offset * GST_SECOND);
261         } else if (strcmp (key, "Right") == 0) {
262           /* Seek forward */
263           gst_navseek_seek (navseek, navseek->seek_offset * GST_SECOND);
264         } else if (strcmp (key, "s") == 0) {
265           /* Grab the next frame as the start frame of a segment */
266           navseek->grab_seg_start = TRUE;
267         } else if (strcmp (key, "e") == 0) {
268           /* Grab the next frame as the end frame of a segment */
269           navseek->grab_seg_end = TRUE;
270         } else if (strcmp (key, "l") == 0) {
271           /* Toggle the loop flag. If we have both start and end segment times send a seek */
272           navseek->loop = !navseek->loop;
273           gst_navseek_segseek (navseek);
274         } else if (strcmp (key, "f") == 0) {
275           /* fast forward */
276           gst_navseek_change_playback_rate (navseek, 2.0);
277         } else if (strcmp (key, "r") == 0) {
278           /* rewind */
279           gst_navseek_change_playback_rate (navseek, -2.0);
280         } else if (strcmp (key, "n") == 0) {
281           /* normal speed */
282           gst_navseek_change_playback_rate (navseek, 1.0);
283         } else if (strcmp (key, "space") == 0) {
284           gst_navseek_toggle_play_pause (navseek);
285         }
286       } else {
287         break;
288       }
289       gst_event_unref (event);
290       event = NULL;
291     }
292       break;
293     default:
294       break;
295   }
296
297   if (event && GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad)) {
298     GstPad *peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
299
300     ret = gst_pad_send_event (peer_pad, event);
301     gst_object_unref (peer_pad);
302   }
303
304   return ret;
305 }
306
307 static void
308 gst_navseek_set_property (GObject * object, guint prop_id,
309     const GValue * value, GParamSpec * pspec)
310 {
311   GstNavSeek *navseek = GST_NAVSEEK (object);
312
313   switch (prop_id) {
314     case ARG_SEEKOFFSET:
315       GST_OBJECT_LOCK (navseek);
316       navseek->seek_offset = g_value_get_double (value);
317       GST_OBJECT_UNLOCK (navseek);
318       break;
319     default:
320       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
321       break;
322   }
323 }
324
325 static void
326 gst_navseek_get_property (GObject * object, guint prop_id,
327     GValue * value, GParamSpec * pspec)
328 {
329   GstNavSeek *navseek = GST_NAVSEEK (object);
330
331   switch (prop_id) {
332     case ARG_SEEKOFFSET:
333       GST_OBJECT_LOCK (navseek);
334       g_value_set_double (value, navseek->seek_offset);
335       GST_OBJECT_UNLOCK (navseek);
336       break;
337     default:
338       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
339       break;
340   }
341 }
342
343 static gboolean
344 gst_navseek_event (GstBaseTransform * trans, GstEvent * event)
345 {
346   GstNavSeek *navseek = GST_NAVSEEK (trans);
347
348   switch (GST_EVENT_TYPE (event)) {
349     case GST_EVENT_EOS:
350       GST_OBJECT_LOCK (navseek);
351       if (navseek->loop)
352         gst_navseek_segseek (navseek);
353       GST_OBJECT_UNLOCK (navseek);
354       break;
355     default:
356       break;
357   }
358   return GST_BASE_TRANSFORM_CLASS (parent_class)->event (trans, event);
359 }
360
361 static GstFlowReturn
362 gst_navseek_transform_ip (GstBaseTransform * basetrans, GstBuffer * buf)
363 {
364   GstNavSeek *navseek = GST_NAVSEEK (basetrans);
365
366   GST_OBJECT_LOCK (navseek);
367
368   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
369     if (navseek->grab_seg_start) {
370       navseek->segment_start = GST_BUFFER_TIMESTAMP (buf);
371       navseek->segment_end = GST_CLOCK_TIME_NONE;
372       navseek->grab_seg_start = FALSE;
373     }
374
375     if (navseek->grab_seg_end) {
376       navseek->segment_end = GST_BUFFER_TIMESTAMP (buf);
377       navseek->grab_seg_end = FALSE;
378       gst_navseek_segseek (navseek);
379     }
380   }
381
382   GST_OBJECT_UNLOCK (navseek);
383
384   return GST_FLOW_OK;
385 }
386
387 static gboolean
388 gst_navseek_start (GstBaseTransform * trans)
389 {
390   /* anything we should be doing here? */
391   return TRUE;
392 }
393
394 static gboolean
395 gst_navseek_stop (GstBaseTransform * trans)
396 {
397   /* anything we should be doing here? */
398   return TRUE;
399 }