summaryrefslogtreecommitdiff
path: root/src/decoder/plugins
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2018-02-17 13:10:04 +0100
committerMax Kellermann <max@musicpd.org>2018-02-17 13:33:53 +0100
commit026aef7465506429ee94e7b5b68e36ab8ed5a849 (patch)
tree98e41d2b3e99db64a7fafdc25707e67dc64ad77b /src/decoder/plugins
parentb53a23b51b8d02a709af0bc8681a25197f12481b (diff)
decoder/flac: move the SubmitData() call out of the callback
This addresses two problems: 1. the libFLAC write callback had to send an error status to its caller when SubmitData() returned a command; this disrupted libFLAC and the resulting command could not be used for anything; 2. the libFLAC function FLAC__stream_decoder_seek_absolute() also calls the write callback, but its result cannot be used, because seeking is still in progress, so we lose all data from one FLAC frame. By moving the SubmitData() call until after CommandFinished(), we avoid losing this data. This fixes another part of #113
Diffstat (limited to 'src/decoder/plugins')
-rw-r--r--src/decoder/plugins/FlacCommon.cxx20
-rw-r--r--src/decoder/plugins/FlacCommon.hxx14
-rw-r--r--src/decoder/plugins/FlacDecoderPlugin.cxx21
3 files changed, 34 insertions, 21 deletions
diff --git a/src/decoder/plugins/FlacCommon.cxx b/src/decoder/plugins/FlacCommon.cxx
index 1abd5682e..5dfd8555f 100644
--- a/src/decoder/plugins/FlacCommon.cxx
+++ b/src/decoder/plugins/FlacCommon.cxx
@@ -24,7 +24,6 @@
#include "config.h"
#include "FlacCommon.hxx"
#include "FlacMetadata.hxx"
-#include "util/ConstBuffer.hxx"
#include "Log.hxx"
#include <stdexcept>
@@ -143,25 +142,10 @@ FlacDecoder::OnWrite(const FLAC__Frame &frame,
if (!initialized && !OnFirstFrame(frame.header))
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
- const auto data = pcm_import.Import(buf, frame.header.blocksize);
+ chunk = pcm_import.Import(buf, frame.header.blocksize);
- unsigned bit_rate = nbytes * 8 * frame.header.sample_rate /
+ kbit_rate = nbytes * 8 * frame.header.sample_rate /
(1000 * frame.header.blocksize);
- auto cmd = GetClient()->SubmitData(GetInputStream(),
- data.data, data.size,
- bit_rate);
- switch (cmd) {
- case DecoderCommand::NONE:
- case DecoderCommand::START:
- break;
-
- case DecoderCommand::STOP:
- return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
-
- case DecoderCommand::SEEK:
- return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
- }
-
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
diff --git a/src/decoder/plugins/FlacCommon.hxx b/src/decoder/plugins/FlacCommon.hxx
index c33ca6e47..5f8c21b5e 100644
--- a/src/decoder/plugins/FlacCommon.hxx
+++ b/src/decoder/plugins/FlacCommon.hxx
@@ -27,6 +27,7 @@
#include "FlacInput.hxx"
#include "FlacPcm.hxx"
#include "../DecoderAPI.hxx"
+#include "util/ConstBuffer.hxx"
#include <FLAC/stream_decoder.h>
@@ -41,6 +42,12 @@ struct FlacDecoder : public FlacInput {
*/
bool unsupported = false;
+ /**
+ * The kbit_rate parameter for the next
+ * DecoderBridge::SubmitData() call.
+ */
+ uint16_t kbit_rate;
+
FlacPcmImport pcm_import;
/**
@@ -51,6 +58,13 @@ struct FlacDecoder : public FlacInput {
Tag tag;
+ /**
+ * Decoded PCM data obtained by our libFLAC write callback.
+ * If this is non-empty, then DecoderBridge::SubmitData()
+ * should be called.
+ */
+ ConstBuffer<void> chunk = nullptr;
+
FlacDecoder(DecoderClient &_client, InputStream &_input_stream)
:FlacInput(_input_stream, &_client) {}
diff --git a/src/decoder/plugins/FlacDecoderPlugin.cxx b/src/decoder/plugins/FlacDecoderPlugin.cxx
index 0b1c2a12a..80647d07a 100644
--- a/src/decoder/plugins/FlacDecoderPlugin.cxx
+++ b/src/decoder/plugins/FlacDecoderPlugin.cxx
@@ -142,13 +142,28 @@ flac_decoder_initialize(FlacDecoder *data, FLAC__StreamDecoder *sd)
static DecoderCommand
FlacSubmitToClient(DecoderClient &client, FlacDecoder &d) noexcept
{
+ if (d.tag.IsEmpty() && d.chunk.IsEmpty())
+ return client.GetCommand();
+
if (!d.tag.IsEmpty()) {
auto cmd = client.SubmitTag(d.GetInputStream(),
std::move(d.tag));
d.tag.Clear();
- return cmd;
- } else
- return client.GetCommand();
+ if (cmd != DecoderCommand::NONE)
+ return cmd;
+ }
+
+ if (!d.chunk.IsEmpty()) {
+ auto cmd = client.SubmitData(d.GetInputStream(),
+ d.chunk.data,
+ d.chunk.size,
+ d.kbit_rate);
+ d.chunk = nullptr;
+ if (cmd != DecoderCommand::NONE)
+ return cmd;
+ }
+
+ return DecoderCommand::NONE;
}
static void