diff options
author | Eric Buehl <eric.buehl@gmail.com> | 2008-03-19 18:14:17 +0000 |
---|---|---|
committer | Sebastian Dröge <slomo@circular-chaos.org> | 2008-03-19 18:14:17 +0000 |
commit | ef2cb71d5fcad4dc3cbc239368a7bb9c30206761 (patch) | |
tree | fa5920a13c4b97898006780e1239196c0fe4bc94 | |
parent | 603b409c33ecc45e2e9b42e368ada98ff0c14d94 (diff) | |
download | gst-plugins-bad-ef2cb71d5fcad4dc3cbc239368a7bb9c30206761.tar.gz gst-plugins-bad-ef2cb71d5fcad4dc3cbc239368a7bb9c30206761.tar.bz2 gst-plugins-bad-ef2cb71d5fcad4dc3cbc239368a7bb9c30206761.zip |
Add an OFA element, the successor of MusicBrainz TRM fingerprinting.
Original commit message from CVS:
Based on a patch by: Eric Buehl <eric dot buehl at gmail dot com>
* configure.ac:
* ext/ofa/Makefile.am:
* ext/ofa/gstofa.c: (gst_ofa_base_init), (gst_ofa_finalize),
(gst_ofa_class_init), (create_fingerprint), (gst_ofa_event),
(gst_ofa_init), (gst_ofa_transform_ip), (gst_ofa_get_property),
(plugin_init):
* ext/ofa/gstofa.h:
Add an OFA element, the successor of MusicBrainz TRM fingerprinting.
Fixes bug #351309.
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | configure.ac | 13 | ||||
-rw-r--r-- | ext/ofa/Makefile.am | 18 | ||||
-rw-r--r-- | ext/ofa/gstofa.c | 250 | ||||
-rw-r--r-- | ext/ofa/gstofa.h | 79 |
5 files changed, 374 insertions, 0 deletions
@@ -1,3 +1,17 @@ +2008-03-19 Sebastian Dröge <slomo@circular-chaos.org> + + Based on a patch by: Eric Buehl <eric dot buehl at gmail dot com> + + * configure.ac: + * ext/ofa/Makefile.am: + * ext/ofa/gstofa.c: (gst_ofa_base_init), (gst_ofa_finalize), + (gst_ofa_class_init), (create_fingerprint), (gst_ofa_event), + (gst_ofa_init), (gst_ofa_transform_ip), (gst_ofa_get_property), + (plugin_init): + * ext/ofa/gstofa.h: + Add an OFA element, the successor of MusicBrainz TRM fingerprinting. + Fixes bug #351309. + 2008-03-18 Andy Wingo <wingo@pobox.com> * ext/faad/gstfaad.c (gst_faad_chain): Fix a bad format argument, diff --git a/configure.ac b/configure.ac index 16aa5ea1..10372ef1 100644 --- a/configure.ac +++ b/configure.ac @@ -845,6 +845,17 @@ AG_GST_CHECK_FEATURE(NEON, [neon http client plugins], neonhttpsrc, [ AC_SUBST(NEON_LIBS) ]) +dnl *** ofa *** +translit(dnm, m, l) AM_CONDITIONAL(USE_OFA, true) +AG_GST_CHECK_FEATURE(OFA, [ofa plugins], ofa, [ + PKG_CHECK_MODULES(OFA, libofa >= 0.9.3, HAVE_OFA="yes", [ + HAVE_OFA="no" + AC_MSG_RESULT(no) + ]) + AC_SUBST(OFA_CFLAGS) + AC_SUBST(OFA_LIBS) +]) + dnl *** soup *** translit(dnm, m, l) AM_CONDITIONAL(USE_SOUP, true) AG_GST_CHECK_FEATURE(SOUP, [soup http client plugin (2.4)], souphttpsrc, [ @@ -1044,6 +1055,7 @@ AM_CONDITIONAL(USE_MUSICBRAINZ, false) AM_CONDITIONAL(USE_MYTHTV, false) AM_CONDITIONAL(USE_NAS, false) AM_CONDITIONAL(USE_NEON, false) +AM_CONDITIONAL(USE_OFA, false) AM_CONDITIONAL(USE_SOUP, false) AM_CONDITIONAL(USE_SDL, false) AM_CONDITIONAL(USE_SNDFILE, false) @@ -1192,6 +1204,7 @@ ext/musepack/Makefile ext/musicbrainz/Makefile ext/mythtv/Makefile ext/neon/Makefile +ext/ofa/Makefile ext/soup/Makefile ext/sdl/Makefile ext/sndfile/Makefile diff --git a/ext/ofa/Makefile.am b/ext/ofa/Makefile.am new file mode 100644 index 00000000..346ec8d8 --- /dev/null +++ b/ext/ofa/Makefile.am @@ -0,0 +1,18 @@ +plugin_LTLIBRARIES = libgstofa.la + +libgstofa_la_SOURCES = gstofa.c + +libgstofa_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ + $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) \ + $(OFA_CFLAGS) + +libgstofa_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ + -lgstaudio-$(GST_MAJORMINOR) \ + $(GST_BASE_LIBS) \ + $(GST_LIBS) \ + $(OFA_LIBS) + +libgstofa_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = gstofa.h diff --git a/ext/ofa/gstofa.c b/ext/ofa/gstofa.c new file mode 100644 index 00000000..cf86048d --- /dev/null +++ b/ext/ofa/gstofa.c @@ -0,0 +1,250 @@ +/* GStreamer + * + * gstofa.c + * + * Copyright (C) 2006 M. Derezynski + * Copyright (C) 2008 Eric Buehl + * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gst/gst.h> +#include <ofa1/ofa.h> +#include "gstofa.h" + +#define PAD_CAPS \ + "audio/x-raw-int, " \ + "rate = (int) [ 1, MAX ], " \ + "channels = (int) [ 1, 2 ], " \ + "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ + "width = (int) { 16 }, " \ + "depth = (int) { 16 }, " \ + "signed = (boolean) true" + +GST_DEBUG_CATEGORY_STATIC (gst_ofa_debug); +#define GST_CAT_DEFAULT gst_ofa_debug + +enum +{ + PROP_0, + PROP_FINGERPRINT, +}; + + +#define _do_init(bla) \ + GST_DEBUG_CATEGORY_INIT (gst_ofa_debug, "ofa", 0, "ofa element"); + +GST_BOILERPLATE_FULL (GstOFA, gst_ofa, GstAudioFilter, + GST_TYPE_AUDIO_FILTER, _do_init); + +static void gst_ofa_finalize (GObject * object); +static void gst_ofa_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static GstFlowReturn gst_ofa_transform_ip (GstBaseTransform * trans, + GstBuffer * buf); +static gboolean gst_ofa_event (GstBaseTransform * trans, GstEvent * event); + +static void +gst_ofa_base_init (gpointer g_class) +{ + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class); + GstAudioFilterClass *audio_filter_class = (GstAudioFilterClass *) g_class; + GstCaps *caps; + + gst_element_class_set_details_simple (gstelement_class, "OFA", + "MusicIP Fingerprinting element", + "Find a music fingerprint using MusicIP's libofa", + "Milosz Derezynski <internalerror@gmail.com>, Eric Buehl <eric.buehl@gmail.com>"); + + caps = gst_caps_from_string (PAD_CAPS); + gst_audio_filter_class_add_pad_templates (audio_filter_class, caps); + gst_caps_unref (caps); +} + +static void +gst_ofa_finalize (GObject * object) +{ + GstOFA *ofa = GST_OFA (object); + + if (ofa->adapter) { + g_object_unref (ofa->adapter); + ofa->adapter = NULL; + } + + g_free (ofa->fingerprint); + ofa->fingerprint = NULL; + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gst_ofa_class_init (GstOFAClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GstBaseTransformClass *gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass); + + gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_ofa_get_property); + + g_object_class_install_property (gobject_class, PROP_FINGERPRINT, + g_param_spec_string ("fingerprint", "Resulting fingerprint", + "Resulting fingerprint", NULL, G_PARAM_READABLE)); + + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ofa_finalize); + + gstbasetrans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_ofa_transform_ip); + gstbasetrans_class->event = GST_DEBUG_FUNCPTR (gst_ofa_event); + gstbasetrans_class->passthrough_on_same_caps = TRUE; +} + +static void +create_fingerprint (GstOFA * ofa) +{ + GstBuffer *buf; + gint rate = GST_AUDIO_FILTER (ofa)->format.rate; + gint channels = GST_AUDIO_FILTER (ofa)->format.channels; + gint width = GST_AUDIO_FILTER (ofa)->format.width / 8; + gint endianness = + (GST_AUDIO_FILTER (ofa)->format. + bigend) ? OFA_BIG_ENDIAN : OFA_LITTLE_ENDIAN; + GstTagList *tags; + + buf = + gst_adapter_take_buffer (ofa->adapter, + gst_adapter_available (ofa->adapter)); + + ofa->fingerprint = g_strdup (ofa_create_print (GST_BUFFER_DATA (buf), + endianness, + GST_BUFFER_SIZE (buf) / width, rate, (channels == 2) ? 1 : 0)); + + gst_buffer_unref (buf); + + tags = gst_tag_list_new (); + gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, + GST_TAG_OFA_FINGERPRINT, ofa->fingerprint, NULL); + gst_element_found_tags (GST_ELEMENT (ofa), tags); + + ofa->record = FALSE; +} + +static gboolean +gst_ofa_event (GstBaseTransform * trans, GstEvent * event) +{ + GstOFA *ofa = GST_OFA (trans); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_STOP: + case GST_EVENT_NEWSEGMENT: + gst_adapter_clear (ofa->adapter); + ofa->record = TRUE; + g_free (ofa->fingerprint); + ofa->fingerprint = NULL; + break; + case GST_EVENT_EOS: + /* we got to the end of the stream but never generated a fingerprint + * (probably under 135 seconds) + */ + if (!ofa->fingerprint) + create_fingerprint (ofa); + break; + default: + break; + } + + return TRUE; +} + +static void +gst_ofa_init (GstOFA * ofa, GstOFAClass * g_class) +{ + gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (ofa), TRUE); + + ofa->fingerprint = NULL; + ofa->record = TRUE; + + ofa->adapter = gst_adapter_new (); +} + +static GstFlowReturn +gst_ofa_transform_ip (GstBaseTransform * trans, GstBuffer * buf) +{ + GstOFA *ofa = GST_OFA (trans); + guint64 nframes; + GstClockTime duration; + gint rate = GST_AUDIO_FILTER (ofa)->format.rate; + gint channels = GST_AUDIO_FILTER (ofa)->format.channels; + gint width = GST_AUDIO_FILTER (ofa)->format.width / 8; + + g_return_val_if_fail (rate > 0 && channels > 0 + && width > 0, GST_FLOW_NOT_NEGOTIATED); + + if (ofa->record) + gst_adapter_push (ofa->adapter, gst_buffer_copy (buf)); + + nframes = + gst_util_uint64_scale (gst_adapter_available (ofa->adapter), 1, + channels * width); + duration = + GST_FRAMES_TO_CLOCK_TIME (gst_adapter_available (ofa->adapter), rate); + + if (duration >= 135 * GST_SECOND && ofa->fingerprint == NULL) + create_fingerprint (ofa); + + return GST_FLOW_OK; +} + +static void +gst_ofa_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstOFA *ofa = GST_OFA (object); + + switch (prop_id) { + case PROP_FINGERPRINT: + g_value_set_string (value, ofa->fingerprint); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + gboolean ret; + + ret = gst_element_register (plugin, "ofa", GST_RANK_NONE, GST_TYPE_OFA); + + if (ret) { + /* TODO: get this into core */ + gst_tag_register (GST_TAG_OFA_FINGERPRINT, GST_TAG_FLAG_META, + G_TYPE_STRING, "ofa fingerprint", "OFA fingerprint", NULL); + } + + return ret; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "ofa", + "Calculate MusicIP fingerprint from audio files", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/ext/ofa/gstofa.h b/ext/ofa/gstofa.h new file mode 100644 index 00000000..347a8ca4 --- /dev/null +++ b/ext/ofa/gstofa.h @@ -0,0 +1,79 @@ +/* GStreamer + * + * gstofa.h + * + * Copyright (C) 2006 M. Derezynski + * Copyright (C) 2008 Eric Buehl + * Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.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., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __GST_OFA_H__ +#define __GST_OFA_H__ + +#include <gst/gst.h> +#include <gst/base/gstadapter.h> +#include <gst/audio/gstaudiofilter.h> +#include <gst/audio/audio.h> + +G_BEGIN_DECLS + +#define GST_TYPE_OFA \ + (gst_ofa_get_type()) +#define GST_OFA(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OFA,GstOFA)) +#define GST_OFA_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OFA,GstOFAClass)) +#define GST_IS_OFA(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OFA)) +#define GST_IS_OFA_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OFA)) + +#define GST_TAG_OFA_FINGERPRINT "ofa-fingerprint" + +typedef struct _GstOFA GstOFA; +typedef struct _GstOFAClass GstOFAClass; + + +/** + * GstOFA: + * + * Opaque #GstOFA data structure + */ + +struct _GstOFA +{ + GstAudioFilter element; + + /*< private > */ + + GstAdapter *adapter; + char *fingerprint; + gboolean record; +}; + +struct _GstOFAClass +{ + GstAudioFilterClass parent_class; +}; + +GType gst_ofa_get_type (void); + +G_END_DECLS + +#endif /* __GST_OFA_H__ */ |