[vlc-devel] [PATCH 1/4] chromaprint: add stream out chromaprint module

Francois Cartegnie fcvlcdev at free.fr
Tue Feb 26 13:51:49 CET 2013


---
 configure.ac                          |    5 +
 modules/stream_out/Modules.am         |    2 +
 modules/stream_out/chromaprint.c      |  252 +++++++++++++++++++++++++++++++++
 modules/stream_out/chromaprint_data.h |   27 ++++
 4 files changed, 286 insertions(+), 0 deletions(-)
 create mode 100644 modules/stream_out/chromaprint.c
 create mode 100644 modules/stream_out/chromaprint_data.h

diff --git a/configure.ac b/configure.ac
index 238de73..c8d36a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3767,6 +3767,11 @@ dnl
 PKG_ENABLE_MODULES_VLC([GOOM], [], [libgoom2], [goom visualization plugin], [auto])
 
 dnl
+dnl  chromaprint audio track fingerprinter
+dnl
+PKG_ENABLE_MODULES_VLC([CHROMAPRINT], [stream_out_chromaprint], [libchromaprint >= 6.0], (Chromaprint based audio fingerprinter), [auto])
+
+dnl
 dnl libprojectM visualization plugin
 dnl
 AC_ARG_ENABLE(projectm,
diff --git a/modules/stream_out/Modules.am b/modules/stream_out/Modules.am
index 26ad06b..6ddffea 100644
--- a/modules/stream_out/Modules.am
+++ b/modules/stream_out/Modules.am
@@ -14,6 +14,7 @@ SOURCES_stream_out_record = record.c
 SOURCES_stream_out_smem = smem.c
 SOURCES_stream_out_setid = setid.c
 SOURCES_stream_out_langfromtelx = langfromtelx.c
+SOURCES_stream_out_chromaprint = chromaprint.c chromaprint_data.h
 
 libstream_out_transcode_plugin_la_SOURCES = \
 	transcode/transcode.c transcode/transcode.h \
@@ -61,3 +62,4 @@ libstream_out_raop_plugin_la_LIBADD = $(AM_LIBADD) $(GCRYPT_LIBS) -lgpg-error $(
 if HAVE_GCRYPT
 libvlc_LTLIBRARIES += libstream_out_raop_plugin.la
 endif
+
diff --git a/modules/stream_out/chromaprint.c b/modules/stream_out/chromaprint.c
new file mode 100644
index 0000000..795c8fb
--- /dev/null
+++ b/modules/stream_out/chromaprint.c
@@ -0,0 +1,252 @@
+/*****************************************************************************
+ * chromaprint.c: Chromaprint Fingerprinter Module
+ *****************************************************************************
+ * Copyright (C) 2012 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_input.h>
+#include <vlc_block.h>
+#include <vlc_sout.h>
+
+#include <assert.h>
+
+#include <chromaprint.h> /* chromaprint lib */
+#include "chromaprint_data.h"
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+static int      Open    ( vlc_object_t * );
+static void     Close   ( vlc_object_t * );
+
+static sout_stream_id_t *Add ( sout_stream_t *, es_format_t * );
+static int               Del ( sout_stream_t *, sout_stream_id_t * );
+static int               Send( sout_stream_t *, sout_stream_id_t *, block_t* );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+#define DURATION_TEXT N_("Duration of the fingerprinting" )
+#define DURATION_LONGTEXT N_("Default: 90sec")
+
+vlc_module_begin ()
+    set_description( N_("Chromaprint stream output") )
+    set_capability( "sout stream", 0 )
+    add_shortcut( "chromaprint" )
+    add_integer( "duration", 90, DURATION_TEXT, DURATION_LONGTEXT, true )
+    set_callbacks( Open, Close )
+vlc_module_end ()
+
+struct sout_stream_sys_t
+{
+    unsigned int i_duration;
+    unsigned int i_total_samples;
+    int i_samples;
+    bool b_finished;
+    bool b_done;
+    ChromaprintContext *p_chromaprint_ctx;
+    sout_stream_id_t *id;
+    chromaprint_fingerprint_t *p_data;
+};
+
+struct sout_stream_id_t
+{
+    int i_samples;
+    unsigned int i_channels;
+    unsigned int i_samplesize;
+    unsigned int i_samplerate;
+};
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+    sout_stream_t *p_stream = (sout_stream_t*)p_this;
+    sout_stream_sys_t *p_sys;
+
+    p_stream->p_sys = p_sys = malloc(sizeof(sout_stream_sys_t));
+    if ( ! p_sys ) return VLC_ENOMEM;
+    p_sys->id = NULL;
+    p_sys->b_finished = false;
+    p_sys->b_done = false;
+    p_sys->i_total_samples = 0;
+    p_sys->i_duration = var_InheritInteger( p_stream, "duration" );
+    p_sys->p_data = var_InheritAddress( p_stream, "fingerprint-data" );
+    if ( !p_sys->p_data )
+    {
+        msg_Err( p_stream, "Fingerprint data holder not set" );
+        free( p_sys );
+        return VLC_ENOVAR;
+    }
+    msg_Dbg( p_stream, "chromaprint version %s", chromaprint_get_version() );
+    p_sys->p_chromaprint_ctx = chromaprint_new( CHROMAPRINT_ALGORITHM_DEFAULT );
+    if ( ! p_sys->p_chromaprint_ctx )
+    {
+        msg_Err( p_stream, "Can't create chromaprint context" );
+        free( p_sys );
+        return VLC_EGENERIC;
+    }
+    p_stream->pf_add  = Add;
+    p_stream->pf_del  = Del;
+    p_stream->pf_send = Send;
+    return VLC_SUCCESS;
+}
+
+static void Finish( sout_stream_t *p_stream )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    char *psz_fingerprint = NULL;
+    if ( p_sys->b_finished && chromaprint_finish( p_sys->p_chromaprint_ctx ) )
+    {
+        chromaprint_get_fingerprint( p_sys->p_chromaprint_ctx,
+                                     &psz_fingerprint );
+        if ( psz_fingerprint )
+        {
+            p_sys->p_data->i_duration = p_sys->i_total_samples / p_sys->id->i_samplerate;
+            p_sys->p_data->psz_fingerprint = strdup( psz_fingerprint );
+            chromaprint_dealloc( psz_fingerprint );
+            msg_Dbg( p_stream, "DURATION=%d;FINGERPRINT=%s",
+                    p_sys->p_data->i_duration,
+                    p_sys->p_data->psz_fingerprint );
+        }
+    } else {
+        msg_Dbg( p_stream, "Cannot create %ds fingerprint (not enough samples?)",
+                 p_sys->i_duration );
+    }
+    p_sys->b_done = true;
+    msg_Dbg( p_stream, "Fingerprinting finished" );
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+static void Close( vlc_object_t * p_this )
+{
+    sout_stream_t *p_stream = (sout_stream_t *)p_this;
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+
+    if ( !p_sys->b_done ) Finish( p_stream );
+
+    if ( !p_sys->p_chromaprint_ctx ) goto end;
+    chromaprint_free( p_sys->p_chromaprint_ctx );
+end:
+    free( p_sys );
+}
+
+static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    sout_stream_id_t *id = NULL;
+
+    if ( p_fmt->i_cat == AUDIO_ES && !p_sys->id )
+    {
+        if( p_fmt->i_codec != VLC_CODEC_S16L )
+        {
+            msg_Warn( p_stream, "bad input format: need s16l" );
+            goto error;
+        }
+
+        id = malloc( sizeof( sout_stream_id_t ) );
+        if ( !id ) goto error;
+
+        id->i_samplesize = p_fmt->audio.i_bitspersample >> 3;
+        id->i_channels = p_fmt->audio.i_channels;
+        id->i_samplerate = p_fmt->audio.i_rate;
+        id->i_samples = p_sys->i_duration * id->i_samplerate;
+
+        if ( id->i_channels > 2 || !p_sys->p_chromaprint_ctx )
+            goto error;
+
+        if ( !chromaprint_start( p_sys->p_chromaprint_ctx, p_fmt->audio.i_rate, id->i_channels ) )
+        {
+            msg_Err( p_stream, "Failed starting chromaprint on %dHz %dch samples",
+                     p_fmt->audio.i_rate, id->i_channels );
+            goto error;
+        }
+        else
+        {
+            p_sys->id = id;
+            msg_Dbg( p_stream, "Starting chromaprint on %dHz %dch samples",
+                     p_fmt->audio.i_rate, id->i_channels );
+        }
+        return id;
+    }
+
+error:
+    if ( id != NULL )
+        free( id );
+    return NULL;
+}
+
+static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    Finish( p_stream );
+    if ( p_sys->id == id ) /* not assuming only 1 id is in use.. */
+        FREENULL( p_sys->id );
+    else
+        free( id );
+    return VLC_SUCCESS;
+}
+
+static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
+                 block_t *p_buf )
+{
+    sout_stream_sys_t *p_sys = p_stream->p_sys;
+    if ( p_sys->id == id )
+    {
+        while( p_buf )
+        {
+            block_t *p_next;
+            int i_samples = p_buf->i_buffer / (id->i_samplesize * id->i_channels);
+            p_sys->i_total_samples += i_samples;
+            if ( !p_sys->b_finished && id->i_samples > 0 && p_buf->i_buffer )
+            {
+                if(! chromaprint_feed( p_sys->p_chromaprint_ctx,
+                                       p_buf->p_buffer,
+                                       p_buf->i_buffer / id->i_samplesize ) )
+                    msg_Warn( p_stream, "feed error" );
+                id->i_samples -= i_samples;
+                if ( id->i_samples < 1 && !p_sys->b_finished )
+                {
+                    p_sys->b_finished = true;
+                    msg_Dbg( p_stream, "Fingerprint collection finished" );
+                }
+            }
+            p_next = p_buf->p_next;
+            block_Release( p_buf );
+            p_buf = p_next;
+        }
+    }
+    else
+    {
+        /* drop the whole buffer at once */
+        block_ChainRelease( p_buf );
+    }
+    return VLC_SUCCESS;
+}
diff --git a/modules/stream_out/chromaprint_data.h b/modules/stream_out/chromaprint_data.h
new file mode 100644
index 0000000..6fc3077
--- /dev/null
+++ b/modules/stream_out/chromaprint_data.h
@@ -0,0 +1,27 @@
+/*****************************************************************************
+ * chromaprint_data.h: Chromaprint's sout fingerprint data header
+ *****************************************************************************
+ * Copyright (C) 2012 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+struct chromaprint_fingerprint_t
+{
+    char *psz_fingerprint;
+    unsigned int i_duration;
+};
+
+typedef struct chromaprint_fingerprint_t chromaprint_fingerprint_t;
-- 
1.7.9




More information about the vlc-devel mailing list