[gst-devel] Plugin help/samba streaming
Gert van Valkenhoef
gertvv at hccnet.nl
Sat Jan 10 15:15:09 CET 2004
Hello gstreamer developers,
I have written a gstreamer source element for gstreamer 0.6.x, that can
stream files from a samba share. I used gstreamer 0.6.x because it needs
to run on a debian box we have in the living room :)
I have a problem with it: if I play back an MP3 file
gst-launch --gst-plugin-spew --gst-plugin-path=. smbsrc
location=smb://GERT/music/metal/Marilyn\ Manson/Cleansing.mp3 ! spider !
osssink
for example, everything is fine.
With ogg files however, the ogg filter complains:
ERROR: /pipeline0/spider0/vorbisfile0: this is not a vorbis file
execution ended after 1 iterations (sum 50130000 ns, average 50130000 ns,
min 50130000 ns, max 50130000 ns)
I can't really figure out what I did wrong (especially since I've never
written anything for gstreamer or samba before). Perhaps you can help me
out with this? I'm probably making a lot of mistakes...
I do think a samba streaming element is useful in general so if there is
interest I could work on porting to 0.7.x :)
It's only dependency except for standard gstreamer dependencies is
libsmbclient (included in samba, 2.2.x and 3.0.x both work). I did a lot
of copy/paste/adjust from the fdsrc and filesrc elements to make this.
The code listings are below.
Thank you,
Gert van Valkenhoef
=========== .h ===========
#ifndef __GST_SMBSRC_H__
#define __GST_SMBSRC_H__
/*#include <config.h>*/
#include <gst/gst.h>
G_BEGIN_DECLS
GstElementDetails gst_smbsrc_details;
typedef enum {
GST_SMBSRC_OPEN = GST_ELEMENT_FLAG_LAST,
GST_SMBSRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST + 2
} GstSmbSrcFlags;
#define GST_TYPE_SMBSRC \
(gst_smbsrc_get_type())
#define GST_SMBSRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMBSRC,GstSmbSrc))
#define GST_SMBSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMBSRC,GstSmbSrcClass))
#define GST_IS_SMBSRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMBSRC))
#define GST_IS_SMBSRC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMBSRC))
typedef struct _GstSmbSrc GstSmbSrc;
typedef struct _GstSmbSrcClass GstSmbSrcClass;
struct _GstSmbSrc {
GstElement element;
/* pads */
GstPad *srcpad;
/* location */
gchar *location;
/* fd */
gint fd;
gulong curoffset; /* current offset in file */
gulong blocksize; /* bytes per read */
gulong seq; /* buffer sequence number */
};
struct _GstSmbSrcClass {
GstElementClass parent_class;
};
GType gst_smbsrc_get_type(void);
G_END_DECLS
#endif
================== .c ==========
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <libsmbclient.h>
#include "gstsmbsrc.h"
#define DEFAULT_BLOCKSIZE 4096
#define VERSION "0.0"
GstElementDetails gst_smbsrc_details =
{
"Samba Source",
"Source/File",
"LGPL",
"Synchronous read from a samba source",
VERSION,
"Gert van Valkenhoef <gertvv at hccnet.nl>",
"(C) 2003",
};
/* SmbSrc signals and args */
enum {
/* FILL ME */
LAST_SIGNAL
};
enum {
ARG_0,
ARG_FD,
ARG_LOCATION,
ARG_BLOCKSIZE,
};
static void gst_smbsrc_class_init (GstSmbSrcClass *klass);
static void gst_smbsrc_init (GstSmbSrc *smbsrc);
static void gst_smbsrc_set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec);
static void gst_smbsrc_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
static GstBuffer * gst_smbsrc_get (GstPad *pad);
static void gst_smbsrc_dispose (GObject *object);
static gboolean gst_smbsrc_open_file (GstSmbSrc *src);
static GstElementStateReturn gst_smbsrc_change_state (GstElement *element);
static GstElementClass *parent_class = NULL;
/*static guint gst_fdsrc_signals[LAST_SIGNAL] = { 0 };*/
/* Samba Authentication Function !FIXME! */
void auth_fn(const char *server, const char *share,
char *workgroup, int wgmaxlen, char *username, int unmaxlen,
char *password, int pwmaxlen)
{
strncpy (workgroup, "HARDWIRE", wgmaxlen-1);
strncpy (username, "guest", unmaxlen-1);
strncpy (password, "", pwmaxlen-1);
}
GType
gst_smbsrc_get_type (void)
{
static GType smbsrc_type = 0;
if (!smbsrc_type) {
static const GTypeInfo smbsrc_info = {
sizeof(GstSmbSrcClass),
NULL,
NULL,
(GClassInitFunc)gst_smbsrc_class_init,
NULL,
NULL,
sizeof(GstSmbSrc),
0,
(GInstanceInitFunc)gst_smbsrc_init,
};
smbsrc_type = g_type_register_static (GST_TYPE_ELEMENT, "smbsrc", &smbsrc_info, 0);
}
return smbsrc_type;
}
static void
gst_smbsrc_dispose (GObject *object)
{
GstSmbSrc *src;
src = GST_SMBSRC (object);
G_OBJECT_CLASS (parent_class)->dispose (object);
if (src->location)
g_free (src->location);
}
static void
gst_smbsrc_class_init (GstSmbSrcClass *klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
/* init sambaclient - FIXME: handle errors gracefully */
if(smbc_init ( auth_fn, 10 ))
exit (1);
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
g_param_spec_int ("fd", "fd", "A SMB file descriptor",
0, G_MAXINT, 0, G_PARAM_READABLE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOCATION,
g_param_spec_string ("location", "location", "A URL smb://host/share/path",
NULL, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BLOCKSIZE,
g_param_spec_ulong ("blocksize", "Block size", "Size in bytes to read per buffer",
1, G_MAXULONG, DEFAULT_BLOCKSIZE, G_PARAM_READWRITE));
gobject_class->dispose = gst_smbsrc_dispose;
gobject_class->set_property = gst_smbsrc_set_property;
gobject_class->get_property = gst_smbsrc_get_property;
gstelement_class->change_state = gst_smbsrc_change_state;
}
static void gst_smbsrc_init(GstSmbSrc *smbsrc) {
smbsrc->srcpad = gst_pad_new ("src", GST_PAD_SRC);
gst_pad_set_get_function (smbsrc->srcpad, gst_smbsrc_get);
gst_element_add_pad (GST_ELEMENT (smbsrc), smbsrc->srcpad);
smbsrc->location = NULL;
smbsrc->fd = 0;
smbsrc->curoffset = 0;
smbsrc->blocksize = DEFAULT_BLOCKSIZE;
smbsrc->seq = 0;
}
static void
gst_smbsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GstSmbSrc *src;
g_return_if_fail (object);
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_SMBSRC (object));
src = GST_SMBSRC (object);
switch (prop_id) {
case ARG_LOCATION:
/* the element must be stopped in order to do this */
g_return_if_fail (GST_STATE (src) < GST_STATE_PLAYING);
if (src->location) g_free (src->location);
/* clear the filename if we get a NULL (is that possible?) */
if (g_value_get_string (value) == NULL) {
gst_element_set_state (GST_ELEMENT (object), GST_STATE_NULL);
src->location = NULL;
/* otherwise set the new filename */
} else {
src->location = g_strdup (g_value_get_string (value));
}
g_object_notify (G_OBJECT (src), "location");
break;
case ARG_BLOCKSIZE:
src->blocksize = g_value_get_ulong (value);
break;
default:
break;
}
}
static void
gst_smbsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
{
GstSmbSrc *src;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail (GST_IS_FDSRC (object));
src = GST_SMBSRC (object);
switch (prop_id) {
case ARG_LOCATION:
g_value_set_string (value, src->location);
break;
case ARG_BLOCKSIZE:
g_value_set_ulong (value, src->blocksize);
break;
case ARG_FD:
g_value_set_int (value, src->fd);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
gst_smbsrc_open_file (GstSmbSrc *src)
{
g_return_val_if_fail (!GST_FLAG_IS_SET (src ,GST_SMBSRC_OPEN), FALSE);
GST_DEBUG(0, "opening file %s",src->filename);
/* open the file */
src->fd = smbc_open (src->location, O_RDONLY, 0);
if (src->fd < 0) {
gst_element_error (GST_ELEMENT (src), "opening file \"%s\" (%s)",
src->location, strerror (errno), NULL);
return FALSE;
} else {
src->curoffset = 0;
GST_FLAG_SET (src, GST_SMBSRC_OPEN);
}
return TRUE;
}
static void
gst_smbsrc_close_file (GstSmbSrc *src)
{
g_return_if_fail (GST_FLAG_IS_SET (src, GST_SMBSRC_OPEN));
/* close the file */
smbc_close (src->fd);
/* zero out a lot of our state */
src->fd = 0;
src->curoffset = 0;
GST_FLAG_UNSET (src, GST_SMBSRC_OPEN);
}
static GstElementStateReturn
gst_smbsrc_change_state (GstElement *element)
{
GstSmbSrc *src = GST_SMBSRC(element);
switch (GST_STATE_TRANSITION (element)) {
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_NULL:
break;
case GST_STATE_READY_TO_PAUSED:
if (!GST_FLAG_IS_SET (element, GST_SMBSRC_OPEN)) {
if (!gst_smbsrc_open_file (GST_SMBSRC (element)))
return GST_STATE_FAILURE;
}
break;
case GST_STATE_PAUSED_TO_READY:
if (GST_FLAG_IS_SET (element, GST_SMBSRC_OPEN))
gst_smbsrc_close_file (GST_SMBSRC (element));
/*src->seek_happened = TRUE;*/
break;
default:
break;
}
if (GST_ELEMENT_CLASS (parent_class)->change_state)
return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}
static GstBuffer *
gst_smbsrc_get(GstPad *pad)
{
GstSmbSrc *src;
GstBuffer *buf;
glong readbytes;
printf("smbsrc_get\n");
src = GST_SMBSRC (gst_pad_get_parent (pad));
/* create the buffer */
buf = gst_buffer_new_and_alloc (src->blocksize);
/* read it in from the file */
readbytes = smbc_read (src->fd, GST_BUFFER_DATA (buf), src->blocksize);
/* if nothing was read, we're in eos */
if (readbytes == 0) {
gst_element_set_eos (GST_ELEMENT (src));
return GST_BUFFER (gst_event_new (GST_EVENT_EOS));
}
if (readbytes == -1) {
g_error ("Error reading from file descriptor. Ending stream.\n");
gst_element_set_eos (GST_ELEMENT (src));
return GST_BUFFER (gst_event_new (GST_EVENT_EOS));
}
GST_BUFFER_OFFSET (buf) = src->curoffset;
GST_BUFFER_SIZE (buf) = readbytes;
GST_BUFFER_TIMESTAMP (buf) = GST_CLOCK_TIME_NONE;
src->curoffset += readbytes;
/* we're done, return the buffer */
return buf;
}
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
{
GstElementFactory *factory;
gst_plugin_set_longname (plugin, "Samba GST Element");
factory = gst_element_factory_new ("smbsrc", (gst_smbsrc_get_type)(), &gst_smbsrc_details);
if (!factory)
{
g_warning ("gst_element_factory_new failed for `smbsrc'");
return TRUE;
}
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE(factory));
return TRUE;
}
GstPluginDesc plugin_desc = {
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"smbsrc",
plugin_init
};
More information about the gstreamer-devel
mailing list