1 /*
2 * Copyright (c) 2013 Andrew Kelley
3 *
4 * This file is part of libgroove, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8 #include "fingerprinter.h"
9 #include <groove/queue.h>
10
11 #include <chromaprint.h>
12
13 #include <libavutil/mem.h>
14 #include <libavutil/log.h>
15
16 #include <limits.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <pthread.h>
20
21 struct GrooveFingerprinterPrivate {
22 struct GrooveFingerprinter externals;
23
24 int state_history_count;
25
26 // index into all_track_states
27 struct GrooveSink *sink;
28 struct GrooveQueue *info_queue;
29 pthread_t thread_id;
30
31 // info_head_mutex applies to variables inside this block.
32 pthread_mutex_t info_head_mutex;
33 char info_head_mutex_inited;
34 // current playlist item pointer
35 struct GroovePlaylistItem *info_head;
36 double info_pos;
37 // analyze_thread waits on this when the info queue is full
38 pthread_cond_t drain_cond;
39 char drain_cond_inited;
40 // how many items are in the queue
41 int info_queue_count;
42 double track_duration;
43 double album_duration;
44
45 ChromaprintContext *chroma_ctx;
46
47 // set temporarily
48 struct GroovePlaylistItem *purge_item;
49
50 int abort_request;
51 };
52
emit_track_info(struct GrooveFingerprinterPrivate * p)53 static int emit_track_info(struct GrooveFingerprinterPrivate *p) {
54 struct GrooveFingerprinterInfo *info = av_mallocz(sizeof(struct GrooveFingerprinterInfo));
55 if (!info) {
56 av_log(NULL, AV_LOG_ERROR, "unable to allocate fingerprinter info\n");
57 return -1;
58 }
59 info->item = p->info_head;
60 info->duration = p->track_duration;
61
62 if (!chromaprint_finish(p->chroma_ctx)) {
63 av_log(NULL, AV_LOG_ERROR, "unable to finish chromaprint\n");
64 return -1;
65 }
66 if (!chromaprint_get_raw_fingerprint(p->chroma_ctx,
67 #if CHROMAPRINT_VERSION_MAJOR > 1 || CHROMAPRINT_VERSION_MINOR >= 4
68 (uint32_t**)&info->fingerprint, &info->fingerprint_size))
69 #else
70 (void**)&info->fingerprint, &info->fingerprint_size))
71 #endif
72 {
73 av_log(NULL, AV_LOG_ERROR, "unable to get fingerprint\n");
74 return -1;
75 }
76
77 groove_queue_put(p->info_queue, info);
78
79 return 0;
80 }
81
print_thread(void * arg)82 static void *print_thread(void *arg) {
83 struct GrooveFingerprinterPrivate *p = arg;
84 struct GrooveFingerprinter *printer = &p->externals;
85
86 struct GrooveBuffer *buffer;
87 while (!p->abort_request) {
88 pthread_mutex_lock(&p->info_head_mutex);
89
90 if (p->info_queue_count >= printer->info_queue_size) {
91 pthread_cond_wait(&p->drain_cond, &p->info_head_mutex);
92 pthread_mutex_unlock(&p->info_head_mutex);
93 continue;
94 }
95
96 // we definitely want to unlock the mutex while we wait for the
97 // next buffer. Otherwise there will be a deadlock when sink_flush or
98 // sink_purge is called.
99 pthread_mutex_unlock(&p->info_head_mutex);
100
101 int result = groove_sink_buffer_get(p->sink, &buffer, 1);
102
103 pthread_mutex_lock(&p->info_head_mutex);
104
105 if (result == GROOVE_BUFFER_END) {
106 // last file info
107 emit_track_info(p);
108
109 // send album info
110 struct GrooveFingerprinterInfo *info = av_mallocz(
111 sizeof(struct GrooveFingerprinterInfo));
112 if (info) {
113 info->duration = p->album_duration;
114 groove_queue_put(p->info_queue, info);
115 } else {
116 av_log(NULL, AV_LOG_ERROR, "unable to allocate album fingerprint info\n");
117 }
118
119 p->album_duration = 0.0;
120
121 p->info_head = NULL;
122 p->info_pos = -1.0;
123
124 pthread_mutex_unlock(&p->info_head_mutex);
125 continue;
126 }
127
128 if (result != GROOVE_BUFFER_YES) {
129 pthread_mutex_unlock(&p->info_head_mutex);
130 break;
131 }
132
133 if (buffer->item != p->info_head) {
134 if (p->info_head) {
135 emit_track_info(p);
136 }
137 if (!chromaprint_start(p->chroma_ctx, 44100, 2)) {
138 av_log(NULL, AV_LOG_ERROR, "unable to start fingerprint\n");
139 }
140 p->track_duration = 0.0;
141 p->info_head = buffer->item;
142 p->info_pos = buffer->pos;
143 }
144
145 double buffer_duration = buffer->frame_count / (double)buffer->format.sample_rate;
146 p->track_duration += buffer_duration;
147 p->album_duration += buffer_duration;
148 #if CHROMAPRINT_VERSION_MAJOR > 1 || CHROMAPRINT_VERSION_MINOR >= 4
149 if (!chromaprint_feed(p->chroma_ctx, (const int16_t*)buffer->data[0], buffer->frame_count * 2)) {
150 #else
151 if (!chromaprint_feed(p->chroma_ctx, buffer->data[0], buffer->frame_count * 2)) {
152 #endif
153 av_log(NULL, AV_LOG_ERROR, "unable to feed fingerprint\n");
154 }
155
156 pthread_mutex_unlock(&p->info_head_mutex);
157 groove_buffer_unref(buffer);
158 }
159
160 return NULL;
161 }
162
163 static void info_queue_cleanup(struct GrooveQueue* queue, void *obj) {
164 struct GrooveFingerprinterInfo *info = obj;
165 struct GrooveFingerprinterPrivate *p = queue->context;
166 p->info_queue_count -= 1;
167 av_free(info);
168 }
169
170 static void info_queue_put(struct GrooveQueue *queue, void *obj) {
171 struct GrooveFingerprinterPrivate *p = queue->context;
172 p->info_queue_count += 1;
173 }
174
175 static void info_queue_get(struct GrooveQueue *queue, void *obj) {
176 struct GrooveFingerprinterPrivate *p = queue->context;
177 struct GrooveFingerprinter *printer = &p->externals;
178
179 p->info_queue_count -= 1;
180
181 if (p->info_queue_count < printer->info_queue_size)
182 pthread_cond_signal(&p->drain_cond);
183 }
184
185 static int info_queue_purge(struct GrooveQueue* queue, void *obj) {
186 struct GrooveFingerprinterInfo *info = obj;
187 struct GrooveFingerprinterPrivate *p = queue->context;
188
189 return info->item == p->purge_item;
190 }
191
192 static void sink_purge(struct GrooveSink *sink, struct GroovePlaylistItem *item) {
193 struct GrooveFingerprinterPrivate *p = sink->userdata;
194
195 pthread_mutex_lock(&p->info_head_mutex);
196 p->purge_item = item;
197 groove_queue_purge(p->info_queue);
198 p->purge_item = NULL;
199
200 if (p->info_head == item) {
201 p->info_head = NULL;
202 p->info_pos = -1.0;
203 }
204 pthread_cond_signal(&p->drain_cond);
205 pthread_mutex_unlock(&p->info_head_mutex);
206 }
207
208 static void sink_flush(struct GrooveSink *sink) {
209 struct GrooveFingerprinterPrivate *p = sink->userdata;
210
211 pthread_mutex_lock(&p->info_head_mutex);
212 groove_queue_flush(p->info_queue);
213 p->track_duration = 0.0;
214 p->info_head = NULL;
215 p->info_pos = -1.0;
216
217 pthread_cond_signal(&p->drain_cond);
218 pthread_mutex_unlock(&p->info_head_mutex);
219 }
220
221 struct GrooveFingerprinter *groove_fingerprinter_create(void) {
222 struct GrooveFingerprinterPrivate *p = av_mallocz(sizeof(struct GrooveFingerprinterPrivate));
223 if (!p) {
224 av_log(NULL, AV_LOG_ERROR, "unable to allocate fingerprinter\n");
225 return NULL;
226 }
227
228 struct GrooveFingerprinter *printer = &p->externals;
229
230 if (pthread_mutex_init(&p->info_head_mutex, NULL) != 0) {
231 groove_fingerprinter_destroy(printer);
232 av_log(NULL, AV_LOG_ERROR, "unable to create mutex\n");
233 return NULL;
234 }
235 p->info_head_mutex_inited = 1;
236
237 if (pthread_cond_init(&p->drain_cond, NULL) != 0) {
238 groove_fingerprinter_destroy(printer);
239 av_log(NULL, AV_LOG_ERROR, "unable to create mutex condition\n");
240 return NULL;
241 }
242 p->drain_cond_inited = 1;
243
244 p->info_queue = groove_queue_create();
245 if (!p->info_queue) {
246 groove_fingerprinter_destroy(printer);
247 av_log(NULL, AV_LOG_ERROR, "unable to allocate queue\n");
248 return NULL;
249 }
250 p->info_queue->context = printer;
251 p->info_queue->cleanup = info_queue_cleanup;
252 p->info_queue->put = info_queue_put;
253 p->info_queue->get = info_queue_get;
254 p->info_queue->purge = info_queue_purge;
255
256 p->sink = groove_sink_create();
257 if (!p->sink) {
258 groove_fingerprinter_destroy(printer);
259 av_log(NULL, AV_LOG_ERROR, "unable to allocate sink\n");
260 return NULL;
261 }
262 p->sink->audio_format.sample_rate = 44100;
263 p->sink->audio_format.channel_layout = GROOVE_CH_LAYOUT_STEREO;
264 p->sink->audio_format.sample_fmt = GROOVE_SAMPLE_FMT_S16;
265 p->sink->userdata = printer;
266 p->sink->purge = sink_purge;
267 p->sink->flush = sink_flush;
268
269 // set some defaults
270 printer->info_queue_size = INT_MAX;
271 printer->sink_buffer_size = p->sink->buffer_size;
272
273 return printer;
274 }
275
276 void groove_fingerprinter_destroy(struct GrooveFingerprinter *printer) {
277 if (!printer)
278 return;
279
280 struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
281
282 if (p->sink)
283 groove_sink_destroy(p->sink);
284
285 if (p->info_queue)
286 groove_queue_destroy(p->info_queue);
287
288 if (p->info_head_mutex_inited)
289 pthread_mutex_destroy(&p->info_head_mutex);
290
291 if (p->drain_cond_inited)
292 pthread_cond_destroy(&p->drain_cond);
293
294 av_free(p);
295 }
296
297 int groove_fingerprinter_attach(struct GrooveFingerprinter *printer,
298 struct GroovePlaylist *playlist)
299 {
300 struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
301
302 printer->playlist = playlist;
303 groove_queue_reset(p->info_queue);
304
305 p->chroma_ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT);
306 if (!p->chroma_ctx) {
307 groove_fingerprinter_detach(printer);
308 av_log(NULL, AV_LOG_ERROR, "unable to allocate chromaprint\n");
309 return -1;
310 }
311
312 if (groove_sink_attach(p->sink, playlist) < 0) {
313 groove_fingerprinter_detach(printer);
314 av_log(NULL, AV_LOG_ERROR, "unable to attach sink\n");
315 return -1;
316 }
317
318 if (pthread_create(&p->thread_id, NULL, print_thread, printer) != 0) {
319 groove_fingerprinter_detach(printer);
320 av_log(NULL, AV_LOG_ERROR, "unable to create printer thread\n");
321 return -1;
322 }
323
324 return 0;
325 }
326
327 int groove_fingerprinter_detach(struct GrooveFingerprinter *printer) {
328 struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
329
330 p->abort_request = 1;
331 groove_sink_detach(p->sink);
332 groove_queue_flush(p->info_queue);
333 groove_queue_abort(p->info_queue);
334 pthread_cond_signal(&p->drain_cond);
335 pthread_join(p->thread_id, NULL);
336
337 printer->playlist = NULL;
338
339 if (p->chroma_ctx) {
340 chromaprint_free(p->chroma_ctx);
341 p->chroma_ctx = NULL;
342 }
343
344 p->abort_request = 0;
345 p->info_head = NULL;
346 p->info_pos = 0;
347 p->track_duration = 0.0;
348
349 return 0;
350 }
351
352 int groove_fingerprinter_info_get(struct GrooveFingerprinter *printer,
353 struct GrooveFingerprinterInfo *info, int block)
354 {
355 struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
356
357 struct GrooveFingerprinterInfo *info_ptr;
358 if (groove_queue_get(p->info_queue, (void**)&info_ptr, block) == 1) {
359 *info = *info_ptr;
360 av_free(info_ptr);
361 return 1;
362 }
363
364 return 0;
365 }
366
367 int groove_fingerprinter_info_peek(struct GrooveFingerprinter *printer,
368 int block)
369 {
370 struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
371 return groove_queue_peek(p->info_queue, block);
372 }
373
374 void groove_fingerprinter_position(struct GrooveFingerprinter *printer,
375 struct GroovePlaylistItem **item, double *seconds)
376 {
377 struct GrooveFingerprinterPrivate *p = (struct GrooveFingerprinterPrivate *) printer;
378
379 pthread_mutex_lock(&p->info_head_mutex);
380
381 if (item)
382 *item = p->info_head;
383
384 if (seconds)
385 *seconds = p->info_pos;
386
387 pthread_mutex_unlock(&p->info_head_mutex);
388 }
389
390 void groove_fingerprinter_free_info(struct GrooveFingerprinterInfo *info) {
391 if (!info->fingerprint) return;
392 chromaprint_dealloc((void*)info->fingerprint);
393 info->fingerprint = NULL;
394 }
395
396 int groove_fingerprinter_encode(int32_t *fp, int size, char **encoded_fp) {
397 int encoded_size;
398 #if CHROMAPRINT_VERSION_MAJOR > 1 || CHROMAPRINT_VERSION_MINOR >= 4
399 int err = chromaprint_encode_fingerprint((const uint32_t*)fp, size,
400 #else
401 int err = chromaprint_encode_fingerprint(fp, size,
402 #endif
403 CHROMAPRINT_ALGORITHM_DEFAULT, (void*)encoded_fp, &encoded_size, 1);
404 return err == 1 ? 0 : -1;
405 }
406
407 int groove_fingerprinter_decode(char *encoded_fp, int32_t **fp, int *size) {
408 int algorithm;
409 int encoded_size = strlen(encoded_fp);
410 #if CHROMAPRINT_VERSION_MAJOR > 1 || CHROMAPRINT_VERSION_MINOR >= 4
411 int err = chromaprint_decode_fingerprint(encoded_fp, encoded_size, (uint32_t**)fp, size,
412 #else
413 int err = chromaprint_decode_fingerprint(encoded_fp, encoded_size, (void**)fp, size,
414 #endif
415 &algorithm, 1);
416 return err == 1 ? 0 : -1;
417 }
418
419 void groove_fingerprinter_dealloc(void *ptr) {
420 if (!ptr) return;
421 chromaprint_dealloc(ptr);
422 }
423