diff options
author | Andy Wingo <wingo@pobox.com> | 2007-02-05 18:42:45 +0000 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2007-02-05 18:42:45 +0000 |
commit | 8334e7d4b0d0bf330e0483747532b4fff8a883e2 (patch) | |
tree | 502966c9b20e9f40949246ec7d154fe2419cf6e1 /ext/sndfile | |
parent | add17e34f0b5d163bd09e02b95c19ec6b9473945 (diff) | |
download | gstreamer-plugins-bad-8334e7d4b0d0bf330e0483747532b4fff8a883e2.tar.gz |
ext/sndfile/: Port sfsrc to 0.10, pull or push, with random access woo.
Original commit message from CVS:
2007-02-05 Andy Wingo <wingo@pobox.com>
* ext/sndfile/Makefile.am:
* ext/sndfile/gstsfsrc.h:
* ext/sndfile/gstsfsrc.c: Port sfsrc to 0.10, pull or push, with
random access woo.
Diffstat (limited to 'ext/sndfile')
-rw-r--r-- | ext/sndfile/Makefile.am | 4 | ||||
-rw-r--r-- | ext/sndfile/gstsf.c | 4 | ||||
-rw-r--r-- | ext/sndfile/gstsf.h | 1 | ||||
-rw-r--r-- | ext/sndfile/gstsfsrc.c | 507 | ||||
-rw-r--r-- | ext/sndfile/gstsfsrc.h | 69 |
5 files changed, 583 insertions, 2 deletions
diff --git a/ext/sndfile/Makefile.am b/ext/sndfile/Makefile.am index bd0511536..c8fac77ad 100644 --- a/ext/sndfile/Makefile.am +++ b/ext/sndfile/Makefile.am @@ -1,9 +1,9 @@ plugin_LTLIBRARIES = libgstsndfile.la -libgstsndfile_la_SOURCES = gstsf.c gstsfsink.c +libgstsndfile_la_SOURCES = gstsf.c gstsfsrc.c gstsfsink.c libgstsndfile_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(SNDFILE_CFLAGS) libgstsndfile_la_LIBADD = $(GST_BASE_LIBS) $(GST_LIBS) $(SNDFILE_LIBS) libgstsndfile_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = gstsf.h gstsfsink.h +noinst_HEADERS = gstsf.h gstsfsrc.h gstsfsink.h diff --git a/ext/sndfile/gstsf.c b/ext/sndfile/gstsf.c index 084e69ac3..e41586513 100644 --- a/ext/sndfile/gstsf.c +++ b/ext/sndfile/gstsf.c @@ -108,6 +108,10 @@ plugin_init (GstPlugin * plugin) gst_sf_sink_get_type ())) return FALSE; + if (!gst_element_register (plugin, "sfsrc", GST_RANK_NONE, + gst_sf_src_get_type ())) + return FALSE; + return TRUE; } diff --git a/ext/sndfile/gstsf.h b/ext/sndfile/gstsf.h index 129ddd93b..f57d3f7f6 100644 --- a/ext/sndfile/gstsf.h +++ b/ext/sndfile/gstsf.h @@ -36,6 +36,7 @@ GType gst_sf_major_types_get_type (void); GType gst_sf_minor_types_get_type (void); GType gst_sf_sink_get_type (void); +GType gst_sf_src_get_type (void); G_END_DECLS diff --git a/ext/sndfile/gstsfsrc.c b/ext/sndfile/gstsfsrc.c new file mode 100644 index 000000000..da0236c0a --- /dev/null +++ b/ext/sndfile/gstsfsrc.c @@ -0,0 +1,507 @@ +/* GStreamer libsndfile plugin + * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> + * 2000,2005 Wim Taymans <wim@fluendo.com> + * 2003,2007 Andy Wingo <wingo@pobox.com> + * + * gstsfsrc.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <gst/gst-i18n-lib.h> + +#include "gstsfsrc.h" + + +static const GstElementDetails sf_src_details = +GST_ELEMENT_DETAILS ("Sndfile source", + "Source/Audio", + "Read audio streams from disk using libsndfile", + "Andy Wingo <wingo at pobox dot com>"); + +enum +{ + PROP_0, + PROP_LOCATION +}; + +static GstStaticPadTemplate sf_src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-float, " + "rate = (int) [ 1, MAX ], " + "channels = (int) [ 1, MAX ], " + "endianness = (int) BYTE_ORDER, " + "width = (int) 32; " + "audio/x-raw-int, " + "rate = (int) [ 1, MAX ], " + "channels = (int) [ 1, MAX ], " + "endianness = (int) BYTE_ORDER, " + "width = (int) {16, 32}, " + "depth = (int) {16, 32}, " "signed = (boolean) true") + ); + + +GST_DEBUG_CATEGORY_STATIC (gst_sf_src_debug); +#define GST_CAT_DEFAULT gst_sf_src_debug + + +#define DEFAULT_BUFFER_FRAMES (256) + + +static void gst_sf_src_finalize (GObject * object); +static void gst_sf_src_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_sf_src_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_sf_src_start (GstBaseSrc * bsrc); +static gboolean gst_sf_src_stop (GstBaseSrc * bsrc); +static gboolean gst_sf_src_is_seekable (GstBaseSrc * bsrc); +static gboolean gst_sf_src_get_size (GstBaseSrc * bsrc, guint64 * size); +static GstFlowReturn gst_sf_src_create (GstBaseSrc * bsrc, guint64 offset, + guint length, GstBuffer ** buffer); +static GstCaps *gst_sf_src_get_caps (GstBaseSrc * bsrc); +static gboolean gst_sf_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps); +static gboolean gst_sf_src_check_get_range (GstBaseSrc * bsrc); +static void gst_sf_src_fixate (GstBaseSrc * bsrc, GstCaps * caps); + +GST_BOILERPLATE (GstSFSrc, gst_sf_src, GstBaseSrc, GST_TYPE_BASE_SRC); + +static void +gst_sf_src_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sf_src_factory)); + + gst_element_class_set_details (gstelement_class, &sf_src_details); + GST_DEBUG_CATEGORY_INIT (gst_sf_src_debug, "sfsrc", 0, "sfsrc element"); +} + +static void +gst_sf_src_class_init (GstSFSrcClass * klass) +{ + GObjectClass *gobject_class; + GstBaseSrcClass *gstbasesrc_class; + + gobject_class = G_OBJECT_CLASS (klass); + gstbasesrc_class = GST_BASE_SRC_CLASS (klass); + + gobject_class->set_property = gst_sf_src_set_property; + gobject_class->get_property = gst_sf_src_get_property; + + g_object_class_install_property (gobject_class, PROP_LOCATION, + g_param_spec_string ("location", "File Location", + "Location of the file to read", NULL, G_PARAM_READWRITE)); + + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_sf_src_finalize); + + gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_sf_src_start); + gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_sf_src_stop); + gstbasesrc_class->is_seekable = GST_DEBUG_FUNCPTR (gst_sf_src_is_seekable); + gstbasesrc_class->get_size = GST_DEBUG_FUNCPTR (gst_sf_src_get_size); + gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_sf_src_create); + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_sf_src_get_caps); + gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_sf_src_set_caps); + gstbasesrc_class->check_get_range = + GST_DEBUG_FUNCPTR (gst_sf_src_check_get_range); + gstbasesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_sf_src_fixate); +} + +static void +gst_sf_src_init (GstSFSrc * src, GstSFSrcClass * g_class) +{ +} + +static void +gst_sf_src_finalize (GObject * object) +{ + GstSFSrc *src; + + src = GST_SF_SRC (object); + + g_free (src->location); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_sf_src_set_location (GstSFSrc * this, const gchar * location) +{ + if (this->file) + goto was_open; + + if (this->location) + g_free (this->location); + + this->location = location ? g_strdup (location) : NULL; + + return; + +was_open: + { + g_warning ("Changing the `location' property on sfsrc when " + "a file is open not supported."); + return; + } +} + +static void +gst_sf_src_set_property (GObject * object, guint prop_id, const GValue * value, + GParamSpec * pspec) +{ + GstSFSrc *this = GST_SF_SRC (object); + + switch (prop_id) { + case PROP_LOCATION: + gst_sf_src_set_location (this, g_value_get_string (value)); + break; + + default: + break; + } +} + +static void +gst_sf_src_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstSFSrc *this = GST_SF_SRC (object); + + switch (prop_id) { + case PROP_LOCATION: + g_value_set_string (value, this->location); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstFlowReturn +gst_sf_src_create (GstBaseSrc * bsrc, guint64 offset, guint length, + GstBuffer ** buffer) +{ + GstSFSrc *this; + GstBuffer *buf; + gboolean discont = FALSE; + sf_count_t bytes_read; + + this = GST_SF_SRC (bsrc); + + if (G_UNLIKELY (offset % this->bytes_per_frame)) + goto bad_offset; + if (G_UNLIKELY (length % this->bytes_per_frame)) + goto bad_length; + + offset /= this->bytes_per_frame; + + if (G_UNLIKELY (this->offset != offset)) { + sf_count_t pos; + + pos = sf_seek (this->file, offset, SEEK_SET); + + if (G_UNLIKELY (pos < 0 || pos != offset)) + goto seek_failed; + + this->offset = offset; + discont = TRUE; + } + + buf = gst_buffer_new_and_alloc (length); + + /* now make length in frames */ + length /= this->bytes_per_frame; + + bytes_read = this->reader (this->file, GST_BUFFER_DATA (buf), length); + if (G_UNLIKELY (bytes_read < 0)) + goto could_not_read; + + if (G_UNLIKELY (bytes_read == 0 && length > 0)) + goto eos; + + GST_BUFFER_SIZE (buf) = bytes_read * this->bytes_per_frame; + + GST_BUFFER_OFFSET (buf) = offset; + GST_BUFFER_OFFSET_END (buf) = offset + length; + GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (offset, + GST_SECOND, this->rate); + GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (offset + length, + GST_SECOND, this->rate) - GST_BUFFER_TIMESTAMP (buf); + + gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (bsrc))); + + *buffer = buf; + + this->offset += length; + + return GST_FLOW_OK; + + /* ERROR */ +bad_offset: + { + GST_ELEMENT_ERROR (this, RESOURCE, SEEK, + (NULL), ("offset %" G_GUINT64_FORMAT " not divisible by %d bytes per " + "frame", offset, this->bytes_per_frame)); + return GST_FLOW_ERROR; + } +bad_length: + { + GST_ELEMENT_ERROR (this, RESOURCE, SEEK, + (NULL), ("length %" G_GUINT64_FORMAT " not divisible by %d bytes per " + "frame", length, this->bytes_per_frame)); + return GST_FLOW_ERROR; + } +seek_failed: + { + GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); + return GST_FLOW_ERROR; + } +could_not_read: + { + GST_ELEMENT_ERROR (this, RESOURCE, READ, (NULL), GST_ERROR_SYSTEM); + gst_buffer_unref (buf); + return GST_FLOW_ERROR; + } +eos: + { + GST_DEBUG ("EOS, baby"); + gst_buffer_unref (buf); + return GST_FLOW_UNEXPECTED; + } +} + +static gboolean +gst_sf_src_is_seekable (GstBaseSrc * basesrc) +{ + return TRUE; +} + +static gboolean +gst_sf_src_get_size (GstBaseSrc * basesrc, guint64 * size) +{ + GstSFSrc *this; + sf_count_t end; + + this = GST_SF_SRC (basesrc); + + end = sf_seek (this->file, 0, SEEK_END); + + sf_seek (this->file, this->offset, SEEK_SET); + + *size = end * this->bytes_per_frame; + + return TRUE; +} + +static gboolean +gst_sf_src_open_file (GstSFSrc * this) +{ + int mode; + SF_INFO info; + + g_return_val_if_fail (this->file == NULL, FALSE); + + if (!this->location) + goto no_filename; + + mode = SFM_READ; + info.format = 0; + + this->file = sf_open (this->location, mode, &info); + + if (!this->file) + goto open_failed; + + this->channels = info.channels; + this->rate = info.samplerate; + /* do something with info.seekable? */ + + return TRUE; + +no_filename: + { + GST_ELEMENT_ERROR (this, RESOURCE, NOT_FOUND, + (_("No file name specified for writing.")), (NULL)); + return FALSE; + } +open_failed: + { + GST_ELEMENT_ERROR (this, RESOURCE, OPEN_WRITE, + (_("Could not open file \"%s\" for writing."), this->location), + ("soundfile error: %s", sf_strerror (NULL))); + return FALSE; + } +} + +static void +gst_sf_src_close_file (GstSFSrc * this) +{ + int err = 0; + + g_return_if_fail (this->file != NULL); + + GST_INFO_OBJECT (this, "Closing file %s", this->location); + + if ((err = sf_close (this->file))) + goto close_failed; + + this->file = NULL; + this->offset = 0; + this->channels = 0; + this->rate = 0; + + return; + +close_failed: + { + GST_ELEMENT_ERROR (this, RESOURCE, CLOSE, + ("Could not close file file \"%s\".", this->location), + ("soundfile error: %s", sf_error_number (err))); + return; + } +} + +static gboolean +gst_sf_src_start (GstBaseSrc * basesrc) +{ + GstSFSrc *this = GST_SF_SRC (basesrc); + + return gst_sf_src_open_file (this); +} + +/* unmap and close the file */ +static gboolean +gst_sf_src_stop (GstBaseSrc * basesrc) +{ + GstSFSrc *this = GST_SF_SRC (basesrc); + + gst_sf_src_close_file (this); + + return TRUE; +} + +static GstCaps * +gst_sf_src_get_caps (GstBaseSrc * bsrc) +{ + GstSFSrc *this; + GstCaps *ret; + + this = GST_SF_SRC (bsrc); + + ret = gst_caps_copy (gst_pad_get_pad_template_caps (bsrc->srcpad)); + + if (this->file) { + GstStructure *s; + gint i; + + for (i = 0; i < gst_caps_get_size (ret); i++) { + s = gst_caps_get_structure (ret, i); + gst_structure_set (s, "channels", G_TYPE_INT, this->channels, + "rate", G_TYPE_INT, this->rate, NULL); + } + } + + return ret; +} + +static gboolean +gst_sf_src_set_caps (GstBaseSrc * bsrc, GstCaps * caps) +{ + GstSFSrc *this = (GstSFSrc *) bsrc; + GstStructure *structure; + gint width; + + structure = gst_caps_get_structure (caps, 0); + + if (!this->file) + goto file_not_open; + + if (!gst_structure_get_int (structure, "width", &width)) + goto impossible; + + if (gst_structure_has_name (structure, "audio/x-raw-int")) { + switch (width) { + case 16: + this->reader = (GstSFReader) sf_readf_short; + break; + case 32: + this->reader = (GstSFReader) sf_readf_int; + break; + default: + goto impossible; + } + } else { + switch (width) { + case 32: + this->reader = (GstSFReader) sf_readf_float; + break; + default: + goto impossible; + } + } + + this->bytes_per_frame = width * this->channels / 8; + + return TRUE; + +impossible: + { + g_warning ("something impossible happened"); + return FALSE; + } +file_not_open: + { + GST_WARNING_OBJECT (this, "file has to be open in order to set caps"); + return FALSE; + } +} + +static gboolean +gst_sf_src_check_get_range (GstBaseSrc * bsrc) +{ + return TRUE; +} + +static void +gst_sf_src_fixate (GstBaseSrc * bsrc, GstCaps * caps) +{ + GstStructure *s; + gint width, depth; + + s = gst_caps_get_structure (caps, 0); + + gst_structure_fixate_field_nearest_int (s, "width", 16); + + /* fields for int */ + if (gst_structure_has_field (s, "depth")) { + gst_structure_get_int (s, "width", &width); + /* round width to nearest multiple of 8 for the depth */ + depth = GST_ROUND_UP_8 (width); + gst_structure_fixate_field_nearest_int (s, "depth", depth); + } + if (gst_structure_has_field (s, "signed")) + gst_structure_fixate_field_boolean (s, "signed", TRUE); + if (gst_structure_has_field (s, "endianness")) + gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER); +} diff --git a/ext/sndfile/gstsfsrc.h b/ext/sndfile/gstsfsrc.h new file mode 100644 index 000000000..7f9fedb99 --- /dev/null +++ b/ext/sndfile/gstsfsrc.h @@ -0,0 +1,69 @@ +/* GStreamer libsndfile plugin + * Copyright (C) 2003,2007 Andy Wingo <wingo at pobox dot com> + * + * 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_SF_SRC_H__ +#define __GST_SF_SRC_H__ + + +#include "gstsf.h" +#include <gst/base/gstbasesrc.h> + + +G_BEGIN_DECLS + + +#define GST_TYPE_SF_SRC \ + (gst_sf_src_get_type()) +#define GST_SF_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SF_SRC,GstSFSrc)) +#define GST_SF_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SF_SRC,GstSFSrcClass)) +#define GST_IS_SF_SRC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SF_SRC)) +#define GST_IS_SF_SRC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SF_SRC)) + +typedef struct _GstSFSrc GstSFSrc; +typedef struct _GstSFSrcClass GstSFSrcClass; + +typedef sf_count_t (*GstSFReader)(SNDFILE *f, void *data, sf_count_t nframes); + +struct _GstSFSrc { + GstBaseSrc parent; + + gchar *location; + SNDFILE *file; + sf_count_t offset; + GstSFReader reader; + gint bytes_per_frame; + + gint channels; + gint rate; +}; + +struct _GstSFSrcClass { + GstBaseSrcClass parent_class; +}; + + +G_END_DECLS + + +#endif /* __GST_SF_SRC_H__ */ |