diff options
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | gst/gstvalue.c | 1 | ||||
-rw-r--r-- | libs/gst/bytestream/Makefile.am | 4 | ||||
-rw-r--r-- | libs/gst/bytestream/filepad.c | 435 | ||||
-rw-r--r-- | libs/gst/bytestream/filepad.h | 95 | ||||
-rw-r--r-- | tests/old/testsuite/bytestream/.gitignore | 1 | ||||
-rw-r--r-- | tests/old/testsuite/bytestream/Makefile.am | 3 | ||||
-rw-r--r-- | tests/old/testsuite/bytestream/filepadsink.c | 281 | ||||
-rw-r--r-- | testsuite/bytestream/.gitignore | 1 | ||||
-rw-r--r-- | testsuite/bytestream/Makefile.am | 3 | ||||
-rw-r--r-- | testsuite/bytestream/filepadsink.c | 281 |
11 files changed, 1114 insertions, 4 deletions
@@ -1,3 +1,16 @@ +2004-06-20 Benjamin Otte <otte@gnome.org> + + * gst/gstvalue.c: (gst_value_set_int_range): + test that start is smaller then end + * libs/gst/bytestream/Makefile.am: + * libs/gst/bytestream/filepad.c: + * libs/gst/bytestream/filepad.h: + add GstFilePad - a pad that behaves like a FILE* + * testsuite/bytestream/.cvsignore: + * testsuite/bytestream/Makefile.am: + * testsuite/bytestream/filepadsink.c: + test for the GstFilePad + 2004-06-18 Thomas Vander Stichele <thomas at apestaart dot org> * gst/elements/gstidentity.c: (gst_identity_class_init), diff --git a/gst/gstvalue.c b/gst/gstvalue.c index b02ac1098..2594592dd 100644 --- a/gst/gstvalue.c +++ b/gst/gstvalue.c @@ -590,6 +590,7 @@ void gst_value_set_int_range (GValue * value, int start, int end) { g_return_if_fail (GST_VALUE_HOLDS_INT_RANGE (value)); + g_return_if_fail (start < end); value->data[0].v_int = start; value->data[1].v_int = end; diff --git a/libs/gst/bytestream/Makefile.am b/libs/gst/bytestream/Makefile.am index 3d7b26585..b1a0e4e93 100644 --- a/libs/gst/bytestream/Makefile.am +++ b/libs/gst/bytestream/Makefile.am @@ -6,9 +6,9 @@ EXTRA_DIST = $(as_libtool_EXTRA_DIST) noinst_DATA = $(as_libtool_noinst_DATA_files) libgstbytestreamincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/bytestream -libgstbytestreaminclude_HEADERS = bytestream.h adapter.h +libgstbytestreaminclude_HEADERS = bytestream.h adapter.h filepad.h -libgstbytestream_la_SOURCES = bytestream.c adapter.c +libgstbytestream_la_SOURCES = bytestream.c adapter.c filepad.c libgstbytestream_la_CFLAGS = $(GST_OBJ_CFLAGS) libgstbytestream_la_LIBS = $(GST_OBJ_LIBS) libgstbytestream_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(as_libtool_LDFLAGS) diff --git a/libs/gst/bytestream/filepad.c b/libs/gst/bytestream/filepad.c new file mode 100644 index 000000000..743c7630d --- /dev/null +++ b/libs/gst/bytestream/filepad.c @@ -0,0 +1,435 @@ +/* GStreamer + * Copyright (C) 2004 Benjamin Otte <otte@gnome.org> + * + * 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 "filepad.h" +#include <string.h> /* memcpy */ + +#define RETURN_IF_FAIL(pad,check,error) G_STMT_START { \ + if (!(check)) { \ + GST_LOG_OBJECT (pad, "setting error to %d: " #error, error); \ + pad->error_number = error; \ + return -error; \ + } \ +} G_STMT_END + +GST_DEBUG_CATEGORY_STATIC (gst_file_pad_debug); +#define GST_CAT_DEFAULT gst_file_pad_debug + +#define _do_init(thing) \ + GST_DEBUG_CATEGORY_INIT (gst_file_pad_debug, "GstFilePad", 0, "object to splice and merge buffers to dewsired size") +GST_BOILERPLATE_FULL (GstFilePad, gst_file_pad, GstRealPad, GST_TYPE_REAL_PAD, + _do_init) + + static void gst_file_pad_dispose (GObject * object); + static void gst_file_pad_finalize (GObject * object); + + static void gst_file_pad_chain (GstPad * pad, GstData * data); + static void gst_file_pad_parent_set (GstObject * object, + GstObject * parent); + + + static void gst_file_pad_base_init (gpointer g_class) +{ +} + +static void +gst_file_pad_class_init (GstFilePadClass * klass) +{ + GstObjectClass *gst = GST_OBJECT_CLASS (klass); + GObjectClass *object = G_OBJECT_CLASS (klass); + + object->dispose = gst_file_pad_dispose; + object->finalize = gst_file_pad_finalize; + + gst->parent_set = gst_file_pad_parent_set; +} + +static void +gst_file_pad_init (GstFilePad * pad) +{ + GstRealPad *real = GST_REAL_PAD (pad); + + /* must do this for set_chain_function to work */ + real->direction = GST_PAD_SINK; + + gst_pad_set_chain_function (GST_PAD (real), gst_file_pad_chain); + + pad->adapter = gst_adapter_new (); + pad->in_seek = FALSE; + pad->eos = FALSE; + + pad->iterate_func = NULL; + pad->event_func = gst_pad_event_default; +} + +static void +gst_file_pad_dispose (GObject * object) +{ + GstFilePad *file_pad = GST_FILE_PAD (object); + + gst_adapter_clear (file_pad->adapter); + + GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); +} + +static void +gst_file_pad_finalize (GObject * object) +{ + GstFilePad *file_pad = GST_FILE_PAD (object); + + g_object_unref (file_pad->adapter); + + GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +gst_file_pad_chain (GstPad * gst_pad, GstData * data) +{ + GstFilePad *pad = GST_FILE_PAD (gst_pad); + gboolean got_value; + gint64 value; + + if (GST_IS_EVENT (data)) { + GstEvent *event = GST_EVENT (data); + + /* INSERT ME */ + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_DISCONTINUOUS: + got_value = + gst_event_discont_get_value (event, GST_FORMAT_BYTES, &value); + if (!got_value) + got_value = + gst_event_discont_get_value (event, GST_FORMAT_DEFAULT, &value); + if (pad->in_seek) { + /* discard broken disconts */ + if ((pad->position >= 0) && got_value && (value != pad->position)) { + GST_DEBUG_OBJECT (pad, + "unexpected discont during seek (want %" G_GINT64_FORMAT + ", got %" G_GINT64_FORMAT "), discarding", pad->position, + value); + break; + } + if (got_value) { + GST_INFO_OBJECT (pad, "got discont to %" G_GINT64_FORMAT, value); + pad->position = value; + } else { + GST_WARNING_OBJECT (pad, "got discont without position"); + if (pad->position == -1) { + GST_WARNING_OBJECT (pad, + "need to reset position to 0 because we have no position info"); + pad->position = 0; + } + } + pad->in_seek = FALSE; + } else { + /* we're not seeking, what does the event want from us? */ + if (!got_value || + value != pad->position + gst_adapter_available (pad->adapter)) { + /* discont doesn't match position */ + GST_WARNING_OBJECT (pad, "DISCONT arrived to %" G_GINT64_FORMAT + ", we're expecting %" G_GINT64_FORMAT " though", value, + pad->position + gst_adapter_available (pad->adapter)); + /* off to event function, let the user decide */ + break; + } + } + gst_event_unref (event); + return; + case GST_EVENT_EOS: + pad->eos = TRUE; + gst_event_unref (event); + g_return_if_fail (pad->iterate_func); + pad->iterate_func (pad); + return; + default: + break; + } + + g_return_if_fail (pad->event_func); + pad->event_func (gst_pad, event); + } else { + if (pad->in_seek) { + GST_DEBUG_OBJECT (pad, "discarding buffer %p, we're seeking", data); + gst_data_unref (data); + } else { + gst_adapter_push (pad->adapter, GST_BUFFER (data)); + g_return_if_fail (pad->iterate_func); + pad->iterate_func (pad); + } + } +} + +static void +gst_file_pad_parent_set (GstObject * object, GstObject * parent) +{ + GstElement *element; + + /* FIXME: we can only be added to elements, right? */ + element = GST_ELEMENT (parent); + + if (element->loopfunc) + g_warning ("attempt to add a GstFilePad to a loopbased element."); + if (!GST_FLAG_IS_SET (element, GST_ELEMENT_EVENT_AWARE)) + g_warning ("elements using GstFilePad must be event-aware."); + + GST_CALL_PARENT (GST_OBJECT_CLASS, parent_set, (object, parent)); +} + +/** + * gst_file_pad_new: + * @templ: the #GstPadTemplate to use + * @name: name of the pad + * + * creates a new file pad. Note that the template must be a sink template. + * + * Returns: the new file pad. + */ +GstPad * +gst_file_pad_new (GstPadTemplate * templ, gchar * name) +{ + g_return_val_if_fail (GST_IS_PAD_TEMPLATE (templ), NULL); + g_return_val_if_fail (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SINK, + NULL); + g_return_val_if_fail (name != NULL, NULL); + + return gst_pad_custom_new_from_template (GST_TYPE_FILE_PAD, templ, name); +} + +/** + * gst_file_pad_set_event_function: + * @pad: a #GstFilePad + * @event: the #GstPadEventFunction to use + * + * sets the function to use for handling events arriving on the pad, that aren't + * intercepted by the pad. The pad intercepts EOS and DISCONT events for its own + * usage. An exception are unexpected DISCONT events that signal discontinuities + * in the data stream. So when your event function receives a DISCONT event, it has + * to decide what to do with a hole of data coming up. + * If you don't set one, gst_pad_event_default() will be used. + */ +void +gst_file_pad_set_event_function (GstFilePad * pad, GstPadEventFunction event) +{ + g_return_if_fail (GST_IS_FILE_PAD (pad)); + g_return_if_fail (event != NULL); + + pad->event_func = event; +} + +/** + * gst_file_pad_set_iterate_function: + * @pad: a #GstFilePad + * @iterate: the #GstFilePadIterateFunction to use + * + * Sets the iterate function of the pad. Don't use chain functions with file + * pads, they are used internally. The iteration function is called whenever + * there is new data to process. You can then use operations like + * gst_file_pad_read() to get the data. + */ +void +gst_file_pad_set_iterate_function (GstFilePad * pad, + GstFilePadIterateFunction iterate) +{ + g_return_if_fail (GST_IS_FILE_PAD (pad)); + g_return_if_fail (iterate != NULL); + + pad->iterate_func = iterate; +} + +/** + * gst_file_pad_read: + * @pad: a #GstFilePad + * @buf: buffer to fill + * @count: number of bytes to put into buffer + * + * read @count bytes from the @pad into the buffer starting at @buf. + * Note that this function does not return less bytes even in the EOS case. + * + * Returns: On success, @count is returned, and the file position is + * advanced by this number. 0 indicates end of stream. + * On error, -errno is returned, and the errno of the pad is set + * appropriately. In this case the file position will not change. + */ +gint64 +gst_file_pad_read (GstFilePad * pad, void *buf, gint64 count) +{ + const guint8 *data; + + /* FIXME: set pad's errno? */ + g_return_val_if_fail (GST_IS_FILE_PAD (pad), -EBADF); + g_return_val_if_fail (buf != NULL, -EFAULT); + g_return_val_if_fail (count >= 0, -EINVAL); + + if (gst_file_pad_eof (pad)) + return 0; + data = gst_adapter_peek (pad->adapter, count); + RETURN_IF_FAIL (pad, data != NULL, EAGAIN); + + memcpy (buf, data, count); + gst_adapter_flush (pad->adapter, count); + pad->position += count; + + return count; +} + +/** + * gst_file_pad_try_read: + * @pad: a #GstFilePad + * @buf: buffer to fill + * @count: number of bytes to put into buffer + * + * Attempts to read up to @count bytes into the buffer pointed to by @buf. + * This function is modeled after the libc read() function. + * + * Returns: On success, the number of bytes read is returned, and the file + * position is advanced by this number. 0 indicates end of stream. + * On error, -errno is returned, and the errno of the pad is set + * appropriately. In this case the file position will not change. + * Note that the number of bytes read may and often will be + * smaller then @count. If you don't want this behaviour, use + * gst_file_pad_read() instead. + **/ +gint64 +gst_file_pad_try_read (GstFilePad * pad, void *buf, gint64 count) +{ + g_return_val_if_fail (GST_IS_FILE_PAD (pad), -EBADF); + g_return_val_if_fail (buf != NULL, -EFAULT); + g_return_val_if_fail (count >= 0, -EINVAL); + + count = MIN (count, (gint64) gst_adapter_available (pad->adapter)); + return gst_file_pad_read (pad, buf, count); +} + +/** + * gst_file_pad_seek: + * @pad: a #GstFilePad + * @offset: new offset to start reading from + * @whence: specifies relative to which position @offset should be interpreted + * + * Sets the new position to read from to @offset bytes relative to @whence. This + * function is modelled after the fseek() libc function. + * + * Returns: 0 on success, a negative error number on failure. + */ +int +gst_file_pad_seek (GstFilePad * pad, gint64 offset, GstSeekType whence) +{ + GstEvent *event; + + g_return_val_if_fail (GST_IS_FILE_PAD (pad), -EBADF); + g_return_val_if_fail ((whence & (GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_SET | + GST_SEEK_METHOD_END)) == whence, -EINVAL); + g_return_val_if_fail (whence != 0, -EINVAL); + + RETURN_IF_FAIL (pad, GST_PAD_PEER (pad), EBADF); /* FIXME: better return val? */ + /* adjust offset by number of bytes buffered */ + if (whence & GST_SEEK_METHOD_CUR) + offset -= gst_adapter_available (pad->adapter); + event = + gst_event_new_seek (whence | GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE + | GST_FORMAT_BYTES, offset); + RETURN_IF_FAIL (pad, gst_pad_send_event (GST_PAD_PEER (pad), event), EBADF); + GST_DEBUG_OBJECT (pad, + "seeking to position %" G_GINT64_FORMAT " relative to %s", offset, + whence == GST_SEEK_METHOD_CUR ? "start" : whence == + GST_SEEK_METHOD_SET ? "current" : "end"); + switch (whence) { + case GST_SEEK_METHOD_SET: + pad->position = offset; + break; + case GST_SEEK_METHOD_CUR: + pad->position += offset + gst_adapter_available (pad->adapter); + break; + case GST_SEEK_METHOD_END: + /* FIXME: query length and use that */ + pad->position = -1; + break; + default: + g_assert_not_reached (); + break; + } + gst_adapter_clear (pad->adapter); + pad->in_seek = TRUE; + pad->eos = FALSE; + + return 0; +} + +/** + * gst_file_pad_tell: + * @pad: a #GstFilePad + * + * gets the current position inside the stream if the position is available. If + * the position is not available due to a pending seek, it returns -EAGAIN. If + * the stream does not provide this information, -EBADF is returned. The @pad's + * errno is set apropriatly. This function is modeled after the ftell() libc + * function. + * + * Returns: The position or a negative error code. + */ +gint64 +gst_file_pad_tell (GstFilePad * pad) +{ + g_return_val_if_fail (GST_IS_FILE_PAD (pad), -EBADF); + + RETURN_IF_FAIL (pad, !(pad->position < 0 && pad->in_seek), EAGAIN); + RETURN_IF_FAIL (pad, pad->position >= 0, EBADF); + + return pad->position; +} + +/** + * gst_file_pad_error: + * @pad: a #GstFilePad + * + * Gets the last error. This is modeled after the ferror() function from libc. + * + * Returns: Number of the last error or 0 if there hasn't been an error yet. + */ +int +gst_file_pad_error (GstFilePad * pad) +{ + g_return_val_if_fail (GST_IS_FILE_PAD (pad), 0); + + return pad->error_number; +} + +/** + * gst_file_pad_eof: + * @pad: ia #GstFilePad + * + * Checks if the EOS has been reached. This function is modeled after the + * function feof() from libc. + * + * Returns: non-zero if EOS has been reached, zero if not. + **/ +int +gst_file_pad_eof (GstFilePad * pad) +{ + g_return_val_if_fail (GST_IS_FILE_PAD (pad), 0); + + if (pad->in_seek) + return 0; + if (gst_adapter_available (pad->adapter)) + return 0; + if (!pad->eos) + return 0; + + return 1; +} diff --git a/libs/gst/bytestream/filepad.h b/libs/gst/bytestream/filepad.h new file mode 100644 index 000000000..2f1267495 --- /dev/null +++ b/libs/gst/bytestream/filepad.h @@ -0,0 +1,95 @@ +/* GStreamer + * Copyright (C) 2004 Benjamin Otte <otte@gnome.org> + * + * 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 <gst/gst.h> +#include <gst/bytestream/adapter.h> + +#ifndef __GST_FILE_PAD_H__ +#define __GST_FILE_PAD_H__ + +G_BEGIN_DECLS + + +#define GST_TYPE_FILE_PAD \ + (gst_file_pad_get_type()) +#define GST_FILE_PAD(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FILE_PAD,GstFilePad)) +#define GST_FILE_PAD_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FILE_PAD,GstFilePadClass)) +#define GST_IS_FILE_PAD(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FILE_PAD)) +#define GST_IS_FILE_PAD_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FILE_PAD)) + +typedef struct _GstFilePad GstFilePad; +typedef struct _GstFilePadClass GstFilePadClass; + +typedef void (* GstFilePadIterateFunction) (GstFilePad *pad); + +struct _GstFilePad { + GstRealPad pad; + + GstAdapter * adapter; + gint64 position; /* FIXME: add to adapter? */ + gboolean in_seek; + gboolean eos; + int error_number; + + GstFilePadIterateFunction iterate_func; + GstPadEventFunction event_func; + + gpointer _gst_reserved[GST_PADDING]; +}; + +struct _GstFilePadClass { + GstRealPadClass parent_class; + + gpointer _gst_reserved[GST_PADDING]; +}; + +GType gst_file_pad_get_type (void); + +/* FIXME: need this? */ +GstPad * gst_file_pad_new (GstPadTemplate* templ, + gchar *name); + +void gst_file_pad_set_event_function (GstFilePad *file_pad, + GstPadEventFunction event); +void gst_file_pad_set_iterate_function (GstFilePad *file_pad, + GstFilePadIterateFunction iterate); + +/* this is a file like interface */ +/* FIXME: is gint64 the correct type? (it must be signed to get error return vals */ +gint64 gst_file_pad_read (GstFilePad *pad, + void *buf, + gint64 count); +gint64 gst_file_pad_try_read (GstFilePad *pad, + void *buf, + gint64 count); +int gst_file_pad_seek (GstFilePad *pad, + gint64 offset, + GstSeekType whence); +gint64 gst_file_pad_tell (GstFilePad *pad); +int gst_file_pad_error (GstFilePad *pad); +int gst_file_pad_eof (GstFilePad *pad); + + +G_END_DECLS + +#endif /* __GST_FILE_PAD_H__ */ diff --git a/tests/old/testsuite/bytestream/.gitignore b/tests/old/testsuite/bytestream/.gitignore index 7df60c92d..6b90160e0 100644 --- a/tests/old/testsuite/bytestream/.gitignore +++ b/tests/old/testsuite/bytestream/.gitignore @@ -6,3 +6,4 @@ Makefile.in .deps .libs test1 +filepadsink diff --git a/tests/old/testsuite/bytestream/Makefile.am b/tests/old/testsuite/bytestream/Makefile.am index 583c94b92..77ea58526 100644 --- a/tests/old/testsuite/bytestream/Makefile.am +++ b/tests/old/testsuite/bytestream/Makefile.am @@ -1,9 +1,10 @@ include ../Rules -tests_pass = +tests_pass = filepadsink tests_fail = test1 tests_ignore = test1_SOURCES = test1.c gstbstest.c test1_LDFLAGS = $(top_builddir)/libs/gst/bytestream/libgstbytestream.la +filepadsink_LDFLAGS = $(top_builddir)/libs/gst/bytestream/libgstbytestream.la diff --git a/tests/old/testsuite/bytestream/filepadsink.c b/tests/old/testsuite/bytestream/filepadsink.c new file mode 100644 index 000000000..410cf643a --- /dev/null +++ b/tests/old/testsuite/bytestream/filepadsink.c @@ -0,0 +1,281 @@ +/* GStreamer + * Copyright (C) 2004 Benjamin Otte <otte@gnome.org> + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include <gst/gst.h> +#include <gst/bytestream/filepad.h> +#include <stdio.h> +#include <string.h> + +#define GST_TYPE_FP_SINK \ + (gst_fp_sink_get_type()) +#define GST_FP_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FP_SINK,GstFpSink)) +#define GST_FP_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FP_SINK,GstFpSinkClass)) +#define GST_IS_FP_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FP_SINK)) +#define GST_IS_FP_SINK_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FP_SINK)) + + +typedef struct _GstFpSink GstFpSink; +typedef struct _GstFpSinkClass GstFpSinkClass; + +struct _GstFpSink +{ + GstElement element; + /* pads */ + GstFilePad *sinkpad; + + /* fd */ + FILE *stream; + guint state; +}; + +struct _GstFpSinkClass +{ + GstElementClass parent_class; +}; + +GST_BOILERPLATE (GstFpSink, gst_fp_sink, GstElement, GST_TYPE_ELEMENT); + +static void do_tests (GstFilePad * pad); + + +static void +gst_fp_sink_base_init (gpointer g_class) +{ +} + +static void +gst_fp_sink_class_init (GstFpSinkClass * klass) +{ +} + +static GstStaticPadTemplate template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("ANY") + ); + +static void +gst_fp_sink_init (GstFpSink * fp) +{ + GST_FLAG_SET (fp, GST_ELEMENT_EVENT_AWARE); + + fp->sinkpad = + GST_FILE_PAD (gst_file_pad_new (gst_static_pad_template_get (&template), + "src")); + gst_file_pad_set_iterate_function (fp->sinkpad, do_tests); + gst_element_add_pad (GST_ELEMENT (fp), GST_PAD (fp->sinkpad)); +} + +#define THE_CHECK(result) G_STMT_START{ \ + gint64 pos = gst_file_pad_tell(fp->sinkpad); \ + if (pos >= 0) \ + g_assert (pos == ftell (fp->stream)); \ + g_print ("%s (%"G_GINT64_FORMAT")\n", result ? "OK" : "no", pos); \ + return result; \ +}G_STMT_END +#define FAIL THE_CHECK(FALSE) +#define SUCCESS THE_CHECK(TRUE) + +static gboolean +fp_read (GstFpSink * fp, guint size) +{ + guint8 buf[size], buf2[size]; + gint64 amount; + + g_print ("reading %u bytes...", size); + amount = gst_file_pad_read (fp->sinkpad, buf, size); + if (amount == -EAGAIN) + FAIL; + g_assert (amount == size); + amount = fread (buf2, 1, amount, fp->stream); + g_assert (amount == size); + if (memcmp (buf, buf2, amount) != 0) + g_assert_not_reached (); + fp->state++; + SUCCESS; +} + +static gboolean +fp_try_read (GstFpSink * fp, guint size) +{ + guint8 buf[size], buf2[size]; + gint64 amount; + size_t amount2; + + g_print ("reading %u bytes...", size); + amount = gst_file_pad_try_read (fp->sinkpad, buf, size); + if (amount == -EAGAIN) + FAIL; + g_assert (amount > 0); + amount2 = fread (buf2, 1, amount, fp->stream); + g_assert (amount == amount2); + if (memcmp (buf, buf2, amount) != 0) + g_assert_not_reached (); + fp->state++; + SUCCESS; +} + +static gboolean +fp_seek (GstFpSink * fp, gint64 pos, GstSeekType whence) +{ + int seek_type = whence == GST_SEEK_METHOD_SET ? SEEK_SET : + whence == GST_SEEK_METHOD_CUR ? SEEK_CUR : SEEK_END; + + g_print ("seeking to %s %" G_GINT64_FORMAT " bytes...", + whence == GST_SEEK_METHOD_SET ? "" : whence == + GST_SEEK_METHOD_CUR ? "+-" : "-", pos); + if (gst_file_pad_seek (fp->sinkpad, pos, whence) != 0) + g_assert_not_reached (); + if (fseek (fp->stream, pos, seek_type) != 0) + g_assert_not_reached (); + fp->state++; + SUCCESS; +} + +static gboolean +fp_eof (GstFpSink * fp) +{ + guint8 buf; + + g_print ("checking for EOF..."); + if (!gst_file_pad_eof (fp->sinkpad)) + FAIL; + if (fread (&buf, 1, 1, fp->stream) != 0) + g_assert_not_reached (); + fp->state++; + SUCCESS; +} + +#define MIN_SIZE 10050 +#define MAX_SIZE 1000000 +static void +do_tests (GstFilePad * pad) +{ + GstFpSink *fp = GST_FP_SINK (gst_pad_get_parent (GST_PAD (pad))); + + while (TRUE) { + switch (fp->state) { + case 0: + if (!fp_try_read (fp, 50)) + return; + break; + case 1: + if (!fp_try_read (fp, MAX_SIZE)) /* more than file size */ + return; + break; + case 2: + if (!fp_seek (fp, 0, GST_SEEK_METHOD_SET)) + return; + break; + case 3: + if (!fp_read (fp, 50)) + return; + break; + case 4: + if (!fp_read (fp, MIN_SIZE - 50)) /* bigger than 1 buffer */ + return; + break; + case 5: + if (!fp_seek (fp, -200, GST_SEEK_METHOD_CUR)) + return; + break; + case 6: + if (!fp_read (fp, 50)) + return; + break; + case 7: + if (!fp_seek (fp, 50, GST_SEEK_METHOD_CUR)) + return; + break; + case 8: + if (!fp_read (fp, 50)) + return; + break; + case 9: + if (!fp_seek (fp, MIN_SIZE - 50, GST_SEEK_METHOD_SET)) + return; + break; + case 10: + if (!fp_read (fp, 50)) + return; + break; + case 11: + if (!fp_seek (fp, 0, GST_SEEK_METHOD_END)) + return; + break; + case 12: + if (!fp_eof (fp)) + return; + gst_element_set_eos (GST_ELEMENT (fp)); + return; + default: + g_assert_not_reached (); + } + } +} + +#ifndef THE_FILE +# define THE_FILE "../../configure.ac" +#endif +gint +main (gint argc, gchar ** argv) +{ + GstElement *pipeline, *src, *sink; + long size; + + gst_init (&argc, &argv); + gst_library_load ("bytestream"); + + pipeline = gst_element_factory_make ("pipeline", NULL); + g_assert (pipeline); + src = gst_element_factory_make ("filesrc", NULL); + g_assert (src); + sink = g_object_new (GST_TYPE_FP_SINK, NULL); + gst_object_set_name (GST_OBJECT (sink), "sink"); + gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); + if (!gst_element_link (src, sink)) + g_assert_not_reached (); + g_object_set (src, "location", THE_FILE, NULL); + GST_FP_SINK (sink)->stream = fopen (THE_FILE, "r"); + g_assert (GST_FP_SINK (sink)->stream); + /* check correct file sizes */ + if (fseek (GST_FP_SINK (sink)->stream, 0, SEEK_END) != 0) + g_assert_not_reached (); + size = ftell (GST_FP_SINK (sink)->stream); + if (fseek (GST_FP_SINK (sink)->stream, 0, SEEK_SET) != 0) + g_assert_not_reached (); + g_assert (size >= MIN_SIZE); + g_assert (size <= MAX_SIZE); + + if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS) + g_assert_not_reached (); + while (gst_bin_iterate (GST_BIN (pipeline))); + + g_assert (GST_FP_SINK (sink)->state == 13); + g_object_unref (pipeline); + pipeline = NULL; + return 0; +} diff --git a/testsuite/bytestream/.gitignore b/testsuite/bytestream/.gitignore index 7df60c92d..6b90160e0 100644 --- a/testsuite/bytestream/.gitignore +++ b/testsuite/bytestream/.gitignore @@ -6,3 +6,4 @@ Makefile.in .deps .libs test1 +filepadsink diff --git a/testsuite/bytestream/Makefile.am b/testsuite/bytestream/Makefile.am index 583c94b92..77ea58526 100644 --- a/testsuite/bytestream/Makefile.am +++ b/testsuite/bytestream/Makefile.am @@ -1,9 +1,10 @@ include ../Rules -tests_pass = +tests_pass = filepadsink tests_fail = test1 tests_ignore = test1_SOURCES = test1.c gstbstest.c test1_LDFLAGS = $(top_builddir)/libs/gst/bytestream/libgstbytestream.la +filepadsink_LDFLAGS = $(top_builddir)/libs/gst/bytestream/libgstbytestream.la diff --git a/testsuite/bytestream/filepadsink.c b/testsuite/bytestream/filepadsink.c new file mode 100644 index 000000000..410cf643a --- /dev/null +++ b/testsuite/bytestream/filepadsink.c @@ -0,0 +1,281 @@ +/* GStreamer + * Copyright (C) 2004 Benjamin Otte <otte@gnome.org> + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include <gst/gst.h> +#include <gst/bytestream/filepad.h> +#include <stdio.h> +#include <string.h> + +#define GST_TYPE_FP_SINK \ + (gst_fp_sink_get_type()) +#define GST_FP_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FP_SINK,GstFpSink)) +#define GST_FP_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FP_SINK,GstFpSinkClass)) +#define GST_IS_FP_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FP_SINK)) +#define GST_IS_FP_SINK_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FP_SINK)) + + +typedef struct _GstFpSink GstFpSink; +typedef struct _GstFpSinkClass GstFpSinkClass; + +struct _GstFpSink +{ + GstElement element; + /* pads */ + GstFilePad *sinkpad; + + /* fd */ + FILE *stream; + guint state; +}; + +struct _GstFpSinkClass +{ + GstElementClass parent_class; +}; + +GST_BOILERPLATE (GstFpSink, gst_fp_sink, GstElement, GST_TYPE_ELEMENT); + +static void do_tests (GstFilePad * pad); + + +static void +gst_fp_sink_base_init (gpointer g_class) +{ +} + +static void +gst_fp_sink_class_init (GstFpSinkClass * klass) +{ +} + +static GstStaticPadTemplate template = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("ANY") + ); + +static void +gst_fp_sink_init (GstFpSink * fp) +{ + GST_FLAG_SET (fp, GST_ELEMENT_EVENT_AWARE); + + fp->sinkpad = + GST_FILE_PAD (gst_file_pad_new (gst_static_pad_template_get (&template), + "src")); + gst_file_pad_set_iterate_function (fp->sinkpad, do_tests); + gst_element_add_pad (GST_ELEMENT (fp), GST_PAD (fp->sinkpad)); +} + +#define THE_CHECK(result) G_STMT_START{ \ + gint64 pos = gst_file_pad_tell(fp->sinkpad); \ + if (pos >= 0) \ + g_assert (pos == ftell (fp->stream)); \ + g_print ("%s (%"G_GINT64_FORMAT")\n", result ? "OK" : "no", pos); \ + return result; \ +}G_STMT_END +#define FAIL THE_CHECK(FALSE) +#define SUCCESS THE_CHECK(TRUE) + +static gboolean +fp_read (GstFpSink * fp, guint size) +{ + guint8 buf[size], buf2[size]; + gint64 amount; + + g_print ("reading %u bytes...", size); + amount = gst_file_pad_read (fp->sinkpad, buf, size); + if (amount == -EAGAIN) + FAIL; + g_assert (amount == size); + amount = fread (buf2, 1, amount, fp->stream); + g_assert (amount == size); + if (memcmp (buf, buf2, amount) != 0) + g_assert_not_reached (); + fp->state++; + SUCCESS; +} + +static gboolean +fp_try_read (GstFpSink * fp, guint size) +{ + guint8 buf[size], buf2[size]; + gint64 amount; + size_t amount2; + + g_print ("reading %u bytes...", size); + amount = gst_file_pad_try_read (fp->sinkpad, buf, size); + if (amount == -EAGAIN) + FAIL; + g_assert (amount > 0); + amount2 = fread (buf2, 1, amount, fp->stream); + g_assert (amount == amount2); + if (memcmp (buf, buf2, amount) != 0) + g_assert_not_reached (); + fp->state++; + SUCCESS; +} + +static gboolean +fp_seek (GstFpSink * fp, gint64 pos, GstSeekType whence) +{ + int seek_type = whence == GST_SEEK_METHOD_SET ? SEEK_SET : + whence == GST_SEEK_METHOD_CUR ? SEEK_CUR : SEEK_END; + + g_print ("seeking to %s %" G_GINT64_FORMAT " bytes...", + whence == GST_SEEK_METHOD_SET ? "" : whence == + GST_SEEK_METHOD_CUR ? "+-" : "-", pos); + if (gst_file_pad_seek (fp->sinkpad, pos, whence) != 0) + g_assert_not_reached (); + if (fseek (fp->stream, pos, seek_type) != 0) + g_assert_not_reached (); + fp->state++; + SUCCESS; +} + +static gboolean +fp_eof (GstFpSink * fp) +{ + guint8 buf; + + g_print ("checking for EOF..."); + if (!gst_file_pad_eof (fp->sinkpad)) + FAIL; + if (fread (&buf, 1, 1, fp->stream) != 0) + g_assert_not_reached (); + fp->state++; + SUCCESS; +} + +#define MIN_SIZE 10050 +#define MAX_SIZE 1000000 +static void +do_tests (GstFilePad * pad) +{ + GstFpSink *fp = GST_FP_SINK (gst_pad_get_parent (GST_PAD (pad))); + + while (TRUE) { + switch (fp->state) { + case 0: + if (!fp_try_read (fp, 50)) + return; + break; + case 1: + if (!fp_try_read (fp, MAX_SIZE)) /* more than file size */ + return; + break; + case 2: + if (!fp_seek (fp, 0, GST_SEEK_METHOD_SET)) + return; + break; + case 3: + if (!fp_read (fp, 50)) + return; + break; + case 4: + if (!fp_read (fp, MIN_SIZE - 50)) /* bigger than 1 buffer */ + return; + break; + case 5: + if (!fp_seek (fp, -200, GST_SEEK_METHOD_CUR)) + return; + break; + case 6: + if (!fp_read (fp, 50)) + return; + break; + case 7: + if (!fp_seek (fp, 50, GST_SEEK_METHOD_CUR)) + return; + break; + case 8: + if (!fp_read (fp, 50)) + return; + break; + case 9: + if (!fp_seek (fp, MIN_SIZE - 50, GST_SEEK_METHOD_SET)) + return; + break; + case 10: + if (!fp_read (fp, 50)) + return; + break; + case 11: + if (!fp_seek (fp, 0, GST_SEEK_METHOD_END)) + return; + break; + case 12: + if (!fp_eof (fp)) + return; + gst_element_set_eos (GST_ELEMENT (fp)); + return; + default: + g_assert_not_reached (); + } + } +} + +#ifndef THE_FILE +# define THE_FILE "../../configure.ac" +#endif +gint +main (gint argc, gchar ** argv) +{ + GstElement *pipeline, *src, *sink; + long size; + + gst_init (&argc, &argv); + gst_library_load ("bytestream"); + + pipeline = gst_element_factory_make ("pipeline", NULL); + g_assert (pipeline); + src = gst_element_factory_make ("filesrc", NULL); + g_assert (src); + sink = g_object_new (GST_TYPE_FP_SINK, NULL); + gst_object_set_name (GST_OBJECT (sink), "sink"); + gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL); + if (!gst_element_link (src, sink)) + g_assert_not_reached (); + g_object_set (src, "location", THE_FILE, NULL); + GST_FP_SINK (sink)->stream = fopen (THE_FILE, "r"); + g_assert (GST_FP_SINK (sink)->stream); + /* check correct file sizes */ + if (fseek (GST_FP_SINK (sink)->stream, 0, SEEK_END) != 0) + g_assert_not_reached (); + size = ftell (GST_FP_SINK (sink)->stream); + if (fseek (GST_FP_SINK (sink)->stream, 0, SEEK_SET) != 0) + g_assert_not_reached (); + g_assert (size >= MIN_SIZE); + g_assert (size <= MAX_SIZE); + + if (gst_element_set_state (pipeline, GST_STATE_PLAYING) != GST_STATE_SUCCESS) + g_assert_not_reached (); + while (gst_bin_iterate (GST_BIN (pipeline))); + + g_assert (GST_FP_SINK (sink)->state == 13); + g_object_unref (pipeline); + pipeline = NULL; + return 0; +} |