gst/: Added object to help in making collect pad based elements.

Original commit message from CVS:
* gst/base/Makefile.am:
* gst/base/gstbasesink.h:
* gst/base/gstbasesrc.c: (gst_basesrc_init),
(gst_basesrc_set_dataflow_funcs), (gst_basesrc_query):
* gst/base/gstcollectpads.c: (gst_collectpads_get_type),
(gst_collectpads_class_init), (gst_collectpads_init),
(gst_collectpads_finalize), (gst_collectpads_new),
(gst_collectpads_set_function), (gst_collectpads_add_pad),
(find_pad), (gst_collectpads_remove_pad),
(gst_collectpads_is_active), (gst_collectpads_collect),
(gst_collectpads_collect_range), (gst_collectpads_start),
(gst_collectpads_stop), (gst_collectpads_peek),
(gst_collectpads_pop), (gst_collectpads_available),
(gst_collectpads_read), (gst_collectpads_flush),
(gst_collectpads_chain):
* gst/base/gstcollectpads.h:
* gst/elements/Makefile.am:
* gst/elements/gstelements.c:
* gst/elements/gstfakesink.c: (gst_fakesink_class_init),
(gst_fakesink_get_times), (gst_fakesink_event),
(gst_fakesink_preroll), (gst_fakesink_render):
* gst/elements/gstfilesink.c: (gst_filesink_class_init),
(gst_filesink_init), (gst_filesink_set_location),
(gst_filesink_open_file), (gst_filesink_close_file),
(gst_filesink_pad_query), (gst_filesink_event),
(gst_filesink_render), (gst_filesink_change_state):
* gst/elements/gstfilesink.h:
Added object to help in making collect pad based elements.
Ported filesink.
Make event function in sink baseclass return gboolean.
This commit is contained in:
Wim Taymans 2005-05-05 09:31:59 +00:00
parent d2bf92842c
commit 113250d274
21 changed files with 1551 additions and 254 deletions

View file

@ -1,3 +1,36 @@
2005-05-05 Wim Taymans <wim@fluendo.com>
* gst/base/Makefile.am:
* gst/base/gstbasesink.h:
* gst/base/gstbasesrc.c: (gst_basesrc_init),
(gst_basesrc_set_dataflow_funcs), (gst_basesrc_query):
* gst/base/gstcollectpads.c: (gst_collectpads_get_type),
(gst_collectpads_class_init), (gst_collectpads_init),
(gst_collectpads_finalize), (gst_collectpads_new),
(gst_collectpads_set_function), (gst_collectpads_add_pad),
(find_pad), (gst_collectpads_remove_pad),
(gst_collectpads_is_active), (gst_collectpads_collect),
(gst_collectpads_collect_range), (gst_collectpads_start),
(gst_collectpads_stop), (gst_collectpads_peek),
(gst_collectpads_pop), (gst_collectpads_available),
(gst_collectpads_read), (gst_collectpads_flush),
(gst_collectpads_chain):
* gst/base/gstcollectpads.h:
* gst/elements/Makefile.am:
* gst/elements/gstelements.c:
* gst/elements/gstfakesink.c: (gst_fakesink_class_init),
(gst_fakesink_get_times), (gst_fakesink_event),
(gst_fakesink_preroll), (gst_fakesink_render):
* gst/elements/gstfilesink.c: (gst_filesink_class_init),
(gst_filesink_init), (gst_filesink_set_location),
(gst_filesink_open_file), (gst_filesink_close_file),
(gst_filesink_pad_query), (gst_filesink_event),
(gst_filesink_render), (gst_filesink_change_state):
* gst/elements/gstfilesink.h:
Added object to help in making collect pad based elements.
Ported filesink.
Make event function in sink baseclass return gboolean.
2005-05-05 Wim Taymans <wim@fluendo.com> 2005-05-05 Wim Taymans <wim@fluendo.com>
* gst/gstbin.c: (gst_bin_send_event), (compare_name), * gst/gstbin.c: (gst_bin_send_event), (compare_name),

View file

@ -6,6 +6,7 @@ libgstbase_@GST_MAJORMINOR@_la_SOURCES = \
gstbasesink.c \ gstbasesink.c \
gstbasesrc.c \ gstbasesrc.c \
gstbasetransform.c \ gstbasetransform.c \
gstcollectpads.c \
gsttypefindhelper.c gsttypefindhelper.c
libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
@ -20,5 +21,6 @@ libgstbase_@GST_MAJORMINOR@include_HEADERS = \
gstbasesink.h \ gstbasesink.h \
gstbasesrc.h \ gstbasesrc.h \
gstbasetransform.h \ gstbasetransform.h \
gstcollectpads.h \
gsttypefindhelper.h gsttypefindhelper.h

View file

@ -75,7 +75,7 @@ struct _GstBaseSinkClass {
void (*get_times) (GstBaseSink *sink, GstBuffer *buffer, void (*get_times) (GstBaseSink *sink, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end); GstClockTime *start, GstClockTime *end);
void (*event) (GstBaseSink *sink, GstEvent *event); gboolean (*event) (GstBaseSink *sink, GstEvent *event);
GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer); GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer);
GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer); GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);
}; };

View file

@ -169,6 +169,7 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
basesrc->srcpad = pad; basesrc->srcpad = pad;
gst_element_add_pad (GST_ELEMENT (basesrc), pad); gst_element_add_pad (GST_ELEMENT (basesrc), pad);
basesrc->random_access = TRUE;
basesrc->segment_start = -1; basesrc->segment_start = -1;
basesrc->segment_end = -1; basesrc->segment_end = -1;
basesrc->blocksize = DEFAULT_BLOCKSIZE; basesrc->blocksize = DEFAULT_BLOCKSIZE;
@ -179,6 +180,8 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
static void static void
gst_basesrc_set_dataflow_funcs (GstBaseSrc * this) gst_basesrc_set_dataflow_funcs (GstBaseSrc * this)
{ {
GST_DEBUG ("updating dataflow functions");
if (this->has_loop) if (this->has_loop)
gst_pad_set_loop_function (this->srcpad, gst_basesrc_loop); gst_pad_set_loop_function (this->srcpad, gst_basesrc_loop);
else else
@ -232,7 +235,6 @@ gst_basesrc_query (GstPad * pad, GstQueryType type,
{ {
gboolean ret; gboolean ret;
/* FIXME-wim: is this cast right? */
ret = gst_basesrc_get_size (src, (guint64 *) value); ret = gst_basesrc_get_size (src, (guint64 *) value);
GST_DEBUG ("getting length %d %lld", ret, *value); GST_DEBUG ("getting length %d %lld", ret, *value);
return ret; return ret;

538
gst/base/gstcollectpads.c Normal file
View file

@ -0,0 +1,538 @@
/* GStreamer
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
*
* gstcollectpads.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 "gstcollectpads.h"
static GstFlowReturn gst_collectpads_chain (GstPad * pad, GstBuffer * buffer);
static void gst_collectpads_class_init (GstCollectPadsClass * klass);
static void gst_collectpads_init (GstCollectPads * pads);
static void gst_collectpads_finalize (GObject * object);
static GstObjectClass *parent_class = NULL;
GType
gst_collectpads_get_type (void)
{
static GType collect_type = 0;
if (!collect_type) {
static const GTypeInfo collect_info = {
sizeof (GstCollectPadsClass),
NULL,
NULL,
(GClassInitFunc) gst_collectpads_class_init,
NULL,
NULL,
sizeof (GstCollectPads),
0,
(GInstanceInitFunc) gst_collectpads_init,
NULL
};
collect_type = g_type_register_static (GST_TYPE_OBJECT, "GstCollectPads",
&collect_info, 0);
}
return collect_type;
}
static void
gst_collectpads_class_init (GstCollectPadsClass * klass)
{
GObjectClass *gobject_class;
GstObjectClass *gstobject_class;
gobject_class = (GObjectClass *) klass;
gstobject_class = (GstObjectClass *) klass;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_collectpads_finalize);
parent_class = g_type_class_ref (GST_TYPE_OBJECT);
}
static void
gst_collectpads_init (GstCollectPads * pads)
{
pads->cond = g_cond_new ();
pads->data = NULL;
pads->cookie = 0;
pads->numpads = 0;
pads->queuedpads = 0;
pads->started = FALSE;
}
static void
gst_collectpads_finalize (GObject * object)
{
GstCollectPads *pads = GST_COLLECTPADS (object);
g_cond_free (pads->cond);
/* FIXME, free data */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/**
* gst_collectpads_new:
*
* Create a new instance of #GstCollectsPads.
*
* Returns: a new #GstCollectPads, or NULL in case of an error.
*
* MT safe.
*/
GstCollectPads *
gst_collectpads_new (void)
{
GstCollectPads *newcoll;
newcoll = g_object_new (GST_TYPE_COLLECTPADS, NULL);
return newcoll;
}
/**
* gst_collectpads_set_function:
* @pads: the collectspads to use
* @func: the function to set
* @user_data: user data passed to the function
*
* Set the callback function and user data that will be called when
* all the pads added to the collection have buffers queued.
*
* MT safe.
*/
void
gst_collectpads_set_function (GstCollectPads * pads,
GstCollectPadsFunction func, gpointer user_data)
{
g_return_if_fail (pads != NULL);
GST_LOCK (pads);
pads->func = func;
pads->user_data = user_data;
GST_UNLOCK (pads);
}
/**
* gst_collectpads_add_pad:
* @pads: the collectspads to use
* @pad: the pad to add
* @size: the size of the returned GstCollectData structure
*
* Add a pad to the collection of collect pads. The pad has to be
* a sinkpad.
*
* You specify a size for the returned #GstCollectData structure
* so that you can use it to store additional information.
*
* Returns: a new #GstCollectData to identify the new pad. Or NULL
* if wrong parameters are supplied.
*
* MT safe.
*/
GstCollectData *
gst_collectpads_add_pad (GstCollectPads * pads, GstPad * pad, guint size)
{
GstCollectData *data;
g_return_val_if_fail (pads != NULL, NULL);
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_PAD_IS_SINK (pad), NULL);
g_return_val_if_fail (size >= sizeof (GstCollectData), NULL);
data = g_malloc0 (size);
data->collect = pads;
data->pad = pad;
data->buffer = NULL;
GST_LOCK (pads);
pads->data = g_slist_append (pads->data, data);
gst_pad_set_chain_function (pad, gst_collectpads_chain);
gst_pad_set_element_private (pad, data);
pads->numpads++;
pads->cookie++;
GST_UNLOCK (pads);
return data;
}
static gint
find_pad (GstCollectData * data, GstPad * pad)
{
if (data->pad == pad)
return 0;
return 1;
}
/**
* gst_collectpads_remove_pad:
* @pads: the collectspads to use
* @pad: the pad to remove
*
* Remove a pad from the collection of collect pads.
*
* Returns: TRUE if the pad could be removed.
*
* MT safe.
*/
gboolean
gst_collectpads_remove_pad (GstCollectPads * pads, GstPad * pad)
{
GSList *list;
g_return_val_if_fail (pads != NULL, FALSE);
g_return_val_if_fail (pad != NULL, FALSE);
GST_LOCK (pads);
list = g_slist_find_custom (pads->data, pad, (GCompareFunc) find_pad);
if (list) {
g_free (list->data);
pads->data = g_slist_delete_link (pads->data, list);
}
pads->numpads--;
pads->cookie++;
GST_UNLOCK (pads);
return list != NULL;
}
/**
* gst_collectpads_is_active:
* @pads: the collectspads to use
* @pad: the pad to check
*
* Check if a pad is active.
*
* Returns: TRUE if the pad is active.
*
* MT safe.
*/
gboolean
gst_collectpads_is_active (GstCollectPads * pads, GstPad * pad)
{
g_return_val_if_fail (pads != NULL, FALSE);
g_return_val_if_fail (pad != NULL, FALSE);
return FALSE;
}
/**
* gst_collectpads_collect:
* @pads: the collectspads to use
*
* Collect data on all pads. This function is usually called
* from a GstTask function in an element.
*
* Returns: GstFlowReturn of the operation.
*
* MT safe.
*/
GstFlowReturn
gst_collectpads_collect (GstCollectPads * pads)
{
g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
return GST_FLOW_ERROR;
}
/**
* gst_collectpads_collect_range:
* @pads: the collectspads to use
* @offset: the offset to collect
* @length: the length to collect
*
* Collect data with @offset and @length on all pads. This function
* is typically called in the getrange function of an element.
*
* Returns: GstFlowReturn of the operation.
*
* MT safe.
*/
GstFlowReturn
gst_collectpads_collect_range (GstCollectPads * pads, guint64 offset,
guint length)
{
g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
return GST_FLOW_ERROR;
}
/**
* gst_collectpads_start:
* @pads: the collectspads to use
*
* Starts the processing of data in the collectpads.
*
* MT safe.
*/
void
gst_collectpads_start (GstCollectPads * pads)
{
g_return_if_fail (pads != NULL);
GST_LOCK (pads);
pads->started = TRUE;
GST_UNLOCK (pads);
}
/**
* gst_collectpads_stop:
* @pads: the collectspads to use
*
* Stops the processing of data in the collectpads. this function
* will also unblock any blocking operations.
*
* MT safe.
*/
void
gst_collectpads_stop (GstCollectPads * pads)
{
g_return_if_fail (pads != NULL);
GST_LOCK (pads);
pads->started = FALSE;
GST_COLLECTPADS_SIGNAL (pads);
GST_UNLOCK (pads);
}
/**
* gst_collectpads_peek:
* @pads: the collectspads to peek
* @data: the data to use
*
* Peek at the buffer currently queued in @data. This function
* should be called with the @pads LOCK held, such as in the callback
* handler.
*
* Returns: The buffer in @data or NULL if no buffer is queued. You
* should unref the buffer after usage.
*
* MT safe.
*/
GstBuffer *
gst_collectpads_peek (GstCollectPads * pads, GstCollectData * data)
{
GstBuffer *result;
result = data->buffer;
gst_buffer_ref (result);
return result;
}
/**
* gst_collectpads_pop:
* @pads: the collectspads to pop
* @data: the data to use
*
* Pop the buffer currently queued in @data. This function
* should be called with the @pads LOCK held, such as in the callback
* handler.
*
* Returns: The buffer in @data or NULL if no buffer was queued. The
* You should unref the buffer after usage.
*
* MT safe.
*/
GstBuffer *
gst_collectpads_pop (GstCollectPads * pads, GstCollectData * data)
{
GstBuffer *result;
result = data->buffer;
gst_buffer_replace (&data->buffer, NULL);
data->pos = 0;
pads->queuedpads--;
GST_COLLECTPADS_SIGNAL (pads);
return result;
}
/**
* gst_collectpads_available:
* @pads: the collectspads to query
*
* Query how much bytes can be read from each queued buffer. This means
* that the result of this call is the maximum number of bytes that can
* be read from each of the pads.
*
* This function should be called with @pads LOCK held, such as
* in the callback.
*
* Returns: The maximum number of bytes queued on all pad. This function
* returns 0 if a pad has no queued buffer.
*
* MT safe.
*/
guint
gst_collectpads_available (GstCollectPads * pads)
{
GSList *collected;
guint result = G_MAXUINT;
for (collected = pads->data; collected; collected = g_slist_next (collected)) {
GstCollectData *pdata;
gint size;
pdata = (GstCollectData *) collected->data;
if (pdata->buffer == NULL)
goto not_filled;
size = GST_BUFFER_SIZE (pdata->buffer) - pdata->pos;
if (size < result)
result = size;
}
return result;
not_filled:
{
return 0;
}
}
/**
* gst_collectpads_read:
* @pads: the collectspads to query
* @data: the data to use
* @bytes: a pointer to a byte array
* @size: the number of bytes to read
*
* Get a pointer in @bytes where @size bytes can be read from the
* given pad data.
*
* This function should be called with @pads LOCK held, such as
* in the callback.
*
* Returns: The number of bytes available for consumption in the
* memory pointed to by @bytes. This can be less than @size and
* is 0 if the pad is end-of-stream.
*
* MT safe.
*/
guint
gst_collectpads_read (GstCollectPads * pads, GstCollectData * data,
guint8 ** bytes, guint size)
{
guint readsize;
readsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
*bytes = GST_BUFFER_DATA (data->buffer) + data->pos;
return readsize;
}
/**
* gst_collectpads_flush:
* @pads: the collectspads to query
* @data: the data to use
* @size: the number of bytes to flush
*
* Flush @size bytes from the pad @data.
*
* This function should be called with @pads LOCK held, such as
* in the callback.
*
* Returns: The number of bytes flushed This can be less than @size and
* is 0 if the pad was end-of-stream.
*
* MT safe.
*/
guint
gst_collectpads_flush (GstCollectPads * pads, GstCollectData * data, guint size)
{
guint flushsize;
flushsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
data->pos += size;
if (data->pos >= GST_BUFFER_SIZE (data->buffer)) {
GstBuffer *buf;
buf = gst_collectpads_pop (pads, data);
gst_buffer_unref (buf);
}
return flushsize;
}
static GstFlowReturn
gst_collectpads_chain (GstPad * pad, GstBuffer * buffer)
{
GstCollectData *data;
GstCollectPads *pads;
guint64 size;
GstFlowReturn ret;
GST_DEBUG ("chain");
/* some magic to get the managing collectpads */
data = (GstCollectData *) gst_pad_get_element_private (pad);
if (data == NULL)
goto not_ours;
pads = data->collect;
size = GST_BUFFER_SIZE (buffer);
GST_LOCK (pads);
/* if not started, bail out */
if (!pads->started)
goto not_started;
/* queue buffer on this pad, block if filled */
while (data->buffer != NULL) {
GST_COLLECTPADS_WAIT (pads);
/* after a signal, we could be stopped */
if (!pads->started)
goto not_started;
}
pads->queuedpads++;
gst_buffer_replace (&data->buffer, buffer);
/* if all pads have data and we have a function, call it */
if ((pads->queuedpads == pads->numpads) && pads->func) {
ret = pads->func (pads, pads->user_data);
} else {
ret = GST_FLOW_OK;
}
GST_UNLOCK (pads);
return ret;
/* ERRORS */
not_ours:
{
GST_DEBUG ("collectpads not ours");
return GST_FLOW_ERROR;
}
not_started:
{
GST_UNLOCK (pads);
GST_DEBUG ("collectpads not started");
return GST_FLOW_WRONG_STATE;
}
}

132
gst/base/gstcollectpads.h Normal file
View file

@ -0,0 +1,132 @@
/* GStreamer
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
*
* gstcollectpads.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_COLLECTPADS_H__
#define __GST_COLLECTPADS_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_COLLECTPADS (gst_collectpads_get_type())
#define GST_COLLECTPADS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_COLLECTPADS,GstCollectPads))
#define GST_COLLECTPADS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_COLLECTPADS,GstCollectPadsClass))
#define GST_COLLECTPADS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_COLLECTPADS, GstCollectPadsClass))
#define GST_IS_COLLECTPADS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_COLLECTPADS))
#define GST_IS_COLLECTPADS_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_COLLECTPADS))
/* manages a set of pads that operate in collect mode. This means
* that control is given to the manager of this object when all
* pads have data.
*
* - pads are added to the collection with add/remove_pad. The pad
* has to be a sinkpad. The chain function of the pad is
* overridden. The element_private of the pad is used to store
* private information.
* - For each pad, data is queued in the chain function or by
* performing a pull_range.
* - When data is queued on all pads, a callback function is
* called.
* - Data can be dequeued from the pad with the _pop() method.
* One can _peek() at the data with the peek function.
* - Data can also be dequeued with the available/read/flush
* calls.
*/
typedef struct _GstCollectPads GstCollectPads;
typedef struct _GstCollectPadsClass GstCollectPadsClass;
typedef struct _GstCollectData
{
GstCollectPads *collect;
GstPad *pad;
GstBuffer *buffer;
guint pos;
gboolean eos;
} GstCollectData;
/* function will be called when all pads have data */
typedef GstFlowReturn (*GstCollectPadsFunction) (GstCollectPads *pads, gpointer user_data);
#define GST_COLLECTPADS_GET_COND(pads) (((GstCollectPads *)pads)->cond)
#define GST_COLLECTPADS_WAIT(pads) (g_cond_wait (GST_COLLECTPADS_GET_COND (pads), GST_GET_LOCK (pads)))
#define GST_COLLECTPADS_SIGNAL(pads) (g_cond_signal (GST_COLLECTPADS_GET_COND (pads)))
#define GST_COLLECTPADS_BROADCAST(pads)(g_cond_broadcast (GST_COLLECTPADS_GET_COND (pads)))
struct _GstCollectPads {
GstObject object;
/*< public >*/ /* with LOCK */
GSList *data; /* GstCollectData in this collection */
guint32 cookie;
GCond *cond; /* to signal removal of data */
/*< private >*/
GstCollectPadsFunction func; /* function and user_data for callback */
gpointer user_data;
guint numpads; /* number of pads */
guint queuedpads; /* number of pads with a buffer */
gboolean started;
};
struct _GstCollectPadsClass {
GstObjectClass parent_class;
};
GType gst_collectpads_get_type(void);
/* creating the object */
GstCollectPads* gst_collectpads_new (void);
/* set the callback */
void gst_collectpads_set_function (GstCollectPads *pads, GstCollectPadsFunction func,
gpointer user_data);
/* pad management */
GstCollectData* gst_collectpads_add_pad (GstCollectPads *pads, GstPad *pad, guint size);
gboolean gst_collectpads_remove_pad (GstCollectPads *pads, GstPad *pad);
gboolean gst_collectpads_is_active (GstCollectPads *pads, GstPad *pad);
/* start/stop collection */
GstFlowReturn gst_collectpads_collect (GstCollectPads *pads);
GstFlowReturn gst_collectpads_collect_range (GstCollectPads *pads, guint64 offset, guint length);
void gst_collectpads_start (GstCollectPads *pads);
void gst_collectpads_stop (GstCollectPads *pads);
/* get collected buffers */
GstBuffer* gst_collectpads_peek (GstCollectPads *pads, GstCollectData *data);
GstBuffer* gst_collectpads_pop (GstCollectPads *pads, GstCollectData *data);
/* get collected bytes */
guint gst_collectpads_available (GstCollectPads *pads);
guint gst_collectpads_read (GstCollectPads *pads, GstCollectData *data,
guint8 **bytes, guint size);
guint gst_collectpads_flush (GstCollectPads *pads, GstCollectData *data,
guint size);
G_END_DECLS
#endif /* __GST_COLLECTPADS_H__ */

View file

@ -15,6 +15,7 @@ libgstelements_la_SOURCES = \
gstcapsfilter.c \ gstcapsfilter.c \
gstfakesrc.c \ gstfakesrc.c \
gstfakesink.c \ gstfakesink.c \
gstfilesink.c \
gstfilesrc.c \ gstfilesrc.c \
gstidentity.c \ gstidentity.c \
gstelements.c \ gstelements.c \
@ -27,7 +28,6 @@ libgstelements_la_SOURCES = \
EXTRA_DIST = \ EXTRA_DIST = \
gstaggregator.c \ gstaggregator.c \
gstcapsfilter.c \ gstcapsfilter.c \
gstfilesink.c \
gstfdsink.c \ gstfdsink.c \
gstfdsrc.c \ gstfdsrc.c \
gstmd5sink.c \ gstmd5sink.c \

View file

@ -64,7 +64,7 @@ static struct _elements_entry _elements[] = {
{"identity", GST_RANK_NONE, gst_identity_get_type}, {"identity", GST_RANK_NONE, gst_identity_get_type},
// {"fdsink", GST_RANK_NONE, gst_fdsink_get_type}, // {"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
// {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type}, // {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
// {"filesink", GST_RANK_NONE, gst_filesink_get_type}, {"filesink", GST_RANK_NONE, gst_filesink_get_type},
// {"md5sink", GST_RANK_NONE, gst_md5sink_get_type}, // {"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
#ifndef HAVE_WIN32 #ifndef HAVE_WIN32
// {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type}, // {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},

View file

@ -116,7 +116,7 @@ static GstFlowReturn gst_fakesink_preroll (GstBaseSink * bsink,
GstBuffer * buffer); GstBuffer * buffer);
static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink, static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink,
GstBuffer * buffer); GstBuffer * buffer);
static void gst_fakesink_event (GstBaseSink * bsink, GstEvent * event); static gboolean gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
static void gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer, static void gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end); GstClockTime * start, GstClockTime * end);
@ -269,7 +269,7 @@ gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
} }
} }
static void static gboolean
gst_fakesink_event (GstBaseSink * bsink, GstEvent * event) gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
{ {
GstFakeSink *sink = GST_FAKESINK (bsink); GstFakeSink *sink = GST_FAKESINK (bsink);
@ -283,6 +283,8 @@ gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
g_object_notify (G_OBJECT (sink), "last_message"); g_object_notify (G_OBJECT (sink), "last_message");
} }
return TRUE;
} }
static GstFlowReturn static GstFlowReturn

View file

@ -99,17 +99,19 @@ static void gst_filesink_get_property (GObject * object, guint prop_id,
static gboolean gst_filesink_open_file (GstFileSink * sink); static gboolean gst_filesink_open_file (GstFileSink * sink);
static void gst_filesink_close_file (GstFileSink * sink); static void gst_filesink_close_file (GstFileSink * sink);
static gboolean gst_filesink_handle_event (GstPad * pad, GstEvent * event); static gboolean gst_filesink_event (GstBaseSink * sink, GstEvent * event);
static GstFlowReturn gst_filesink_render (GstBaseSink * sink,
GstBuffer * buffer);
static gboolean gst_filesink_pad_query (GstPad * pad, GstQueryType type, static gboolean gst_filesink_pad_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value); GstFormat * format, gint64 * value);
static void gst_filesink_chain (GstPad * pad, GstData * _data);
static void gst_filesink_uri_handler_init (gpointer g_iface, static void gst_filesink_uri_handler_init (gpointer g_iface,
gpointer iface_data); gpointer iface_data);
static GstElementStateReturn gst_filesink_change_state (GstElement * element); static GstElementStateReturn gst_filesink_change_state (GstElement * element);
static guint gst_filesink_signals[LAST_SIGNAL] = { 0 }; //static guint gst_filesink_signals[LAST_SIGNAL] = { 0 };
static void static void
_do_init (GType filesink_type) _do_init (GType filesink_type)
@ -126,10 +128,9 @@ _do_init (GType filesink_type)
"filesink element"); "filesink element");
} }
GST_BOILERPLATE_FULL (GstFileSink, gst_filesink, GstElement, GST_TYPE_ELEMENT, GST_BOILERPLATE_FULL (GstFileSink, gst_filesink, GstBaseSink, GST_TYPE_BASESINK,
_do_init); _do_init);
static void static void
gst_filesink_base_init (gpointer g_class) gst_filesink_base_init (gpointer g_class)
{ {
@ -144,6 +145,7 @@ static void
gst_filesink_class_init (GstFileSinkClass * klass) gst_filesink_class_init (GstFileSinkClass * klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstBaseSinkClass *gstbasesink_class = GST_BASESINK_CLASS (klass);
gobject_class->set_property = gst_filesink_set_property; gobject_class->set_property = gst_filesink_set_property;
gobject_class->get_property = gst_filesink_get_property; gobject_class->get_property = gst_filesink_get_property;
@ -152,25 +154,17 @@ gst_filesink_class_init (GstFileSinkClass * klass)
g_param_spec_string ("location", "File Location", g_param_spec_string ("location", "File Location",
"Location of the file to write", NULL, G_PARAM_READWRITE)); "Location of the file to write", NULL, G_PARAM_READWRITE));
gst_filesink_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstFileSinkClass, handoff), NULL, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
gobject_class->dispose = gst_filesink_dispose; gobject_class->dispose = gst_filesink_dispose;
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_filesink_render);
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_filesink_event);
} }
static void static void
gst_filesink_init (GstFileSink * filesink) gst_filesink_init (GstFileSink * filesink)
{ {
GstPad *pad; GstPad *pad;
pad = pad = GST_BASESINK_PAD (filesink);
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (filesink), pad);
gst_pad_set_chain_function (pad, gst_filesink_chain);
GST_FLAG_SET (GST_ELEMENT (filesink), GST_ELEMENT_EVENT_AWARE);
gst_pad_set_query_function (pad, gst_filesink_pad_query); gst_pad_set_query_function (pad, gst_filesink_pad_query);
gst_pad_set_query_type_function (pad, gst_filesink_get_query_types); gst_pad_set_query_type_function (pad, gst_filesink_get_query_types);
@ -196,10 +190,7 @@ static gboolean
gst_filesink_set_location (GstFileSink * sink, const gchar * location) gst_filesink_set_location (GstFileSink * sink, const gchar * location)
{ {
/* the element must be stopped or paused in order to do this */ /* the element must be stopped or paused in order to do this */
if (GST_STATE (sink) > GST_STATE_PAUSED) if (GST_STATE (sink) >= GST_STATE_PAUSED)
return FALSE;
if (GST_STATE (sink) == GST_STATE_PAUSED &&
GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN))
return FALSE; return FALSE;
g_free (sink->filename); g_free (sink->filename);
@ -212,9 +203,6 @@ gst_filesink_set_location (GstFileSink * sink, const gchar * location)
sink->uri = NULL; sink->uri = NULL;
} }
if (GST_STATE (sink) == GST_STATE_PAUSED)
gst_filesink_open_file (sink);
return TRUE; return TRUE;
} }
static void static void
@ -260,8 +248,6 @@ gst_filesink_get_property (GObject * object, guint prop_id, GValue * value,
static gboolean static gboolean
gst_filesink_open_file (GstFileSink * sink) gst_filesink_open_file (GstFileSink * sink)
{ {
g_return_val_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN), FALSE);
/* open the file */ /* open the file */
if (sink->filename == NULL || sink->filename[0] == '\0') { if (sink->filename == NULL || sink->filename[0] == '\0') {
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
@ -277,8 +263,6 @@ gst_filesink_open_file (GstFileSink * sink)
return FALSE; return FALSE;
} }
GST_FLAG_SET (sink, GST_FILESINK_OPEN);
sink->data_written = 0; sink->data_written = 0;
return TRUE; return TRUE;
@ -287,13 +271,9 @@ gst_filesink_open_file (GstFileSink * sink)
static void static void
gst_filesink_close_file (GstFileSink * sink) gst_filesink_close_file (GstFileSink * sink)
{ {
g_return_if_fail (GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN));
if (fclose (sink->file) != 0) { if (fclose (sink->file) != 0) {
GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE, GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
(_("Error closing file \"%s\"."), sink->filename), GST_ERROR_SYSTEM); (_("Error closing file \"%s\"."), sink->filename), GST_ERROR_SYSTEM);
} else {
GST_FLAG_UNSET (sink, GST_FILESINK_OPEN);
} }
} }
@ -307,11 +287,9 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
case GST_QUERY_TOTAL: case GST_QUERY_TOTAL:
switch (*format) { switch (*format) {
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) { *value = sink->data_written; /* FIXME - doesn't the kernel provide
*value = sink->data_written; /* FIXME - doesn't the kernel provide such a function? */
such a function? */ break;
break;
}
default: default:
return FALSE; return FALSE;
} }
@ -319,10 +297,8 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
case GST_QUERY_POSITION: case GST_QUERY_POSITION:
switch (*format) { switch (*format) {
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) { *value = ftell (sink->file);
*value = ftell (sink->file); break;
break;
}
default: default:
return FALSE; return FALSE;
} }
@ -336,30 +312,23 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
/* handle events (search) */ /* handle events (search) */
static gboolean static gboolean
gst_filesink_handle_event (GstPad * pad, GstEvent * event) gst_filesink_event (GstBaseSink * sink, GstEvent * event)
{ {
GstEventType type; GstEventType type;
GstFileSink *filesink; GstFileSink *filesink;
filesink = GST_FILESINK (gst_pad_get_parent (pad)); filesink = GST_FILESINK (sink);
if (!(GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN))) {
gst_event_unref (event);
return FALSE;
}
type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
switch (type) { switch (type) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
gst_event_unref (event);
return FALSE; return FALSE;
} }
if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) { if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
if (fflush (filesink->file)) { if (fflush (filesink->file)) {
gst_event_unref (event);
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE, GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
(_("Error while writing to file \"%s\"."), filesink->filename), (_("Error while writing to file \"%s\"."), filesink->filename),
GST_ERROR_SYSTEM); GST_ERROR_SYSTEM);
@ -381,33 +350,24 @@ gst_filesink_handle_event (GstPad * pad, GstEvent * event)
g_warning ("unknown seek method!"); g_warning ("unknown seek method!");
break; break;
} }
gst_event_unref (event);
break; break;
case GST_EVENT_DISCONTINUOUS: case GST_EVENT_DISCONTINUOUS:
{ {
gint64 offset; gint64 soffset, eoffset;
if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset)) if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &soffset,
fseek (filesink->file, offset, SEEK_SET); &eoffset))
fseek (filesink->file, soffset, SEEK_SET);
gst_event_unref (event);
break; break;
} }
case GST_EVENT_FLUSH: case GST_EVENT_FLUSH:
if (fflush (filesink->file)) { if (fflush (filesink->file)) {
gst_event_unref (event);
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE, GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
(_("Error while writing to file \"%s\"."), filesink->filename), (_("Error while writing to file \"%s\"."), filesink->filename),
GST_ERROR_SYSTEM); GST_ERROR_SYSTEM);
} }
break; break;
case GST_EVENT_EOS:
gst_event_unref (event);
gst_filesink_close_file (filesink);
gst_element_set_eos (GST_ELEMENT (filesink));
break;
default: default:
gst_pad_event_default (pad, event);
break; break;
} }
@ -421,75 +381,80 @@ gst_filesink_handle_event (GstPad * pad, GstEvent * event)
* *
* take the buffer from the pad and write to file if it's open * take the buffer from the pad and write to file if it's open
*/ */
static void static GstFlowReturn
gst_filesink_chain (GstPad * pad, GstData * _data) gst_filesink_render (GstBaseSink * sink, GstBuffer * buffer)
{ {
GstBuffer *buf = GST_BUFFER (_data);
GstFileSink *filesink; GstFileSink *filesink;
guint bytes_written = 0, back_pending = 0;
guint size;
g_return_if_fail (pad != NULL); size = GST_BUFFER_SIZE (buffer);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
filesink = GST_FILESINK (gst_pad_get_parent (pad)); filesink = GST_FILESINK (sink);
if (GST_IS_EVENT (buf)) { if (ftell (filesink->file) < filesink->data_written)
gst_filesink_handle_event (pad, GST_EVENT (buf)); back_pending = filesink->data_written - ftell (filesink->file);
return;
}
if (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN)) { while (bytes_written < size) {
guint bytes_written = 0, back_pending = 0; size_t wrote = fwrite (GST_BUFFER_DATA (buffer) + bytes_written, 1,
size - bytes_written, filesink->file);
if (ftell (filesink->file) < filesink->data_written) if (wrote <= 0) {
back_pending = filesink->data_written - ftell (filesink->file); GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
while (bytes_written < GST_BUFFER_SIZE (buf)) { (_("Error while writing to file \"%s\"."), filesink->filename),
size_t wrote = fwrite (GST_BUFFER_DATA (buf) + bytes_written, 1, ("Only %d of %d bytes written: %s",
GST_BUFFER_SIZE (buf) - bytes_written, bytes_written, size, strerror (errno)));
filesink->file); break;
if (wrote <= 0) {
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
(_("Error while writing to file \"%s\"."), filesink->filename),
("Only %d of %d bytes written: %s",
bytes_written, GST_BUFFER_SIZE (buf), strerror (errno)));
break;
}
bytes_written += wrote;
} }
bytes_written += wrote;
filesink->data_written += bytes_written - back_pending;
} }
gst_buffer_unref (buf); filesink->data_written += bytes_written - back_pending;
g_signal_emit (G_OBJECT (filesink), return GST_FLOW_OK;
gst_filesink_signals[SIGNAL_HANDOFF], 0, filesink);
} }
static GstElementStateReturn static GstElementStateReturn
gst_filesink_change_state (GstElement * element) gst_filesink_change_state (GstElement * element)
{ {
g_return_val_if_fail (GST_IS_FILESINK (element), GST_STATE_FAILURE); GstElementStateReturn ret;
gint transition;
switch (GST_STATE_TRANSITION (element)) { transition = GST_STATE_TRANSITION (element);
case GST_STATE_PAUSED_TO_READY:
if (GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) switch (transition) {
gst_filesink_close_file (GST_FILESINK (element)); case GST_STATE_NULL_TO_READY:
break; break;
case GST_STATE_READY_TO_PAUSED: case GST_STATE_READY_TO_PAUSED:
if (!GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) { if (!gst_filesink_open_file (GST_FILESINK (element)))
if (!gst_filesink_open_file (GST_FILESINK (element))) goto open_error;
return GST_STATE_FAILURE; break;
} case GST_STATE_PAUSED_TO_PLAYING:
break;
default:
break; break;
} }
if (GST_ELEMENT_CLASS (parent_class)->change_state) ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS; switch (transition) {
case GST_STATE_PLAYING_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_READY:
gst_filesink_close_file (GST_FILESINK (element));
break;
case GST_STATE_READY_TO_NULL:
break;
default:
break;
}
return ret;
open_error:
{
return GST_STATE_FAILURE;
}
} }
/*** GSTURIHANDLER INTERFACE *************************************************/ /*** GSTURIHANDLER INTERFACE *************************************************/

View file

@ -25,10 +25,10 @@
#define __GST_FILESINK_H__ #define __GST_FILESINK_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasesink.h>
G_BEGIN_DECLS G_BEGIN_DECLS
#define GST_TYPE_FILESINK \ #define GST_TYPE_FILESINK \
(gst_filesink_get_type()) (gst_filesink_get_type())
#define GST_FILESINK(obj) \ #define GST_FILESINK(obj) \
@ -43,14 +43,8 @@ G_BEGIN_DECLS
typedef struct _GstFileSink GstFileSink; typedef struct _GstFileSink GstFileSink;
typedef struct _GstFileSinkClass GstFileSinkClass; typedef struct _GstFileSinkClass GstFileSinkClass;
typedef enum {
GST_FILESINK_OPEN = GST_ELEMENT_FLAG_LAST,
GST_FILESINK_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
} GstFileSinkFlags;
struct _GstFileSink { struct _GstFileSink {
GstElement element; GstBaseSink parent;
gchar *filename; gchar *filename;
gchar *uri; gchar *uri;
@ -60,10 +54,7 @@ struct _GstFileSink {
}; };
struct _GstFileSinkClass { struct _GstFileSinkClass {
GstElementClass parent_class; GstBaseSinkClass parent_class;
/* signals */
void (*handoff) (GstElement *element, GstPad *pad);
}; };
GType gst_filesink_get_type(void); GType gst_filesink_get_type(void);

View file

@ -6,6 +6,7 @@ libgstbase_@GST_MAJORMINOR@_la_SOURCES = \
gstbasesink.c \ gstbasesink.c \
gstbasesrc.c \ gstbasesrc.c \
gstbasetransform.c \ gstbasetransform.c \
gstcollectpads.c \
gsttypefindhelper.c gsttypefindhelper.c
libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS) libgstbase_@GST_MAJORMINOR@_la_CFLAGS = $(GST_OBJ_CFLAGS)
@ -20,5 +21,6 @@ libgstbase_@GST_MAJORMINOR@include_HEADERS = \
gstbasesink.h \ gstbasesink.h \
gstbasesrc.h \ gstbasesrc.h \
gstbasetransform.h \ gstbasetransform.h \
gstcollectpads.h \
gsttypefindhelper.h gsttypefindhelper.h

View file

@ -75,7 +75,7 @@ struct _GstBaseSinkClass {
void (*get_times) (GstBaseSink *sink, GstBuffer *buffer, void (*get_times) (GstBaseSink *sink, GstBuffer *buffer,
GstClockTime *start, GstClockTime *end); GstClockTime *start, GstClockTime *end);
void (*event) (GstBaseSink *sink, GstEvent *event); gboolean (*event) (GstBaseSink *sink, GstEvent *event);
GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer); GstFlowReturn (*preroll) (GstBaseSink *sink, GstBuffer *buffer);
GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer); GstFlowReturn (*render) (GstBaseSink *sink, GstBuffer *buffer);
}; };

View file

@ -169,6 +169,7 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
basesrc->srcpad = pad; basesrc->srcpad = pad;
gst_element_add_pad (GST_ELEMENT (basesrc), pad); gst_element_add_pad (GST_ELEMENT (basesrc), pad);
basesrc->random_access = TRUE;
basesrc->segment_start = -1; basesrc->segment_start = -1;
basesrc->segment_end = -1; basesrc->segment_end = -1;
basesrc->blocksize = DEFAULT_BLOCKSIZE; basesrc->blocksize = DEFAULT_BLOCKSIZE;
@ -179,6 +180,8 @@ gst_basesrc_init (GstBaseSrc * basesrc, gpointer g_class)
static void static void
gst_basesrc_set_dataflow_funcs (GstBaseSrc * this) gst_basesrc_set_dataflow_funcs (GstBaseSrc * this)
{ {
GST_DEBUG ("updating dataflow functions");
if (this->has_loop) if (this->has_loop)
gst_pad_set_loop_function (this->srcpad, gst_basesrc_loop); gst_pad_set_loop_function (this->srcpad, gst_basesrc_loop);
else else
@ -232,7 +235,6 @@ gst_basesrc_query (GstPad * pad, GstQueryType type,
{ {
gboolean ret; gboolean ret;
/* FIXME-wim: is this cast right? */
ret = gst_basesrc_get_size (src, (guint64 *) value); ret = gst_basesrc_get_size (src, (guint64 *) value);
GST_DEBUG ("getting length %d %lld", ret, *value); GST_DEBUG ("getting length %d %lld", ret, *value);
return ret; return ret;

View file

@ -0,0 +1,538 @@
/* GStreamer
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
*
* gstcollectpads.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 "gstcollectpads.h"
static GstFlowReturn gst_collectpads_chain (GstPad * pad, GstBuffer * buffer);
static void gst_collectpads_class_init (GstCollectPadsClass * klass);
static void gst_collectpads_init (GstCollectPads * pads);
static void gst_collectpads_finalize (GObject * object);
static GstObjectClass *parent_class = NULL;
GType
gst_collectpads_get_type (void)
{
static GType collect_type = 0;
if (!collect_type) {
static const GTypeInfo collect_info = {
sizeof (GstCollectPadsClass),
NULL,
NULL,
(GClassInitFunc) gst_collectpads_class_init,
NULL,
NULL,
sizeof (GstCollectPads),
0,
(GInstanceInitFunc) gst_collectpads_init,
NULL
};
collect_type = g_type_register_static (GST_TYPE_OBJECT, "GstCollectPads",
&collect_info, 0);
}
return collect_type;
}
static void
gst_collectpads_class_init (GstCollectPadsClass * klass)
{
GObjectClass *gobject_class;
GstObjectClass *gstobject_class;
gobject_class = (GObjectClass *) klass;
gstobject_class = (GstObjectClass *) klass;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_collectpads_finalize);
parent_class = g_type_class_ref (GST_TYPE_OBJECT);
}
static void
gst_collectpads_init (GstCollectPads * pads)
{
pads->cond = g_cond_new ();
pads->data = NULL;
pads->cookie = 0;
pads->numpads = 0;
pads->queuedpads = 0;
pads->started = FALSE;
}
static void
gst_collectpads_finalize (GObject * object)
{
GstCollectPads *pads = GST_COLLECTPADS (object);
g_cond_free (pads->cond);
/* FIXME, free data */
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/**
* gst_collectpads_new:
*
* Create a new instance of #GstCollectsPads.
*
* Returns: a new #GstCollectPads, or NULL in case of an error.
*
* MT safe.
*/
GstCollectPads *
gst_collectpads_new (void)
{
GstCollectPads *newcoll;
newcoll = g_object_new (GST_TYPE_COLLECTPADS, NULL);
return newcoll;
}
/**
* gst_collectpads_set_function:
* @pads: the collectspads to use
* @func: the function to set
* @user_data: user data passed to the function
*
* Set the callback function and user data that will be called when
* all the pads added to the collection have buffers queued.
*
* MT safe.
*/
void
gst_collectpads_set_function (GstCollectPads * pads,
GstCollectPadsFunction func, gpointer user_data)
{
g_return_if_fail (pads != NULL);
GST_LOCK (pads);
pads->func = func;
pads->user_data = user_data;
GST_UNLOCK (pads);
}
/**
* gst_collectpads_add_pad:
* @pads: the collectspads to use
* @pad: the pad to add
* @size: the size of the returned GstCollectData structure
*
* Add a pad to the collection of collect pads. The pad has to be
* a sinkpad.
*
* You specify a size for the returned #GstCollectData structure
* so that you can use it to store additional information.
*
* Returns: a new #GstCollectData to identify the new pad. Or NULL
* if wrong parameters are supplied.
*
* MT safe.
*/
GstCollectData *
gst_collectpads_add_pad (GstCollectPads * pads, GstPad * pad, guint size)
{
GstCollectData *data;
g_return_val_if_fail (pads != NULL, NULL);
g_return_val_if_fail (pad != NULL, NULL);
g_return_val_if_fail (GST_PAD_IS_SINK (pad), NULL);
g_return_val_if_fail (size >= sizeof (GstCollectData), NULL);
data = g_malloc0 (size);
data->collect = pads;
data->pad = pad;
data->buffer = NULL;
GST_LOCK (pads);
pads->data = g_slist_append (pads->data, data);
gst_pad_set_chain_function (pad, gst_collectpads_chain);
gst_pad_set_element_private (pad, data);
pads->numpads++;
pads->cookie++;
GST_UNLOCK (pads);
return data;
}
static gint
find_pad (GstCollectData * data, GstPad * pad)
{
if (data->pad == pad)
return 0;
return 1;
}
/**
* gst_collectpads_remove_pad:
* @pads: the collectspads to use
* @pad: the pad to remove
*
* Remove a pad from the collection of collect pads.
*
* Returns: TRUE if the pad could be removed.
*
* MT safe.
*/
gboolean
gst_collectpads_remove_pad (GstCollectPads * pads, GstPad * pad)
{
GSList *list;
g_return_val_if_fail (pads != NULL, FALSE);
g_return_val_if_fail (pad != NULL, FALSE);
GST_LOCK (pads);
list = g_slist_find_custom (pads->data, pad, (GCompareFunc) find_pad);
if (list) {
g_free (list->data);
pads->data = g_slist_delete_link (pads->data, list);
}
pads->numpads--;
pads->cookie++;
GST_UNLOCK (pads);
return list != NULL;
}
/**
* gst_collectpads_is_active:
* @pads: the collectspads to use
* @pad: the pad to check
*
* Check if a pad is active.
*
* Returns: TRUE if the pad is active.
*
* MT safe.
*/
gboolean
gst_collectpads_is_active (GstCollectPads * pads, GstPad * pad)
{
g_return_val_if_fail (pads != NULL, FALSE);
g_return_val_if_fail (pad != NULL, FALSE);
return FALSE;
}
/**
* gst_collectpads_collect:
* @pads: the collectspads to use
*
* Collect data on all pads. This function is usually called
* from a GstTask function in an element.
*
* Returns: GstFlowReturn of the operation.
*
* MT safe.
*/
GstFlowReturn
gst_collectpads_collect (GstCollectPads * pads)
{
g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
return GST_FLOW_ERROR;
}
/**
* gst_collectpads_collect_range:
* @pads: the collectspads to use
* @offset: the offset to collect
* @length: the length to collect
*
* Collect data with @offset and @length on all pads. This function
* is typically called in the getrange function of an element.
*
* Returns: GstFlowReturn of the operation.
*
* MT safe.
*/
GstFlowReturn
gst_collectpads_collect_range (GstCollectPads * pads, guint64 offset,
guint length)
{
g_return_val_if_fail (pads != NULL, GST_FLOW_ERROR);
return GST_FLOW_ERROR;
}
/**
* gst_collectpads_start:
* @pads: the collectspads to use
*
* Starts the processing of data in the collectpads.
*
* MT safe.
*/
void
gst_collectpads_start (GstCollectPads * pads)
{
g_return_if_fail (pads != NULL);
GST_LOCK (pads);
pads->started = TRUE;
GST_UNLOCK (pads);
}
/**
* gst_collectpads_stop:
* @pads: the collectspads to use
*
* Stops the processing of data in the collectpads. this function
* will also unblock any blocking operations.
*
* MT safe.
*/
void
gst_collectpads_stop (GstCollectPads * pads)
{
g_return_if_fail (pads != NULL);
GST_LOCK (pads);
pads->started = FALSE;
GST_COLLECTPADS_SIGNAL (pads);
GST_UNLOCK (pads);
}
/**
* gst_collectpads_peek:
* @pads: the collectspads to peek
* @data: the data to use
*
* Peek at the buffer currently queued in @data. This function
* should be called with the @pads LOCK held, such as in the callback
* handler.
*
* Returns: The buffer in @data or NULL if no buffer is queued. You
* should unref the buffer after usage.
*
* MT safe.
*/
GstBuffer *
gst_collectpads_peek (GstCollectPads * pads, GstCollectData * data)
{
GstBuffer *result;
result = data->buffer;
gst_buffer_ref (result);
return result;
}
/**
* gst_collectpads_pop:
* @pads: the collectspads to pop
* @data: the data to use
*
* Pop the buffer currently queued in @data. This function
* should be called with the @pads LOCK held, such as in the callback
* handler.
*
* Returns: The buffer in @data or NULL if no buffer was queued. The
* You should unref the buffer after usage.
*
* MT safe.
*/
GstBuffer *
gst_collectpads_pop (GstCollectPads * pads, GstCollectData * data)
{
GstBuffer *result;
result = data->buffer;
gst_buffer_replace (&data->buffer, NULL);
data->pos = 0;
pads->queuedpads--;
GST_COLLECTPADS_SIGNAL (pads);
return result;
}
/**
* gst_collectpads_available:
* @pads: the collectspads to query
*
* Query how much bytes can be read from each queued buffer. This means
* that the result of this call is the maximum number of bytes that can
* be read from each of the pads.
*
* This function should be called with @pads LOCK held, such as
* in the callback.
*
* Returns: The maximum number of bytes queued on all pad. This function
* returns 0 if a pad has no queued buffer.
*
* MT safe.
*/
guint
gst_collectpads_available (GstCollectPads * pads)
{
GSList *collected;
guint result = G_MAXUINT;
for (collected = pads->data; collected; collected = g_slist_next (collected)) {
GstCollectData *pdata;
gint size;
pdata = (GstCollectData *) collected->data;
if (pdata->buffer == NULL)
goto not_filled;
size = GST_BUFFER_SIZE (pdata->buffer) - pdata->pos;
if (size < result)
result = size;
}
return result;
not_filled:
{
return 0;
}
}
/**
* gst_collectpads_read:
* @pads: the collectspads to query
* @data: the data to use
* @bytes: a pointer to a byte array
* @size: the number of bytes to read
*
* Get a pointer in @bytes where @size bytes can be read from the
* given pad data.
*
* This function should be called with @pads LOCK held, such as
* in the callback.
*
* Returns: The number of bytes available for consumption in the
* memory pointed to by @bytes. This can be less than @size and
* is 0 if the pad is end-of-stream.
*
* MT safe.
*/
guint
gst_collectpads_read (GstCollectPads * pads, GstCollectData * data,
guint8 ** bytes, guint size)
{
guint readsize;
readsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
*bytes = GST_BUFFER_DATA (data->buffer) + data->pos;
return readsize;
}
/**
* gst_collectpads_flush:
* @pads: the collectspads to query
* @data: the data to use
* @size: the number of bytes to flush
*
* Flush @size bytes from the pad @data.
*
* This function should be called with @pads LOCK held, such as
* in the callback.
*
* Returns: The number of bytes flushed This can be less than @size and
* is 0 if the pad was end-of-stream.
*
* MT safe.
*/
guint
gst_collectpads_flush (GstCollectPads * pads, GstCollectData * data, guint size)
{
guint flushsize;
flushsize = MIN (size, GST_BUFFER_SIZE (data->buffer) - data->pos);
data->pos += size;
if (data->pos >= GST_BUFFER_SIZE (data->buffer)) {
GstBuffer *buf;
buf = gst_collectpads_pop (pads, data);
gst_buffer_unref (buf);
}
return flushsize;
}
static GstFlowReturn
gst_collectpads_chain (GstPad * pad, GstBuffer * buffer)
{
GstCollectData *data;
GstCollectPads *pads;
guint64 size;
GstFlowReturn ret;
GST_DEBUG ("chain");
/* some magic to get the managing collectpads */
data = (GstCollectData *) gst_pad_get_element_private (pad);
if (data == NULL)
goto not_ours;
pads = data->collect;
size = GST_BUFFER_SIZE (buffer);
GST_LOCK (pads);
/* if not started, bail out */
if (!pads->started)
goto not_started;
/* queue buffer on this pad, block if filled */
while (data->buffer != NULL) {
GST_COLLECTPADS_WAIT (pads);
/* after a signal, we could be stopped */
if (!pads->started)
goto not_started;
}
pads->queuedpads++;
gst_buffer_replace (&data->buffer, buffer);
/* if all pads have data and we have a function, call it */
if ((pads->queuedpads == pads->numpads) && pads->func) {
ret = pads->func (pads, pads->user_data);
} else {
ret = GST_FLOW_OK;
}
GST_UNLOCK (pads);
return ret;
/* ERRORS */
not_ours:
{
GST_DEBUG ("collectpads not ours");
return GST_FLOW_ERROR;
}
not_started:
{
GST_UNLOCK (pads);
GST_DEBUG ("collectpads not started");
return GST_FLOW_WRONG_STATE;
}
}

View file

@ -0,0 +1,132 @@
/* GStreamer
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
*
* gstcollectpads.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_COLLECTPADS_H__
#define __GST_COLLECTPADS_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_COLLECTPADS (gst_collectpads_get_type())
#define GST_COLLECTPADS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_COLLECTPADS,GstCollectPads))
#define GST_COLLECTPADS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_COLLECTPADS,GstCollectPadsClass))
#define GST_COLLECTPADS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_COLLECTPADS, GstCollectPadsClass))
#define GST_IS_COLLECTPADS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_COLLECTPADS))
#define GST_IS_COLLECTPADS_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_COLLECTPADS))
/* manages a set of pads that operate in collect mode. This means
* that control is given to the manager of this object when all
* pads have data.
*
* - pads are added to the collection with add/remove_pad. The pad
* has to be a sinkpad. The chain function of the pad is
* overridden. The element_private of the pad is used to store
* private information.
* - For each pad, data is queued in the chain function or by
* performing a pull_range.
* - When data is queued on all pads, a callback function is
* called.
* - Data can be dequeued from the pad with the _pop() method.
* One can _peek() at the data with the peek function.
* - Data can also be dequeued with the available/read/flush
* calls.
*/
typedef struct _GstCollectPads GstCollectPads;
typedef struct _GstCollectPadsClass GstCollectPadsClass;
typedef struct _GstCollectData
{
GstCollectPads *collect;
GstPad *pad;
GstBuffer *buffer;
guint pos;
gboolean eos;
} GstCollectData;
/* function will be called when all pads have data */
typedef GstFlowReturn (*GstCollectPadsFunction) (GstCollectPads *pads, gpointer user_data);
#define GST_COLLECTPADS_GET_COND(pads) (((GstCollectPads *)pads)->cond)
#define GST_COLLECTPADS_WAIT(pads) (g_cond_wait (GST_COLLECTPADS_GET_COND (pads), GST_GET_LOCK (pads)))
#define GST_COLLECTPADS_SIGNAL(pads) (g_cond_signal (GST_COLLECTPADS_GET_COND (pads)))
#define GST_COLLECTPADS_BROADCAST(pads)(g_cond_broadcast (GST_COLLECTPADS_GET_COND (pads)))
struct _GstCollectPads {
GstObject object;
/*< public >*/ /* with LOCK */
GSList *data; /* GstCollectData in this collection */
guint32 cookie;
GCond *cond; /* to signal removal of data */
/*< private >*/
GstCollectPadsFunction func; /* function and user_data for callback */
gpointer user_data;
guint numpads; /* number of pads */
guint queuedpads; /* number of pads with a buffer */
gboolean started;
};
struct _GstCollectPadsClass {
GstObjectClass parent_class;
};
GType gst_collectpads_get_type(void);
/* creating the object */
GstCollectPads* gst_collectpads_new (void);
/* set the callback */
void gst_collectpads_set_function (GstCollectPads *pads, GstCollectPadsFunction func,
gpointer user_data);
/* pad management */
GstCollectData* gst_collectpads_add_pad (GstCollectPads *pads, GstPad *pad, guint size);
gboolean gst_collectpads_remove_pad (GstCollectPads *pads, GstPad *pad);
gboolean gst_collectpads_is_active (GstCollectPads *pads, GstPad *pad);
/* start/stop collection */
GstFlowReturn gst_collectpads_collect (GstCollectPads *pads);
GstFlowReturn gst_collectpads_collect_range (GstCollectPads *pads, guint64 offset, guint length);
void gst_collectpads_start (GstCollectPads *pads);
void gst_collectpads_stop (GstCollectPads *pads);
/* get collected buffers */
GstBuffer* gst_collectpads_peek (GstCollectPads *pads, GstCollectData *data);
GstBuffer* gst_collectpads_pop (GstCollectPads *pads, GstCollectData *data);
/* get collected bytes */
guint gst_collectpads_available (GstCollectPads *pads);
guint gst_collectpads_read (GstCollectPads *pads, GstCollectData *data,
guint8 **bytes, guint size);
guint gst_collectpads_flush (GstCollectPads *pads, GstCollectData *data,
guint size);
G_END_DECLS
#endif /* __GST_COLLECTPADS_H__ */

View file

@ -15,6 +15,7 @@ libgstelements_la_SOURCES = \
gstcapsfilter.c \ gstcapsfilter.c \
gstfakesrc.c \ gstfakesrc.c \
gstfakesink.c \ gstfakesink.c \
gstfilesink.c \
gstfilesrc.c \ gstfilesrc.c \
gstidentity.c \ gstidentity.c \
gstelements.c \ gstelements.c \
@ -27,7 +28,6 @@ libgstelements_la_SOURCES = \
EXTRA_DIST = \ EXTRA_DIST = \
gstaggregator.c \ gstaggregator.c \
gstcapsfilter.c \ gstcapsfilter.c \
gstfilesink.c \
gstfdsink.c \ gstfdsink.c \
gstfdsrc.c \ gstfdsrc.c \
gstmd5sink.c \ gstmd5sink.c \

View file

@ -64,7 +64,7 @@ static struct _elements_entry _elements[] = {
{"identity", GST_RANK_NONE, gst_identity_get_type}, {"identity", GST_RANK_NONE, gst_identity_get_type},
// {"fdsink", GST_RANK_NONE, gst_fdsink_get_type}, // {"fdsink", GST_RANK_NONE, gst_fdsink_get_type},
// {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type}, // {"fdsrc", GST_RANK_NONE, gst_fdsrc_get_type},
// {"filesink", GST_RANK_NONE, gst_filesink_get_type}, {"filesink", GST_RANK_NONE, gst_filesink_get_type},
// {"md5sink", GST_RANK_NONE, gst_md5sink_get_type}, // {"md5sink", GST_RANK_NONE, gst_md5sink_get_type},
#ifndef HAVE_WIN32 #ifndef HAVE_WIN32
// {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type}, // {"multifilesrc", GST_RANK_NONE, gst_multifilesrc_get_type},

View file

@ -116,7 +116,7 @@ static GstFlowReturn gst_fakesink_preroll (GstBaseSink * bsink,
GstBuffer * buffer); GstBuffer * buffer);
static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink, static GstFlowReturn gst_fakesink_render (GstBaseSink * bsink,
GstBuffer * buffer); GstBuffer * buffer);
static void gst_fakesink_event (GstBaseSink * bsink, GstEvent * event); static gboolean gst_fakesink_event (GstBaseSink * bsink, GstEvent * event);
static void gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer, static void gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
GstClockTime * start, GstClockTime * end); GstClockTime * start, GstClockTime * end);
@ -269,7 +269,7 @@ gst_fakesink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
} }
} }
static void static gboolean
gst_fakesink_event (GstBaseSink * bsink, GstEvent * event) gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
{ {
GstFakeSink *sink = GST_FAKESINK (bsink); GstFakeSink *sink = GST_FAKESINK (bsink);
@ -283,6 +283,8 @@ gst_fakesink_event (GstBaseSink * bsink, GstEvent * event)
g_object_notify (G_OBJECT (sink), "last_message"); g_object_notify (G_OBJECT (sink), "last_message");
} }
return TRUE;
} }
static GstFlowReturn static GstFlowReturn

View file

@ -99,17 +99,19 @@ static void gst_filesink_get_property (GObject * object, guint prop_id,
static gboolean gst_filesink_open_file (GstFileSink * sink); static gboolean gst_filesink_open_file (GstFileSink * sink);
static void gst_filesink_close_file (GstFileSink * sink); static void gst_filesink_close_file (GstFileSink * sink);
static gboolean gst_filesink_handle_event (GstPad * pad, GstEvent * event); static gboolean gst_filesink_event (GstBaseSink * sink, GstEvent * event);
static GstFlowReturn gst_filesink_render (GstBaseSink * sink,
GstBuffer * buffer);
static gboolean gst_filesink_pad_query (GstPad * pad, GstQueryType type, static gboolean gst_filesink_pad_query (GstPad * pad, GstQueryType type,
GstFormat * format, gint64 * value); GstFormat * format, gint64 * value);
static void gst_filesink_chain (GstPad * pad, GstData * _data);
static void gst_filesink_uri_handler_init (gpointer g_iface, static void gst_filesink_uri_handler_init (gpointer g_iface,
gpointer iface_data); gpointer iface_data);
static GstElementStateReturn gst_filesink_change_state (GstElement * element); static GstElementStateReturn gst_filesink_change_state (GstElement * element);
static guint gst_filesink_signals[LAST_SIGNAL] = { 0 }; //static guint gst_filesink_signals[LAST_SIGNAL] = { 0 };
static void static void
_do_init (GType filesink_type) _do_init (GType filesink_type)
@ -126,10 +128,9 @@ _do_init (GType filesink_type)
"filesink element"); "filesink element");
} }
GST_BOILERPLATE_FULL (GstFileSink, gst_filesink, GstElement, GST_TYPE_ELEMENT, GST_BOILERPLATE_FULL (GstFileSink, gst_filesink, GstBaseSink, GST_TYPE_BASESINK,
_do_init); _do_init);
static void static void
gst_filesink_base_init (gpointer g_class) gst_filesink_base_init (gpointer g_class)
{ {
@ -144,6 +145,7 @@ static void
gst_filesink_class_init (GstFileSinkClass * klass) gst_filesink_class_init (GstFileSinkClass * klass)
{ {
GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstBaseSinkClass *gstbasesink_class = GST_BASESINK_CLASS (klass);
gobject_class->set_property = gst_filesink_set_property; gobject_class->set_property = gst_filesink_set_property;
gobject_class->get_property = gst_filesink_get_property; gobject_class->get_property = gst_filesink_get_property;
@ -152,25 +154,17 @@ gst_filesink_class_init (GstFileSinkClass * klass)
g_param_spec_string ("location", "File Location", g_param_spec_string ("location", "File Location",
"Location of the file to write", NULL, G_PARAM_READWRITE)); "Location of the file to write", NULL, G_PARAM_READWRITE));
gst_filesink_signals[SIGNAL_HANDOFF] =
g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstFileSinkClass, handoff), NULL, NULL,
g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
gobject_class->dispose = gst_filesink_dispose; gobject_class->dispose = gst_filesink_dispose;
gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_filesink_render);
gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_filesink_event);
} }
static void static void
gst_filesink_init (GstFileSink * filesink) gst_filesink_init (GstFileSink * filesink)
{ {
GstPad *pad; GstPad *pad;
pad = pad = GST_BASESINK_PAD (filesink);
gst_pad_new_from_template (gst_static_pad_template_get (&sinktemplate),
"sink");
gst_element_add_pad (GST_ELEMENT (filesink), pad);
gst_pad_set_chain_function (pad, gst_filesink_chain);
GST_FLAG_SET (GST_ELEMENT (filesink), GST_ELEMENT_EVENT_AWARE);
gst_pad_set_query_function (pad, gst_filesink_pad_query); gst_pad_set_query_function (pad, gst_filesink_pad_query);
gst_pad_set_query_type_function (pad, gst_filesink_get_query_types); gst_pad_set_query_type_function (pad, gst_filesink_get_query_types);
@ -196,10 +190,7 @@ static gboolean
gst_filesink_set_location (GstFileSink * sink, const gchar * location) gst_filesink_set_location (GstFileSink * sink, const gchar * location)
{ {
/* the element must be stopped or paused in order to do this */ /* the element must be stopped or paused in order to do this */
if (GST_STATE (sink) > GST_STATE_PAUSED) if (GST_STATE (sink) >= GST_STATE_PAUSED)
return FALSE;
if (GST_STATE (sink) == GST_STATE_PAUSED &&
GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN))
return FALSE; return FALSE;
g_free (sink->filename); g_free (sink->filename);
@ -212,9 +203,6 @@ gst_filesink_set_location (GstFileSink * sink, const gchar * location)
sink->uri = NULL; sink->uri = NULL;
} }
if (GST_STATE (sink) == GST_STATE_PAUSED)
gst_filesink_open_file (sink);
return TRUE; return TRUE;
} }
static void static void
@ -260,8 +248,6 @@ gst_filesink_get_property (GObject * object, guint prop_id, GValue * value,
static gboolean static gboolean
gst_filesink_open_file (GstFileSink * sink) gst_filesink_open_file (GstFileSink * sink)
{ {
g_return_val_if_fail (!GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN), FALSE);
/* open the file */ /* open the file */
if (sink->filename == NULL || sink->filename[0] == '\0') { if (sink->filename == NULL || sink->filename[0] == '\0') {
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND, GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
@ -277,8 +263,6 @@ gst_filesink_open_file (GstFileSink * sink)
return FALSE; return FALSE;
} }
GST_FLAG_SET (sink, GST_FILESINK_OPEN);
sink->data_written = 0; sink->data_written = 0;
return TRUE; return TRUE;
@ -287,13 +271,9 @@ gst_filesink_open_file (GstFileSink * sink)
static void static void
gst_filesink_close_file (GstFileSink * sink) gst_filesink_close_file (GstFileSink * sink)
{ {
g_return_if_fail (GST_FLAG_IS_SET (sink, GST_FILESINK_OPEN));
if (fclose (sink->file) != 0) { if (fclose (sink->file) != 0) {
GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE, GST_ELEMENT_ERROR (sink, RESOURCE, CLOSE,
(_("Error closing file \"%s\"."), sink->filename), GST_ERROR_SYSTEM); (_("Error closing file \"%s\"."), sink->filename), GST_ERROR_SYSTEM);
} else {
GST_FLAG_UNSET (sink, GST_FILESINK_OPEN);
} }
} }
@ -307,11 +287,9 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
case GST_QUERY_TOTAL: case GST_QUERY_TOTAL:
switch (*format) { switch (*format) {
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) { *value = sink->data_written; /* FIXME - doesn't the kernel provide
*value = sink->data_written; /* FIXME - doesn't the kernel provide such a function? */
such a function? */ break;
break;
}
default: default:
return FALSE; return FALSE;
} }
@ -319,10 +297,8 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
case GST_QUERY_POSITION: case GST_QUERY_POSITION:
switch (*format) { switch (*format) {
case GST_FORMAT_BYTES: case GST_FORMAT_BYTES:
if (GST_FLAG_IS_SET (GST_ELEMENT (sink), GST_FILESINK_OPEN)) { *value = ftell (sink->file);
*value = ftell (sink->file); break;
break;
}
default: default:
return FALSE; return FALSE;
} }
@ -336,30 +312,23 @@ gst_filesink_pad_query (GstPad * pad, GstQueryType type,
/* handle events (search) */ /* handle events (search) */
static gboolean static gboolean
gst_filesink_handle_event (GstPad * pad, GstEvent * event) gst_filesink_event (GstBaseSink * sink, GstEvent * event)
{ {
GstEventType type; GstEventType type;
GstFileSink *filesink; GstFileSink *filesink;
filesink = GST_FILESINK (gst_pad_get_parent (pad)); filesink = GST_FILESINK (sink);
if (!(GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN))) {
gst_event_unref (event);
return FALSE;
}
type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; type = event ? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
switch (type) { switch (type) {
case GST_EVENT_SEEK: case GST_EVENT_SEEK:
if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) { if (GST_EVENT_SEEK_FORMAT (event) != GST_FORMAT_BYTES) {
gst_event_unref (event);
return FALSE; return FALSE;
} }
if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) { if (GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH) {
if (fflush (filesink->file)) { if (fflush (filesink->file)) {
gst_event_unref (event);
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE, GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
(_("Error while writing to file \"%s\"."), filesink->filename), (_("Error while writing to file \"%s\"."), filesink->filename),
GST_ERROR_SYSTEM); GST_ERROR_SYSTEM);
@ -381,33 +350,24 @@ gst_filesink_handle_event (GstPad * pad, GstEvent * event)
g_warning ("unknown seek method!"); g_warning ("unknown seek method!");
break; break;
} }
gst_event_unref (event);
break; break;
case GST_EVENT_DISCONTINUOUS: case GST_EVENT_DISCONTINUOUS:
{ {
gint64 offset; gint64 soffset, eoffset;
if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &offset)) if (gst_event_discont_get_value (event, GST_FORMAT_BYTES, &soffset,
fseek (filesink->file, offset, SEEK_SET); &eoffset))
fseek (filesink->file, soffset, SEEK_SET);
gst_event_unref (event);
break; break;
} }
case GST_EVENT_FLUSH: case GST_EVENT_FLUSH:
if (fflush (filesink->file)) { if (fflush (filesink->file)) {
gst_event_unref (event);
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE, GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
(_("Error while writing to file \"%s\"."), filesink->filename), (_("Error while writing to file \"%s\"."), filesink->filename),
GST_ERROR_SYSTEM); GST_ERROR_SYSTEM);
} }
break; break;
case GST_EVENT_EOS:
gst_event_unref (event);
gst_filesink_close_file (filesink);
gst_element_set_eos (GST_ELEMENT (filesink));
break;
default: default:
gst_pad_event_default (pad, event);
break; break;
} }
@ -421,75 +381,80 @@ gst_filesink_handle_event (GstPad * pad, GstEvent * event)
* *
* take the buffer from the pad and write to file if it's open * take the buffer from the pad and write to file if it's open
*/ */
static void static GstFlowReturn
gst_filesink_chain (GstPad * pad, GstData * _data) gst_filesink_render (GstBaseSink * sink, GstBuffer * buffer)
{ {
GstBuffer *buf = GST_BUFFER (_data);
GstFileSink *filesink; GstFileSink *filesink;
guint bytes_written = 0, back_pending = 0;
guint size;
g_return_if_fail (pad != NULL); size = GST_BUFFER_SIZE (buffer);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
filesink = GST_FILESINK (gst_pad_get_parent (pad)); filesink = GST_FILESINK (sink);
if (GST_IS_EVENT (buf)) { if (ftell (filesink->file) < filesink->data_written)
gst_filesink_handle_event (pad, GST_EVENT (buf)); back_pending = filesink->data_written - ftell (filesink->file);
return;
}
if (GST_FLAG_IS_SET (filesink, GST_FILESINK_OPEN)) { while (bytes_written < size) {
guint bytes_written = 0, back_pending = 0; size_t wrote = fwrite (GST_BUFFER_DATA (buffer) + bytes_written, 1,
size - bytes_written, filesink->file);
if (ftell (filesink->file) < filesink->data_written) if (wrote <= 0) {
back_pending = filesink->data_written - ftell (filesink->file); GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
while (bytes_written < GST_BUFFER_SIZE (buf)) { (_("Error while writing to file \"%s\"."), filesink->filename),
size_t wrote = fwrite (GST_BUFFER_DATA (buf) + bytes_written, 1, ("Only %d of %d bytes written: %s",
GST_BUFFER_SIZE (buf) - bytes_written, bytes_written, size, strerror (errno)));
filesink->file); break;
if (wrote <= 0) {
GST_ELEMENT_ERROR (filesink, RESOURCE, WRITE,
(_("Error while writing to file \"%s\"."), filesink->filename),
("Only %d of %d bytes written: %s",
bytes_written, GST_BUFFER_SIZE (buf), strerror (errno)));
break;
}
bytes_written += wrote;
} }
bytes_written += wrote;
filesink->data_written += bytes_written - back_pending;
} }
gst_buffer_unref (buf); filesink->data_written += bytes_written - back_pending;
g_signal_emit (G_OBJECT (filesink), return GST_FLOW_OK;
gst_filesink_signals[SIGNAL_HANDOFF], 0, filesink);
} }
static GstElementStateReturn static GstElementStateReturn
gst_filesink_change_state (GstElement * element) gst_filesink_change_state (GstElement * element)
{ {
g_return_val_if_fail (GST_IS_FILESINK (element), GST_STATE_FAILURE); GstElementStateReturn ret;
gint transition;
switch (GST_STATE_TRANSITION (element)) { transition = GST_STATE_TRANSITION (element);
case GST_STATE_PAUSED_TO_READY:
if (GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) switch (transition) {
gst_filesink_close_file (GST_FILESINK (element)); case GST_STATE_NULL_TO_READY:
break; break;
case GST_STATE_READY_TO_PAUSED: case GST_STATE_READY_TO_PAUSED:
if (!GST_FLAG_IS_SET (element, GST_FILESINK_OPEN)) { if (!gst_filesink_open_file (GST_FILESINK (element)))
if (!gst_filesink_open_file (GST_FILESINK (element))) goto open_error;
return GST_STATE_FAILURE; break;
} case GST_STATE_PAUSED_TO_PLAYING:
break;
default:
break; break;
} }
if (GST_ELEMENT_CLASS (parent_class)->change_state) ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS; switch (transition) {
case GST_STATE_PLAYING_TO_PAUSED:
break;
case GST_STATE_PAUSED_TO_READY:
gst_filesink_close_file (GST_FILESINK (element));
break;
case GST_STATE_READY_TO_NULL:
break;
default:
break;
}
return ret;
open_error:
{
return GST_STATE_FAILURE;
}
} }
/*** GSTURIHANDLER INTERFACE *************************************************/ /*** GSTURIHANDLER INTERFACE *************************************************/

View file

@ -25,10 +25,10 @@
#define __GST_FILESINK_H__ #define __GST_FILESINK_H__
#include <gst/gst.h> #include <gst/gst.h>
#include <gst/base/gstbasesink.h>
G_BEGIN_DECLS G_BEGIN_DECLS
#define GST_TYPE_FILESINK \ #define GST_TYPE_FILESINK \
(gst_filesink_get_type()) (gst_filesink_get_type())
#define GST_FILESINK(obj) \ #define GST_FILESINK(obj) \
@ -43,14 +43,8 @@ G_BEGIN_DECLS
typedef struct _GstFileSink GstFileSink; typedef struct _GstFileSink GstFileSink;
typedef struct _GstFileSinkClass GstFileSinkClass; typedef struct _GstFileSinkClass GstFileSinkClass;
typedef enum {
GST_FILESINK_OPEN = GST_ELEMENT_FLAG_LAST,
GST_FILESINK_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
} GstFileSinkFlags;
struct _GstFileSink { struct _GstFileSink {
GstElement element; GstBaseSink parent;
gchar *filename; gchar *filename;
gchar *uri; gchar *uri;
@ -60,10 +54,7 @@ struct _GstFileSink {
}; };
struct _GstFileSinkClass { struct _GstFileSinkClass {
GstElementClass parent_class; GstBaseSinkClass parent_class;
/* signals */
void (*handoff) (GstElement *element, GstPad *pad);
}; };
GType gst_filesink_get_type(void); GType gst_filesink_get_type(void);