Commit 18a5bfb3 authored by François Cartegnie's avatar François Cartegnie 🤞

chromaprint: add stream out chromaprint module

parent 4e5004f5
......@@ -3831,6 +3831,11 @@ dnl goom visualization plugin
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
......
......@@ -312,6 +312,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
......
......@@ -13,6 +13,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 \
......@@ -60,3 +61,4 @@ libstream_out_raop_plugin_la_LIBADD = $(AM_LIBADD) $(GCRYPT_LIBS) -lgpg-error $(
if HAVE_GCRYPT
libvlc_LTLIBRARIES += libstream_out_raop_plugin.la
endif
/*****************************************************************************
* 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 ( unlikely( ! 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=%u;FINGERPRINT=%s",
p_sys->p_data->i_duration,
p_sys->p_data->psz_fingerprint );
}
} else {
msg_Dbg( p_stream, "Cannot create %us 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 );
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_S16N || p_fmt->audio.i_channels > 2 )
{
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 %uHz %uch samples",
p_fmt->audio.i_rate, id->i_channels );
goto error;
}
else
{
p_sys->id = id;
msg_Dbg( p_stream, "Starting chromaprint on %uHz %uch samples",
p_fmt->audio.i_rate, id->i_channels );
}
return id;
}
error:
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.. */
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 )
{
/* drop the whole buffer at once */
block_ChainRelease( p_buf );
return VLC_SUCCESS;
}
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;
}
return VLC_SUCCESS;
}
/*****************************************************************************
* 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;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment