gst/: Made base source class, make fakesrc extend it.

Original commit message from CVS:
* gst/base/Makefile.am:
* gst/base/README:
* gst/base/gstbasesink.c: (gst_basesink_base_init),
(gst_basesink_pad_getcaps), (gst_basesink_pad_setcaps),
(gst_basesink_pad_buffer_alloc), (gst_basesink_init),
(gst_basesink_do_sync), (gst_basesink_chain_unlocked):
* gst/base/gstbasesrc.c: (gst_basesrc_get_type),
(gst_basesrc_base_init), (gst_basesrc_class_init),
(gst_basesrc_init), (gst_basesrc_get_formats),
(gst_basesrc_get_query_types), (gst_basesrc_query),
(gst_basesrc_get_event_mask), (gst_basesrc_event_handler),
(gst_basesrc_set_property), (gst_basesrc_get_property),
(gst_basesrc_get_range_unlocked), (gst_basesrc_get_range),
(gst_basesrc_loop), (gst_basesrc_activate),
(gst_basesrc_change_state):
* gst/base/gstbasesrc.h:
* gst/elements/gstfakesrc.c: (gst_fakesrc_base_init),
(gst_fakesrc_class_init), (gst_fakesrc_init),
(gst_fakesrc_event_handler), (gst_fakesrc_set_property),
(gst_fakesrc_get_property), (gst_fakesrc_create):
* gst/elements/gstfakesrc.h:
* gst/elements/gstfilesrc.c: (gst_filesrc_getrange),
(gst_filesrc_open_file), (gst_filesrc_loop),
(gst_filesrc_activate), (filesrc_find_peek),
(gst_filesrc_type_find):
Made base source class, make fakesrc extend it.
Add comments to basesink class.
Some filesrc cleanup.
This commit is contained in:
Wim Taymans 2005-04-05 08:44:20 +00:00
parent be4471d6cf
commit 8cf38d3d3a
17 changed files with 1167 additions and 628 deletions

View file

@ -1,3 +1,34 @@
2005-04-04 Wim Taymans <wim@fluendo.com>
* gst/base/Makefile.am:
* gst/base/README:
* gst/base/gstbasesink.c: (gst_basesink_base_init),
(gst_basesink_pad_getcaps), (gst_basesink_pad_setcaps),
(gst_basesink_pad_buffer_alloc), (gst_basesink_init),
(gst_basesink_do_sync), (gst_basesink_chain_unlocked):
* gst/base/gstbasesrc.c: (gst_basesrc_get_type),
(gst_basesrc_base_init), (gst_basesrc_class_init),
(gst_basesrc_init), (gst_basesrc_get_formats),
(gst_basesrc_get_query_types), (gst_basesrc_query),
(gst_basesrc_get_event_mask), (gst_basesrc_event_handler),
(gst_basesrc_set_property), (gst_basesrc_get_property),
(gst_basesrc_get_range_unlocked), (gst_basesrc_get_range),
(gst_basesrc_loop), (gst_basesrc_activate),
(gst_basesrc_change_state):
* gst/base/gstbasesrc.h:
* gst/elements/gstfakesrc.c: (gst_fakesrc_base_init),
(gst_fakesrc_class_init), (gst_fakesrc_init),
(gst_fakesrc_event_handler), (gst_fakesrc_set_property),
(gst_fakesrc_get_property), (gst_fakesrc_create):
* gst/elements/gstfakesrc.h:
* gst/elements/gstfilesrc.c: (gst_filesrc_getrange),
(gst_filesrc_open_file), (gst_filesrc_loop),
(gst_filesrc_activate), (filesrc_find_peek),
(gst_filesrc_type_find):
Made base source class, make fakesrc extend it.
Add comments to basesink class.
Some filesrc cleanup.
2005-03-31 David Schleef <ds@schleef.org> 2005-03-31 David Schleef <ds@schleef.org>
* gst/gstplugin.c: (gst_plugin_check_file), (gst_plugin_load_file): * gst/gstplugin.c: (gst_plugin_check_file), (gst_plugin_load_file):

View file

@ -8,6 +8,7 @@ libgstbase_@GST_MAJORMINOR@_la_DEPENDENCIES = \
../libgstreamer-@GST_MAJORMINOR@.la ../libgstreamer-@GST_MAJORMINOR@.la
libgstbase_@GST_MAJORMINOR@_la_SOURCES = \ libgstbase_@GST_MAJORMINOR@_la_SOURCES = \
gstbasesink.c \ gstbasesink.c \
gstbasesrc.c \
gstbasetransform.c gstbasetransform.c
libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
@ -20,6 +21,7 @@ libgstbase_@GST_MAJORMINOR@includedir = \
libgstbase_@GST_MAJORMINOR@include_HEADERS = \ libgstbase_@GST_MAJORMINOR@include_HEADERS = \
gstbasesink.h \ gstbasesink.h \
gstbasesrc.h \
gstbasetransform.h gstbasetransform.h
install-data-local: as-libtool-install-data-local install-data-local: as-libtool-install-data-local

View file

@ -25,3 +25,11 @@ GstBaseTransform
- does flushing - does flushing
- push mode - push mode
- pull mode if transform can operate on arbitrary data - pull mode if transform can operate on arbitrary data
GstBaseSrc
Base class for getrange based source elements
- one sinkpad
- handles state changes
- pull/push mode

View file

@ -190,6 +190,7 @@ gst_basesink_pad_setcaps (GstPad * pad, GstCaps * caps)
bsink = GST_BASESINK (GST_PAD_PARENT (pad)); bsink = GST_BASESINK (GST_PAD_PARENT (pad));
bclass = GST_BASESINK_GET_CLASS (bsink); bclass = GST_BASESINK_GET_CLASS (bsink);
if (bclass->set_caps) if (bclass->set_caps)
res = bclass->set_caps (bsink, caps); res = bclass->set_caps (bsink, caps);
@ -206,6 +207,7 @@ gst_basesink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
bsink = GST_BASESINK (GST_PAD_PARENT (pad)); bsink = GST_BASESINK (GST_PAD_PARENT (pad));
bclass = GST_BASESINK_GET_CLASS (bsink); bclass = GST_BASESINK_GET_CLASS (bsink);
if (bclass->buffer_alloc) if (bclass->buffer_alloc)
buffer = bclass->buffer_alloc (bsink, offset, size, caps); buffer = bclass->buffer_alloc (bsink, offset, size, caps);
@ -571,6 +573,9 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
return result; return result;
} }
/* default implementation to calculate the start and end
* timestamps on a buffer, subclasses cna override
*/
static void static void
gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer, gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end) GstClockTime * start, GstClockTime * end)
@ -587,6 +592,15 @@ gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
} }
} }
/* perform synchronisation on a buffer
*
* 1) check if we have a clock, if not, do nothing
* 2) calculate the start and end time of the buffer
* 3) create a single shot notification to wait on
* the clock, save the entry so we can unlock it
* 4) wait on the clock, this blocks
* 5) unref the clockid again
*/
static void static void
gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
{ {
@ -615,6 +629,7 @@ gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
gst_clock_id_unref (basesink->clock_id); gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL; basesink->clock_id = NULL;
} }
/* FIXME, don't mess with end_time here */
basesink->end_time = GST_CLOCK_TIME_NONE; basesink->end_time = GST_CLOCK_TIME_NONE;
GST_UNLOCK (basesink); GST_UNLOCK (basesink);
@ -623,6 +638,12 @@ gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
} }
} }
/* handle a buffer
*
* 1) first sync on the buffer
* 2) render the buffer
* 3) unref the buffer
*/
static inline void static inline void
gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf) gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
{ {
@ -662,7 +683,7 @@ gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
return GST_FLOW_UNEXPECTED; return GST_FLOW_UNEXPECTED;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
return GST_FLOW_UNEXPECTED; return GST_FLOW_ERROR;
} }
} }
@ -683,6 +704,8 @@ gst_basesink_chain (GstPad * pad, GstBuffer * buf)
return result; return result;
} }
/* FIXME, not all sinks can operate in pull mode
*/
static void static void
gst_basesink_loop (GstPad * pad) gst_basesink_loop (GstPad * pad)
{ {

423
gst/base/gstbasesrc.c Normal file
View file

@ -0,0 +1,423 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstbasesrc.c:
*
* 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.
*/
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gstbasesrc.h"
#include <gst/gstmarshal.h>
#define DEFAULT_BLOCKSIZE 4096
GST_DEBUG_CATEGORY_STATIC (gst_basesrc_debug);
#define GST_CAT_DEFAULT gst_basesrc_debug
/* BaseSrc signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_BLOCKSIZE,
};
static GstElementClass *parent_class = NULL;
static void gst_basesrc_base_init (gpointer g_class);
static void gst_basesrc_class_init (GstBaseSrcClass * klass);
static void gst_basesrc_init (GstBaseSrc * src, gpointer g_class);
GType
gst_basesrc_get_type (void)
{
static GType basesrc_type = 0;
if (!basesrc_type) {
static const GTypeInfo basesrc_info = {
sizeof (GstBaseSrcClass),
(GBaseInitFunc) gst_basesrc_base_init,
NULL,
(GClassInitFunc) gst_basesrc_class_init,
NULL,
NULL,
sizeof (GstBaseSrc),
0,
(GInstanceInitFunc) gst_basesrc_init,
};
basesrc_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstBaseSrc", &basesrc_info, G_TYPE_FLAG_ABSTRACT);
}
return basesrc_type;
}
static gboolean gst_basesrc_activate (GstPad * pad, GstActivateMode mode);
static void gst_basesrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_basesrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_basesrc_event_handler (GstPad * pad, GstEvent * event);
static const GstEventMask *gst_basesrc_get_event_mask (GstPad * pad);
static const GstQueryType *gst_basesrc_get_query_types (GstPad * pad);
static gboolean gst_basesrc_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value);
static const GstFormat *gst_basesrc_get_formats (GstPad * pad);
static GstElementStateReturn gst_basesrc_change_state (GstElement * element);
static void gst_basesrc_loop (GstPad * pad);
static GstFlowReturn gst_basesrc_get_range (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buf);
static void
gst_basesrc_base_init (gpointer g_class)
{
GST_DEBUG_CATEGORY_INIT (gst_basesrc_debug, "basesrc", 0, "basesrc element");
}
static void
gst_basesrc_class_init (GstBaseSrcClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesrc_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesrc_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLOCKSIZE,
g_param_spec_ulong ("blocksize", "Block size",
"Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
G_PARAM_READWRITE));
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_basesrc_change_state);
}
static void
gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
{
GstPad *pad;
GstPadTemplate *pad_template;
pad_template =
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
g_return_if_fail (pad_template != NULL);
pad = gst_pad_new_from_template (pad_template, "src");
gst_pad_set_activate_function (pad, gst_basesrc_activate);
gst_pad_set_event_function (pad, gst_basesrc_event_handler);
gst_pad_set_event_mask_function (pad, gst_basesrc_get_event_mask);
gst_pad_set_query_function (pad, gst_basesrc_query);
gst_pad_set_query_type_function (pad, gst_basesrc_get_query_types);
gst_pad_set_formats_function (pad, gst_basesrc_get_formats);
gst_pad_set_loop_function (pad, gst_basesrc_loop);
gst_pad_set_getrange_function (pad, gst_basesrc_get_range);
gst_element_add_pad (GST_ELEMENT (basesrc), pad);
basesrc->segment_start = -1;
basesrc->segment_end = -1;
basesrc->blocksize = DEFAULT_BLOCKSIZE;
}
static const GstFormat *
gst_basesrc_get_formats (GstPad * pad)
{
static const GstFormat formats[] = {
GST_FORMAT_DEFAULT,
0,
};
return formats;
}
static const GstQueryType *
gst_basesrc_get_query_types (GstPad * pad)
{
static const GstQueryType types[] = {
GST_QUERY_TOTAL,
GST_QUERY_POSITION,
GST_QUERY_START,
GST_QUERY_SEGMENT_END,
0,
};
return types;
}
static gboolean
gst_basesrc_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value)
{
GstBaseSrc *src = GST_BASESRC (GST_PAD_PARENT (pad));
switch (type) {
case GST_QUERY_START:
*value = src->segment_start;
break;
case GST_QUERY_SEGMENT_END:
*value = src->segment_end;
break;
default:
return FALSE;
}
return TRUE;
}
static const GstEventMask *
gst_basesrc_get_event_mask (GstPad * pad)
{
static const GstEventMask masks[] = {
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
{GST_EVENT_FLUSH, 0},
{0, 0},
};
return masks;
}
static gboolean
gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
{
GstBaseSrc *src;
src = GST_BASESRC (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
src->segment_start = GST_EVENT_SEEK_OFFSET (event);
src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
src->segment_loop =
GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
break;
case GST_EVENT_FLUSH:
break;
default:
break;
}
gst_event_unref (event);
return TRUE;
}
static void
gst_basesrc_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
GstBaseSrc *src;
src = GST_BASESRC (object);
switch (prop_id) {
case ARG_BLOCKSIZE:
src->blocksize = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_basesrc_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstBaseSrc *src;
src = GST_BASESRC (object);
switch (prop_id) {
case ARG_BLOCKSIZE:
g_value_set_int (value, src->blocksize);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstFlowReturn
gst_basesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
GstBuffer ** buf)
{
GstFlowReturn ret;
GstBaseSrc *src;
GstBaseSrcClass *bclass;
src = GST_BASESRC (GST_OBJECT_PARENT (pad));
bclass = GST_BASESRC_GET_CLASS (src);
if (bclass->create)
ret = bclass->create (src, offset, length, buf);
else
ret = GST_FLOW_ERROR;
return ret;
}
static GstFlowReturn
gst_basesrc_get_range (GstPad * pad, guint64 offset, guint length,
GstBuffer ** ret)
{
GstFlowReturn fret;
GST_STREAM_LOCK (pad);
fret = gst_basesrc_get_range_unlocked (pad, offset, length, ret);
GST_STREAM_UNLOCK (pad);
return fret;
}
static void
gst_basesrc_loop (GstPad * pad)
{
GstBaseSrc *src;
GstBuffer *buf = NULL;
GstFlowReturn ret;
src = GST_BASESRC (GST_OBJECT_PARENT (pad));
GST_STREAM_LOCK (pad);
ret =
gst_basesrc_get_range_unlocked (pad, src->offset, DEFAULT_BLOCKSIZE,
&buf);
if (ret != GST_FLOW_OK)
goto pause;
src->offset += GST_BUFFER_SIZE (buf);
ret = gst_pad_push (pad, buf);
if (ret != GST_FLOW_OK)
goto pause;
GST_STREAM_UNLOCK (pad);
return;
pause:
{
gst_task_pause (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
return;
}
}
static gboolean
gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstBaseSrc *basesrc;
basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
/* if we have a scheduler we can start the task */
if (GST_ELEMENT_SCHEDULER (basesrc)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (basesrc),
(GstTaskFunction) gst_basesrc_loop, pad);
gst_task_start (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
result = TRUE;
}
break;
case GST_ACTIVATE_PULL:
result = TRUE;
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
/* step 3, stop the task */
if (GST_RPAD_TASK (pad)) {
gst_task_stop (GST_RPAD_TASK (pad));
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
GST_RPAD_TASK (pad) = NULL;
}
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
return result;
}
static GstElementStateReturn
gst_basesrc_change_state (GstElement * element)
{
GstBaseSrc *basesrc;
GstElementStateReturn result = GST_STATE_FAILURE;
GstElementState transition;
basesrc = GST_BASESRC (element);
transition = GST_STATE_TRANSITION (element);
switch (transition) {
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_PAUSED:
{
basesrc->offset = 0;
break;
}
case GST_STATE_PAUSED_TO_PLAYING:
break;
default:
break;
}
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
switch (transition) {
case GST_STATE_PLAYING_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_READY:
break;
case GST_STATE_READY_TO_NULL:
break;
default:
break;
}
return result;
}

74
gst/base/gstbasesrc.h Normal file
View file

@ -0,0 +1,74 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstbasesrc.h:
*
* 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.
*/
#ifndef __GST_BASESRC_H__
#define __GST_BASESRC_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_BASESRC (gst_basesrc_get_type())
#define GST_BASESRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASESRC,GstBaseSrc))
#define GST_BASESRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASESRC,GstBaseSrcClass))
#define GST_BASESRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASESRC, GstBaseSrcClass))
#define GST_IS_BASESRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESRC))
#define GST_IS_BASESRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESRC))
typedef struct _GstBaseSrc GstBaseSrc;
typedef struct _GstBaseSrcClass GstBaseSrcClass;
struct _GstBaseSrc {
GstElement element;
gint blocksize;
gint64 segment_start;
gint64 segment_end;
gboolean segment_loop;
guint64 offset;
};
struct _GstBaseSrcClass {
GstElementClass parent_class;
GstCaps* (*get_caps) (GstBaseSrc *src);
gboolean (*set_caps) (GstBaseSrc *src, GstCaps *caps);
gboolean (*start) (GstBaseSrc *src);
gboolean (*stop) (GstBaseSrc *src);
void (*get_times) (GstBaseSrc *src, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
gboolean (*event) (GstBaseSrc *src, GstEvent *event);
GstFlowReturn (*create) (GstBaseSrc *src, guint64 offset, guint size,
GstBuffer **buf);
};
GType gst_basesrc_get_type(void);
G_END_DECLS
#endif /* __GST_BASESRC_H__ */

View file

@ -64,8 +64,6 @@ enum
{ {
ARG_0, ARG_0,
ARG_NUM_SOURCES, ARG_NUM_SOURCES,
ARG_HAS_LOOP,
ARG_HAS_GETRANGE,
ARG_OUTPUT, ARG_OUTPUT,
ARG_DATA, ARG_DATA,
ARG_SIZETYPE, ARG_SIZETYPE,
@ -84,11 +82,6 @@ enum
ARG_LAST_MESSAGE ARG_LAST_MESSAGE
}; };
GstStaticPadTemplate fakesrc_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
GST_PAD_SRC,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
#define GST_TYPE_FAKESRC_OUTPUT (gst_fakesrc_output_get_type()) #define GST_TYPE_FAKESRC_OUTPUT (gst_fakesrc_output_get_type())
static GType static GType
gst_fakesrc_output_get_type (void) gst_fakesrc_output_get_type (void)
@ -175,22 +168,18 @@ gst_fakesrc_filltype_get_type (void)
#define _do_init(bla) \ #define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element"); GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
GST_BOILERPLATE_FULL (GstFakeSrc, gst_fakesrc, GstElement, GST_TYPE_ELEMENT, GST_BOILERPLATE_FULL (GstFakeSrc, gst_fakesrc, GstBaseSrc, GST_TYPE_BASESRC,
_do_init); _do_init);
static GstPad *gst_fakesrc_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * unused);
static gboolean gst_fakesrc_activate (GstPad * pad, GstActivateMode mode);
static void gst_fakesrc_set_property (GObject * object, guint prop_id, static void gst_fakesrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec); const GValue * value, GParamSpec * pspec);
static void gst_fakesrc_get_property (GObject * object, guint prop_id, static void gst_fakesrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static void gst_fakesrc_set_clock (GstElement * element, GstClock * clock);
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element); static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
static void gst_fakesrc_loop (GstPad * pad); static gboolean gst_fakesrc_event_handler (GstBaseSrc * src, GstEvent * event);
static GstFlowReturn gst_fakesrc_get_range (GstPad * pad, guint64 offset, static GstFlowReturn gst_fakesrc_create (GstBaseSrc * src, guint64 offset,
guint length, GstBuffer ** buf); guint length, GstBuffer ** buf);
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 }; static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
@ -202,9 +191,8 @@ gst_fakesrc_base_init (gpointer g_class)
gst_element_class_add_pad_template (gstelement_class, gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&srctemplate)); gst_static_pad_template_get (&srctemplate));
gst_element_class_set_details (gstelement_class, &gst_fakesrc_details); gst_element_class_set_details (gstelement_class, &gst_fakesrc_details);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&fakesrc_src_template));
} }
static void static void
@ -212,9 +200,11 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class;
GstElementClass *gstelement_class; GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
gobject_class = (GObjectClass *) klass; gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass; gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
@ -222,14 +212,6 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES, g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
g_param_spec_int ("num-sources", "num-sources", "Number of sources", g_param_spec_int ("num-sources", "num-sources", "Number of sources",
1, G_MAXINT, 1, G_PARAM_READABLE)); 1, G_MAXINT, 1, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_LOOP,
g_param_spec_boolean ("has-loop", "has-loop",
"Enable loop-based operation", TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_GETRANGE,
g_param_spec_boolean ("has-getrange", "has-getrange",
"Enable getrange-based operation", TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OUTPUT, g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OUTPUT,
g_param_spec_enum ("output", "output", "Output method (currently unused)", g_param_spec_enum ("output", "output", "Output method (currently unused)",
GST_TYPE_FAKESRC_OUTPUT, FAKESRC_FIRST_LAST_LOOP, G_PARAM_READWRITE)); GST_TYPE_FAKESRC_OUTPUT, FAKESRC_FIRST_LAST_LOOP, G_PARAM_READWRITE));
@ -287,26 +269,18 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
gst_fakesrc_signals[SIGNAL_HANDOFF] = gst_fakesrc_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstFakeSrcClass, handoff), NULL, NULL, G_STRUCT_OFFSET (GstFakeSrcClass, handoff), NULL, NULL,
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2, gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 1,
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD); GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesrc_set_clock);
gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_fakesrc_event_handler);
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_fakesrc_create);
} }
static void static void
gst_fakesrc_init (GstFakeSrc * fakesrc) gst_fakesrc_init (GstFakeSrc * fakesrc)
{ {
GstPad *pad;
/* create our first output pad */
pad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_element_add_pad (GST_ELEMENT (fakesrc), pad);
fakesrc->output = FAKESRC_FIRST_LAST_LOOP; fakesrc->output = FAKESRC_FIRST_LAST_LOOP;
fakesrc->segment_start = -1; fakesrc->segment_start = -1;
fakesrc->segment_end = -1; fakesrc->segment_end = -1;
@ -331,84 +305,12 @@ gst_fakesrc_init (GstFakeSrc * fakesrc)
fakesrc->pad_mode = GST_ACTIVATE_NONE; fakesrc->pad_mode = GST_ACTIVATE_NONE;
} }
static void static gboolean
gst_fakesrc_set_clock (GstElement * element, GstClock * clock) gst_fakesrc_event_handler (GstBaseSrc * basesrc, GstEvent * event)
{ {
GstFakeSrc *src; GstFakeSrc *src;
src = GST_FAKESRC (element); src = GST_FAKESRC (basesrc);
src->clock = clock;
}
static const GstFormat *
gst_fakesrc_get_formats (GstPad * pad)
{
static const GstFormat formats[] = {
GST_FORMAT_DEFAULT,
0,
};
return formats;
}
static const GstQueryType *
gst_fakesrc_get_query_types (GstPad * pad)
{
static const GstQueryType types[] = {
GST_QUERY_TOTAL,
GST_QUERY_POSITION,
GST_QUERY_START,
GST_QUERY_SEGMENT_END,
0,
};
return types;
}
static gboolean
gst_fakesrc_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value)
{
GstFakeSrc *src = GST_FAKESRC (GST_PAD_PARENT (pad));
switch (type) {
case GST_QUERY_TOTAL:
*value = src->num_buffers;
break;
case GST_QUERY_POSITION:
*value = src->buffer_count;
break;
case GST_QUERY_START:
*value = src->segment_start;
break;
case GST_QUERY_SEGMENT_END:
*value = src->segment_end;
break;
default:
return FALSE;
}
return TRUE;
}
static const GstEventMask *
gst_fakesrc_get_event_mask (GstPad * pad)
{
static const GstEventMask masks[] = {
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
{GST_EVENT_FLUSH, 0},
{0, 0},
};
return masks;
}
static gboolean
gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
{
GstFakeSrc *src;
src = GST_FAKESRC (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
@ -430,64 +332,6 @@ gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
return TRUE; return TRUE;
} }
static void
gst_fakesrc_set_pad_functions (GstFakeSrc * src, GstPad * pad)
{
gst_pad_set_activate_function (pad, gst_fakesrc_activate);
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
gst_pad_set_query_function (pad, gst_fakesrc_query);
gst_pad_set_query_type_function (pad, gst_fakesrc_get_query_types);
gst_pad_set_formats_function (pad, gst_fakesrc_get_formats);
if (src->has_loop)
gst_pad_set_loop_function (pad, gst_fakesrc_loop);
else
gst_pad_set_loop_function (pad, NULL);
if (src->has_getrange)
gst_pad_set_getrange_function (pad, gst_fakesrc_get_range);
else
gst_pad_set_getrange_function (pad, NULL);
}
static void
gst_fakesrc_set_all_pad_functions (GstFakeSrc * src)
{
GList *l;
for (l = GST_ELEMENT_PADS (src); l; l = l->next)
gst_fakesrc_set_pad_functions (src, (GstPad *) l->data);
}
static GstPad *
gst_fakesrc_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * unused)
{
gchar *name;
GstPad *srcpad;
GstFakeSrc *fakesrc;
g_return_val_if_fail (GST_IS_FAKESRC (element), NULL);
if (templ->direction != GST_PAD_SRC) {
g_warning ("gstfakesrc: request new pad that is not a SRC pad\n");
return NULL;
}
fakesrc = GST_FAKESRC (element);
name = g_strdup_printf ("src%d", GST_ELEMENT (fakesrc)->numsrcpads);
srcpad = gst_pad_new_from_template (templ, name);
gst_element_add_pad (GST_ELEMENT (fakesrc), srcpad);
gst_fakesrc_set_pad_functions (fakesrc, srcpad);
g_free (name);
return srcpad;
}
static void static void
gst_fakesrc_alloc_parent (GstFakeSrc * src) gst_fakesrc_alloc_parent (GstFakeSrc * src)
{ {
@ -510,14 +354,6 @@ gst_fakesrc_set_property (GObject * object, guint prop_id, const GValue * value,
src = GST_FAKESRC (object); src = GST_FAKESRC (object);
switch (prop_id) { switch (prop_id) {
case ARG_HAS_LOOP:
src->has_loop = g_value_get_boolean (value);
gst_fakesrc_set_all_pad_functions (src);
break;
case ARG_HAS_GETRANGE:
src->has_getrange = g_value_get_boolean (value);
gst_fakesrc_set_all_pad_functions (src);
break;
case ARG_OUTPUT: case ARG_OUTPUT:
g_warning ("not yet implemented"); g_warning ("not yet implemented");
break; break;
@ -594,12 +430,6 @@ gst_fakesrc_get_property (GObject * object, guint prop_id, GValue * value,
case ARG_NUM_SOURCES: case ARG_NUM_SOURCES:
g_value_set_int (value, GST_ELEMENT (src)->numsrcpads); g_value_set_int (value, GST_ELEMENT (src)->numsrcpads);
break; break;
case ARG_HAS_LOOP:
g_value_set_boolean (value, src->has_loop);
break;
case ARG_HAS_GETRANGE:
g_value_set_boolean (value, src->has_getrange);
break;
case ARG_OUTPUT: case ARG_OUTPUT:
g_value_set_enum (value, src->output); g_value_set_enum (value, src->output);
break; break;
@ -792,26 +622,20 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
} }
static GstFlowReturn static GstFlowReturn
gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length, gst_fakesrc_create (GstBaseSrc * basesrc, guint64 offset, guint length,
GstBuffer ** ret) GstBuffer ** ret)
{ {
GstFakeSrc *src; GstFakeSrc *src;
GstBuffer *buf; GstBuffer *buf;
GstClockTime time; GstClockTime time;
src = GST_FAKESRC (GST_OBJECT_PARENT (pad)); src = GST_FAKESRC (basesrc);
if (src->buffer_count == src->segment_end) { if (src->buffer_count == src->segment_end) {
if (src->segment_loop) {
//gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
} else {
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED; return GST_FLOW_UNEXPECTED;
} }
}
if (src->rt_num_buffers == 0) { if (src->rt_num_buffers == 0) {
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED; return GST_FLOW_UNEXPECTED;
} else { } else {
if (src->rt_num_buffers > 0) if (src->rt_num_buffers > 0)
@ -820,7 +644,6 @@ gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
if (src->eos) { if (src->eos) {
GST_INFO ("fakesrc is setting eos on pad"); GST_INFO ("fakesrc is setting eos on pad");
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED; return GST_FLOW_UNEXPECTED;
} }
@ -844,8 +667,8 @@ gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
g_free (src->last_message); g_free (src->last_message);
src->last_message = src->last_message =
g_strdup_printf ("get ******* (%s:%s)> (%d bytes, %" g_strdup_printf ("get ******* > (%d bytes, %"
G_GUINT64_FORMAT " ) %p", GST_DEBUG_PAD_NAME (pad), G_GUINT64_FORMAT " ) %p",
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf); GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_object_notify (G_OBJECT (src), "last_message"); g_object_notify (G_OBJECT (src), "last_message");
@ -853,8 +676,7 @@ gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
if (src->signal_handoffs) { if (src->signal_handoffs) {
GST_LOG_OBJECT (src, "pre handoff emit"); GST_LOG_OBJECT (src, "pre handoff emit");
g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0, g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0, buf);
buf, pad);
GST_LOG_OBJECT (src, "post handoff emit"); GST_LOG_OBJECT (src, "post handoff emit");
} }
@ -864,110 +686,6 @@ gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
return GST_FLOW_OK; return GST_FLOW_OK;
} }
static GstFlowReturn
gst_fakesrc_get_range (GstPad * pad, guint64 offset, guint length,
GstBuffer ** ret)
{
GstFlowReturn fret;
g_assert (GST_FAKESRC (GST_OBJECT_PARENT (pad))->pad_mode ==
GST_ACTIVATE_PULL);
GST_STREAM_LOCK (pad);
fret = gst_fakesrc_get_range_unlocked (pad, offset, length, ret);
GST_STREAM_UNLOCK (pad);
return fret;
}
static void
gst_fakesrc_loop (GstPad * pad)
{
GstFakeSrc *src;
GstBuffer *buf = NULL;
GstFlowReturn ret;
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
g_assert (src->pad_mode == GST_ACTIVATE_PUSH);
GST_STREAM_LOCK (pad);
if (src->need_flush) {
src->need_flush = FALSE;
gst_pad_push_event (pad, gst_event_new (GST_EVENT_FLUSH));
}
ret = gst_fakesrc_get_range_unlocked (pad, src->buffer_count,
DEFAULT_SIZEMAX, &buf);
if (ret != GST_FLOW_OK) {
goto pause;
}
ret = gst_pad_push (pad, buf);
if (ret != GST_FLOW_OK) {
goto pause;
}
GST_STREAM_UNLOCK (pad);
return;
pause:
gst_task_pause (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
return;
}
static gboolean
gst_fakesrc_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstFakeSrc *fakesrc;
fakesrc = GST_FAKESRC (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
/* if we have a scheduler we can start the task */
g_return_val_if_fail (fakesrc->has_loop, FALSE);
if (GST_ELEMENT_SCHEDULER (fakesrc)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (fakesrc),
(GstTaskFunction) gst_fakesrc_loop, pad);
gst_task_start (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
result = TRUE;
}
break;
case GST_ACTIVATE_PULL:
g_return_val_if_fail (fakesrc->has_getrange, FALSE);
result = TRUE;
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
/* step 3, stop the task */
if (GST_RPAD_TASK (pad)) {
gst_task_stop (GST_RPAD_TASK (pad));
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
GST_RPAD_TASK (pad) = NULL;
}
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
fakesrc->pad_mode = mode;
return result;
}
static GstElementStateReturn static GstElementStateReturn
gst_fakesrc_change_state (GstElement * element) gst_fakesrc_change_state (GstElement * element)
{ {

View file

@ -25,10 +25,10 @@
#define __GST_FAKESRC_H__ #define __GST_FAKESRC_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasesrc.h>
G_BEGIN_DECLS G_BEGIN_DECLS
typedef enum { typedef enum {
FAKESRC_FIRST_LAST_LOOP = 1, FAKESRC_FIRST_LAST_LOOP = 1,
FAKESRC_LAST_FIRST_LOOP, FAKESRC_LAST_FIRST_LOOP,
@ -74,7 +74,7 @@ typedef struct _GstFakeSrc GstFakeSrc;
typedef struct _GstFakeSrcClass GstFakeSrcClass; typedef struct _GstFakeSrcClass GstFakeSrcClass;
struct _GstFakeSrc { struct _GstFakeSrc {
GstElement element; GstBaseSrc element;
gboolean has_loop; gboolean has_loop;
gboolean has_getrange; gboolean has_getrange;
@ -114,7 +114,7 @@ struct _GstFakeSrc {
}; };
struct _GstFakeSrcClass { struct _GstFakeSrcClass {
GstElementClass parent_class; GstBaseSrcClass parent_class;
/* signals */ /* signals */
void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad); void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);

View file

@ -910,16 +910,22 @@ gst_filesrc_loop (GstPad * pad)
GST_STREAM_LOCK (pad); GST_STREAM_LOCK (pad);
result = gst_filesrc_get (pad, &buffer); result = gst_filesrc_get (pad, &buffer);
if (result != GST_FLOW_OK) { if (result != GST_FLOW_OK)
gst_task_pause (GST_RPAD_TASK (pad)); goto need_pause;
goto done;
}
result = gst_pad_push (pad, buffer); result = gst_pad_push (pad, buffer);
if (result != GST_FLOW_OK) { if (result != GST_FLOW_OK)
gst_task_pause (GST_RPAD_TASK (pad)); goto need_pause;
}
done:
GST_STREAM_UNLOCK (pad); GST_STREAM_UNLOCK (pad);
return;
need_pause:
{
gst_task_pause (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
return;
}
} }

View file

@ -8,6 +8,7 @@ libgstbase_@GST_MAJORMINOR@_la_DEPENDENCIES = \
../libgstreamer-@GST_MAJORMINOR@.la ../libgstreamer-@GST_MAJORMINOR@.la
libgstbase_@GST_MAJORMINOR@_la_SOURCES = \ libgstbase_@GST_MAJORMINOR@_la_SOURCES = \
gstbasesink.c \ gstbasesink.c \
gstbasesrc.c \
gstbasetransform.c gstbasetransform.c
libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
@ -20,6 +21,7 @@ libgstbase_@GST_MAJORMINOR@includedir = \
libgstbase_@GST_MAJORMINOR@include_HEADERS = \ libgstbase_@GST_MAJORMINOR@include_HEADERS = \
gstbasesink.h \ gstbasesink.h \
gstbasesrc.h \
gstbasetransform.h gstbasetransform.h
install-data-local: as-libtool-install-data-local install-data-local: as-libtool-install-data-local

View file

@ -25,3 +25,11 @@ GstBaseTransform
- does flushing - does flushing
- push mode - push mode
- pull mode if transform can operate on arbitrary data - pull mode if transform can operate on arbitrary data
GstBaseSrc
Base class for getrange based source elements
- one sinkpad
- handles state changes
- pull/push mode

View file

@ -190,6 +190,7 @@ gst_basesink_pad_setcaps (GstPad * pad, GstCaps * caps)
bsink = GST_BASESINK (GST_PAD_PARENT (pad)); bsink = GST_BASESINK (GST_PAD_PARENT (pad));
bclass = GST_BASESINK_GET_CLASS (bsink); bclass = GST_BASESINK_GET_CLASS (bsink);
if (bclass->set_caps) if (bclass->set_caps)
res = bclass->set_caps (bsink, caps); res = bclass->set_caps (bsink, caps);
@ -206,6 +207,7 @@ gst_basesink_pad_buffer_alloc (GstPad * pad, guint64 offset, guint size,
bsink = GST_BASESINK (GST_PAD_PARENT (pad)); bsink = GST_BASESINK (GST_PAD_PARENT (pad));
bclass = GST_BASESINK_GET_CLASS (bsink); bclass = GST_BASESINK_GET_CLASS (bsink);
if (bclass->buffer_alloc) if (bclass->buffer_alloc)
buffer = bclass->buffer_alloc (bsink, offset, size, caps); buffer = bclass->buffer_alloc (bsink, offset, size, caps);
@ -571,6 +573,9 @@ gst_basesink_event (GstPad * pad, GstEvent * event)
return result; return result;
} }
/* default implementation to calculate the start and end
* timestamps on a buffer, subclasses cna override
*/
static void static void
gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer, gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end) GstClockTime * start, GstClockTime * end)
@ -587,6 +592,15 @@ gst_basesink_get_times (GstBaseSink * basesink, GstBuffer * buffer,
} }
} }
/* perform synchronisation on a buffer
*
* 1) check if we have a clock, if not, do nothing
* 2) calculate the start and end time of the buffer
* 3) create a single shot notification to wait on
* the clock, save the entry so we can unlock it
* 4) wait on the clock, this blocks
* 5) unref the clockid again
*/
static void static void
gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer) gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
{ {
@ -615,6 +629,7 @@ gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
gst_clock_id_unref (basesink->clock_id); gst_clock_id_unref (basesink->clock_id);
basesink->clock_id = NULL; basesink->clock_id = NULL;
} }
/* FIXME, don't mess with end_time here */
basesink->end_time = GST_CLOCK_TIME_NONE; basesink->end_time = GST_CLOCK_TIME_NONE;
GST_UNLOCK (basesink); GST_UNLOCK (basesink);
@ -623,6 +638,12 @@ gst_basesink_do_sync (GstBaseSink * basesink, GstBuffer * buffer)
} }
} }
/* handle a buffer
*
* 1) first sync on the buffer
* 2) render the buffer
* 3) unref the buffer
*/
static inline void static inline void
gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf) gst_basesink_handle_buffer (GstBaseSink * basesink, GstBuffer * buf)
{ {
@ -662,7 +683,7 @@ gst_basesink_chain_unlocked (GstPad * pad, GstBuffer * buf)
return GST_FLOW_UNEXPECTED; return GST_FLOW_UNEXPECTED;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
return GST_FLOW_UNEXPECTED; return GST_FLOW_ERROR;
} }
} }
@ -683,6 +704,8 @@ gst_basesink_chain (GstPad * pad, GstBuffer * buf)
return result; return result;
} }
/* FIXME, not all sinks can operate in pull mode
*/
static void static void
gst_basesink_loop (GstPad * pad) gst_basesink_loop (GstPad * pad)
{ {

423
libs/gst/base/gstbasesrc.c Normal file
View file

@ -0,0 +1,423 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstbasesrc.c:
*
* 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.
*/
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "gstbasesrc.h"
#include <gst/gstmarshal.h>
#define DEFAULT_BLOCKSIZE 4096
GST_DEBUG_CATEGORY_STATIC (gst_basesrc_debug);
#define GST_CAT_DEFAULT gst_basesrc_debug
/* BaseSrc signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
ARG_BLOCKSIZE,
};
static GstElementClass *parent_class = NULL;
static void gst_basesrc_base_init (gpointer g_class);
static void gst_basesrc_class_init (GstBaseSrcClass * klass);
static void gst_basesrc_init (GstBaseSrc * src, gpointer g_class);
GType
gst_basesrc_get_type (void)
{
static GType basesrc_type = 0;
if (!basesrc_type) {
static const GTypeInfo basesrc_info = {
sizeof (GstBaseSrcClass),
(GBaseInitFunc) gst_basesrc_base_init,
NULL,
(GClassInitFunc) gst_basesrc_class_init,
NULL,
NULL,
sizeof (GstBaseSrc),
0,
(GInstanceInitFunc) gst_basesrc_init,
};
basesrc_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstBaseSrc", &basesrc_info, G_TYPE_FLAG_ABSTRACT);
}
return basesrc_type;
}
static gboolean gst_basesrc_activate (GstPad * pad, GstActivateMode mode);
static void gst_basesrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_basesrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_basesrc_event_handler (GstPad * pad, GstEvent * event);
static const GstEventMask *gst_basesrc_get_event_mask (GstPad * pad);
static const GstQueryType *gst_basesrc_get_query_types (GstPad * pad);
static gboolean gst_basesrc_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value);
static const GstFormat *gst_basesrc_get_formats (GstPad * pad);
static GstElementStateReturn gst_basesrc_change_state (GstElement * element);
static void gst_basesrc_loop (GstPad * pad);
static GstFlowReturn gst_basesrc_get_range (GstPad * pad, guint64 offset,
guint length, GstBuffer ** buf);
static void
gst_basesrc_base_init (gpointer g_class)
{
GST_DEBUG_CATEGORY_INIT (gst_basesrc_debug, "basesrc", 0, "basesrc element");
}
static void
gst_basesrc_class_init (GstBaseSrcClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_basesrc_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_basesrc_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLOCKSIZE,
g_param_spec_ulong ("blocksize", "Block size",
"Size in bytes to read per buffer", 1, G_MAXULONG, DEFAULT_BLOCKSIZE,
G_PARAM_READWRITE));
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_basesrc_change_state);
}
static void
gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
{
GstPad *pad;
GstPadTemplate *pad_template;
pad_template =
gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
g_return_if_fail (pad_template != NULL);
pad = gst_pad_new_from_template (pad_template, "src");
gst_pad_set_activate_function (pad, gst_basesrc_activate);
gst_pad_set_event_function (pad, gst_basesrc_event_handler);
gst_pad_set_event_mask_function (pad, gst_basesrc_get_event_mask);
gst_pad_set_query_function (pad, gst_basesrc_query);
gst_pad_set_query_type_function (pad, gst_basesrc_get_query_types);
gst_pad_set_formats_function (pad, gst_basesrc_get_formats);
gst_pad_set_loop_function (pad, gst_basesrc_loop);
gst_pad_set_getrange_function (pad, gst_basesrc_get_range);
gst_element_add_pad (GST_ELEMENT (basesrc), pad);
basesrc->segment_start = -1;
basesrc->segment_end = -1;
basesrc->blocksize = DEFAULT_BLOCKSIZE;
}
static const GstFormat *
gst_basesrc_get_formats (GstPad * pad)
{
static const GstFormat formats[] = {
GST_FORMAT_DEFAULT,
0,
};
return formats;
}
static const GstQueryType *
gst_basesrc_get_query_types (GstPad * pad)
{
static const GstQueryType types[] = {
GST_QUERY_TOTAL,
GST_QUERY_POSITION,
GST_QUERY_START,
GST_QUERY_SEGMENT_END,
0,
};
return types;
}
static gboolean
gst_basesrc_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value)
{
GstBaseSrc *src = GST_BASESRC (GST_PAD_PARENT (pad));
switch (type) {
case GST_QUERY_START:
*value = src->segment_start;
break;
case GST_QUERY_SEGMENT_END:
*value = src->segment_end;
break;
default:
return FALSE;
}
return TRUE;
}
static const GstEventMask *
gst_basesrc_get_event_mask (GstPad * pad)
{
static const GstEventMask masks[] = {
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
{GST_EVENT_FLUSH, 0},
{0, 0},
};
return masks;
}
static gboolean
gst_basesrc_event_handler (GstPad * pad, GstEvent * event)
{
GstBaseSrc *src;
src = GST_BASESRC (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK:
src->segment_start = GST_EVENT_SEEK_OFFSET (event);
src->segment_end = GST_EVENT_SEEK_ENDOFFSET (event);
src->segment_loop =
GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_SEGMENT_LOOP;
break;
case GST_EVENT_FLUSH:
break;
default:
break;
}
gst_event_unref (event);
return TRUE;
}
static void
gst_basesrc_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
GstBaseSrc *src;
src = GST_BASESRC (object);
switch (prop_id) {
case ARG_BLOCKSIZE:
src->blocksize = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_basesrc_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstBaseSrc *src;
src = GST_BASESRC (object);
switch (prop_id) {
case ARG_BLOCKSIZE:
g_value_set_int (value, src->blocksize);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstFlowReturn
gst_basesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
GstBuffer ** buf)
{
GstFlowReturn ret;
GstBaseSrc *src;
GstBaseSrcClass *bclass;
src = GST_BASESRC (GST_OBJECT_PARENT (pad));
bclass = GST_BASESRC_GET_CLASS (src);
if (bclass->create)
ret = bclass->create (src, offset, length, buf);
else
ret = GST_FLOW_ERROR;
return ret;
}
static GstFlowReturn
gst_basesrc_get_range (GstPad * pad, guint64 offset, guint length,
GstBuffer ** ret)
{
GstFlowReturn fret;
GST_STREAM_LOCK (pad);
fret = gst_basesrc_get_range_unlocked (pad, offset, length, ret);
GST_STREAM_UNLOCK (pad);
return fret;
}
static void
gst_basesrc_loop (GstPad * pad)
{
GstBaseSrc *src;
GstBuffer *buf = NULL;
GstFlowReturn ret;
src = GST_BASESRC (GST_OBJECT_PARENT (pad));
GST_STREAM_LOCK (pad);
ret =
gst_basesrc_get_range_unlocked (pad, src->offset, DEFAULT_BLOCKSIZE,
&buf);
if (ret != GST_FLOW_OK)
goto pause;
src->offset += GST_BUFFER_SIZE (buf);
ret = gst_pad_push (pad, buf);
if (ret != GST_FLOW_OK)
goto pause;
GST_STREAM_UNLOCK (pad);
return;
pause:
{
gst_task_pause (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
return;
}
}
static gboolean
gst_basesrc_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstBaseSrc *basesrc;
basesrc = GST_BASESRC (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
/* if we have a scheduler we can start the task */
if (GST_ELEMENT_SCHEDULER (basesrc)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (basesrc),
(GstTaskFunction) gst_basesrc_loop, pad);
gst_task_start (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
result = TRUE;
}
break;
case GST_ACTIVATE_PULL:
result = TRUE;
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
/* step 3, stop the task */
if (GST_RPAD_TASK (pad)) {
gst_task_stop (GST_RPAD_TASK (pad));
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
GST_RPAD_TASK (pad) = NULL;
}
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
return result;
}
static GstElementStateReturn
gst_basesrc_change_state (GstElement * element)
{
GstBaseSrc *basesrc;
GstElementStateReturn result = GST_STATE_FAILURE;
GstElementState transition;
basesrc = GST_BASESRC (element);
transition = GST_STATE_TRANSITION (element);
switch (transition) {
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_PAUSED:
{
basesrc->offset = 0;
break;
}
case GST_STATE_PAUSED_TO_PLAYING:
break;
default:
break;
}
result = GST_ELEMENT_CLASS (parent_class)->change_state (element);
switch (transition) {
case GST_STATE_PLAYING_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_READY:
break;
case GST_STATE_READY_TO_NULL:
break;
default:
break;
}
return result;
}

View file

@ -0,0 +1,74 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstbasesrc.h:
*
* 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.
*/
#ifndef __GST_BASESRC_H__
#define __GST_BASESRC_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_BASESRC (gst_basesrc_get_type())
#define GST_BASESRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASESRC,GstBaseSrc))
#define GST_BASESRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASESRC,GstBaseSrcClass))
#define GST_BASESRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASESRC, GstBaseSrcClass))
#define GST_IS_BASESRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASESRC))
#define GST_IS_BASESRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASESRC))
typedef struct _GstBaseSrc GstBaseSrc;
typedef struct _GstBaseSrcClass GstBaseSrcClass;
struct _GstBaseSrc {
GstElement element;
gint blocksize;
gint64 segment_start;
gint64 segment_end;
gboolean segment_loop;
guint64 offset;
};
struct _GstBaseSrcClass {
GstElementClass parent_class;
GstCaps* (*get_caps) (GstBaseSrc *src);
gboolean (*set_caps) (GstBaseSrc *src, GstCaps *caps);
gboolean (*start) (GstBaseSrc *src);
gboolean (*stop) (GstBaseSrc *src);
void (*get_times) (GstBaseSrc *src, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end);
gboolean (*event) (GstBaseSrc *src, GstEvent *event);
GstFlowReturn (*create) (GstBaseSrc *src, guint64 offset, guint size,
GstBuffer **buf);
};
GType gst_basesrc_get_type(void);
G_END_DECLS
#endif /* __GST_BASESRC_H__ */

View file

@ -64,8 +64,6 @@ enum
{ {
ARG_0, ARG_0,
ARG_NUM_SOURCES, ARG_NUM_SOURCES,
ARG_HAS_LOOP,
ARG_HAS_GETRANGE,
ARG_OUTPUT, ARG_OUTPUT,
ARG_DATA, ARG_DATA,
ARG_SIZETYPE, ARG_SIZETYPE,
@ -84,11 +82,6 @@ enum
ARG_LAST_MESSAGE ARG_LAST_MESSAGE
}; };
GstStaticPadTemplate fakesrc_src_template = GST_STATIC_PAD_TEMPLATE ("src%d",
GST_PAD_SRC,
GST_PAD_REQUEST,
GST_STATIC_CAPS_ANY);
#define GST_TYPE_FAKESRC_OUTPUT (gst_fakesrc_output_get_type()) #define GST_TYPE_FAKESRC_OUTPUT (gst_fakesrc_output_get_type())
static GType static GType
gst_fakesrc_output_get_type (void) gst_fakesrc_output_get_type (void)
@ -175,22 +168,18 @@ gst_fakesrc_filltype_get_type (void)
#define _do_init(bla) \ #define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element"); GST_DEBUG_CATEGORY_INIT (gst_fakesrc_debug, "fakesrc", 0, "fakesrc element");
GST_BOILERPLATE_FULL (GstFakeSrc, gst_fakesrc, GstElement, GST_TYPE_ELEMENT, GST_BOILERPLATE_FULL (GstFakeSrc, gst_fakesrc, GstBaseSrc, GST_TYPE_BASESRC,
_do_init); _do_init);
static GstPad *gst_fakesrc_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * unused);
static gboolean gst_fakesrc_activate (GstPad * pad, GstActivateMode mode);
static void gst_fakesrc_set_property (GObject * object, guint prop_id, static void gst_fakesrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec); const GValue * value, GParamSpec * pspec);
static void gst_fakesrc_get_property (GObject * object, guint prop_id, static void gst_fakesrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec); GValue * value, GParamSpec * pspec);
static void gst_fakesrc_set_clock (GstElement * element, GstClock * clock);
static GstElementStateReturn gst_fakesrc_change_state (GstElement * element); static GstElementStateReturn gst_fakesrc_change_state (GstElement * element);
static void gst_fakesrc_loop (GstPad * pad); static gboolean gst_fakesrc_event_handler (GstBaseSrc * src, GstEvent * event);
static GstFlowReturn gst_fakesrc_get_range (GstPad * pad, guint64 offset, static GstFlowReturn gst_fakesrc_create (GstBaseSrc * src, guint64 offset,
guint length, GstBuffer ** buf); guint length, GstBuffer ** buf);
static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 }; static guint gst_fakesrc_signals[LAST_SIGNAL] = { 0 };
@ -202,9 +191,8 @@ gst_fakesrc_base_init (gpointer g_class)
gst_element_class_add_pad_template (gstelement_class, gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&srctemplate)); gst_static_pad_template_get (&srctemplate));
gst_element_class_set_details (gstelement_class, &gst_fakesrc_details); gst_element_class_set_details (gstelement_class, &gst_fakesrc_details);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&fakesrc_src_template));
} }
static void static void
@ -212,9 +200,11 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
{ {
GObjectClass *gobject_class; GObjectClass *gobject_class;
GstElementClass *gstelement_class; GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
gobject_class = (GObjectClass *) klass; gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass; gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_fakesrc_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property); gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_fakesrc_get_property);
@ -222,14 +212,6 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES, g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_NUM_SOURCES,
g_param_spec_int ("num-sources", "num-sources", "Number of sources", g_param_spec_int ("num-sources", "num-sources", "Number of sources",
1, G_MAXINT, 1, G_PARAM_READABLE)); 1, G_MAXINT, 1, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_LOOP,
g_param_spec_boolean ("has-loop", "has-loop",
"Enable loop-based operation", TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_HAS_GETRANGE,
g_param_spec_boolean ("has-getrange", "has-getrange",
"Enable getrange-based operation", TRUE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OUTPUT, g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_OUTPUT,
g_param_spec_enum ("output", "output", "Output method (currently unused)", g_param_spec_enum ("output", "output", "Output method (currently unused)",
GST_TYPE_FAKESRC_OUTPUT, FAKESRC_FIRST_LAST_LOOP, G_PARAM_READWRITE)); GST_TYPE_FAKESRC_OUTPUT, FAKESRC_FIRST_LAST_LOOP, G_PARAM_READWRITE));
@ -287,26 +269,18 @@ gst_fakesrc_class_init (GstFakeSrcClass * klass)
gst_fakesrc_signals[SIGNAL_HANDOFF] = gst_fakesrc_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstFakeSrcClass, handoff), NULL, NULL, G_STRUCT_OFFSET (GstFakeSrcClass, handoff), NULL, NULL,
gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 2, gst_marshal_VOID__BOXED_OBJECT, G_TYPE_NONE, 1,
GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD); GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
gstelement_class->request_new_pad =
GST_DEBUG_FUNCPTR (gst_fakesrc_request_new_pad);
gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state); gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_fakesrc_change_state);
gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_fakesrc_set_clock);
gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_fakesrc_event_handler);
gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_fakesrc_create);
} }
static void static void
gst_fakesrc_init (GstFakeSrc * fakesrc) gst_fakesrc_init (GstFakeSrc * fakesrc)
{ {
GstPad *pad;
/* create our first output pad */
pad =
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
"src");
gst_element_add_pad (GST_ELEMENT (fakesrc), pad);
fakesrc->output = FAKESRC_FIRST_LAST_LOOP; fakesrc->output = FAKESRC_FIRST_LAST_LOOP;
fakesrc->segment_start = -1; fakesrc->segment_start = -1;
fakesrc->segment_end = -1; fakesrc->segment_end = -1;
@ -331,84 +305,12 @@ gst_fakesrc_init (GstFakeSrc * fakesrc)
fakesrc->pad_mode = GST_ACTIVATE_NONE; fakesrc->pad_mode = GST_ACTIVATE_NONE;
} }
static void static gboolean
gst_fakesrc_set_clock (GstElement * element, GstClock * clock) gst_fakesrc_event_handler (GstBaseSrc * basesrc, GstEvent * event)
{ {
GstFakeSrc *src; GstFakeSrc *src;
src = GST_FAKESRC (element); src = GST_FAKESRC (basesrc);
src->clock = clock;
}
static const GstFormat *
gst_fakesrc_get_formats (GstPad * pad)
{
static const GstFormat formats[] = {
GST_FORMAT_DEFAULT,
0,
};
return formats;
}
static const GstQueryType *
gst_fakesrc_get_query_types (GstPad * pad)
{
static const GstQueryType types[] = {
GST_QUERY_TOTAL,
GST_QUERY_POSITION,
GST_QUERY_START,
GST_QUERY_SEGMENT_END,
0,
};
return types;
}
static gboolean
gst_fakesrc_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value)
{
GstFakeSrc *src = GST_FAKESRC (GST_PAD_PARENT (pad));
switch (type) {
case GST_QUERY_TOTAL:
*value = src->num_buffers;
break;
case GST_QUERY_POSITION:
*value = src->buffer_count;
break;
case GST_QUERY_START:
*value = src->segment_start;
break;
case GST_QUERY_SEGMENT_END:
*value = src->segment_end;
break;
default:
return FALSE;
}
return TRUE;
}
static const GstEventMask *
gst_fakesrc_get_event_mask (GstPad * pad)
{
static const GstEventMask masks[] = {
{GST_EVENT_SEEK, GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_SEGMENT_LOOP},
{GST_EVENT_FLUSH, 0},
{0, 0},
};
return masks;
}
static gboolean
gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
{
GstFakeSrc *src;
src = GST_FAKESRC (GST_PAD_PARENT (pad));
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
@ -430,64 +332,6 @@ gst_fakesrc_event_handler (GstPad * pad, GstEvent * event)
return TRUE; return TRUE;
} }
static void
gst_fakesrc_set_pad_functions (GstFakeSrc * src, GstPad * pad)
{
gst_pad_set_activate_function (pad, gst_fakesrc_activate);
gst_pad_set_event_function (pad, gst_fakesrc_event_handler);
gst_pad_set_event_mask_function (pad, gst_fakesrc_get_event_mask);
gst_pad_set_query_function (pad, gst_fakesrc_query);
gst_pad_set_query_type_function (pad, gst_fakesrc_get_query_types);
gst_pad_set_formats_function (pad, gst_fakesrc_get_formats);
if (src->has_loop)
gst_pad_set_loop_function (pad, gst_fakesrc_loop);
else
gst_pad_set_loop_function (pad, NULL);
if (src->has_getrange)
gst_pad_set_getrange_function (pad, gst_fakesrc_get_range);
else
gst_pad_set_getrange_function (pad, NULL);
}
static void
gst_fakesrc_set_all_pad_functions (GstFakeSrc * src)
{
GList *l;
for (l = GST_ELEMENT_PADS (src); l; l = l->next)
gst_fakesrc_set_pad_functions (src, (GstPad *) l->data);
}
static GstPad *
gst_fakesrc_request_new_pad (GstElement * element, GstPadTemplate * templ,
const gchar * unused)
{
gchar *name;
GstPad *srcpad;
GstFakeSrc *fakesrc;
g_return_val_if_fail (GST_IS_FAKESRC (element), NULL);
if (templ->direction != GST_PAD_SRC) {
g_warning ("gstfakesrc: request new pad that is not a SRC pad\n");
return NULL;
}
fakesrc = GST_FAKESRC (element);
name = g_strdup_printf ("src%d", GST_ELEMENT (fakesrc)->numsrcpads);
srcpad = gst_pad_new_from_template (templ, name);
gst_element_add_pad (GST_ELEMENT (fakesrc), srcpad);
gst_fakesrc_set_pad_functions (fakesrc, srcpad);
g_free (name);
return srcpad;
}
static void static void
gst_fakesrc_alloc_parent (GstFakeSrc * src) gst_fakesrc_alloc_parent (GstFakeSrc * src)
{ {
@ -510,14 +354,6 @@ gst_fakesrc_set_property (GObject * object, guint prop_id, const GValue * value,
src = GST_FAKESRC (object); src = GST_FAKESRC (object);
switch (prop_id) { switch (prop_id) {
case ARG_HAS_LOOP:
src->has_loop = g_value_get_boolean (value);
gst_fakesrc_set_all_pad_functions (src);
break;
case ARG_HAS_GETRANGE:
src->has_getrange = g_value_get_boolean (value);
gst_fakesrc_set_all_pad_functions (src);
break;
case ARG_OUTPUT: case ARG_OUTPUT:
g_warning ("not yet implemented"); g_warning ("not yet implemented");
break; break;
@ -594,12 +430,6 @@ gst_fakesrc_get_property (GObject * object, guint prop_id, GValue * value,
case ARG_NUM_SOURCES: case ARG_NUM_SOURCES:
g_value_set_int (value, GST_ELEMENT (src)->numsrcpads); g_value_set_int (value, GST_ELEMENT (src)->numsrcpads);
break; break;
case ARG_HAS_LOOP:
g_value_set_boolean (value, src->has_loop);
break;
case ARG_HAS_GETRANGE:
g_value_set_boolean (value, src->has_getrange);
break;
case ARG_OUTPUT: case ARG_OUTPUT:
g_value_set_enum (value, src->output); g_value_set_enum (value, src->output);
break; break;
@ -792,26 +622,20 @@ gst_fakesrc_create_buffer (GstFakeSrc * src)
} }
static GstFlowReturn static GstFlowReturn
gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length, gst_fakesrc_create (GstBaseSrc * basesrc, guint64 offset, guint length,
GstBuffer ** ret) GstBuffer ** ret)
{ {
GstFakeSrc *src; GstFakeSrc *src;
GstBuffer *buf; GstBuffer *buf;
GstClockTime time; GstClockTime time;
src = GST_FAKESRC (GST_OBJECT_PARENT (pad)); src = GST_FAKESRC (basesrc);
if (src->buffer_count == src->segment_end) { if (src->buffer_count == src->segment_end) {
if (src->segment_loop) {
//gst_pad_push_event (pad, gst_event_new (GST_EVENT_SEGMENT_DONE));
} else {
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED; return GST_FLOW_UNEXPECTED;
} }
}
if (src->rt_num_buffers == 0) { if (src->rt_num_buffers == 0) {
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED; return GST_FLOW_UNEXPECTED;
} else { } else {
if (src->rt_num_buffers > 0) if (src->rt_num_buffers > 0)
@ -820,7 +644,6 @@ gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
if (src->eos) { if (src->eos) {
GST_INFO ("fakesrc is setting eos on pad"); GST_INFO ("fakesrc is setting eos on pad");
gst_pad_push_event (pad, gst_event_new (GST_EVENT_EOS));
return GST_FLOW_UNEXPECTED; return GST_FLOW_UNEXPECTED;
} }
@ -844,8 +667,8 @@ gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
g_free (src->last_message); g_free (src->last_message);
src->last_message = src->last_message =
g_strdup_printf ("get ******* (%s:%s)> (%d bytes, %" g_strdup_printf ("get ******* > (%d bytes, %"
G_GUINT64_FORMAT " ) %p", GST_DEBUG_PAD_NAME (pad), G_GUINT64_FORMAT " ) %p",
GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf); GST_BUFFER_SIZE (buf), GST_BUFFER_TIMESTAMP (buf), buf);
g_object_notify (G_OBJECT (src), "last_message"); g_object_notify (G_OBJECT (src), "last_message");
@ -853,8 +676,7 @@ gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
if (src->signal_handoffs) { if (src->signal_handoffs) {
GST_LOG_OBJECT (src, "pre handoff emit"); GST_LOG_OBJECT (src, "pre handoff emit");
g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0, g_signal_emit (G_OBJECT (src), gst_fakesrc_signals[SIGNAL_HANDOFF], 0, buf);
buf, pad);
GST_LOG_OBJECT (src, "post handoff emit"); GST_LOG_OBJECT (src, "post handoff emit");
} }
@ -864,110 +686,6 @@ gst_fakesrc_get_range_unlocked (GstPad * pad, guint64 offset, guint length,
return GST_FLOW_OK; return GST_FLOW_OK;
} }
static GstFlowReturn
gst_fakesrc_get_range (GstPad * pad, guint64 offset, guint length,
GstBuffer ** ret)
{
GstFlowReturn fret;
g_assert (GST_FAKESRC (GST_OBJECT_PARENT (pad))->pad_mode ==
GST_ACTIVATE_PULL);
GST_STREAM_LOCK (pad);
fret = gst_fakesrc_get_range_unlocked (pad, offset, length, ret);
GST_STREAM_UNLOCK (pad);
return fret;
}
static void
gst_fakesrc_loop (GstPad * pad)
{
GstFakeSrc *src;
GstBuffer *buf = NULL;
GstFlowReturn ret;
src = GST_FAKESRC (GST_OBJECT_PARENT (pad));
g_assert (src->pad_mode == GST_ACTIVATE_PUSH);
GST_STREAM_LOCK (pad);
if (src->need_flush) {
src->need_flush = FALSE;
gst_pad_push_event (pad, gst_event_new (GST_EVENT_FLUSH));
}
ret = gst_fakesrc_get_range_unlocked (pad, src->buffer_count,
DEFAULT_SIZEMAX, &buf);
if (ret != GST_FLOW_OK) {
goto pause;
}
ret = gst_pad_push (pad, buf);
if (ret != GST_FLOW_OK) {
goto pause;
}
GST_STREAM_UNLOCK (pad);
return;
pause:
gst_task_pause (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
return;
}
static gboolean
gst_fakesrc_activate (GstPad * pad, GstActivateMode mode)
{
gboolean result = FALSE;
GstFakeSrc *fakesrc;
fakesrc = GST_FAKESRC (GST_OBJECT_PARENT (pad));
switch (mode) {
case GST_ACTIVATE_PUSH:
/* if we have a scheduler we can start the task */
g_return_val_if_fail (fakesrc->has_loop, FALSE);
if (GST_ELEMENT_SCHEDULER (fakesrc)) {
GST_STREAM_LOCK (pad);
GST_RPAD_TASK (pad) =
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (fakesrc),
(GstTaskFunction) gst_fakesrc_loop, pad);
gst_task_start (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
result = TRUE;
}
break;
case GST_ACTIVATE_PULL:
g_return_val_if_fail (fakesrc->has_getrange, FALSE);
result = TRUE;
break;
case GST_ACTIVATE_NONE:
/* step 1, unblock clock sync (if any) */
/* step 2, make sure streaming finishes */
GST_STREAM_LOCK (pad);
/* step 3, stop the task */
if (GST_RPAD_TASK (pad)) {
gst_task_stop (GST_RPAD_TASK (pad));
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
GST_RPAD_TASK (pad) = NULL;
}
GST_STREAM_UNLOCK (pad);
result = TRUE;
break;
}
fakesrc->pad_mode = mode;
return result;
}
static GstElementStateReturn static GstElementStateReturn
gst_fakesrc_change_state (GstElement * element) gst_fakesrc_change_state (GstElement * element)
{ {

View file

@ -25,10 +25,10 @@
#define __GST_FAKESRC_H__ #define __GST_FAKESRC_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasesrc.h>
G_BEGIN_DECLS G_BEGIN_DECLS
typedef enum { typedef enum {
FAKESRC_FIRST_LAST_LOOP = 1, FAKESRC_FIRST_LAST_LOOP = 1,
FAKESRC_LAST_FIRST_LOOP, FAKESRC_LAST_FIRST_LOOP,
@ -74,7 +74,7 @@ typedef struct _GstFakeSrc GstFakeSrc;
typedef struct _GstFakeSrcClass GstFakeSrcClass; typedef struct _GstFakeSrcClass GstFakeSrcClass;
struct _GstFakeSrc { struct _GstFakeSrc {
GstElement element; GstBaseSrc element;
gboolean has_loop; gboolean has_loop;
gboolean has_getrange; gboolean has_getrange;
@ -114,7 +114,7 @@ struct _GstFakeSrc {
}; };
struct _GstFakeSrcClass { struct _GstFakeSrcClass {
GstElementClass parent_class; GstBaseSrcClass parent_class;
/* signals */ /* signals */
void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad); void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);

View file

@ -910,16 +910,22 @@ gst_filesrc_loop (GstPad * pad)
GST_STREAM_LOCK (pad); GST_STREAM_LOCK (pad);
result = gst_filesrc_get (pad, &buffer); result = gst_filesrc_get (pad, &buffer);
if (result != GST_FLOW_OK) { if (result != GST_FLOW_OK)
gst_task_pause (GST_RPAD_TASK (pad)); goto need_pause;
goto done;
}
result = gst_pad_push (pad, buffer); result = gst_pad_push (pad, buffer);
if (result != GST_FLOW_OK) { if (result != GST_FLOW_OK)
gst_task_pause (GST_RPAD_TASK (pad)); goto need_pause;
}
done:
GST_STREAM_UNLOCK (pad); GST_STREAM_UNLOCK (pad);
return;
need_pause:
{
gst_task_pause (GST_RPAD_TASK (pad));
GST_STREAM_UNLOCK (pad);
return;
}
} }