ofa: port to 1.0

This commit is contained in:
Tim-Philipp Müller 2013-05-12 22:41:32 +01:00
parent 0c23ac0565
commit 020c93b973
5 changed files with 92 additions and 118 deletions

View file

@ -346,7 +346,7 @@ GST_PLUGINS_NONPORTED=" cdxaparse \
linsys vcd \
apexsink cdaudio dc1394 dirac directfb \
gsettings \
musepack nas ofa openal sdl sndfile timidity \
musepack nas openal sdl sndfile timidity \
directdraw direct3d9 acm wininet \
xvid lv2 teletextdec sndio osx_video quicktime"
AC_SUBST(GST_PLUGINS_NONPORTED)

View file

@ -8,8 +8,8 @@ libgstofa_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
$(OFA_CFLAGS)
libgstofa_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
-lgstaudio-$(GST_API_VERSION) \
$(GST_BASE_LIBS) \
-lgstaudio-$(GST_API_VERSION) \
$(GST_BASE_LIBS) \
$(GST_LIBS) \
$(OFA_LIBS)

View file

@ -1,7 +1,4 @@
/* GStreamer
*
* gstofa.c
*
/* GStreamer ofa fingerprinting element
* Copyright (C) 2006 M. Derezynski
* Copyright (C) 2008 Eric Buehl
* Copyright (C) 2008 Sebastian Dröge <slomo@circular-chaos.org>
@ -31,13 +28,10 @@
#include "gstofa.h"
#define PAD_CAPS \
"audio/x-raw-int, " \
"audio/x-raw, " \
"format = { S16LE, S16BE }, " \
"rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 2 ], " \
"endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) { 16 }, " \
"depth = (int) { 16 }, " \
"signed = (boolean) true"
"channels = (int) [ 1, 2 ]"
GST_DEBUG_CATEGORY_STATIC (gst_ofa_debug);
#define GST_CAT_DEFAULT gst_ofa_debug
@ -48,32 +42,15 @@ enum
PROP_FINGERPRINT,
};
GST_BOILERPLATE (GstOFA, gst_ofa, GstAudioFilter, GST_TYPE_AUDIO_FILTER);
#define parent_class gst_ofa_parent_class
G_DEFINE_TYPE (GstOFA, gst_ofa, GST_TYPE_AUDIO_FILTER);
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_static_metadata (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 gboolean gst_ofa_sink_event (GstBaseTransform * trans, GstEvent * event);
static void
gst_ofa_finalize (GObject * object)
@ -94,34 +71,45 @@ gst_ofa_finalize (GObject * object)
static void
gst_ofa_class_init (GstOFAClass * klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstBaseTransformClass *gstbasetrans_class = GST_BASE_TRANSFORM_CLASS (klass);
GstAudioFilterClass *audio_filter_class = GST_AUDIO_FILTER_CLASS (klass);
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GstCaps *caps;
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_ofa_get_property);
gobject_class->get_property = 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 | G_PARAM_STATIC_STRINGS));
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ofa_finalize);
gobject_class->finalize = 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->sink_event = GST_DEBUG_FUNCPTR (gst_ofa_sink_event);
gstbasetrans_class->passthrough_on_same_caps = TRUE;
gst_element_class_set_static_metadata (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
create_fingerprint (GstOFA * ofa)
{
GstBuffer *buf;
GstAudioFilter *ofa_filter = GST_AUDIO_FILTER (ofa);
gint rate = ofa_filter->format.rate;
gint channels = ofa_filter->format.channels;
gint endianness =
ofa_filter->format.bigend ? OFA_BIG_ENDIAN : OFA_LITTLE_ENDIAN;
GstAudioFilter *audiofilter = GST_AUDIO_FILTER (ofa);
const guint8 *samples;
const gchar *fingerprint;
gint rate, channels, endianness;
GstTagList *tags;
guint available;
gsize available;
available = gst_adapter_available (ofa->adapter);
@ -131,52 +119,60 @@ create_fingerprint (GstOFA * ofa)
return;
}
if (GST_AUDIO_FILTER (ofa)->format.bigend)
rate = GST_AUDIO_INFO_RATE (&audiofilter->info);
channels = GST_AUDIO_INFO_CHANNELS (&audiofilter->info);
if (GST_AUDIO_INFO_ENDIANNESS (&audiofilter->info) == G_BIG_ENDIAN)
endianness = OFA_BIG_ENDIAN;
else
endianness = OFA_LITTLE_ENDIAN;
GST_DEBUG_OBJECT (ofa, "Generating fingerprint for %u samples",
available / 2);
GST_DEBUG_OBJECT (ofa, "Generating fingerprint for %" G_GSIZE_FORMAT
" samples", available / sizeof (gint16));
buf = gst_adapter_take_buffer (ofa->adapter, available);
samples = gst_adapter_map (ofa->adapter, available);
ofa->fingerprint = g_strdup (ofa_create_print (GST_BUFFER_DATA (buf),
endianness, GST_BUFFER_SIZE (buf) / 2, rate,
(channels == 2) ? 1 : 0));
fingerprint = ofa_create_print ((unsigned char *) samples, endianness,
available / sizeof (gint16), rate, (channels == 2) ? 1 : 0);
if (ofa->fingerprint) {
GST_INFO_OBJECT (ofa, "Generated fingerprint: %s", ofa->fingerprint);
} else {
gst_adapter_unmap (ofa->adapter);
gst_adapter_flush (ofa->adapter, available);
if (fingerprint == NULL) {
GST_WARNING_OBJECT (ofa, "Failed to generate fingerprint");
goto done;
}
gst_buffer_unref (buf);
GST_INFO_OBJECT (ofa, "Generated fingerprint: %s", fingerprint);
ofa->fingerprint = g_strdup (fingerprint);
if (ofa->fingerprint) {
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);
// FIXME: combine with upstream tags
tags = gst_tag_list_new (GST_TAG_OFA_FINGERPRINT, ofa->fingerprint, NULL);
gst_pad_push_event (GST_BASE_TRANSFORM_SRC_PAD (ofa),
gst_event_new_tag (tags));
g_object_notify (G_OBJECT (ofa), "fingerprint");
}
g_object_notify (G_OBJECT (ofa), "fingerprint");
done:
ofa->record = FALSE;
}
static gboolean
gst_ofa_event (GstBaseTransform * trans, GstEvent * event)
gst_ofa_sink_event (GstBaseTransform * trans, GstEvent * event)
{
GstOFA *ofa = GST_OFA (trans);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH_STOP:
case GST_EVENT_NEWSEGMENT:
case GST_EVENT_SEGMENT:
GST_DEBUG_OBJECT (ofa, "Got %s event, clearing buffer",
GST_EVENT_TYPE_NAME (event));
gst_adapter_clear (ofa->adapter);
/* FIXME: should we really always reset this instead of using an
* already-existing fingerprint? Assumes fingerprints are always
* extracted in a separate pipeline instead of a live playback
* situation */
ofa->record = TRUE;
g_free (ofa->fingerprint);
ofa->fingerprint = NULL;
@ -192,11 +188,11 @@ gst_ofa_event (GstBaseTransform * trans, GstEvent * event)
break;
}
return TRUE;
return GST_BASE_TRANSFORM_CLASS (parent_class)->sink_event (trans, event);
}
static void
gst_ofa_init (GstOFA * ofa, GstOFAClass * g_class)
gst_ofa_init (GstOFA * ofa)
{
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (ofa), TRUE);
@ -209,14 +205,17 @@ gst_ofa_init (GstOFA * ofa, GstOFAClass * g_class)
static GstFlowReturn
gst_ofa_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
{
GstAudioFilter *audiofilter = GST_AUDIO_FILTER (trans);
GstOFA *ofa = GST_OFA (trans);
GstAudioFilter *ofa_filter = GST_AUDIO_FILTER (ofa);
guint64 nframes;
GstClockTime duration;
gint rate = ofa_filter->format.rate;
gint channels = ofa_filter->format.channels;
gint rate, channels;
g_return_val_if_fail (rate > 0 && channels > 0, GST_FLOW_NOT_NEGOTIATED);
rate = GST_AUDIO_INFO_RATE (&audiofilter->info);
channels = GST_AUDIO_INFO_CHANNELS (&audiofilter->info);
if (rate == 0 || channels == 0)
return GST_FLOW_NOT_NEGOTIATED;
if (!ofa->record)
return GST_FLOW_OK;
@ -253,7 +252,6 @@ static gboolean
plugin_init (GstPlugin * plugin)
{
gboolean ret;
int major, minor, rev;
GST_DEBUG_CATEGORY_INIT (gst_ofa_debug, "ofa", 0, "ofa element");
@ -273,6 +271,7 @@ plugin_init (GstPlugin * plugin)
return ret;
}
/* FIXME: someone write a libofa replacement with an LGPL or BSD license */
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
ofa,

View file

@ -58,7 +58,7 @@ typedef struct _GstOFAClass GstOFAClass;
struct _GstOFA
{
GstAudioFilter element;
GstAudioFilter audiofilter;
/*< private > */
@ -69,7 +69,7 @@ struct _GstOFA
struct _GstOFAClass
{
GstAudioFilterClass parent_class;
GstAudioFilterClass audiofilter_class;
};
GType gst_ofa_get_type (void);

View file

@ -40,7 +40,6 @@ bus_handler (GstBus * bus, GstMessage * message, gpointer data)
else
gst_message_parse_error (message, &gerror, &debug);
gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
gst_message_unref (message);
g_error_free (gerror);
g_free (debug);
g_main_loop_quit (loop);
@ -53,6 +52,13 @@ bus_handler (GstBus * bus, GstMessage * message, gpointer data)
gst_message_parse_tag (message, &tag_list);
GST_DEBUG ("tag message: %" GST_PTR_FORMAT, tag_list);
if (!gst_tag_list_get_value_index (tag_list, "ofa-fingerprint", 0)) {
gst_tag_list_unref (tag_list);
break;
}
fail_unless (gst_tag_list_get_string (tag_list, "ofa-fingerprint", &fpr));
p = fpr;
@ -102,12 +108,8 @@ GST_START_TEST (test_ofa_le_1ch)
capsfilter = gst_element_factory_make ("capsfilter", "capsfilter");
fail_unless (capsfilter != NULL);
caps = gst_caps_new_simple ("audio/x-raw-int",
"rate", G_TYPE_INT, 44100,
"channels", G_TYPE_INT, 1,
"endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
"width", G_TYPE_INT, 16,
"depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S16LE",
"rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 1, NULL);
g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);
gst_caps_unref (caps);
@ -135,7 +137,7 @@ GST_START_TEST (test_ofa_le_1ch)
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
fail_unless (gst_element_query_position (audiotestsrc, &fmt, &position));
fail_unless (gst_element_query_position (audiotestsrc, fmt, &position));
fail_unless (position >= 135 * GST_SECOND);
gst_element_set_state (pipeline, GST_STATE_NULL);
@ -173,12 +175,8 @@ GST_START_TEST (test_ofa_be_1ch)
capsfilter = gst_element_factory_make ("capsfilter", "capsfilter");
fail_unless (capsfilter != NULL);
caps = gst_caps_new_simple ("audio/x-raw-int",
"rate", G_TYPE_INT, 44100,
"channels", G_TYPE_INT, 1,
"endianness", G_TYPE_INT, G_BIG_ENDIAN,
"width", G_TYPE_INT, 16,
"depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S16BE",
"rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 1, NULL);
g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);
gst_caps_unref (caps);
@ -206,7 +204,7 @@ GST_START_TEST (test_ofa_be_1ch)
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
fail_unless (gst_element_query_position (audiotestsrc, &fmt, &position));
fail_unless (gst_element_query_position (audiotestsrc, fmt, &position));
fail_unless (position >= 135 * GST_SECOND);
gst_element_set_state (pipeline, GST_STATE_NULL);
@ -243,12 +241,8 @@ GST_START_TEST (test_ofa_le_2ch)
capsfilter = gst_element_factory_make ("capsfilter", "capsfilter");
fail_unless (capsfilter != NULL);
caps = gst_caps_new_simple ("audio/x-raw-int",
"rate", G_TYPE_INT, 44100,
"channels", G_TYPE_INT, 2,
"endianness", G_TYPE_INT, G_LITTLE_ENDIAN,
"width", G_TYPE_INT, 16,
"depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S16LE",
"rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 2, NULL);
g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);
gst_caps_unref (caps);
@ -276,7 +270,7 @@ GST_START_TEST (test_ofa_le_2ch)
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
fail_unless (gst_element_query_position (audiotestsrc, &fmt, &position));
fail_unless (gst_element_query_position (audiotestsrc, fmt, &position));
fail_unless (position >= 135 * GST_SECOND);
gst_element_set_state (pipeline, GST_STATE_NULL);
@ -314,12 +308,8 @@ GST_START_TEST (test_ofa_be_2ch)
capsfilter = gst_element_factory_make ("capsfilter", "capsfilter");
fail_unless (capsfilter != NULL);
caps = gst_caps_new_simple ("audio/x-raw-int",
"rate", G_TYPE_INT, 44100,
"channels", G_TYPE_INT, 2,
"endianness", G_TYPE_INT, G_BIG_ENDIAN,
"width", G_TYPE_INT, 16,
"depth", G_TYPE_INT, 16, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
caps = gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S16BE",
"rate", G_TYPE_INT, 44100, "channels", G_TYPE_INT, 2, NULL);
g_object_set (G_OBJECT (capsfilter), "caps", caps, NULL);
gst_caps_unref (caps);
@ -347,7 +337,7 @@ GST_START_TEST (test_ofa_be_2ch)
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_main_loop_run (loop);
fail_unless (gst_element_query_position (audiotestsrc, &fmt, &position));
fail_unless (gst_element_query_position (audiotestsrc, fmt, &position));
fail_unless (position >= 135 * GST_SECOND);
gst_element_set_state (pipeline, GST_STATE_NULL);
@ -378,19 +368,4 @@ ofa_suite (void)
return s;
}
int
main (int argc, char **argv)
{
int nf;
Suite *s = ofa_suite ();
SRunner *sr = srunner_create (s);
gst_check_init (&argc, &argv);
srunner_run_all (sr, CK_NORMAL);
nf = srunner_ntests_failed (sr);
srunner_free (sr);
return nf;
}
GST_CHECK_MAIN (ofa)