Added a basic element: pipefilter. This element connects the stdin/stdout of an exter...
authorWim Taymans <wim.taymans@gmail.com>
Sun, 28 May 2000 20:04:31 +0000 (20:04 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Sun, 28 May 2000 20:04:31 +0000 (20:04 +0000)
Original commit message from CVS:
Added a basic element: pipefilter. This element connects the stdin/stdout
of an external program into the pipeline. We now have virtually all of
the capabilities of sox, lame, ...

gst/elements/gstpipefilter.c [new file with mode: 0644]
gst/elements/gstpipefilter.h [new file with mode: 0644]
plugins/elements/gstpipefilter.c [new file with mode: 0644]
plugins/elements/gstpipefilter.h [new file with mode: 0644]
test/pipetest.c [new file with mode: 0644]

diff --git a/gst/elements/gstpipefilter.c b/gst/elements/gstpipefilter.c
new file mode 100644 (file)
index 0000000..b054c93
--- /dev/null
@@ -0,0 +1,296 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+//#define DEBUG_ENABLED
+#include "gstpipefilter.h"
+
+
+GstElementDetails gst_pipefilter_details = {
+  "Pipefilter",
+  "Filter",
+  "Pass data without modification",
+  VERSION,
+  "Erik Walthinsen <omega@cse.ogi.edu>",
+  "(C) 1999",
+};
+
+
+/* Pipefilter signals and args */
+enum {
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum {
+  ARG_0,
+  ARG_CONTROL
+};
+
+
+static void gst_pipefilter_class_init(GstPipefilterClass *klass);
+static void gst_pipefilter_init(GstPipefilter *pipefilter);
+static void gst_pipefilter_set_arg(GtkObject *object,GtkArg *arg,guint id);
+static void gst_pipefilter_get_arg(GtkObject *object,GtkArg *arg,guint id);
+
+void gst_pipefilter_chain(GstPad *pad,GstBuffer *buf);
+
+static gboolean gst_pipefilter_change_state(GstElement *element,
+                                         GstElementState state);
+
+static GstFilterClass *parent_class = NULL;
+//static guint gst_pipefilter_signals[LAST_SIGNAL] = { 0 };
+
+GtkType
+gst_pipefilter_get_type(void) {
+  static GtkType pipefilter_type = 0;
+
+  if (!pipefilter_type) {
+    static const GtkTypeInfo pipefilter_info = {
+      "GstPipefilter",
+      sizeof(GstPipefilter),
+      sizeof(GstPipefilterClass),
+      (GtkClassInitFunc)gst_pipefilter_class_init,
+      (GtkObjectInitFunc)gst_pipefilter_init,
+      (GtkArgSetFunc)gst_pipefilter_set_arg,
+      (GtkArgGetFunc)gst_pipefilter_get_arg,
+      (GtkClassInitFunc)NULL,
+    };
+    pipefilter_type = gtk_type_unique(GST_TYPE_FILTER,&pipefilter_info);
+  }
+  return pipefilter_type;
+}
+
+static void gst_pipefilter_class_init(GstPipefilterClass *klass) {
+  GtkObjectClass *gtkobject_class;
+  GstFilterClass *gstfilter_class;
+  GstElementClass *gstelement_class;
+
+  gtkobject_class = (GtkObjectClass*)klass;
+  gstfilter_class = (GstFilterClass*)klass;
+  gstelement_class = (GstElementClass*)klass;
+
+  parent_class = gtk_type_class(GST_TYPE_FILTER);
+
+  gstelement_class->change_state = gst_pipefilter_change_state;
+
+  //gtk_object_add_arg_type("GstPipefilter::control", GTK_TYPE_INT,
+   //                       GTK_ARG_READWRITE, ARG_CONTROL);
+
+  //gtkobject_class->set_arg = gst_pipefilter_set_arg;  
+  //gtkobject_class->get_arg = gst_pipefilter_get_arg;
+}
+
+static void gst_pipefilter_init(GstPipefilter *pipefilter) {
+  pipefilter->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
+  gst_element_add_pad(GST_ELEMENT(pipefilter),pipefilter->sinkpad);
+  gst_pad_set_chain_function(pipefilter->sinkpad,gst_pipefilter_chain);
+  pipefilter->srcpad = gst_pad_new("src",GST_PAD_SRC);
+  gst_element_add_pad(GST_ELEMENT(pipefilter),pipefilter->srcpad);
+
+  pipefilter->control = 0;
+  pipefilter->curoffset = 0;
+  pipefilter->bytes_per_read = 4096;
+  pipefilter->seq = 0;
+}
+
+GstElement *gst_pipefilter_new(gchar *name) {
+  GstElement *pipefilter = GST_ELEMENT(gtk_type_new(GST_TYPE_PIPEFILTER));
+  gst_element_set_name(GST_ELEMENT(pipefilter),name);
+  return pipefilter;
+}
+
+void gst_pipefilter_chain(GstPad *pad,GstBuffer *buf) {
+  GstPipefilter *pipefilter;
+  GstBuffer *newbuf;
+  glong readbytes, writebytes;
+  guchar *data;
+  gulong size;
+
+  g_return_if_fail(pad != NULL);
+  g_return_if_fail(GST_IS_PAD(pad));
+  g_return_if_fail(buf != NULL);
+
+  pipefilter = GST_PIPEFILTER(pad->parent);
+
+  data = GST_BUFFER_DATA(buf);
+  size = GST_BUFFER_SIZE(buf);
+
+  DEBUG("attemting to write %d bytes\n", size);
+  writebytes = write(pipefilter->fdin[1],data,size);
+  DEBUG("written %d bytes\n", writebytes);
+  if (writebytes < 0) {
+    perror("write");
+    gst_element_error(GST_ELEMENT(pipefilter),"writing");
+    return;
+  }
+  gst_buffer_unref(buf);
+
+
+  /* create the buffer */
+  // FIXME: should eventually use a bufferpool for this
+  newbuf = gst_buffer_new();
+  g_return_if_fail(newbuf);
+
+  /* allocate the space for the buffer data */
+  GST_BUFFER_DATA(newbuf) = g_malloc(pipefilter->bytes_per_read);
+  g_return_if_fail(GST_BUFFER_DATA(newbuf) != NULL);
+
+  /* read it in from the file */
+  DEBUG("attemting to read %d bytes\n", pipefilter->bytes_per_read);
+  readbytes = read(pipefilter->fdout[0],GST_BUFFER_DATA(newbuf),pipefilter->bytes_per_read);
+  DEBUG("read %d bytes\n", readbytes);
+  if (readbytes < 0) {
+    if (errno == EAGAIN) {
+      DEBUG("no input yet\n");
+      gst_buffer_unref(newbuf);
+      return;
+    }
+    else {
+      perror("read");
+      gst_element_error(GST_ELEMENT(pipefilter),"reading");
+      return;
+    }
+  }
+  if (readbytes == 0) {
+    gst_buffer_unref(newbuf);
+    return;
+  }
+  /* if we didn't get as many bytes as we asked for, we're at EOF */
+  if (readbytes < pipefilter->bytes_per_read)
+    GST_BUFFER_FLAG_SET(newbuf,GST_BUFFER_EOS);
+  GST_BUFFER_OFFSET(newbuf) = pipefilter->curoffset;
+  GST_BUFFER_SIZE(newbuf) = readbytes;
+  pipefilter->curoffset += readbytes;
+
+  /* we're done, push the buffer off now */
+  gst_pad_push(pipefilter->srcpad,newbuf);
+}
+
+static void gst_pipefilter_set_arg(GtkObject *object,GtkArg *arg,guint id) {
+  GstPipefilter *pipefilter;
+
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(GST_IS_PIPEFILTER(object));
+  pipefilter = GST_PIPEFILTER(object);
+
+  switch(id) {
+    case ARG_CONTROL:
+      pipefilter->control = GTK_VALUE_INT(*arg);
+      break;
+    default:
+      break;
+  }
+}
+
+static void gst_pipefilter_get_arg(GtkObject *object,GtkArg *arg,guint id) {
+  GstPipefilter *pipefilter;
+
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(GST_IS_PIPEFILTER(object));
+  pipefilter = GST_PIPEFILTER(object);
+
+  switch (id) {
+    case ARG_CONTROL:
+      GTK_VALUE_INT(*arg) = pipefilter->control;
+      break;
+    default:
+      arg->type = GTK_TYPE_INVALID;
+      break;
+  }
+}
+
+/* open the file, necessary to go to RUNNING state */
+static gboolean gst_pipefilter_open_file(GstPipefilter *src) {
+  g_return_val_if_fail(!GST_FLAG_IS_SET(src,GST_PIPEFILTER_OPEN), FALSE);
+
+  pipe(src->fdin);
+  pipe(src->fdout);
+
+  if (fcntl(src->fdout[0], F_SETFL, O_NONBLOCK) < 0) {
+    perror("fcntl");
+    gst_element_error(GST_ELEMENT(src),"fcntl");
+    return FALSE;
+  }
+
+  if((src->childpid = fork()) == -1)
+  {
+    perror("fork");
+    gst_element_error(GST_ELEMENT(src),"forking");
+    return FALSE;
+  }
+
+  if(src->childpid == 0)
+  {
+    close(1);
+    dup(src->fdout[1]);  /* set the childs output stream */
+    close(0);
+    dup(src->fdin[0]);  /* set the childs output stream */
+    execlp("lame", "lame", "-x", "-", "-", NULL);
+  }
+  
+  GST_FLAG_SET(src,GST_PIPEFILTER_OPEN);
+  return TRUE;
+}
+
+/* close the file */
+static void gst_pipefilter_close_file(GstPipefilter *src) {
+  g_return_if_fail(GST_FLAG_IS_SET(src,GST_PIPEFILTER_OPEN));
+
+  /* close the file */
+  close(src->fdout[0]);
+  close(src->fdout[1]);
+  close(src->fdin[0]);
+  close(src->fdin[1]);
+
+  /* zero out a lot of our state */
+  src->curoffset = 0;
+  src->seq = 0;
+
+  GST_FLAG_UNSET(src,GST_PIPEFILTER_OPEN);
+}
+
+static gboolean gst_pipefilter_change_state(GstElement *element,
+                                         GstElementState state) {
+  g_return_val_if_fail(GST_IS_PIPEFILTER(element), FALSE);
+
+  switch (state) {
+    case GST_STATE_RUNNING:
+      if (!gst_pipefilter_open_file(GST_PIPEFILTER(element)))
+        return FALSE;
+      break;  
+    case ~GST_STATE_RUNNING:
+      gst_pipefilter_close_file(GST_PIPEFILTER(element));
+      break;
+    default:
+      break;
+  }     
+      
+  if (GST_ELEMENT_CLASS(parent_class)->change_state)
+    return GST_ELEMENT_CLASS(parent_class)->change_state(element,state);
+  return TRUE;
+}
diff --git a/gst/elements/gstpipefilter.h b/gst/elements/gstpipefilter.h
new file mode 100644 (file)
index 0000000..4e20e2b
--- /dev/null
@@ -0,0 +1,88 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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_PIPEFILTER_H__
+#define __GST_PIPEFILTER_H__
+
+#include <sys/types.h>
+#include <gst/gst.h>
+
+#include "config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+GstElementDetails gst_pipefilter_details;
+
+// NOTE: per-element flags start with 16 for now
+typedef enum {
+  GST_PIPEFILTER_OPEN              = (1 << 16),
+} GstPipefilterFlags;
+
+#define GST_TYPE_PIPEFILTER \
+  (gst_pipefilter_get_type())
+#define GST_PIPEFILTER(obj) \
+  (GTK_CHECK_CAST((obj),GST_TYPE_PIPEFILTER,GstPipefilter))
+#define GST_PIPEFILTER_CLASS(klass) \
+  (GTK_CHECK_CLASS_CAST((klass),GST_TYPE_PIPEFILTER,GstPipefilterClass))
+#define GST_IS_PIPEFILTER(obj) \
+  (GTK_CHECK_TYPE((obj),GST_TYPE_PIPEFILTER))
+#define GST_IS_PIPEFILTER_CLASS(obj) \
+  (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_PIPEFILTER))
+
+typedef struct _GstPipefilter GstPipefilter;
+typedef struct _GstPipefilterClass GstPipefilterClass;
+
+struct _GstPipefilter {
+  GstFilter filter;
+
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  /* filename */
+  gchar *filename;
+  /* fd */
+  gint fdout[2];
+  gint fdin[2];
+  pid_t   childpid;
+
+  gulong curoffset;                     /* current offset in file */
+  gulong bytes_per_read;                /* bytes per read */
+
+  gulong seq;                           /* buffer sequence number */
+
+  gint control;
+};
+
+struct _GstPipefilterClass {
+  GstFilterClass parent_class;
+};
+
+GtkType gst_pipefilter_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_PIPEFILTER_H__ */
diff --git a/plugins/elements/gstpipefilter.c b/plugins/elements/gstpipefilter.c
new file mode 100644 (file)
index 0000000..b054c93
--- /dev/null
@@ -0,0 +1,296 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+//#define DEBUG_ENABLED
+#include "gstpipefilter.h"
+
+
+GstElementDetails gst_pipefilter_details = {
+  "Pipefilter",
+  "Filter",
+  "Pass data without modification",
+  VERSION,
+  "Erik Walthinsen <omega@cse.ogi.edu>",
+  "(C) 1999",
+};
+
+
+/* Pipefilter signals and args */
+enum {
+  /* FILL ME */
+  LAST_SIGNAL
+};
+
+enum {
+  ARG_0,
+  ARG_CONTROL
+};
+
+
+static void gst_pipefilter_class_init(GstPipefilterClass *klass);
+static void gst_pipefilter_init(GstPipefilter *pipefilter);
+static void gst_pipefilter_set_arg(GtkObject *object,GtkArg *arg,guint id);
+static void gst_pipefilter_get_arg(GtkObject *object,GtkArg *arg,guint id);
+
+void gst_pipefilter_chain(GstPad *pad,GstBuffer *buf);
+
+static gboolean gst_pipefilter_change_state(GstElement *element,
+                                         GstElementState state);
+
+static GstFilterClass *parent_class = NULL;
+//static guint gst_pipefilter_signals[LAST_SIGNAL] = { 0 };
+
+GtkType
+gst_pipefilter_get_type(void) {
+  static GtkType pipefilter_type = 0;
+
+  if (!pipefilter_type) {
+    static const GtkTypeInfo pipefilter_info = {
+      "GstPipefilter",
+      sizeof(GstPipefilter),
+      sizeof(GstPipefilterClass),
+      (GtkClassInitFunc)gst_pipefilter_class_init,
+      (GtkObjectInitFunc)gst_pipefilter_init,
+      (GtkArgSetFunc)gst_pipefilter_set_arg,
+      (GtkArgGetFunc)gst_pipefilter_get_arg,
+      (GtkClassInitFunc)NULL,
+    };
+    pipefilter_type = gtk_type_unique(GST_TYPE_FILTER,&pipefilter_info);
+  }
+  return pipefilter_type;
+}
+
+static void gst_pipefilter_class_init(GstPipefilterClass *klass) {
+  GtkObjectClass *gtkobject_class;
+  GstFilterClass *gstfilter_class;
+  GstElementClass *gstelement_class;
+
+  gtkobject_class = (GtkObjectClass*)klass;
+  gstfilter_class = (GstFilterClass*)klass;
+  gstelement_class = (GstElementClass*)klass;
+
+  parent_class = gtk_type_class(GST_TYPE_FILTER);
+
+  gstelement_class->change_state = gst_pipefilter_change_state;
+
+  //gtk_object_add_arg_type("GstPipefilter::control", GTK_TYPE_INT,
+   //                       GTK_ARG_READWRITE, ARG_CONTROL);
+
+  //gtkobject_class->set_arg = gst_pipefilter_set_arg;  
+  //gtkobject_class->get_arg = gst_pipefilter_get_arg;
+}
+
+static void gst_pipefilter_init(GstPipefilter *pipefilter) {
+  pipefilter->sinkpad = gst_pad_new("sink",GST_PAD_SINK);
+  gst_element_add_pad(GST_ELEMENT(pipefilter),pipefilter->sinkpad);
+  gst_pad_set_chain_function(pipefilter->sinkpad,gst_pipefilter_chain);
+  pipefilter->srcpad = gst_pad_new("src",GST_PAD_SRC);
+  gst_element_add_pad(GST_ELEMENT(pipefilter),pipefilter->srcpad);
+
+  pipefilter->control = 0;
+  pipefilter->curoffset = 0;
+  pipefilter->bytes_per_read = 4096;
+  pipefilter->seq = 0;
+}
+
+GstElement *gst_pipefilter_new(gchar *name) {
+  GstElement *pipefilter = GST_ELEMENT(gtk_type_new(GST_TYPE_PIPEFILTER));
+  gst_element_set_name(GST_ELEMENT(pipefilter),name);
+  return pipefilter;
+}
+
+void gst_pipefilter_chain(GstPad *pad,GstBuffer *buf) {
+  GstPipefilter *pipefilter;
+  GstBuffer *newbuf;
+  glong readbytes, writebytes;
+  guchar *data;
+  gulong size;
+
+  g_return_if_fail(pad != NULL);
+  g_return_if_fail(GST_IS_PAD(pad));
+  g_return_if_fail(buf != NULL);
+
+  pipefilter = GST_PIPEFILTER(pad->parent);
+
+  data = GST_BUFFER_DATA(buf);
+  size = GST_BUFFER_SIZE(buf);
+
+  DEBUG("attemting to write %d bytes\n", size);
+  writebytes = write(pipefilter->fdin[1],data,size);
+  DEBUG("written %d bytes\n", writebytes);
+  if (writebytes < 0) {
+    perror("write");
+    gst_element_error(GST_ELEMENT(pipefilter),"writing");
+    return;
+  }
+  gst_buffer_unref(buf);
+
+
+  /* create the buffer */
+  // FIXME: should eventually use a bufferpool for this
+  newbuf = gst_buffer_new();
+  g_return_if_fail(newbuf);
+
+  /* allocate the space for the buffer data */
+  GST_BUFFER_DATA(newbuf) = g_malloc(pipefilter->bytes_per_read);
+  g_return_if_fail(GST_BUFFER_DATA(newbuf) != NULL);
+
+  /* read it in from the file */
+  DEBUG("attemting to read %d bytes\n", pipefilter->bytes_per_read);
+  readbytes = read(pipefilter->fdout[0],GST_BUFFER_DATA(newbuf),pipefilter->bytes_per_read);
+  DEBUG("read %d bytes\n", readbytes);
+  if (readbytes < 0) {
+    if (errno == EAGAIN) {
+      DEBUG("no input yet\n");
+      gst_buffer_unref(newbuf);
+      return;
+    }
+    else {
+      perror("read");
+      gst_element_error(GST_ELEMENT(pipefilter),"reading");
+      return;
+    }
+  }
+  if (readbytes == 0) {
+    gst_buffer_unref(newbuf);
+    return;
+  }
+  /* if we didn't get as many bytes as we asked for, we're at EOF */
+  if (readbytes < pipefilter->bytes_per_read)
+    GST_BUFFER_FLAG_SET(newbuf,GST_BUFFER_EOS);
+  GST_BUFFER_OFFSET(newbuf) = pipefilter->curoffset;
+  GST_BUFFER_SIZE(newbuf) = readbytes;
+  pipefilter->curoffset += readbytes;
+
+  /* we're done, push the buffer off now */
+  gst_pad_push(pipefilter->srcpad,newbuf);
+}
+
+static void gst_pipefilter_set_arg(GtkObject *object,GtkArg *arg,guint id) {
+  GstPipefilter *pipefilter;
+
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(GST_IS_PIPEFILTER(object));
+  pipefilter = GST_PIPEFILTER(object);
+
+  switch(id) {
+    case ARG_CONTROL:
+      pipefilter->control = GTK_VALUE_INT(*arg);
+      break;
+    default:
+      break;
+  }
+}
+
+static void gst_pipefilter_get_arg(GtkObject *object,GtkArg *arg,guint id) {
+  GstPipefilter *pipefilter;
+
+  /* it's not null if we got it, but it might not be ours */
+  g_return_if_fail(GST_IS_PIPEFILTER(object));
+  pipefilter = GST_PIPEFILTER(object);
+
+  switch (id) {
+    case ARG_CONTROL:
+      GTK_VALUE_INT(*arg) = pipefilter->control;
+      break;
+    default:
+      arg->type = GTK_TYPE_INVALID;
+      break;
+  }
+}
+
+/* open the file, necessary to go to RUNNING state */
+static gboolean gst_pipefilter_open_file(GstPipefilter *src) {
+  g_return_val_if_fail(!GST_FLAG_IS_SET(src,GST_PIPEFILTER_OPEN), FALSE);
+
+  pipe(src->fdin);
+  pipe(src->fdout);
+
+  if (fcntl(src->fdout[0], F_SETFL, O_NONBLOCK) < 0) {
+    perror("fcntl");
+    gst_element_error(GST_ELEMENT(src),"fcntl");
+    return FALSE;
+  }
+
+  if((src->childpid = fork()) == -1)
+  {
+    perror("fork");
+    gst_element_error(GST_ELEMENT(src),"forking");
+    return FALSE;
+  }
+
+  if(src->childpid == 0)
+  {
+    close(1);
+    dup(src->fdout[1]);  /* set the childs output stream */
+    close(0);
+    dup(src->fdin[0]);  /* set the childs output stream */
+    execlp("lame", "lame", "-x", "-", "-", NULL);
+  }
+  
+  GST_FLAG_SET(src,GST_PIPEFILTER_OPEN);
+  return TRUE;
+}
+
+/* close the file */
+static void gst_pipefilter_close_file(GstPipefilter *src) {
+  g_return_if_fail(GST_FLAG_IS_SET(src,GST_PIPEFILTER_OPEN));
+
+  /* close the file */
+  close(src->fdout[0]);
+  close(src->fdout[1]);
+  close(src->fdin[0]);
+  close(src->fdin[1]);
+
+  /* zero out a lot of our state */
+  src->curoffset = 0;
+  src->seq = 0;
+
+  GST_FLAG_UNSET(src,GST_PIPEFILTER_OPEN);
+}
+
+static gboolean gst_pipefilter_change_state(GstElement *element,
+                                         GstElementState state) {
+  g_return_val_if_fail(GST_IS_PIPEFILTER(element), FALSE);
+
+  switch (state) {
+    case GST_STATE_RUNNING:
+      if (!gst_pipefilter_open_file(GST_PIPEFILTER(element)))
+        return FALSE;
+      break;  
+    case ~GST_STATE_RUNNING:
+      gst_pipefilter_close_file(GST_PIPEFILTER(element));
+      break;
+    default:
+      break;
+  }     
+      
+  if (GST_ELEMENT_CLASS(parent_class)->change_state)
+    return GST_ELEMENT_CLASS(parent_class)->change_state(element,state);
+  return TRUE;
+}
diff --git a/plugins/elements/gstpipefilter.h b/plugins/elements/gstpipefilter.h
new file mode 100644 (file)
index 0000000..4e20e2b
--- /dev/null
@@ -0,0 +1,88 @@
+/* Gnome-Streamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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_PIPEFILTER_H__
+#define __GST_PIPEFILTER_H__
+
+#include <sys/types.h>
+#include <gst/gst.h>
+
+#include "config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+GstElementDetails gst_pipefilter_details;
+
+// NOTE: per-element flags start with 16 for now
+typedef enum {
+  GST_PIPEFILTER_OPEN              = (1 << 16),
+} GstPipefilterFlags;
+
+#define GST_TYPE_PIPEFILTER \
+  (gst_pipefilter_get_type())
+#define GST_PIPEFILTER(obj) \
+  (GTK_CHECK_CAST((obj),GST_TYPE_PIPEFILTER,GstPipefilter))
+#define GST_PIPEFILTER_CLASS(klass) \
+  (GTK_CHECK_CLASS_CAST((klass),GST_TYPE_PIPEFILTER,GstPipefilterClass))
+#define GST_IS_PIPEFILTER(obj) \
+  (GTK_CHECK_TYPE((obj),GST_TYPE_PIPEFILTER))
+#define GST_IS_PIPEFILTER_CLASS(obj) \
+  (GTK_CHECK_CLASS_TYPE((klass),GST_TYPE_PIPEFILTER))
+
+typedef struct _GstPipefilter GstPipefilter;
+typedef struct _GstPipefilterClass GstPipefilterClass;
+
+struct _GstPipefilter {
+  GstFilter filter;
+
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  /* filename */
+  gchar *filename;
+  /* fd */
+  gint fdout[2];
+  gint fdin[2];
+  pid_t   childpid;
+
+  gulong curoffset;                     /* current offset in file */
+  gulong bytes_per_read;                /* bytes per read */
+
+  gulong seq;                           /* buffer sequence number */
+
+  gint control;
+};
+
+struct _GstPipefilterClass {
+  GstFilterClass parent_class;
+};
+
+GtkType gst_pipefilter_get_type(void);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __GST_PIPEFILTER_H__ */
diff --git a/test/pipetest.c b/test/pipetest.c
new file mode 100644 (file)
index 0000000..7f77e83
--- /dev/null
@@ -0,0 +1,65 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <gst/gst.h>
+
+
+void eof(GstSrc *src) {
+   g_print("have eof, quitting\n");
+   exit(0);
+}
+
+int main(int argc,char *argv[]) {
+  GstPipeline *pipeline;
+  GstElementFactory *srcfactory, *pipefactory, *sinkfactory;
+  GstElement *src, *pipe, *sink;
+  GstPad *infopad;
+  int fd;
+
+  g_print("have %d args\n",argc);
+
+  gst_init(&argc,&argv);
+
+  pipeline = gst_pipeline_new("pipeline");
+  g_return_if_fail(pipeline != NULL);
+
+  srcfactory = gst_elementfactory_find("disksrc");
+  g_return_if_fail(srcfactory != NULL);
+  pipefactory = gst_elementfactory_find("pipefilter");
+  g_return_if_fail(pipefactory != NULL);
+  sinkfactory = gst_elementfactory_find("fdsink");
+  g_return_if_fail(sinkfactory != NULL);
+
+  src = gst_elementfactory_create(srcfactory,"src");
+  g_return_if_fail(src != NULL);
+  gtk_object_set(GTK_OBJECT(src),"location",argv[1],NULL);
+  g_print("should be using file '%s'\n",argv[1]);
+  pipe = gst_elementfactory_create(pipefactory,"pipe");
+  g_return_if_fail(pipe != NULL);
+  sink = gst_elementfactory_create(sinkfactory,"fdsink");
+  g_return_if_fail(sink != NULL);
+
+  fd = open(argv[2],O_CREAT|O_RDWR|O_TRUNC);
+  gtk_object_set(GTK_OBJECT(sink),"fd",fd,NULL);
+
+  gtk_signal_connect(GTK_OBJECT(src),"eos",
+                              GTK_SIGNAL_FUNC(eof),NULL);
+
+  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(src));
+  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(pipe));
+  gst_bin_add(GST_BIN(pipeline),GST_ELEMENT(sink));
+
+  gst_pad_connect(gst_element_get_pad(src,"src"),
+                  gst_element_get_pad(pipe,"sink"));
+  gst_pad_connect(gst_element_get_pad(pipe,"src"),
+                  gst_element_get_pad(sink,"sink"));
+
+  g_print("setting to RUNNING state\n");
+  gst_element_set_state(GST_ELEMENT(pipeline),GST_STATE_RUNNING);
+
+  g_print("about to enter loop\n");
+  while (1) {
+    gst_src_push(GST_SRC(src));
+  }
+}