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 /*****************************************************************************
23 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_input.h>
32 #include <vlc_block.h>
38 # define CHROMAPRINT_NODLL
41 #include <chromaprint.h> /* chromaprint lib */
42 #include "chromaprint_data.h"
44 /*****************************************************************************
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 /*****************************************************************************
56 *****************************************************************************/
57 #define DURATION_TEXT N_("Duration of the fingerprinting" )
58 #define DURATION_LONGTEXT N_("Default: 90sec")
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
)
68 typedef struct sout_stream_id_sys_t sout_stream_id_sys_t
;
71 unsigned int i_duration
;
72 unsigned int i_total_samples
;
76 ChromaprintContext
*p_chromaprint_ctx
;
77 sout_stream_id_sys_t
*id
;
78 chromaprint_fingerprint_t
*p_data
;
81 struct sout_stream_id_sys_t
84 unsigned int i_channels
;
85 unsigned int i_samplerate
;
88 #define BYTESPERSAMPLE 2
90 /*****************************************************************************
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
;
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" );
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" );
120 p_stream
->pf_add
= Add
;
121 p_stream
->pf_del
= Del
;
122 p_stream
->pf_send
= Send
;
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
,
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
);
144 msg_Dbg( p_stream
, "Cannot create %us fingerprint (not enough samples?)",
147 p_sys
->b_done
= true;
148 msg_Dbg( p_stream
, "Fingerprinting finished" );
151 /*****************************************************************************
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
);
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" );
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
);
193 msg_Dbg( p_stream
, "Starting chromaprint on %uHz %uch samples",
194 p_fmt
->audio
.i_rate
, id
->i_channels
);
204 static void Del( sout_stream_t
*p_stream
, void *id
)
206 sout_stream_sys_t
*p_sys
= p_stream
->p_sys
;
208 if ( p_sys
->id
== id
) /* not assuming only 1 id is in use.. */
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
);
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
);