TEST(API, TestEncodeFingerprintBase64) { uint32_t fingerprint[] = { 1, 0 }; char expected[] = "NwAAAkEA"; char *encoded; int encoded_size; ASSERT_EQ(1, chromaprint_encode_fingerprint(fingerprint, 2, 55, &encoded, &encoded_size, 1)); SCOPE_EXIT(chromaprint_dealloc(encoded)); ASSERT_EQ(8, encoded_size); ASSERT_STREQ(expected, encoded); }
TEST(API, TestEncodeFingerprint) { uint32_t fingerprint[] = { 1, 0 }; char expected[] = { 55, 0, 0, 2, 65, 0 }; char *encoded; int encoded_size; ASSERT_EQ(1, chromaprint_encode_fingerprint(fingerprint, 2, 55, &encoded, &encoded_size, 0)); SCOPE_EXIT(chromaprint_dealloc(encoded)); ASSERT_EQ(6, encoded_size); for (int i = 0; i < encoded_size; i++) { ASSERT_EQ(expected[i], encoded[i]) << "Different at " << i; } }
static int write_trailer(AVFormatContext *s) { ChromaprintMuxContext *cpr = s->priv_data; AVIOContext *pb = s->pb; void *fp = NULL, *enc_fp = NULL; int size, enc_size, ret = AVERROR(EINVAL); if (!chromaprint_finish(cpr->ctx)) { av_log(s, AV_LOG_ERROR, "Failed to generate fingerprint\n"); goto fail; } if (!chromaprint_get_raw_fingerprint(cpr->ctx, &fp, &size)) { av_log(s, AV_LOG_ERROR, "Failed to retrieve fingerprint\n"); goto fail; } switch (cpr->fp_format) { case FINGERPRINT_RAW: avio_write(pb, fp, size); break; case FINGERPRINT_COMPRESSED: case FINGERPRINT_BASE64: if (!chromaprint_encode_fingerprint(fp, size, cpr->algorithm, &enc_fp, &enc_size, cpr->fp_format == FINGERPRINT_BASE64)) { av_log(s, AV_LOG_ERROR, "Failed to encode fingerprint\n"); goto fail; } avio_write(pb, enc_fp, enc_size); break; } ret = 0; fail: if (fp) chromaprint_dealloc(fp); if (enc_fp) chromaprint_dealloc(enc_fp); cleanup(cpr); return ret; }
QString Chromaprinter::CreateFingerprint() { Q_ASSERT(QThread::currentThread() != qApp->thread()); buffer_.open(QIODevice::WriteOnly); GMainContext* context = g_main_context_new(); g_main_context_push_thread_default(context); event_loop_ = g_main_loop_new(context, FALSE); pipeline_ = gst_pipeline_new("pipeline"); GstElement* src = CreateElement("filesrc", pipeline_); GstElement* decode = CreateElement("decodebin2", pipeline_); GstElement* convert = CreateElement("audioconvert", pipeline_); GstElement* resample = CreateElement("audioresample", pipeline_); GstElement* sink = CreateElement("appsink", pipeline_); if (!src || !decode || !convert || !resample || !sink) { return QString(); } convert_element_ = convert; // Connect the elements gst_element_link_many(src, decode, nullptr); gst_element_link_many(convert, resample, nullptr); // Chromaprint expects mono floats at a sample rate of 11025Hz. GstCaps* caps = gst_caps_new_simple( "audio/x-raw-int", "width", G_TYPE_INT, 16, "channels", G_TYPE_INT, kDecodeChannels, "rate", G_TYPE_INT, kDecodeRate, nullptr); gst_element_link_filtered(resample, sink, caps); gst_caps_unref(caps); GstAppSinkCallbacks callbacks; memset(&callbacks, 0, sizeof(callbacks)); callbacks.new_buffer = NewBufferCallback; gst_app_sink_set_callbacks(reinterpret_cast<GstAppSink*>(sink), &callbacks, this, nullptr); g_object_set(G_OBJECT(sink), "sync", FALSE, nullptr); g_object_set(G_OBJECT(sink), "emit-signals", TRUE, nullptr); // Set the filename g_object_set(src, "location", filename_.toUtf8().constData(), nullptr); // Connect signals CHECKED_GCONNECT(decode, "new-decoded-pad", &NewPadCallback, this); gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallbackSync, this); guint bus_callback_id = gst_bus_add_watch( gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), BusCallback, this); QTime time; time.start(); // Start playing gst_element_set_state(pipeline_, GST_STATE_PLAYING); g_main_loop_run(event_loop_); g_main_loop_unref(event_loop_); g_main_context_unref(context); int decode_time = time.restart(); buffer_.close(); QByteArray data = buffer_.data(); ChromaprintContext* chromaprint = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT); chromaprint_start(chromaprint, kDecodeRate, kDecodeChannels); chromaprint_feed(chromaprint, reinterpret_cast<void*>(data.data()), data.size() / 2); chromaprint_finish(chromaprint); void* fprint = nullptr; int size = 0; int ret = chromaprint_get_raw_fingerprint(chromaprint, &fprint, &size); QByteArray fingerprint; if (ret == 1) { void* encoded = nullptr; int encoded_size = 0; chromaprint_encode_fingerprint(fprint, size, CHROMAPRINT_ALGORITHM_DEFAULT, &encoded, &encoded_size, 1); fingerprint.append(reinterpret_cast<char*>(encoded), encoded_size); chromaprint_dealloc(fprint); chromaprint_dealloc(encoded); } chromaprint_free(chromaprint); int codegen_time = time.elapsed(); qLog(Debug) << "Decode time:" << decode_time << "Codegen time:" << codegen_time; // Cleanup callbacks.new_buffer = nullptr; gst_app_sink_set_callbacks(reinterpret_cast<GstAppSink*>(sink), &callbacks, this, nullptr); gst_bus_set_sync_handler(gst_pipeline_get_bus(GST_PIPELINE(pipeline_)), nullptr, nullptr); g_source_remove(bus_callback_id); gst_element_set_state(pipeline_, GST_STATE_NULL); gst_object_unref(pipeline_); return fingerprint; }
QString chromaprinter::calcFingerPrint(SoundSourceProxy& soundSource){ soundSource.open(); m_SampleRate = soundSource.getSampleRate(); unsigned int length = soundSource.length(); if (m_SampleRate == 0 ){ qDebug() << "Skipping invalid file:" << soundSource.getFilename(); return QString(); } // this is worth 2min of audio, multiply by 2 because we have 2 channels // AcoustID only stores a fingerprint for the first two minutes of a song // on their server so we need only a fingerprint of the first two minutes // --kain88 July 2012 m_NumSamples = 120*2*m_SampleRate; // check that the song is actually longer then the amount of audio we use if (m_NumSamples > length) { m_NumSamples = length; } SAMPLE *pData = new SAMPLE[m_NumSamples]; QTime timerReadingFile; timerReadingFile.start(); unsigned int read = soundSource.read(m_NumSamples, pData); if (read!=m_NumSamples) { qDebug() << "oh that's embarrasing I couldn't read the track"; return QString(); } qDebug("reading file took: %d ms" , timerReadingFile.elapsed()); ChromaprintContext* ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT); // we have 2 channels in mixxx always chromaprint_start(ctx, m_SampleRate, 2); QTime timerGeneratingFingerPrint; timerGeneratingFingerPrint.start(); int success = chromaprint_feed(ctx, pData, m_NumSamples); if (!success) { qDebug() << "could not generate fingerprint"; delete [] pData; return QString(); } chromaprint_finish(ctx); void* fprint = NULL; int size = 0; int ret = chromaprint_get_raw_fingerprint(ctx, &fprint, &size); QByteArray fingerprint; if (ret == 1) { void* encoded = NULL; int encoded_size = 0; chromaprint_encode_fingerprint(fprint, size, CHROMAPRINT_ALGORITHM_DEFAULT, &encoded, &encoded_size, 1); fingerprint.append(reinterpret_cast<char*>(encoded), encoded_size); chromaprint_dealloc(fprint); chromaprint_dealloc(encoded); } chromaprint_free(ctx); delete [] pData; qDebug("generating fingerprint took: %d ms" , timerGeneratingFingerPrint.elapsed()); return fingerprint; }
int groove_fingerprinter_encode(int32_t *fp, int size, char **encoded_fp) { int encoded_size; int err = chromaprint_encode_fingerprint(fp, size, CHROMAPRINT_ALGORITHM_DEFAULT, (void **)encoded_fp, &encoded_size, 1); return err == 1 ? 0 : -1; }