1f006a0de6805882cddefbac2c478eacb82fc49d
[platform/upstream/gstreamer.git] / gst / debug / 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 const GstElementDetails navseek_details =
51 GST_ELEMENT_DETAILS ("Seek based on left-right arrows",
52     "Filter/Video",
53     "Seek based on navigation keys left-right",
54     "Jan Schmidt <thaytan@mad.scientist.com>");
55
56 static gboolean gst_navseek_event (GstBaseTransform * trans, GstEvent * event);
57 static GstFlowReturn gst_navseek_transform_ip (GstBaseTransform * basetrans,
58     GstBuffer * buf);
59 static gboolean gst_navseek_handle_src_event (GstPad * pad, GstEvent * event);
60 static gboolean gst_navseek_stop (GstBaseTransform * trans);
61 static gboolean gst_navseek_start (GstBaseTransform * trans);
62
63 static void gst_navseek_set_property (GObject * object, guint prop_id,
64     const GValue * value, GParamSpec * pspec);
65 static void gst_navseek_get_property (GObject * object, guint prop_id,
66     GValue * value, GParamSpec * pspec);
67
68 GST_BOILERPLATE (GstNavSeek, gst_navseek, GstBaseTransform,
69     GST_TYPE_BASE_TRANSFORM);
70
71 static void
72 gst_navseek_base_init (gpointer g_class)
73 {
74   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
75
76   gst_element_class_add_pad_template (element_class,
77       gst_static_pad_template_get (&navseek_sink_template));
78   gst_element_class_add_pad_template (element_class,
79       gst_static_pad_template_get (&navseek_src_template));
80
81   gst_element_class_set_details (element_class, &navseek_details);
82 }
83
84 static void
85 gst_navseek_class_init (GstNavSeekClass * klass)
86 {
87   GstBaseTransformClass *gstbasetrans_class;
88   GObjectClass *gobject_class;
89
90   gobject_class = G_OBJECT_CLASS (klass);
91   gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
92
93   gobject_class->set_property = gst_navseek_set_property;
94   gobject_class->get_property = gst_navseek_get_property;
95
96   g_object_class_install_property (gobject_class,
97       ARG_SEEKOFFSET, g_param_spec_double ("seek-offset", "Seek Offset",
98           "Time in seconds to seek by", 0.0, G_MAXDOUBLE, 5.0,
99           G_PARAM_READWRITE));
100
101   gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_navseek_event);
102   gstbasetrans_class->transform_ip =
103       GST_DEBUG_FUNCPTR (gst_navseek_transform_ip);
104   gstbasetrans_class->start = GST_DEBUG_FUNCPTR (gst_navseek_start);
105   gstbasetrans_class->stop = GST_DEBUG_FUNCPTR (gst_navseek_stop);
106 }
107
108 static void
109 gst_navseek_init (GstNavSeek * navseek, GstNavSeekClass * g_class)
110 {
111   gst_pad_set_event_function (GST_BASE_TRANSFORM (navseek)->srcpad,
112       GST_DEBUG_FUNCPTR (gst_navseek_handle_src_event));
113
114   gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (navseek), TRUE);
115
116   navseek->seek_offset = 5.0;
117   navseek->loop = FALSE;
118   navseek->grab_seg_start = FALSE;
119   navseek->grab_seg_end = FALSE;
120   navseek->segment_start = GST_CLOCK_TIME_NONE;
121   navseek->segment_end = GST_CLOCK_TIME_NONE;
122 }
123
124 static void
125 gst_navseek_seek (GstNavSeek * navseek, gint64 offset)
126 {
127   GstFormat peer_format = GST_FORMAT_TIME;
128   gboolean ret;
129   GstPad *peer_pad;
130   gint64 peer_value;
131
132
133   /* Query for the current time then attempt to set to time + offset */
134   peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
135   ret = gst_pad_query_position (peer_pad, &peer_format, &peer_value);
136
137   if (ret && peer_format == GST_FORMAT_TIME) {
138     GstEvent *event;
139
140     peer_value += offset;
141     if (peer_value < 0)
142       peer_value = 0;
143
144     event = gst_event_new_seek (1.0, GST_FORMAT_TIME,
145         GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH,
146         GST_SEEK_TYPE_SET, peer_value, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
147
148     gst_pad_send_event (peer_pad, event);
149   }
150
151   gst_object_unref (peer_pad);
152 }
153
154 static void
155 gst_navseek_segseek (GstNavSeek * navseek)
156 {
157   GstEvent *event;
158   GstPad *peer_pad;
159
160   if ((navseek->segment_start == GST_CLOCK_TIME_NONE) ||
161       (navseek->segment_end == GST_CLOCK_TIME_NONE) ||
162       (!GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad))) {
163     return;
164   }
165
166   if (navseek->loop) {
167     event =
168         gst_event_new_seek (1.0, GST_FORMAT_TIME,
169         GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT,
170         GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
171         navseek->segment_end);
172   } else {
173     event =
174         gst_event_new_seek (1.0, GST_FORMAT_TIME, GST_SEEK_FLAG_ACCURATE,
175         GST_SEEK_TYPE_SET, navseek->segment_start, GST_SEEK_TYPE_SET,
176         navseek->segment_end);
177   }
178
179   peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
180   gst_pad_send_event (peer_pad, event);
181   gst_object_unref (peer_pad);
182 }
183
184 static gboolean
185 gst_navseek_handle_src_event (GstPad * pad, GstEvent * event)
186 {
187   GstNavSeek *navseek;
188   gboolean ret = TRUE;
189
190   navseek = GST_NAVSEEK (GST_PAD_PARENT (pad));
191
192   switch (GST_EVENT_TYPE (event)) {
193     case GST_EVENT_NAVIGATION:
194       /* Check for a keyup and convert left/right to a seek event */
195     {
196       const GstStructure *structure;
197       const gchar *event_type;
198
199       structure = gst_event_get_structure (event);
200       g_return_val_if_fail (structure != NULL, FALSE);
201
202       event_type = gst_structure_get_string (structure, "event");
203       g_return_val_if_fail (event_type != NULL, FALSE);
204
205       if (strcmp (event_type, "key-press") == 0) {
206         const gchar *key;
207
208         key = gst_structure_get_string (structure, "key");
209         g_return_val_if_fail (key != NULL, FALSE);
210
211         if (strcmp (key, "Left") == 0) {
212           /* Seek backward by 5 secs */
213           gst_navseek_seek (navseek, -1.0 * navseek->seek_offset * GST_SECOND);
214         } else if (strcmp (key, "Right") == 0) {
215           /* Seek forward */
216           gst_navseek_seek (navseek, navseek->seek_offset * GST_SECOND);
217         } else if (strcmp (key, "s") == 0) {
218           /* Grab the next frame as the start frame of a segment */
219           navseek->grab_seg_start = TRUE;
220         } else if (strcmp (key, "e") == 0) {
221           /* Grab the next frame as the end frame of a segment */
222           navseek->grab_seg_end = TRUE;
223         } else if (strcmp (key, "l") == 0) {
224           /* Toggle the loop flag. If we have both start and end segment times send a seek */
225           navseek->loop = !navseek->loop;
226           gst_navseek_segseek (navseek);
227         }
228       } else {
229         break;
230       }
231       gst_event_unref (event);
232       event = NULL;
233     }
234       break;
235     default:
236       break;
237   }
238
239   if (event && GST_PAD_IS_LINKED (GST_BASE_TRANSFORM (navseek)->sinkpad)) {
240     GstPad *peer_pad = gst_pad_get_peer (GST_BASE_TRANSFORM (navseek)->sinkpad);
241
242     ret = gst_pad_send_event (peer_pad, event);
243     gst_object_unref (peer_pad);
244   }
245
246   return ret;
247 }
248
249 static void
250 gst_navseek_set_property (GObject * object, guint prop_id,
251     const GValue * value, GParamSpec * pspec)
252 {
253   GstNavSeek *navseek = GST_NAVSEEK (object);
254
255   switch (prop_id) {
256     case ARG_SEEKOFFSET:
257       GST_OBJECT_LOCK (navseek);
258       navseek->seek_offset = g_value_get_double (value);
259       GST_OBJECT_UNLOCK (navseek);
260       break;
261     default:
262       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
263       break;
264   }
265 }
266
267 static void
268 gst_navseek_get_property (GObject * object, guint prop_id,
269     GValue * value, GParamSpec * pspec)
270 {
271   GstNavSeek *navseek = GST_NAVSEEK (object);
272
273   switch (prop_id) {
274     case ARG_SEEKOFFSET:
275       GST_OBJECT_LOCK (navseek);
276       g_value_set_double (value, navseek->seek_offset);
277       GST_OBJECT_UNLOCK (navseek);
278       break;
279     default:
280       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
281       break;
282   }
283 }
284
285 static gboolean
286 gst_navseek_event (GstBaseTransform * trans, GstEvent * event)
287 {
288   GstNavSeek *navseek = GST_NAVSEEK (trans);
289
290   switch (GST_EVENT_TYPE (event)) {
291     case GST_EVENT_EOS:
292       GST_OBJECT_LOCK (navseek);
293       if (navseek->loop)
294         gst_navseek_segseek (navseek);
295       GST_OBJECT_UNLOCK (navseek);
296       break;
297     default:
298       break;
299   }
300   return GST_BASE_TRANSFORM_CLASS (parent_class)->event (trans, event);
301 }
302
303 static GstFlowReturn
304 gst_navseek_transform_ip (GstBaseTransform * basetrans, GstBuffer * buf)
305 {
306   GstNavSeek *navseek = GST_NAVSEEK (basetrans);
307
308   GST_OBJECT_LOCK (navseek);
309
310   if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
311     if (navseek->grab_seg_start) {
312       navseek->segment_start = GST_BUFFER_TIMESTAMP (buf);
313       navseek->segment_end = GST_CLOCK_TIME_NONE;
314       navseek->grab_seg_start = FALSE;
315     }
316
317     if (navseek->grab_seg_end) {
318       navseek->segment_end = GST_BUFFER_TIMESTAMP (buf);
319       navseek->grab_seg_end = FALSE;
320       gst_navseek_segseek (navseek);
321     }
322   }
323
324   GST_OBJECT_UNLOCK (navseek);
325
326   return GST_FLOW_OK;
327 }
328
329 static gboolean
330 gst_navseek_start (GstBaseTransform * trans)
331 {
332   /* anything we should be doing here? */
333   return TRUE;
334 }
335
336 static gboolean
337 gst_navseek_stop (GstBaseTransform * trans)
338 {
339   /* anything we should be doing here? */
340   return TRUE;
341 }
342
343 gboolean
344 gst_navseek_plugin_init (GstPlugin * plugin)
345 {
346   return gst_element_register (plugin, "navseek", GST_RANK_NONE,
347       GST_TYPE_NAVSEEK);
348 }