/* GStreamer * Copyright (C) <1999> Erik Walthinsen * Copyright (C) <2003> David Schleef * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * This file was (probably) generated from gstnavseek.c, * gstnavseek.c,v 1.7 2003/11/08 02:48:59 dschleef Exp */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include /* GstNavSeek signals and args */ enum { /* FILL ME */ LAST_SIGNAL }; enum { ARG_0, ARG_SEEKOFFSET /* FILL ME */ }; GstStaticPadTemplate navseek_src_template = GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); GstStaticPadTemplate navseek_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS_ANY); static void gst_navseek_base_init (gpointer g_class); static void gst_navseek_class_init (gpointer g_class, gpointer class_data); static void gst_navseek_init (GTypeInstance * instance, gpointer g_class); static gboolean gst_navseek_handle_src_event (GstPad * pad, GstEvent * event); static void gst_navseek_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_navseek_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void gst_navseek_chain (GstPad * pad, GstData * _data); static GType gst_navseek_get_type (void) { static GType navseek_type = 0; if (!navseek_type) { static const GTypeInfo navseek_info = { sizeof (GstNavSeekClass), gst_navseek_base_init, NULL, gst_navseek_class_init, NULL, NULL, sizeof (GstNavSeek), 0, gst_navseek_init, }; navseek_type = g_type_register_static (GST_TYPE_ELEMENT, "GstNavSeek", &navseek_info, 0); } return navseek_type; } static void gst_navseek_base_init (gpointer g_class) { static GstElementDetails navseek_details = GST_ELEMENT_DETAILS ("Seek based on left-right arrows", "Filter/Video", "Seek based on navigation keys left-right", "Jan Schmidt "); GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&navseek_sink_template)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&navseek_src_template)); gst_element_class_set_details (element_class, &navseek_details); } static void gst_navseek_class_init (gpointer g_class, gpointer class_data) { GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (g_class); g_object_class_install_property (G_OBJECT_CLASS (g_class), ARG_SEEKOFFSET, g_param_spec_double ("seek-offset", "Seek Offset", "Time in seconds to seek by", 0.0, G_MAXDOUBLE, 5.0, G_PARAM_READWRITE)); gobject_class->set_property = gst_navseek_set_property; gobject_class->get_property = gst_navseek_get_property; } static void gst_navseek_init (GTypeInstance * instance, gpointer g_class) { GstNavSeek *navseek = GST_NAVSEEK (instance); navseek->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get (&navseek_sink_template), "sink"); gst_element_add_pad (GST_ELEMENT (navseek), navseek->sinkpad); gst_pad_set_chain_function (navseek->sinkpad, gst_navseek_chain); gst_pad_set_link_function (navseek->sinkpad, gst_pad_proxy_pad_link); gst_pad_set_getcaps_function (navseek->sinkpad, gst_pad_proxy_getcaps); navseek->srcpad = gst_pad_new_from_template (gst_static_pad_template_get (&navseek_src_template), "src"); gst_element_add_pad (GST_ELEMENT (navseek), navseek->srcpad); gst_pad_set_link_function (navseek->srcpad, gst_pad_proxy_pad_link); gst_pad_set_getcaps_function (navseek->srcpad, gst_pad_proxy_getcaps); gst_pad_set_event_function (navseek->srcpad, gst_navseek_handle_src_event); GST_FLAG_SET (GST_ELEMENT (navseek), GST_ELEMENT_EVENT_AWARE); navseek->seek_offset = 5.0; navseek->loop = FALSE; navseek->grab_seg_start = FALSE; navseek->grab_seg_end = FALSE; navseek->segment_start = GST_CLOCK_TIME_NONE; navseek->segment_end = GST_CLOCK_TIME_NONE; } static void gst_navseek_seek (GstNavSeek * navseek, gint64 offset) { /* Query for the current time then attempt to set to time + offset */ gint64 peer_value; GstFormat peer_format = GST_FORMAT_TIME; if (gst_pad_query (gst_pad_get_peer (navseek->sinkpad), GST_QUERY_POSITION, &peer_format, &peer_value)) { if (peer_format != GST_FORMAT_TIME) return; peer_value += offset; if (peer_value < 0) peer_value = 0; gst_element_seek (GST_ELEMENT (navseek), GST_SEEK_METHOD_SET | GST_FORMAT_TIME | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_FLUSH, peer_value); } } static void gst_navseek_segseek (GstNavSeek * navseek) { GstEvent *event; if ((navseek->segment_start == GST_CLOCK_TIME_NONE) || (navseek->segment_end == GST_CLOCK_TIME_NONE) || (!GST_PAD_IS_LINKED (navseek->sinkpad))) { return; } if (navseek->loop) { event = gst_event_new_segment_seek (GST_SEEK_METHOD_SET | GST_FORMAT_TIME | GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_SEGMENT_LOOP, navseek->segment_start, navseek->segment_end); } else { event = gst_event_new_segment_seek (GST_SEEK_METHOD_SET | GST_FORMAT_TIME | GST_SEEK_FLAG_ACCURATE, navseek->segment_start, navseek->segment_end); } g_return_if_fail (event != NULL); gst_pad_send_event (gst_pad_get_peer (navseek->sinkpad), event); } static gboolean gst_navseek_handle_src_event (GstPad * pad, GstEvent * event) { GstNavSeek *navseek; navseek = GST_NAVSEEK (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NAVIGATION: /* Check for a keyup and convert left/right to a seek event */ { GstStructure *structure; const gchar *event_type; structure = event->event_data.structure.structure; event_type = gst_structure_get_string (structure, "event"); g_return_val_if_fail (event != NULL, FALSE); if (strcmp (event_type, "key-press") == 0) { const char *key = gst_structure_get_string (structure, "key"); g_assert (key != NULL); if (strcmp (key, "Left") == 0) { /* Seek backward by 5 secs */ gst_navseek_seek (navseek, -1.0 * navseek->seek_offset * GST_SECOND); } else if (strcmp (key, "Right") == 0) { /* Seek forward */ gst_navseek_seek (navseek, navseek->seek_offset * GST_SECOND); } else if (strcmp (key, "s") == 0) { /* Grab the next frame as the start frame of a segment */ navseek->grab_seg_start = TRUE; } else if (strcmp (key, "e") == 0) { /* Grab the next frame as the end frame of a segment */ navseek->grab_seg_end = TRUE; } else if (strcmp (key, "l") == 0) { /* Toggle the loop flag. If we have both start and end segment times send a seek */ navseek->loop = !navseek->loop; gst_navseek_segseek (navseek); } } else { break; } gst_event_unref (event); event = NULL; } break; default: break; } if ((event) && GST_PAD_IS_LINKED (navseek->sinkpad)) { return gst_pad_send_event (gst_pad_get_peer (navseek->sinkpad), event); } return TRUE; } static void gst_navseek_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstNavSeek *src; g_return_if_fail (GST_IS_NAVSEEK (object)); src = GST_NAVSEEK (object); switch (prop_id) { case ARG_SEEKOFFSET: src->seek_offset = g_value_get_double (value); break; default: break; } } static void gst_navseek_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstNavSeek *src; g_return_if_fail (GST_IS_NAVSEEK (object)); src = GST_NAVSEEK (object); switch (prop_id) { case ARG_SEEKOFFSET: g_value_set_double (value, src->seek_offset); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_navseek_chain (GstPad * pad, GstData * _data) { GstNavSeek *navseek; navseek = GST_NAVSEEK (gst_pad_get_parent (pad)); if (GST_IS_BUFFER (_data) && GST_BUFFER_TIMESTAMP_IS_VALID (GST_BUFFER (_data))) { if (navseek->grab_seg_start) { navseek->segment_start = GST_BUFFER_TIMESTAMP (GST_BUFFER (_data)); navseek->segment_end = GST_CLOCK_TIME_NONE; navseek->grab_seg_start = FALSE; } if (navseek->grab_seg_end) { navseek->segment_end = GST_BUFFER_TIMESTAMP (GST_BUFFER (_data)); navseek->grab_seg_end = FALSE; gst_navseek_segseek (navseek); } } if (GST_IS_EVENT (_data) && (GST_EVENT_TYPE (GST_EVENT (_data)) == GST_EVENT_SEGMENT_DONE) && navseek->loop) { gst_navseek_segseek (navseek); } gst_pad_push (navseek->srcpad, _data); } gboolean gst_navseek_plugin_init (GstPlugin * plugin) { return gst_element_register (plugin, "navseek", GST_RANK_NONE, GST_TYPE_NAVSEEK); }