diff options
Diffstat (limited to 'gst')
-rw-r--r-- | gst/freeze/FAQ | 4 | ||||
-rw-r--r-- | gst/freeze/Makefile.am | 11 | ||||
-rw-r--r-- | gst/freeze/gstfreeze.c | 362 | ||||
-rw-r--r-- | gst/freeze/gstfreeze.h | 67 |
4 files changed, 444 insertions, 0 deletions
diff --git a/gst/freeze/FAQ b/gst/freeze/FAQ new file mode 100644 index 00000000..2c7e7154 --- /dev/null +++ b/gst/freeze/FAQ @@ -0,0 +1,4 @@ +example usage + +gst-launch-0.10 --gst-debug=*freeze*:5 -mvt filesrc location=gnome-home.png blocksize=4135 ! pngdec ! freeze ! ffmpegcolorspace ! xvimagesink + diff --git a/gst/freeze/Makefile.am b/gst/freeze/Makefile.am new file mode 100644 index 00000000..66c37a67 --- /dev/null +++ b/gst/freeze/Makefile.am @@ -0,0 +1,11 @@ +plugin_LTLIBRARIES = libgstfreeze.la + +libgstfreeze_la_SOURCES = gstfreeze.c +libgstfreeze_la_CFLAGS = $(GST_CFLAGS) +libgstfreeze_la_LIBADD = ${GST_LIBS} +libgstfreeze_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = gstfreeze.h + +EXTRA_DIST = FAQ + diff --git a/gst/freeze/gstfreeze.c b/gst/freeze/gstfreeze.c new file mode 100644 index 00000000..101d5e55 --- /dev/null +++ b/gst/freeze/gstfreeze.c @@ -0,0 +1,362 @@ +/* gst-freeze -- Source freezer + * Copyright (C) 2005 Gergely Nagy <gergely.nagy@neteyes.hu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1, as published by the Free Software Foundation. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gst/gst.h> + +#include "gstfreeze.h" + +#define GST_CAT_DEFAULT freeze_debug +GST_DEBUG_CATEGORY (freeze_debug); + +enum +{ + ARG_0, + ARG_MAX_BUFFERS, +}; + + +static GstElementDetails freeze_details = GST_ELEMENT_DETAILS ("Stream freezer", + "Generic", + "Makes a stream from buffers of data", + "Gergely Nagy <gergely.nagy@neteyes.hu>," + " Renato Filho <renato.filho@indt.org.br>"); + +static GstStaticPadTemplate gst_freeze_src_template = +GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static GstStaticPadTemplate gst_freeze_sink_template = +GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, + GST_STATIC_CAPS_ANY); + +static void gst_freeze_dispose (GObject * object); +static void gst_freeze_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_freeze_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstFlowReturn gst_freeze_chain (GstPad * pad, GstBuffer * buffer); +static GstStateChangeReturn gst_freeze_change_state (GstElement * element, + GstStateChange transition); + +static GstFlowReturn gst_freeze_play (GstPad * pad, GstBuffer * buff); +static void gst_freeze_loop (GstPad * pad); +static gboolean gst_freeze_sink_activate (GstPad * sinkpad); +static gboolean gst_freeze_sink_activate_pull (GstPad * sinkpad, + gboolean active); +static gboolean gst_freeze_sink_event (GstPad * pad, GstEvent * event); + + + +GST_BOILERPLATE (GstFreeze, gst_freeze, GstElement, GST_TYPE_ELEMENT) + + static void gst_freeze_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_set_details (element_class, &freeze_details); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_freeze_sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_freeze_src_template)); + +} + +static void +gst_freeze_class_init (GstFreezeClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + element_class->change_state = gst_freeze_change_state; + object_class->set_property = gst_freeze_set_property; + object_class->get_property = gst_freeze_get_property; + + g_object_class_install_property + (object_class, ARG_MAX_BUFFERS, + g_param_spec_uint ("max-buffers", "max-buffers", + "Maximum number of buffers", 0, G_MAXUINT, 1, G_PARAM_READWRITE)); + + object_class->dispose = gst_freeze_dispose; + +} + +static void +gst_freeze_init (GstFreeze * freeze, GstFreezeClass * klass) +{ + freeze->sinkpad = gst_pad_new_from_template (gst_static_pad_template_get + (&gst_freeze_sink_template), "sink"); + gst_element_add_pad (GST_ELEMENT (freeze), freeze->sinkpad); + gst_pad_set_activate_function (freeze->sinkpad, gst_freeze_sink_activate); + gst_pad_set_activatepull_function (freeze->sinkpad, + gst_freeze_sink_activate_pull); + gst_pad_set_chain_function (freeze->sinkpad, gst_freeze_chain); + gst_pad_set_getcaps_function (freeze->sinkpad, gst_pad_proxy_getcaps); + + freeze->srcpad = gst_pad_new_from_template (gst_static_pad_template_get + (&gst_freeze_src_template), "src"); + gst_element_add_pad (GST_ELEMENT (freeze), freeze->srcpad); + + gst_pad_set_getcaps_function (freeze->srcpad, gst_pad_proxy_getcaps); + + gst_pad_set_event_function (freeze->sinkpad, gst_freeze_sink_event); + + freeze->timestamp_offset = 0; + freeze->running_time = 0; + freeze->buffers = NULL; + freeze->current = NULL; + freeze->max_buffers = 1; +} + +static void +gst_freeze_dispose (GObject * object) +{ + guint i; + GstFreeze *freeze = GST_FREEZE (object); + + if (freeze->buffers != NULL) { + for (i = 0; i < g_list_length (freeze->buffers); i++) + gst_buffer_unref (GST_BUFFER (g_list_nth_data (freeze->buffers, i))); + + g_list_free (freeze->buffers); + freeze->buffers = NULL; + freeze->current = NULL; + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_freeze_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstFreeze *freeze = GST_FREEZE (object); + + switch (prop_id) { + case ARG_MAX_BUFFERS: + freeze->max_buffers = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_freeze_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstFreeze *freeze = GST_FREEZE (object); + + switch (prop_id) { + case ARG_MAX_BUFFERS: + g_value_set_uint (value, freeze->max_buffers); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstFlowReturn +gst_freeze_chain (GstPad * pad, GstBuffer * buffer) +{ + return gst_freeze_play (pad, buffer); +} + + +static GstStateChangeReturn +gst_freeze_change_state (GstElement * element, GstStateChange transition) +{ + GstFreeze *freeze = GST_FREEZE (element); + GstStateChangeReturn return_val = GST_STATE_CHANGE_SUCCESS; + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_NULL_TO_READY: + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + freeze->timestamp_offset = freeze->running_time = 0; + break; + default: + break; + } + + if (GST_ELEMENT_CLASS (parent_class)->change_state) + return_val = + GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + case GST_STATE_CHANGE_READY_TO_NULL: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + freeze->timestamp_offset = freeze->running_time = 0; + break; + default: + break; + } + + return return_val; +} + +static GstFlowReturn +gst_freeze_play (GstPad * pad, GstBuffer * buff) +{ + GstFreeze *freeze; + guint64 cur_offset; + GstFlowReturn ret; + + + + freeze = GST_FREEZE (gst_pad_get_parent (pad)); + + cur_offset = freeze->offset; + + if (!buff) { + ret = + gst_pad_pull_range (GST_PAD (freeze->sinkpad), freeze->offset, 4096, + &buff); + if (ret != GST_FLOW_OK) { + gst_object_unref (freeze); + return ret; + } + + freeze->offset += GST_BUFFER_SIZE (buff); + + } + + if (g_list_length (freeze->buffers) < freeze->max_buffers || + freeze->max_buffers == 0) { + freeze->buffers = g_list_append (freeze->buffers, buff); + GST_DEBUG_OBJECT (freeze, "accepted buffer %u", + g_list_length (freeze->buffers) - 1); + } else { + gst_buffer_unref (buff); + } + + + if (freeze->current != NULL) { + GST_DEBUG_OBJECT (freeze, "switching to next buffer"); + freeze->current = freeze->current->next; + } + + if (freeze->current == NULL) { + if (freeze->max_buffers > 1) + GST_DEBUG_OBJECT (freeze, "restarting the loop"); + freeze->current = freeze->buffers; + } + + GST_BUFFER_TIMESTAMP (freeze->current->data) = freeze->timestamp_offset + + freeze->running_time; + freeze->running_time += GST_BUFFER_DURATION (freeze->current->data); + + gst_buffer_ref (freeze->current->data); + gst_pad_push (freeze->srcpad, freeze->current->data); + + gst_object_unref (freeze); + + return GST_FLOW_OK; +} + +static void +gst_freeze_loop (GstPad * pad) +{ + gst_freeze_play (pad, NULL); +} + +static gboolean +gst_freeze_sink_activate (GstPad * sinkpad) +{ + GstFreeze *freeze; + + freeze = GST_FREEZE (GST_PAD_PARENT (sinkpad)); + + if (gst_pad_check_pull_range (sinkpad)) { + return gst_pad_activate_pull (sinkpad, TRUE); + } else { + return gst_pad_activate_push (sinkpad, TRUE); + } +} + +static gboolean +gst_freeze_sink_activate_pull (GstPad * sinkpad, gboolean active) +{ + gboolean result; + + if (active) { + /* if we have a scheduler we can start the task */ + result = gst_pad_start_task (sinkpad, + (GstTaskFunction) gst_freeze_loop, sinkpad); + } else { + result = gst_pad_stop_task (sinkpad); + } + + return result; +} + +static gboolean +gst_freeze_sink_event (GstPad * pad, GstEvent * event) +{ + gboolean ret = TRUE; + GstFreeze *freeze = GST_FREEZE (gst_pad_get_parent (pad)); + + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + GST_DEBUG_OBJECT (freeze, "EOS on sink pad %s", + gst_pad_get_name (GST_PAD (freeze->sinkpad))); + gst_event_unref (event); + break; + default: + ret = gst_pad_event_default (GST_PAD (freeze->sinkpad), event); + break; + } + + gst_object_unref (freeze); + return ret; + +} + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (freeze_debug, "freeze", 0, "Stream freezer"); + + return gst_element_register (plugin, "freeze", GST_RANK_NONE, + GST_TYPE_FREEZE); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "freeze", + "Stream freezer", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN); + +/* + * Local variables: + * mode: c + * file-style: k&r + * c-basic-offset: 2 + * arch-tag: fb0ee62b-cf74-46c0-8e62-93b58bacc0ed + * End: + */ diff --git a/gst/freeze/gstfreeze.h b/gst/freeze/gstfreeze.h new file mode 100644 index 00000000..a20ca328 --- /dev/null +++ b/gst/freeze/gstfreeze.h @@ -0,0 +1,67 @@ +/* gst-freeze -- Source freezer + * Copyright (C) 2005 Gergely Nagy <gergely.nagy@neteyes.hu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1, as published by the Free Software Foundation. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser 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 + */ + +#ifndef __GST_FREEZE_H__ +#define __GST_FREEZE_H__ 1 + +#include <gst/gst.h> + +G_BEGIN_DECLS +#define GST_TYPE_FREEZE (gst_freeze_get_type ()) +#define GST_FREEZE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST (obj, GST_TYPE_FREEZE, GstFreeze)) +#define GST_FREEZE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST (klass, GST_TYPE_FREEZE, GstFreeze)) +#define GST_IS_FREEZE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE (obj, GST_TYPE_FREEZE)) +#define GST_IS_FREEZE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE (klass, GST_TYPE_FREEZE)) +typedef struct _GstFreeze GstFreeze; +typedef struct _GstFreezeClass GstFreezeClass; + +struct _GstFreeze +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + + GList *buffers; + GList *current; + guint max_buffers; + + gint64 timestamp_offset; + gint64 offset; + GstClockTime running_time; +}; + +struct _GstFreezeClass +{ + GstElementClass parent_class; +}; + +GType gst_freeze_get_type (void); + +G_END_DECLS +#endif +/* + * Local variables: + * mode: c + * file-style: k&r + * c-basic-offset: 2 + * arch-tag: 559a2214-86a1-4c2f-b497-bdcc5f82acf1 + * End: + */ |