summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--gst/gstvalue.c1
-rw-r--r--libs/gst/bytestream/Makefile.am4
-rw-r--r--libs/gst/bytestream/filepad.c435
-rw-r--r--libs/gst/bytestream/filepad.h95
-rw-r--r--tests/old/testsuite/bytestream/.gitignore1
-rw-r--r--tests/old/testsuite/bytestream/Makefile.am3
-rw-r--r--tests/old/testsuite/bytestream/filepadsink.c281
-rw-r--r--testsuite/bytestream/.gitignore1
-rw-r--r--testsuite/bytestream/Makefile.am3
-rw-r--r--testsuite/bytestream/filepadsink.c281
11 files changed, 1114 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 9cbf39123..5c373478f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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;
+}