示例#1
0
TEST(API, Test2SilenceRawFp)
{
	short zeroes[1024];
	std::fill(zeroes, zeroes + 1024, 0);

	ChromaprintContext *ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_TEST2);
	ASSERT_NE(nullptr, ctx);
	SCOPE_EXIT(chromaprint_free(ctx));

	ASSERT_EQ(1, chromaprint_start(ctx, 44100, 1));
	for (int i = 0; i < 130; i++) {
		ASSERT_EQ(1, chromaprint_feed(ctx, zeroes, 1024));
	}

	uint32_t *fp;
	int length;

	ASSERT_EQ(1, chromaprint_finish(ctx));
	ASSERT_EQ(1, chromaprint_get_raw_fingerprint(ctx, &fp, &length));
	SCOPE_EXIT(chromaprint_dealloc(fp));

	ASSERT_EQ(3, length);
	EXPECT_EQ(627964279, fp[0]);
	EXPECT_EQ(627964279, fp[1]);
	EXPECT_EQ(627964279, fp[2]);
}
示例#2
0
TEST(API, Test2SilenceFp)
{
	short zeroes[1024];
	std::fill(zeroes, zeroes + 1024, 0);

	ChromaprintContext *ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_TEST2);
	ASSERT_NE(nullptr, ctx);
	SCOPE_EXIT(chromaprint_free(ctx));

	ASSERT_EQ(1, chromaprint_start(ctx, 44100, 1));
	for (int i = 0; i < 130; i++) {
		ASSERT_EQ(1, chromaprint_feed(ctx, zeroes, 1024));
	}

	char *fp;
	uint32_t fp_hash;

	ASSERT_EQ(1, chromaprint_finish(ctx));
	ASSERT_EQ(1, chromaprint_get_fingerprint(ctx, &fp));
	SCOPE_EXIT(chromaprint_dealloc(fp));
	ASSERT_EQ(1, chromaprint_get_fingerprint_hash(ctx, &fp_hash));

	ASSERT_EQ(18, strlen(fp));
	EXPECT_EQ(std::string("AQAAA0mUaEkSRZEGAA"), std::string(fp));
	ASSERT_EQ(627964279, fp_hash);
}
示例#3
0
static int write_header(AVFormatContext *s)
{
    ChromaprintMuxContext *cpr = s->priv_data;
    AVStream *st;

    avpriv_lock_avformat();
    cpr->ctx = chromaprint_new(cpr->algorithm);
    avpriv_unlock_avformat();

    if (!cpr->ctx) {
        av_log(s, AV_LOG_ERROR, "Failed to create chromaprint context.\n");
        return AVERROR(ENOMEM);
    }

    if (cpr->silence_threshold != -1) {
#if CPR_VERSION_INT >= AV_VERSION_INT(0, 7, 0)
        if (!chromaprint_set_option(cpr->ctx, "silence_threshold", cpr->silence_threshold)) {
            av_log(s, AV_LOG_ERROR, "Failed to set silence threshold.\n");
            goto fail;
        }
#else
        av_log(s, AV_LOG_ERROR, "Setting the silence threshold requires Chromaprint "
                                "version 0.7.0 or later.\n");
        goto fail;
#endif
    }

    if (s->nb_streams != 1) {
        av_log(s, AV_LOG_ERROR, "Only one stream is supported\n");
        goto fail;
    }

    st = s->streams[0];

    if (st->codecpar->channels > 2) {
        av_log(s, AV_LOG_ERROR, "Only up to 2 channels are supported\n");
        goto fail;
    }

    if (st->codecpar->sample_rate < 1000) {
        av_log(s, AV_LOG_ERROR, "Sampling rate must be at least 1000\n");
        goto fail;
    }

    if (!chromaprint_start(cpr->ctx, st->codecpar->sample_rate, st->codecpar->channels)) {
        av_log(s, AV_LOG_ERROR, "Failed to start chromaprint\n");
        goto fail;
    }

    return 0;
fail:
    cleanup(cpr);
    return AVERROR(EINVAL);
}
static GstFlowReturn
gst_chromaprint_transform_ip (GstBaseTransform * trans, GstBuffer * buf)
{
  GstChromaprint *chromaprint = GST_CHROMAPRINT (trans);
  GstAudioFilter *filter = GST_AUDIO_FILTER (trans);
  GstMapInfo map_info;
  guint nsamples;
  gint rate, channels;

  rate = GST_AUDIO_INFO_RATE (&filter->info);
  channels = GST_AUDIO_INFO_CHANNELS (&filter->info);

  if (G_UNLIKELY (rate <= 0 || channels <= 0))
    return GST_FLOW_NOT_NEGOTIATED;

  if (!chromaprint->record)
    return GST_FLOW_OK;

  if (!gst_buffer_map (buf, &map_info, GST_MAP_READ))
    return GST_FLOW_ERROR;

  nsamples = map_info.size / (channels * 2);

  if (nsamples == 0)
    goto end;

  if (chromaprint->nsamples == 0) {
    chromaprint_start (chromaprint->context, rate, channels);
  }
  chromaprint->nsamples += nsamples;
  chromaprint->duration = chromaprint->nsamples / rate;

  chromaprint_feed (chromaprint->context, map_info.data,
      map_info.size / sizeof (guint16));

  if (chromaprint->duration >= chromaprint->max_duration
      && !chromaprint->fingerprint) {
    gst_chromaprint_create_fingerprint (chromaprint);
  }

end:
  gst_buffer_unmap (buf, &map_info);

  return GST_FLOW_OK;
}
示例#5
0
文件: chromaprint.c 项目: AsamQi/vlc
static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
{
    sout_stream_sys_t *p_sys = p_stream->p_sys;
    sout_stream_id_t *id = NULL;

    if ( p_fmt->i_cat == AUDIO_ES && !p_sys->id )
    {
        if( p_fmt->i_codec != VLC_CODEC_S16N || p_fmt->audio.i_channels > 2 )
        {
            msg_Warn( p_stream, "bad input format: need s16l, 1 or 2 channels" );
            goto error;
        }

        id = malloc( sizeof( sout_stream_id_t ) );
        if ( !id ) goto error;

        id->i_channels = p_fmt->audio.i_channels;
        id->i_samplerate = p_fmt->audio.i_rate;
        id->i_samples = p_sys->i_duration * id->i_samplerate;

        if ( !chromaprint_start( p_sys->p_chromaprint_ctx, p_fmt->audio.i_rate, id->i_channels ) )
        {
            msg_Err( p_stream, "Failed starting chromaprint on %uHz %uch samples",
                     p_fmt->audio.i_rate, id->i_channels );
            goto error;
        }
        else
        {
            p_sys->id = id;
            msg_Dbg( p_stream, "Starting chromaprint on %uHz %uch samples",
                     p_fmt->audio.i_rate, id->i_channels );
        }
        return id;
    }

error:
    free( id );
    return NULL;
}
示例#6
0
TEST(API, TestFp) {
	std::vector<short> data = LoadAudioFile("data/test_stereo_44100.raw");

	ChromaprintContext *ctx = chromaprint_new(CHROMAPRINT_ALGORITHM_TEST2);
	ASSERT_NE(nullptr, ctx);
	SCOPE_EXIT(chromaprint_free(ctx));

	ASSERT_EQ(1, chromaprint_get_num_channels(ctx));
	ASSERT_EQ(11025, chromaprint_get_sample_rate(ctx));

	ASSERT_EQ(1, chromaprint_start(ctx, 44100, 1));
	ASSERT_EQ(1, chromaprint_feed(ctx, data.data(), data.size()));

	char *fp;
	uint32_t fp_hash;

	ASSERT_EQ(1, chromaprint_finish(ctx));
	ASSERT_EQ(1, chromaprint_get_fingerprint(ctx, &fp));
	SCOPE_EXIT(chromaprint_dealloc(fp));
	ASSERT_EQ(1, chromaprint_get_fingerprint_hash(ctx, &fp_hash));

	EXPECT_EQ(std::string("AQAAC0kkZUqYREkUnFAXHk8uuMZl6EfO4zu-4ABKFGESWIIMEQE"), std::string(fp));
	ASSERT_EQ(3732003127, fp_hash);
}
示例#7
0
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;
}
示例#8
0
int decode_audio_file(ChromaprintContext *chromaprint_ctx, int16_t *buffer1, int16_t *buffer2, const char *file_name, int max_length, int *duration)
{
	int i, ok = 0, remaining, length, consumed, buffer_size, codec_ctx_opened = 0;
	AVFormatContext *format_ctx = NULL;
	AVCodecContext *codec_ctx = NULL;
	AVCodec *codec = NULL;
	AVStream *stream = NULL;
	AVPacket packet, packet_temp;
#ifdef HAVE_AV_AUDIO_CONVERT
	AVAudioConvert *convert_ctx = NULL;
#endif
	int16_t *buffer;

	if (!strcmp(file_name, "-")) {
		file_name = "pipe:0";
	}

#if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(53, 2, 0)
	if (av_open_input_file(&format_ctx, file_name, NULL, 0, NULL) != 0) {
#else
	if (avformat_open_input(&format_ctx, file_name, NULL, NULL) != 0) {
#endif
		fprintf(stderr, "ERROR: couldn't open the file\n");
		goto done;
	}

	if (av_find_stream_info(format_ctx) < 0) {
		fprintf(stderr, "ERROR: couldn't find stream information in the file\n");
		goto done;
	}

	for (i = 0; i < format_ctx->nb_streams; i++) {
		codec_ctx = format_ctx->streams[i]->codec;
		if (codec_ctx && codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
			stream = format_ctx->streams[i];
			break;
		}
	}
	if (!stream) {
		fprintf(stderr, "ERROR: couldn't find any audio stream in the file\n");
		goto done;
	}

	codec = avcodec_find_decoder(codec_ctx->codec_id);
	if (!codec) {
		fprintf(stderr, "ERROR: unknown codec\n");
		goto done;
	}

	if (avcodec_open(codec_ctx, codec) < 0) {
		fprintf(stderr, "ERROR: couldn't open the codec\n");
		goto done;
	}
	codec_ctx_opened = 1;

	if (codec_ctx->channels <= 0) {
		fprintf(stderr, "ERROR: no channels found in the audio stream\n");
		goto done;
	}

	if (codec_ctx->sample_fmt != AV_SAMPLE_FMT_S16) {
#ifdef HAVE_AV_AUDIO_CONVERT
		convert_ctx = av_audio_convert_alloc(AV_SAMPLE_FMT_S16, codec_ctx->channels,
		                                     codec_ctx->sample_fmt, codec_ctx->channels, NULL, 0);
		if (!convert_ctx) {
			fprintf(stderr, "ERROR: couldn't create sample format converter\n");
			goto done;
		}
#else
		fprintf(stderr, "ERROR: unsupported sample format\n");
		goto done;
#endif
	}

	*duration = stream->time_base.num * stream->duration / stream->time_base.den;

	av_init_packet(&packet);
	av_init_packet(&packet_temp);

	remaining = max_length * codec_ctx->channels * codec_ctx->sample_rate;
	chromaprint_start(chromaprint_ctx, codec_ctx->sample_rate, codec_ctx->channels);

	while (1) {
		if (av_read_frame(format_ctx, &packet) < 0) {
			break;
		}

		packet_temp.data = packet.data;
		packet_temp.size = packet.size;

		while (packet_temp.size > 0) {
			buffer_size = BUFFER_SIZE;
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(52, 23, 0)
			consumed = avcodec_decode_audio2(codec_ctx,
				buffer1, &buffer_size, packet_temp.data, packet_temp.size);
#else
			consumed = avcodec_decode_audio3(codec_ctx,
				buffer1, &buffer_size, &packet_temp);
#endif

			if (consumed < 0) {
				break;
			}

			packet_temp.data += consumed;
			packet_temp.size -= consumed;

			if (buffer_size <= 0) {
				if (buffer_size < 0) {
					fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too small\n");
				}
				continue;
			}
			if (buffer_size > BUFFER_SIZE) {
				fprintf(stderr, "WARNING: size returned from avcodec_decode_audioX is too large\n");
				continue;
			}

#ifdef HAVE_AV_AUDIO_CONVERT
			if (convert_ctx) {
				const void *ibuf[6] = { buffer1 };
				void *obuf[6] = { buffer2 };
#if LIBAVUTIL_VERSION_INT < AV_VERSION_INT(51, 8, 0)
				int istride[6] = { av_get_bits_per_sample_format(codec_ctx->sample_fmt) / 8 };
#else
				int istride[6] = { av_get_bytes_per_sample(codec_ctx->sample_fmt) };
#endif
				int ostride[6] = { 2 };
				int len = buffer_size / istride[0];
				if (av_audio_convert(convert_ctx, obuf, ostride, ibuf, istride, len) < 0) {
					break;
				}
				buffer = buffer2;
				buffer_size = len * ostride[0];
			}
			else {
				buffer = buffer1;
			}
#else
			buffer = buffer1;
#endif

			length = MIN(remaining, buffer_size / 2);
			if (!chromaprint_feed(chromaprint_ctx, buffer, length)) {
				fprintf(stderr, "ERROR: fingerprint calculation failed\n");
				goto done;
			}

			if (max_length) {
				remaining -= length;
				if (remaining <= 0) {
					goto finish;
				}
			}
		}

		if (packet.data) {
			av_free_packet(&packet);
		}
	}

finish:
	if (!chromaprint_finish(chromaprint_ctx)) {
		fprintf(stderr, "ERROR: fingerprint calculation failed\n");
		goto done;
	}

	ok = 1;

done:
	if (codec_ctx_opened) {
		avcodec_close(codec_ctx);
	}
	if (format_ctx) {
		av_close_input_file(format_ctx);
	}
#ifdef HAVE_AV_AUDIO_CONVERT
	if (convert_ctx) {
		av_audio_convert_free(convert_ctx);
	}
#endif
	return ok;
}

int fpcalc_main(int argc, char **argv)
{
	int i, j, max_length = 120, num_file_names = 0, raw = 0, raw_fingerprint_size, duration;
	int16_t *buffer1, *buffer2;
	int32_t *raw_fingerprint;
	char *file_name, *fingerprint, **file_names;
	ChromaprintContext *chromaprint_ctx;
	int algo = CHROMAPRINT_ALGORITHM_DEFAULT;

	file_names = malloc(argc * sizeof(char *));
	for (i = 1; i < argc; i++) {
		char *arg = argv[i];
		if (!strcmp(arg, "-length") && i + 1 < argc) {
			max_length = atoi(argv[++i]);
		}
		else if (!strcmp(arg, "-version") || !strcmp(arg, "-v")) {
			printf("fpcalc version %s\n", chromaprint_get_version());
			return 0;
		}
		else if (!strcmp(arg, "-raw")) {
			raw = 1;
		}
		else if (!strcmp(arg, "-algo") && i + 1 < argc) {
			const char *v = argv[++i];
			if (!strcmp(v, "test1")) { algo = CHROMAPRINT_ALGORITHM_TEST1; }
			else if (!strcmp(v, "test2")) { algo = CHROMAPRINT_ALGORITHM_TEST2; }
			else if (!strcmp(v, "test3")) { algo = CHROMAPRINT_ALGORITHM_TEST3; }
			else if (!strcmp(v, "test4")) { algo = CHROMAPRINT_ALGORITHM_TEST4; }
			else {
				fprintf(stderr, "WARNING: unknown algorithm, using the default\n");
			}
		}
		else if (!strcmp(arg, "-set") && i + 1 < argc) {
			i += 1;
		}
		else {
			file_names[num_file_names++] = argv[i];
		}
	}

	if (!num_file_names) {
		printf("usage: %s [OPTIONS] FILE...\n\n", argv[0]);
		printf("Options:\n");
		printf("  -version      print version information\n");
		printf("  -length SECS  length of the audio data used for fingerprint calculation (default 120)\n");
		printf("  -raw          output the raw uncompressed fingerprint\n");
		printf("  -algo NAME    version of the fingerprint algorithm\n");
		return 2;
	}

	av_register_all();
	av_log_set_level(AV_LOG_ERROR);

	buffer1 = av_malloc(BUFFER_SIZE + 16);
	buffer2 = av_malloc(BUFFER_SIZE + 16);
	chromaprint_ctx = chromaprint_new(algo);

	for (i = 1; i < argc; i++) {
		char *arg = argv[i];
		if (!strcmp(arg, "-set") && i + 1 < argc) {
			char *name = argv[++i];
			char *value = strchr(name, '=');
			if (value) {
				*value++ = '\0';
				chromaprint_set_option(chromaprint_ctx, name, atoi(value));
			}
		}
	}

	for (i = 0; i < num_file_names; i++) {
		file_name = file_names[i];
		if (!decode_audio_file(chromaprint_ctx, buffer1, buffer2, file_name, max_length, &duration)) {
			fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name);
			continue;
		}
		if (i > 0) {
			printf("\n");
		}
		printf("FILE=%s\n", file_name);
		printf("DURATION=%d\n", duration);
		if (raw) {
			if (!chromaprint_get_raw_fingerprint(chromaprint_ctx, (void **)&raw_fingerprint, &raw_fingerprint_size)) {
				fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name);
				continue;
			}
			printf("FINGERPRINT=");
			for (j = 0; j < raw_fingerprint_size; j++) {
				printf("%d%s", raw_fingerprint[j], j + 1 < raw_fingerprint_size ? "," : "");
			}
			printf("\n");
			chromaprint_dealloc(raw_fingerprint);
		}
		else {
			if (!chromaprint_get_fingerprint(chromaprint_ctx, &fingerprint)) {
				fprintf(stderr, "ERROR: unable to calculate fingerprint for file %s, skipping\n", file_name);
				continue;
			}
			printf("FINGERPRINT=%s\n", fingerprint);
			chromaprint_dealloc(fingerprint);
		}
	}

	chromaprint_free(chromaprint_ctx);
	av_free(buffer1);
	av_free(buffer2);
	free(file_names);

	return 0;
}
示例#9
0
Chroma::Result Chroma::operator() (const QString& filename)
{
    std::shared_ptr<AVFormatContext> formatCtx;
    {
        AVFormatContext *formatCtxRaw = nullptr;
        if (avformat_open_input (&formatCtxRaw, filename.toLatin1 ().constData (), nullptr, nullptr))
            throw std::runtime_error ("error opening file");

        formatCtx.reset (formatCtxRaw,
        [] (AVFormatContext *ctx) {
            avformat_close_input (&ctx);
        });
    }

    {
        QMutexLocker locker (&CodecMutex_);
        if (avformat_find_stream_info (formatCtx.get (), nullptr) < 0)
            throw std::runtime_error ("could not find stream");
    }

    AVCodec *codec = nullptr;
    const auto streamIndex = av_find_best_stream (formatCtx.get (), AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
    if (streamIndex < 0)
        throw std::runtime_error ("could not find audio stream");

    auto stream = formatCtx->streams [streamIndex];

    bool codecOpened = false;

    std::shared_ptr<AVCodecContext> codecCtx (stream->codec,
    [&codecOpened] (AVCodecContext *ctx) {
        if (codecOpened) avcodec_close (ctx);
    });
    {
        QMutexLocker locker (&CodecMutex_);
        if (avcodec_open2 (codecCtx.get (), codec, nullptr) < 0)
            throw std::runtime_error ("couldn't open the codec");
    }
    codecOpened = true;

    if (codecCtx->channels <= 0)
        throw std::runtime_error ("no channels found");

    std::shared_ptr<SwrContext> swr;
    if (codecCtx->sample_fmt != AV_SAMPLE_FMT_S16)
    {
        swr.reset (swr_alloc (), [] (SwrContext *ctx) {
            if (ctx) swr_free (&ctx);
        });
        av_opt_set_int (swr.get (), "in_channel_layout", codecCtx->channel_layout, 0);
        av_opt_set_int (swr.get (), "out_channel_layout", codecCtx->channel_layout,  0);
        av_opt_set_int (swr.get (), "in_sample_rate", codecCtx->sample_rate, 0);
        av_opt_set_int (swr.get (), "out_sample_rate", codecCtx->sample_rate, 0);
        av_opt_set_sample_fmt (swr.get (), "in_sample_fmt", codecCtx->sample_fmt, 0);
        av_opt_set_sample_fmt (swr.get (), "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
        swr_init (swr.get ());
    }

    AVPacket packet;
    av_init_packet (&packet);

    const int maxLength = 120;
    auto remaining = maxLength * codecCtx->channels * codecCtx->sample_rate;
    chromaprint_start (Ctx_, codecCtx->sample_rate, codecCtx->channels);

    std::shared_ptr<AVFrame> frame (av_frame_alloc (),
    [] (AVFrame *frame) {
        av_frame_free (&frame);
    });
    auto maxDstNbSamples = 0;

    uint8_t *dstData [1] = { nullptr };
    std::shared_ptr<void> dstDataGuard (nullptr,
    [&dstData] (void*) {
        if (dstData [0]) av_freep (&dstData [0]);
    });
    while (true)
    {
        if (av_read_frame (formatCtx.get (), &packet) < 0)
            break;

        std::shared_ptr<void> guard (nullptr,
        [&packet] (void*) {
            if (packet.data) av_free_packet (&packet);
        });

        if (packet.stream_index != streamIndex)
            continue;

        av_frame_unref (frame.get ());
        int gotFrame = false;
        auto consumed = avcodec_decode_audio4 (codecCtx.get (), frame.get (), &gotFrame, &packet);

        if (consumed < 0 || !gotFrame)
            continue;

        uint8_t **data = nullptr;
        if (swr)
        {
            if (frame->nb_samples > maxDstNbSamples)
            {
                if (dstData [0])
                    av_freep (&dstData [0]);
                int linesize = 0;
                if (av_samples_alloc (dstData, &linesize, codecCtx->channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1) < 0)
                    throw std::runtime_error ("cannot allocate memory for resampling");
            }

            if (swr_convert (swr.get (), dstData, frame->nb_samples, const_cast<const uint8_t**> (frame->data), frame->nb_samples) < 0)
                throw std::runtime_error ("cannot resample audio");

            data = dstData;
        }
        else
            data = frame->data;

        auto length = std::min (remaining, frame->nb_samples * codecCtx->channels);
        if (!chromaprint_feed (Ctx_, data [0], length))
            throw std::runtime_error ("cannot feed data");

        bool finished = false;
        if (maxLength)
        {
            remaining -= length;
            if (remaining <= 0)
                finished = true;
        }
        if (finished)
            break;
    }

    if (!chromaprint_finish (Ctx_))
        throw std::runtime_error ("fingerprint calculation failed");

    char *fingerprint = 0;
    if (!chromaprint_get_fingerprint (Ctx_, &fingerprint))
        throw std::runtime_error ("unable to get fingerprint");

    QByteArray result (fingerprint);
    chromaprint_dealloc (fingerprint);

    const double divideFactor = 1. / av_q2d (stream->time_base);
    const double duration = stream->duration / divideFactor;

    return { result, static_cast<int> (duration) };
}
示例#10
0
int decode_audio_file(ChromaprintContext *chromaprint_ctx, const char *file_name, int max_length, int *duration)
{
	int ok = 0, remaining, length, consumed, codec_ctx_opened = 0, got_frame, stream_index;
	AVFormatContext *format_ctx = NULL;
	AVCodecContext *codec_ctx = NULL;
	AVCodec *codec = NULL;
	AVStream *stream = NULL;
	AVFrame *frame = NULL;
#if defined(HAVE_SWRESAMPLE)
	SwrContext *convert_ctx = NULL;
#elif defined(HAVE_AVRESAMPLE)
	AVAudioResampleContext *convert_ctx = NULL;
#else
	void *convert_ctx = NULL;
#endif
	int max_dst_nb_samples = 0, dst_linsize = 0;
	uint8_t *dst_data[1] = { NULL };
	uint8_t **data;
	AVPacket packet;

	if (!strcmp(file_name, "-")) {
		file_name = "pipe:0";
	}

	if (avformat_open_input(&format_ctx, file_name, NULL, NULL) != 0) {
		fprintf(stderr, "ERROR: couldn't open the file\n");
		goto done;
	}

	if (avformat_find_stream_info(format_ctx, NULL) < 0) {
		fprintf(stderr, "ERROR: couldn't find stream information in the file\n");
		goto done;
	}

	stream_index = av_find_best_stream(format_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
	if (stream_index < 0) {
		fprintf(stderr, "ERROR: couldn't find any audio stream in the file\n");
		goto done;
	}

	stream = format_ctx->streams[stream_index];

	codec_ctx = stream->codec;
	codec_ctx->request_sample_fmt = AV_SAMPLE_FMT_S16;

	if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
		fprintf(stderr, "ERROR: couldn't open the codec\n");
		goto done;
	}
	codec_ctx_opened = 1;

	if (codec_ctx->channels <= 0) {
		fprintf(stderr, "ERROR: no channels found in the audio stream\n");
		goto done;
	}

	if (codec_ctx->sample_fmt != AV_SAMPLE_FMT_S16) {
		int64_t channel_layout = codec_ctx->channel_layout;
		if (!channel_layout) {
			channel_layout = get_default_channel_layout(codec_ctx->channels);
		}
#if defined(HAVE_SWRESAMPLE)
		convert_ctx = swr_alloc_set_opts(NULL,
			channel_layout, AV_SAMPLE_FMT_S16, codec_ctx->sample_rate,
			channel_layout, codec_ctx->sample_fmt, codec_ctx->sample_rate,
			0, NULL);
		if (!convert_ctx) {
			fprintf(stderr, "ERROR: couldn't allocate audio converter\n");
			goto done;
		}
		if (swr_init(convert_ctx) < 0) {
			fprintf(stderr, "ERROR: couldn't initialize the audio converter\n");
			goto done;
		}
#elif defined(HAVE_AVRESAMPLE)
		convert_ctx = avresample_alloc_context();
		av_opt_set_int(convert_ctx, "out_channel_layout", channel_layout, 0);
		av_opt_set_int(convert_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0);
		av_opt_set_int(convert_ctx, "out_sample_rate", codec_ctx->sample_rate, 0);
		av_opt_set_int(convert_ctx, "in_channel_layout", channel_layout, 0);
		av_opt_set_int(convert_ctx, "in_sample_fmt", codec_ctx->sample_fmt, 0);
		av_opt_set_int(convert_ctx, "in_sample_rate", codec_ctx->sample_rate, 0);
		if (!convert_ctx) {
			fprintf(stderr, "ERROR: couldn't allocate audio converter\n");
			goto done;
		}
		if (avresample_open(convert_ctx) < 0) {
			fprintf(stderr, "ERROR: couldn't initialize the audio converter\n");
			goto done;
		}
#else
		fprintf(stderr, "ERROR: unsupported audio format (please build fpcalc with libswresample)\n");
		goto done;
#endif
	}

	if (stream->duration != AV_NOPTS_VALUE) {
		*duration = stream->time_base.num * stream->duration / stream->time_base.den;
	}
	else if (format_ctx->duration != AV_NOPTS_VALUE) {
		*duration = format_ctx->duration / AV_TIME_BASE;
	}
	else {
		fprintf(stderr, "ERROR: couldn't detect the audio duration\n");
		goto done;
	}

	remaining = max_length * codec_ctx->channels * codec_ctx->sample_rate;
	chromaprint_start(chromaprint_ctx, codec_ctx->sample_rate, codec_ctx->channels);

	frame = av_frame_alloc();

	while (1) {
		if (av_read_frame(format_ctx, &packet) < 0) {
			break;
		}

		if (packet.stream_index == stream_index) {
			av_frame_unref(frame);

			got_frame = 0;
			consumed = avcodec_decode_audio4(codec_ctx, frame, &got_frame, &packet);
			if (consumed < 0) {
				fprintf(stderr, "WARNING: error decoding audio\n");
				continue;
			}

			if (got_frame) {
				data = frame->data;
				if (convert_ctx) {
					if (frame->nb_samples > max_dst_nb_samples) {
						av_freep(&dst_data[0]);
						if (av_samples_alloc(dst_data, &dst_linsize, codec_ctx->channels, frame->nb_samples, AV_SAMPLE_FMT_S16, 1) < 0) {
							fprintf(stderr, "ERROR: couldn't allocate audio converter buffer\n");
							goto done;
						}
						max_dst_nb_samples = frame->nb_samples;
					}
#if defined(HAVE_SWRESAMPLE)
					if (swr_convert(convert_ctx, dst_data, frame->nb_samples, (const uint8_t **)frame->data, frame->nb_samples) < 0)
#elif defined(HAVE_AVRESAMPLE)
					if (avresample_convert(convert_ctx, dst_data, 0, frame->nb_samples, (uint8_t **)frame->data, 0, frame->nb_samples) < 0)
#endif
					{
						fprintf(stderr, "ERROR: couldn't convert the audio\n");
						goto done;
					}
					data = dst_data;
				}
				length = MIN(remaining, frame->nb_samples * codec_ctx->channels);
				if (!chromaprint_feed(chromaprint_ctx, data[0], length)) {
					goto done;
				}

				if (max_length) {
					remaining -= length;
					if (remaining <= 0) {
						goto finish;
					}
				}
			}
		}
		av_free_packet(&packet);
	}

finish:
	if (!chromaprint_finish(chromaprint_ctx)) {
		fprintf(stderr, "ERROR: fingerprint calculation failed\n");
		goto done;
	}

	ok = 1;

done:
	if (frame) {
		av_frame_free(&frame);
	}
	if (dst_data[0]) {
		av_freep(&dst_data[0]);
	}
	if (convert_ctx) {
#if defined(HAVE_SWRESAMPLE)
		swr_free(&convert_ctx);
#elif defined(HAVE_AVRESAMPLE)
		avresample_free(&convert_ctx);
#endif
	}
	if (codec_ctx_opened) {
		avcodec_close(codec_ctx);
	}
	if (format_ctx) {
		avformat_close_input(&format_ctx);
	}
	return ok;
}
示例#11
0
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;
}
示例#12
0
static void *print_thread(void *arg) {
    struct GrooveFingerprinterPrivate *p = (GrooveFingerprinterPrivate *)arg;
    struct GrooveFingerprinter *printer = &p->externals;

    struct GrooveBuffer *buffer;
    while (!p->abort_request.load()) {
        pthread_mutex_lock(&p->info_head_mutex);

        if (p->info_queue_count >= printer->info_queue_size) {
            pthread_cond_wait(&p->drain_cond, &p->info_head_mutex);
            pthread_mutex_unlock(&p->info_head_mutex);
            continue;
        }

        // we definitely want to unlock the mutex while we wait for the
        // next buffer. Otherwise there will be a deadlock when sink_flush or
        // sink_purge is called.
        pthread_mutex_unlock(&p->info_head_mutex);

        int result = groove_sink_buffer_get(p->sink, &buffer, 1);

        pthread_mutex_lock(&p->info_head_mutex);

        if (result == GROOVE_BUFFER_END) {
            // last file info
            emit_track_info(p);

            // send album info
            struct GrooveFingerprinterInfo *info = allocate<GrooveFingerprinterInfo>(1);
            if (info) {
                info->duration = p->album_duration;
                groove_queue_put(p->info_queue, info);
            } else {
                av_log(NULL, AV_LOG_ERROR, "unable to allocate album fingerprint info\n");
            }

            p->album_duration = 0.0;

            p->info_head = NULL;
            p->info_pos = -1.0;

            pthread_mutex_unlock(&p->info_head_mutex);
            continue;
        }

        if (result != GROOVE_BUFFER_YES) {
            pthread_mutex_unlock(&p->info_head_mutex);
            break;
        }

        if (buffer->item != p->info_head) {
            if (p->info_head) {
                emit_track_info(p);
            }
            if (!chromaprint_start(p->chroma_ctx, 44100, 2)) {
                av_log(NULL, AV_LOG_ERROR, "unable to start fingerprint\n");
            }
            p->track_duration = 0.0;
            p->info_head = buffer->item;
            p->info_pos = buffer->pos;
        }

        double buffer_duration = buffer->frame_count / (double)buffer->format.sample_rate;
        p->track_duration += buffer_duration;
        p->album_duration += buffer_duration;
        if (!chromaprint_feed(p->chroma_ctx, buffer->data[0], buffer->frame_count * 2)) {
            av_log(NULL, AV_LOG_ERROR, "unable to feed fingerprint\n");
        }

        pthread_mutex_unlock(&p->info_head_mutex);
        groove_buffer_unref(buffer);
    }

    return NULL;
}