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

Rémi Denis-Courmont remi at remlab.net
Tue Mar 26 14:13:21 CET 2013


On Tue, 19 Mar 2013 00:41:16 +0100, Francois Cartegnie <fcvlcdev at free.fr>
wrote:
> ---
>  configure.ac                          |    5 +
>  modules/LIST                          |    1 +
>  modules/stream_out/Modules.am         |    2 +
>  modules/stream_out/chromaprint.c      |  249
>  +++++++++++++++++++++++++++++++++
>  modules/stream_out/chromaprint_data.h |   27 ++++
>  5 files changed, 284 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 d4e1e89..8b52e8e 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -3763,6 +3763,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/LIST b/modules/LIST
> index 5d23040..4a1bdeb 100644
> --- a/modules/LIST
> +++ b/modules/LIST
> @@ -311,6 +311,7 @@ $Id$
>   * stream_filter_rar: Stream filter to read inside Rar files
>   * stream_out_autodel: monitor mux inputs and automatically add/delete
>   streams
>   * stream_out_bridge: "exchange" streams between sout instances. To be
>   used with VLM
> + * stream_out_chromaprint: Audio fingerprinter 
>   * stream_out_delay: introduce delay in an ES when streaming
>   * stream_out_description: helper module for RTSP vod
>   * stream_out_display: displays a stream output chain
> 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..d0c8163
> --- /dev/null
> +++ b/modules/stream_out/chromaprint.c
> @@ -0,0 +1,249 @@
>
+/*****************************************************************************
> + * 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_samplerate;
> +};
> +
> +#define BYTESPERSAMPLE 2
> +
>
+/*****************************************************************************
> + * 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;

unlikely()

> +    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 )

This seems to be a tautology.

> +        chromaprint_free( p_sys->p_chromaprint_ctx );
> +
> +    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 || p_fmt->audio.i_channels
>
> 2 )

Again, is this really correct on big endian? It seems dubious.

> +        {
> +            msg_Warn( p_stream, "bad input format: need s16l, 1 or 2
> channels" );
> +            goto error;
> +        }
> +
> +        id = malloc( sizeof( sout_stream_id_t ) );
> +        if ( !id ) goto error;
> +
> +        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 ( !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 );

%u for unsigned

> +        }
> +        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 );

Seriously:

if( p_sys->id == id )
    p_sys->id = NULL;
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 / (BYTESPERSAMPLE *
> 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 / BYTESPERSAMPLE
)
> )
> +                    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 );

Fine but eliminating this case at the top would avoid indentation and long
if statement.

> +    }
> +    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;

-- 
Rémi Denis-Courmont
Sent from my collocated server



More information about the vlc-devel mailing list