demux: ogg: rename field
[vlc.git] / modules / stream_out / chromaprint.c
blobe81b6b12c41ab1f83d6da08221468bce6d578814
1 /*****************************************************************************
2 * chromaprint.c: Chromaprint Fingerprinter Module
3 *****************************************************************************
4 * Copyright (C) 2012 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 /*****************************************************************************
22 * Preamble
23 *****************************************************************************/
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_input.h>
32 #include <vlc_block.h>
33 #include <vlc_sout.h>
35 #include <assert.h>
37 #ifdef _WIN32
38 # define CHROMAPRINT_NODLL
39 #endif
41 #include <chromaprint.h> /* chromaprint lib */
42 #include "chromaprint_data.h"
44 /*****************************************************************************
45 * Exported prototypes
46 *****************************************************************************/
47 static int Open ( vlc_object_t * );
48 static void Close ( vlc_object_t * );
50 static void *Add( sout_stream_t *, const es_format_t * );
51 static void Del( sout_stream_t *, void * );
52 static int Send( sout_stream_t *, void *, block_t * );
54 /*****************************************************************************
55 * Module descriptor
56 *****************************************************************************/
57 #define DURATION_TEXT N_("Duration of the fingerprinting" )
58 #define DURATION_LONGTEXT N_("Default: 90sec")
60 vlc_module_begin ()
61 set_description( N_("Chromaprint stream output") )
62 set_capability( "sout stream", 0 )
63 add_shortcut( "chromaprint" )
64 add_integer( "duration", 90, DURATION_TEXT, DURATION_LONGTEXT, true )
65 set_callbacks( Open, Close )
66 vlc_module_end ()
68 typedef struct sout_stream_id_sys_t sout_stream_id_sys_t;
69 typedef struct
71 unsigned int i_duration;
72 unsigned int i_total_samples;
73 int i_samples;
74 bool b_finished;
75 bool b_done;
76 ChromaprintContext *p_chromaprint_ctx;
77 sout_stream_id_sys_t *id;
78 chromaprint_fingerprint_t *p_data;
79 } sout_stream_sys_t;
81 struct sout_stream_id_sys_t
83 int i_samples;
84 unsigned int i_channels;
85 unsigned int i_samplerate;
88 #define BYTESPERSAMPLE 2
90 /*****************************************************************************
91 * Open:
92 *****************************************************************************/
93 static int Open( vlc_object_t *p_this )
95 sout_stream_t *p_stream = (sout_stream_t*)p_this;
96 sout_stream_sys_t *p_sys;
98 p_stream->p_sys = p_sys = malloc(sizeof(sout_stream_sys_t));
99 if ( unlikely( ! p_sys ) ) return VLC_ENOMEM;
100 p_sys->id = NULL;
101 p_sys->b_finished = false;
102 p_sys->b_done = false;
103 p_sys->i_total_samples = 0;
104 p_sys->i_duration = var_InheritInteger( p_stream, "duration" );
105 p_sys->p_data = var_InheritAddress( p_stream, "fingerprint-data" );
106 if ( !p_sys->p_data )
108 msg_Err( p_stream, "Fingerprint data holder not set" );
109 free( p_sys );
110 return VLC_ENOVAR;
112 msg_Dbg( p_stream, "chromaprint version %s", chromaprint_get_version() );
113 p_sys->p_chromaprint_ctx = chromaprint_new( CHROMAPRINT_ALGORITHM_DEFAULT );
114 if ( ! p_sys->p_chromaprint_ctx )
116 msg_Err( p_stream, "Can't create chromaprint context" );
117 free( p_sys );
118 return VLC_EGENERIC;
120 p_stream->pf_add = Add;
121 p_stream->pf_del = Del;
122 p_stream->pf_send = Send;
123 return VLC_SUCCESS;
126 static void Finish( sout_stream_t *p_stream )
128 sout_stream_sys_t *p_sys = p_stream->p_sys;
129 char *psz_fingerprint = NULL;
130 if ( p_sys->b_finished && chromaprint_finish( p_sys->p_chromaprint_ctx ) )
132 chromaprint_get_fingerprint( p_sys->p_chromaprint_ctx,
133 &psz_fingerprint );
134 if ( psz_fingerprint )
136 p_sys->p_data->i_duration = p_sys->i_total_samples / p_sys->id->i_samplerate;
137 p_sys->p_data->psz_fingerprint = strdup( psz_fingerprint );
138 chromaprint_dealloc( psz_fingerprint );
139 msg_Dbg( p_stream, "DURATION=%u;FINGERPRINT=%s",
140 p_sys->p_data->i_duration,
141 p_sys->p_data->psz_fingerprint );
143 } else {
144 msg_Dbg( p_stream, "Cannot create %us fingerprint (not enough samples?)",
145 p_sys->i_duration );
147 p_sys->b_done = true;
148 msg_Dbg( p_stream, "Fingerprinting finished" );
151 /*****************************************************************************
152 * Close:
153 *****************************************************************************/
154 static void Close( vlc_object_t * p_this )
156 sout_stream_t *p_stream = (sout_stream_t *)p_this;
157 sout_stream_sys_t *p_sys = p_stream->p_sys;
159 if ( !p_sys->b_done ) Finish( p_stream );
160 chromaprint_free( p_sys->p_chromaprint_ctx );
161 free( p_sys );
164 static void *Add( sout_stream_t *p_stream, const es_format_t *p_fmt )
166 sout_stream_sys_t *p_sys = p_stream->p_sys;
167 sout_stream_id_sys_t *id = NULL;
169 if ( p_fmt->i_cat == AUDIO_ES && !p_sys->id )
171 if( p_fmt->i_codec != VLC_CODEC_S16N || p_fmt->audio.i_channels > 2 )
173 msg_Warn( p_stream, "bad input format: need s16l, 1 or 2 channels" );
174 goto error;
177 id = malloc( sizeof( sout_stream_id_sys_t ) );
178 if ( !id ) goto error;
180 id->i_channels = p_fmt->audio.i_channels;
181 id->i_samplerate = p_fmt->audio.i_rate;
182 id->i_samples = p_sys->i_duration * id->i_samplerate;
184 if ( !chromaprint_start( p_sys->p_chromaprint_ctx, p_fmt->audio.i_rate, id->i_channels ) )
186 msg_Err( p_stream, "Failed starting chromaprint on %uHz %uch samples",
187 p_fmt->audio.i_rate, id->i_channels );
188 goto error;
190 else
192 p_sys->id = id;
193 msg_Dbg( p_stream, "Starting chromaprint on %uHz %uch samples",
194 p_fmt->audio.i_rate, id->i_channels );
196 return id;
199 error:
200 free( id );
201 return NULL;
204 static void Del( sout_stream_t *p_stream, void *id )
206 sout_stream_sys_t *p_sys = p_stream->p_sys;
207 Finish( p_stream );
208 if ( p_sys->id == id ) /* not assuming only 1 id is in use.. */
209 p_sys->id = NULL;
210 free( id );
213 static int Send( sout_stream_t *p_stream, void *_id, block_t *p_buf )
215 sout_stream_sys_t *p_sys = p_stream->p_sys;
216 sout_stream_id_sys_t *id = (sout_stream_id_sys_t *)_id;
218 if ( p_sys->id != id )
220 /* drop the whole buffer at once */
221 block_ChainRelease( p_buf );
222 return VLC_SUCCESS;
225 while( p_buf )
227 block_t *p_next;
228 int i_samples = p_buf->i_buffer / (BYTESPERSAMPLE * id->i_channels);
229 p_sys->i_total_samples += i_samples;
230 if ( !p_sys->b_finished && id->i_samples > 0 && p_buf->i_buffer )
232 if(! chromaprint_feed( p_sys->p_chromaprint_ctx,
233 (int16_t *)p_buf->p_buffer,
234 p_buf->i_buffer / BYTESPERSAMPLE ) )
235 msg_Warn( p_stream, "feed error" );
236 id->i_samples -= i_samples;
237 if ( id->i_samples < 1 && !p_sys->b_finished )
239 p_sys->b_finished = true;
240 msg_Dbg( p_stream, "Fingerprint collection finished" );
243 p_next = p_buf->p_next;
244 block_Release( p_buf );
245 p_buf = p_next;
248 return VLC_SUCCESS;