Commit 0248a7fc authored by Francois Cartegnie's avatar Francois Cartegnie

chromaprint: add fingerprinter module

parent 27431a57
......@@ -124,6 +124,7 @@ $Id$
* fb: video output module for the Linux framebuffer
* fdkaac: AAC encoder using the fdk-aac library
* filesystem: Filesystem access module
* fingerprinter: AcoustID audio fingerprinter using chromaprint
* flac: Flac decoder using libflac
* flacsys: FLAC demuxer
* float_mixer: Precise float audio mixer
......
SOURCES_vod_rtsp = rtsp.c
SOURCES_audioscrobbler = audioscrobbler.c
SOURCES_fingerprinter = fingerprinter.c \
fingerprinter.h \
webservices/acoustid.c \
webservices/json_fixup.h \
webservices/json.c \
webservices/json.h
SOURCES_xml = xml/libxml.c
libexport_plugin_la_SOURCES = \
......@@ -48,6 +54,7 @@ libstats_plugin_la_LIBADD = $(AM_LIBADD)
libvlc_LTLIBRARIES += \
libaudioscrobbler_plugin.la \
libfingerprinter_plugin.la \
liblogger_plugin.la \
libstats_plugin.la
......
This diff is collapsed.
/*****************************************************************************
* acoustid.c: AcoustId webservice parser
*****************************************************************************
* 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_stream.h>
#include <limits.h>
#include <vlc_memory.h>
#include <vlc/vlc.h>
#include "acoustid.h"
#include "use_json.h"
/*****************************************************************************
* Requests lifecycle
*****************************************************************************/
void free_acoustid_result_t( acoustid_result_t * r )
{
free( r->psz_id );
for ( unsigned int i=0; i<r->recordings.count; i++ )
{
free( r->recordings.p_recordings[ i ].psz_artist );
free( r->recordings.p_recordings[ i ].psz_title );
}
free( r->recordings.p_recordings );
}
static json_value * jsongetbyname( json_value *object, const char *psz_name )
{
if ( object->type != json_object ) return NULL;
for ( unsigned int i=0; i < object->u.object.length; i++ )
if ( strcmp( object->u.object.values[i].name, psz_name ) == 0 )
return object->u.object.values[i].value;
return NULL;
}
static void parse_artists( json_value *node, musicbrainz_recording_t *record )
{
/* take only main */
if ( !node || node->type != json_array || node->u.array.length < 1 ) return;
json_value *artistnode = node->u.array.values[ 0 ];
json_value *value = jsongetbyname( artistnode, "name" );
if ( value && value->type == json_string )
record->psz_artist = strdup( value->u.string.ptr );
}
static void parse_recordings( vlc_object_t *p_obj, json_value *node, acoustid_result_t *p_result )
{
if ( !node || node->type != json_array ) return;
p_result->recordings.p_recordings = calloc( node->u.array.length, sizeof(musicbrainz_recording_t) );
if ( ! p_result->recordings.p_recordings ) return;
p_result->recordings.count = node->u.array.length;
for( unsigned int i=0; i<node->u.array.length; i++ )
{
musicbrainz_recording_t *record = & p_result->recordings.p_recordings[ i ];
json_value *recordnode = node->u.array.values[ i ];
if ( !recordnode || recordnode->type != json_object ) break;
json_value *value = jsongetbyname( recordnode, "title" );
if ( value && value->type == json_string )
record->psz_title = strdup( value->u.string.ptr );
value = jsongetbyname( recordnode, "id" );
if ( value && value->type == json_string )
strncpy( record->sz_musicbrainz_id, value->u.string.ptr, MB_ID_SIZE );
parse_artists( jsongetbyname( recordnode, "artists" ), record );
msg_Dbg( p_obj, "recording %d title %s %36s %s", i, record->psz_title, record->sz_musicbrainz_id, record->psz_artist );
}
}
static bool ParseJson( vlc_object_t *p_obj, char *psz_buffer, acoustid_results_t *p_results )
{
json_settings settings;
char psz_error[128];
memset (&settings, 0, sizeof (json_settings));
json_value *root = json_parse_ex( &settings, psz_buffer, psz_error );
if ( root == NULL )
{
msg_Warn( p_obj, "Can't parse json data: %s", psz_error );
goto error;
}
if ( root->type != json_object )
{
msg_Warn( p_obj, "wrong json root node" );
goto error;
}
json_value *node = jsongetbyname( root, "status" );
if ( !node || node->type != json_string )
{
msg_Warn( p_obj, "status node not found or invalid" );
goto error;
}
if ( strcmp( node->u.string.ptr, "ok" ) != 0 )
{
msg_Warn( p_obj, "Bad request status" );
goto error;
}
node = jsongetbyname( root, "results" );
if ( !node || node->type != json_array )
{
msg_Warn( p_obj, "Bad results array or no results" );
goto error;
}
p_results->p_results = calloc( node->u.array.length, sizeof(acoustid_result_t) );
if ( ! p_results->p_results ) goto error;
p_results->count = node->u.array.length;
for( unsigned int i=0; i<node->u.array.length; i++ )
{
json_value *resultnode = node->u.array.values[i];
if ( resultnode && resultnode->type == json_object )
{
acoustid_result_t *p_result = & p_results->p_results[i];
json_value *value = jsongetbyname( resultnode, "score" );
if ( value && value->type == json_double )
p_result->d_score = value->u.dbl;
value = jsongetbyname( resultnode, "id" );
if ( value && value->type == json_string )
p_result->psz_id = strdup( value->u.string.ptr );
parse_recordings( p_obj, jsongetbyname( resultnode, "recordings" ), p_result );
}
}
json_value_free( root );
return true;
error:
if ( root ) json_value_free( root );
return false;
}
struct webrequest_t
{
stream_t *p_stream;
char *psz_url;
char *p_buffer;
};
static void cancelDoAcoustIdWebRequest( void *p_arg )
{
struct webrequest_t *p_request = (struct webrequest_t *) p_arg;
if ( p_request->p_stream )
stream_Delete( p_request->p_stream );
if ( p_request->psz_url )
free( p_request->psz_url );
if ( p_request->p_buffer )
free( p_request->p_buffer );
}
int DoAcoustIdWebRequest( vlc_object_t *p_obj, acoustid_fingerprint_t *p_data )
{
int i_ret;
int i_status;
struct webrequest_t request = { NULL, NULL, NULL };
if ( !p_data->psz_fingerprint ) return VLC_SUCCESS;
i_ret = asprintf( & request.psz_url,
"http://fingerprint.videolan.org/acoustid.php?meta=recordings+tracks+usermeta+releases&duration=%d&fingerprint=%s",
p_data->i_duration, p_data->psz_fingerprint );
if ( i_ret < 1 ) return VLC_EGENERIC;
vlc_cleanup_push( cancelDoAcoustIdWebRequest, &request );
msg_Dbg( p_obj, "Querying AcoustID from %s", request.psz_url );
request.p_stream = stream_UrlNew( p_obj, request.psz_url );
if ( !request.p_stream )
{
i_status = VLC_EGENERIC;
goto cleanup;
}
/* read answer */
i_ret = 0;
for( ;; )
{
int i_read = 65536;
if( i_ret >= INT_MAX - i_read )
break;
request.p_buffer = realloc_or_free( request.p_buffer, 1 + i_ret + i_read );
if( !request.p_buffer )
{
i_status = VLC_ENOMEM;
goto cleanup;
}
i_read = stream_Read( request.p_stream, &request.p_buffer[i_ret], i_read );
if( i_read <= 0 )
break;
i_ret += i_read;
}
stream_Delete( request.p_stream );
request.p_stream = NULL;
request.p_buffer[ i_ret ] = 0;
int i_canc = vlc_savecancel();
if ( ParseJson( p_obj, request.p_buffer, & p_data->results ) )
{
msg_Dbg( p_obj, "results count == %d", p_data->results.count );
} else {
msg_Dbg( p_obj, "No results" );
}
vlc_restorecancel( i_canc );
i_status = VLC_SUCCESS;
cleanup:
vlc_cleanup_run( );
return i_status;
}
/*****************************************************************************
* acoustid.h: AcoustId webservice parser
*****************************************************************************
* 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.
*****************************************************************************/
#define MB_ID_SIZE 36
struct musicbrainz_recording_t
{
char *psz_artist;
char *psz_title;
char sz_musicbrainz_id[MB_ID_SIZE];
};
typedef struct musicbrainz_recording_t musicbrainz_recording_t;
struct acoustid_result_t
{
double d_score;
char *psz_id;
struct
{
unsigned int count;
musicbrainz_recording_t *p_recordings;
} recordings;
};
typedef struct acoustid_result_t acoustid_result_t;
struct acoustid_results_t
{
acoustid_result_t * p_results;
unsigned int count;
};
typedef struct acoustid_results_t acoustid_results_t;
struct acoustid_fingerprint_t
{
char *psz_fingerprint;
unsigned int i_duration;
acoustid_results_t results;
};
typedef struct acoustid_fingerprint_t acoustid_fingerprint_t;
int DoAcoustIdWebRequest( vlc_object_t *p_obj, acoustid_fingerprint_t *p_data );
void free_acoustid_result_t( acoustid_result_t * r );
This diff is collapsed.
/*****************************************************************************
* json.h: json-parser fixups
*****************************************************************************
* 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.
*****************************************************************************/
#ifndef _JSON_H
#ifndef _JSONFIXUPS_H
#define _JSONFIXUPS_H
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_charset.h>
/* json.c depends on the locale */
#define strtod(foo,bar) us_strtod(foo,bar)
#include "use_json.h"
#endif
#endif
/* vim: set et ts=3 sw=3 ft=c:
*
* Copyright (C) 2012 James McLaughlin et al. All rights reserved.
* https://github.com/udp/json-parser
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _JSON_H
#define _JSON_H
#ifndef json_char
#define json_char char
#endif
#ifdef __cplusplus
#include <string.h>
extern "C"
{
#endif
typedef struct
{
unsigned long max_memory;
int settings;
} json_settings;
#define json_relaxed_commas 1
typedef enum
{
json_none,
json_object,
json_array,
json_integer,
json_double,
json_string,
json_boolean,
json_null
} json_type;
extern const struct _json_value json_value_none;
typedef struct _json_value
{
struct _json_value * parent;
json_type type;
union
{
int boolean;
long integer;
double dbl;
struct
{
unsigned int length;
json_char * ptr; /* null terminated */
} string;
struct
{
unsigned int length;
struct
{
json_char * name;
struct _json_value * value;
} * values;
} object;
struct
{
unsigned int length;
struct _json_value ** values;
} array;
} u;
union
{
struct _json_value * next_alloc;
void * object_mem;
} _reserved;
/* Some C++ operator sugar */
#ifdef __cplusplus
public:
inline _json_value ()
{ memset (this, 0, sizeof (_json_value));
}
inline const struct _json_value &operator [] (int index) const
{
if (type != json_array || index < 0
|| ((unsigned int) index) >= u.array.length)
{
return json_value_none;
}
return *u.array.values [index];
}
inline const struct _json_value &operator [] (const char * index) const
{
if (type != json_object)
return json_value_none;
for (unsigned int i = 0; i < u.object.length; ++ i)
if (!strcmp (u.object.values [i].name, index))
return *u.object.values [i].value;
return json_value_none;
}
inline operator const char * () const
{
switch (type)
{
case json_string:
return u.string.ptr;
default:
return "";
};
}
inline operator long () const
{ return u.integer;
}
inline operator bool () const
{ return u.boolean != 0;
}
#endif
} json_value;
json_value * json_parse
(const json_char * json);
json_value * json_parse_ex
(json_settings * settings, const json_char * json, char * error);
void json_value_free (json_value *);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
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