diff --git a/src/lib/chromaprint/DecoderClient.cxx b/src/lib/chromaprint/DecoderClient.cxx new file mode 100644 index 000000000..f71bea82b --- /dev/null +++ b/src/lib/chromaprint/DecoderClient.cxx @@ -0,0 +1,88 @@ +/* + * Copyright 2003-2019 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "DecoderClient.hxx" +#include "input/InputStream.hxx" +#include "util/ConstBuffer.hxx" + +void +ChromaprintDecoderClient::PrintResult() +{ + if (!ready) + throw std::runtime_error("Decoding failed"); + + if (need_convert) { + auto flushed = convert.Flush(); + auto data = ConstBuffer::FromVoid(flushed); + chromaprint.Feed(data.data, data.size); + } + + chromaprint.Finish(); + + printf("%s\n", chromaprint.GetFingerprint().c_str()); +} + +void +ChromaprintDecoderClient::Ready(AudioFormat audio_format, bool, SignedSongTime) +{ + /* feed the first two minutes into libchromaprint */ + remaining_bytes = audio_format.TimeToSize(std::chrono::minutes(2)); + + if (audio_format.format != SampleFormat::S16) { + const AudioFormat src_audio_format = audio_format; + audio_format.format = SampleFormat::S16; + + convert.Open(src_audio_format, audio_format); + need_convert = true; + } + + chromaprint.Start(audio_format.sample_rate, audio_format.channels); + + ready = true; +} + +DecoderCommand +ChromaprintDecoderClient::SubmitData(InputStream *, + const void *_data, size_t length, + uint16_t) +{ + if (length > remaining_bytes) + remaining_bytes = 0; + else + remaining_bytes -= length; + + ConstBuffer src{_data, length}; + ConstBuffer data; + + if (need_convert) { + auto result = convert.Convert(src); + data = ConstBuffer::FromVoid(result); + } else + data = ConstBuffer::FromVoid(src); + + chromaprint.Feed(data.data, data.size); + + return GetCommand(); +} + +size_t +ChromaprintDecoderClient::Read(InputStream &is, void *buffer, size_t length) +{ + return is.LockRead(buffer, length); +} diff --git a/src/lib/chromaprint/DecoderClient.hxx b/src/lib/chromaprint/DecoderClient.hxx new file mode 100644 index 000000000..956983779 --- /dev/null +++ b/src/lib/chromaprint/DecoderClient.hxx @@ -0,0 +1,90 @@ +/* + * Copyright 2003-2019 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef CHROMAPRINT_DECODER_CLIENT_HXX +#define CHROMAPRINT_DECODER_CLIENT_HXX + +#include "Context.hxx" +#include "decoder/Client.hxx" +#include "pcm/PcmConvert.hxx" +#include "thread/Mutex.hxx" + +#include + +class ChromaprintDecoderClient : public DecoderClient { + bool ready = false; + + bool need_convert = false; + + PcmConvert convert; + + Chromaprint::Context chromaprint; + + uint64_t remaining_bytes; + +public: + Mutex mutex; + + ~ChromaprintDecoderClient() noexcept { + if (need_convert) + convert.Close(); + } + + void PrintResult(); + + /* virtual methods from DecoderClient */ + void Ready(AudioFormat audio_format, + bool seekable, SignedSongTime duration) override; + + DecoderCommand GetCommand() noexcept override { + return remaining_bytes > 0 + ? DecoderCommand::NONE + : DecoderCommand::STOP; + } + + void CommandFinished() override {} + + SongTime GetSeekTime() noexcept override { + return SongTime::zero(); + } + + uint64_t GetSeekFrame() noexcept override { + return 0; + } + + void SeekError() override {} + + //InputStreamPtr OpenUri(const char *) override; + + size_t Read(InputStream &is, void *buffer, size_t length) override; + + void SubmitTimestamp(FloatDuration) override {} + DecoderCommand SubmitData(InputStream *is, + const void *data, size_t length, + uint16_t kbit_rate) override; + + DecoderCommand SubmitTag(InputStream *, Tag &&) override { + return GetCommand(); + } + + void SubmitReplayGain(const ReplayGainInfo *) override {} + void SubmitMixRamp(MixRampInfo &&) override {} +}; + +#endif diff --git a/test/RunChromaprint.cxx b/test/RunChromaprint.cxx index 9c7a161fc..cfcfb7f60 100644 --- a/test/RunChromaprint.cxx +++ b/test/RunChromaprint.cxx @@ -1,5 +1,5 @@ /* - * Copyright 2003-2018 The Music Player Daemon Project + * Copyright 2003-2019 The Music Player Daemon Project * http://www.musicpd.org * * This program is free software; you can redistribute it and/or modify @@ -18,12 +18,10 @@ */ #include "ConfigGlue.hxx" -#include "lib/chromaprint/Context.hxx" -#include "pcm/PcmConvert.hxx" +#include "lib/chromaprint/DecoderClient.hxx" #include "event/Thread.hxx" #include "decoder/DecoderList.hxx" #include "decoder/DecoderPlugin.hxx" -#include "decoder/Client.hxx" #include "input/Init.hxx" #include "input/InputStream.hxx" #include "fs/Path.hxx" @@ -105,130 +103,13 @@ public: } }; -class ChromaprintDecoderClient final : public DecoderClient { - bool ready = false; - - bool need_convert = false; - - PcmConvert convert; - - Chromaprint::Context chromaprint; - - uint64_t remaining_bytes; - +class MyChromaprintDecoderClient final : public ChromaprintDecoderClient { public: - Mutex mutex; - - ~ChromaprintDecoderClient() noexcept { - if (need_convert) - convert.Close(); - } - - void PrintResult(); - - /* virtual methods from DecoderClient */ - void Ready(AudioFormat audio_format, - bool seekable, SignedSongTime duration) override; - - DecoderCommand GetCommand() noexcept override { - return remaining_bytes > 0 - ? DecoderCommand::NONE - : DecoderCommand::STOP; - } - - void CommandFinished() override {} - - SongTime GetSeekTime() noexcept override { - return SongTime::zero(); - } - - uint64_t GetSeekFrame() noexcept override { - return 0; - } - - void SeekError() override {} - InputStreamPtr OpenUri(const char *) override { throw std::runtime_error("Not implemented"); } - - size_t Read(InputStream &is, void *buffer, size_t length) override { - return is.LockRead(buffer, length); - } - - void SubmitTimestamp(FloatDuration) override {} - DecoderCommand SubmitData(InputStream *is, - const void *data, size_t length, - uint16_t kbit_rate) override; - - DecoderCommand SubmitTag(InputStream *, Tag &&) override { - return GetCommand(); - } - - void SubmitReplayGain(const ReplayGainInfo *) override {} - void SubmitMixRamp(MixRampInfo &&) override {} }; -void -ChromaprintDecoderClient::PrintResult() -{ - if (!ready) - throw std::runtime_error("Decoding failed"); - - if (need_convert) { - auto flushed = convert.Flush(); - auto data = ConstBuffer::FromVoid(flushed); - chromaprint.Feed(data.data, data.size); - } - - chromaprint.Finish(); - - printf("%s\n", chromaprint.GetFingerprint().c_str()); -} - -void -ChromaprintDecoderClient::Ready(AudioFormat audio_format, bool, SignedSongTime) -{ - /* feed the first two minutes into libchromaprint */ - remaining_bytes = audio_format.TimeToSize(std::chrono::minutes(2)); - - if (audio_format.format != SampleFormat::S16) { - const AudioFormat src_audio_format = audio_format; - audio_format.format = SampleFormat::S16; - - convert.Open(src_audio_format, audio_format); - need_convert = true; - } - - chromaprint.Start(audio_format.sample_rate, audio_format.channels); - - ready = true; -} - -DecoderCommand -ChromaprintDecoderClient::SubmitData(InputStream *, - const void *_data, size_t length, - uint16_t) -{ - if (length > remaining_bytes) - remaining_bytes = 0; - else - remaining_bytes -= length; - - ConstBuffer src{_data, length}; - ConstBuffer data; - - if (need_convert) { - auto result = convert.Convert(src); - data = ConstBuffer::FromVoid(result); - } else - data = ConstBuffer::FromVoid(src); - - chromaprint.Feed(data.data, data.size); - - return GetCommand(); -} - int main(int argc, char **argv) try { const auto c = ParseCommandLine(argc, argv); @@ -242,7 +123,7 @@ try { return EXIT_FAILURE; } - ChromaprintDecoderClient client; + MyChromaprintDecoderClient client; if (plugin->file_decode != nullptr) { plugin->FileDecode(client, Path::FromFS(c.uri)); } else if (plugin->stream_decode != nullptr) { diff --git a/test/meson.build b/test/meson.build index 7345283d9..731ad2cec 100644 --- a/test/meson.build +++ b/test/meson.build @@ -409,6 +409,7 @@ if chromaprint_dep.found() executable( 'RunChromaprint', 'RunChromaprint.cxx', + '../src/lib/chromaprint/DecoderClient.cxx', '../src/Log.cxx', '../src/LogBackend.cxx', include_directories: inc,