aboutsummaryrefslogtreecommitdiffstats
path: root/src/DecoderAPI.cxx
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/DecoderAPI.cxx92
1 files changed, 71 insertions, 21 deletions
diff --git a/src/DecoderAPI.cxx b/src/DecoderAPI.cxx
index 4fea02bef..148d20005 100644
--- a/src/DecoderAPI.cxx
+++ b/src/DecoderAPI.cxx
@@ -20,6 +20,7 @@
#include "config.h"
#include "DecoderAPI.hxx"
#include "DecoderError.hxx"
+#include "pcm/PcmConvert.hxx"
#include "AudioConfig.hxx"
#include "ReplayGainConfig.hxx"
#include "MusicChunk.hxx"
@@ -27,13 +28,12 @@
#include "MusicPipe.hxx"
#include "DecoderControl.hxx"
#include "DecoderInternal.hxx"
-#include "Song.hxx"
+#include "DetachedSong.hxx"
#include "InputStream.hxx"
#include "util/Error.hxx"
#include "Log.hxx"
#include <assert.h>
-#include <stdlib.h>
#include <string.h>
#include <math.h>
@@ -47,6 +47,7 @@ decoder_initialized(Decoder &decoder,
assert(dc.state == DecoderState::START);
assert(dc.pipe != nullptr);
+ assert(decoder.convert == nullptr);
assert(decoder.stream_tag == nullptr);
assert(decoder.decoder_tag == nullptr);
assert(!decoder.seeking);
@@ -59,19 +60,28 @@ decoder_initialized(Decoder &decoder,
dc.seekable = seekable;
dc.total_time = total_time;
- dc.Lock();
- dc.state = DecoderState::DECODE;
- dc.client_cond.signal();
- dc.Unlock();
-
FormatDebug(decoder_domain, "audio_format=%s, seekable=%s",
audio_format_to_string(dc.in_audio_format, &af_string),
seekable ? "true" : "false");
- if (dc.in_audio_format != dc.out_audio_format)
+ if (dc.in_audio_format != dc.out_audio_format) {
FormatDebug(decoder_domain, "converting to %s",
audio_format_to_string(dc.out_audio_format,
&af_string));
+
+ decoder.convert = new PcmConvert();
+
+ Error error;
+ if (!decoder.convert->Open(dc.in_audio_format,
+ dc.out_audio_format,
+ error))
+ decoder.error = std::move(error);
+ }
+
+ dc.Lock();
+ dc.state = DecoderState::DECODE;
+ dc.client_cond.signal();
+ dc.Unlock();
}
/**
@@ -129,6 +139,10 @@ gcc_pure
static DecoderCommand
decoder_get_virtual_command(Decoder &decoder)
{
+ if (decoder.error.IsDefined())
+ /* an error has occurred: stop the decoder plugin */
+ return DecoderCommand::STOP;
+
const DecoderControl &dc = decoder.dc;
assert(dc.pipe != nullptr);
@@ -292,6 +306,40 @@ decoder_read(Decoder *decoder,
return nbytes;
}
+bool
+decoder_read_full(Decoder *decoder, InputStream &is,
+ void *_buffer, size_t size)
+{
+ uint8_t *buffer = (uint8_t *)_buffer;
+
+ while (size > 0) {
+ size_t nbytes = decoder_read(decoder, is, buffer, size);
+ if (nbytes == 0)
+ return false;
+
+ buffer += nbytes;
+ size -= nbytes;
+ }
+
+ return true;
+}
+
+bool
+decoder_skip(Decoder *decoder, InputStream &is, size_t size)
+{
+ while (size > 0) {
+ char buffer[1024];
+ size_t nbytes = decoder_read(decoder, is, buffer,
+ std::min(sizeof(buffer), size));
+ if (nbytes == 0)
+ return false;
+
+ size -= nbytes;
+ }
+
+ return true;
+}
+
void
decoder_timestamp(Decoder &decoder, double t)
{
@@ -312,12 +360,12 @@ do_send_tag(Decoder &decoder, const Tag &tag)
if (decoder.chunk != nullptr) {
/* there is a partial chunk - flush it, we want the
tag in a new chunk */
- decoder_flush_chunk(decoder);
+ decoder.FlushChunk();
}
assert(decoder.chunk == nullptr);
- chunk = decoder_get_chunk(decoder);
+ chunk = decoder.GetChunk();
if (chunk == nullptr) {
assert(decoder.dc.command != DecoderCommand::NONE);
return decoder.dc.command;
@@ -388,13 +436,13 @@ decoder_data(Decoder &decoder,
return cmd;
}
- if (dc.in_audio_format != dc.out_audio_format) {
+ if (decoder.convert != nullptr) {
+ assert(dc.in_audio_format != dc.out_audio_format);
+
Error error;
- data = decoder.conv_state.Convert(dc.in_audio_format,
- data, length,
- dc.out_audio_format,
- &length,
- error);
+ data = decoder.convert->Convert(data, length,
+ &length,
+ error);
if (data == nullptr) {
/* the PCM conversion has failed - stop
playback, since we have no better way to
@@ -402,13 +450,15 @@ decoder_data(Decoder &decoder,
LogError(error);
return DecoderCommand::STOP;
}
+ } else {
+ assert(dc.in_audio_format == dc.out_audio_format);
}
while (length > 0) {
struct music_chunk *chunk;
bool full;
- chunk = decoder_get_chunk(decoder);
+ chunk = decoder.GetChunk();
if (chunk == nullptr) {
assert(dc.command != DecoderCommand::NONE);
return dc.command;
@@ -417,11 +467,11 @@ decoder_data(Decoder &decoder,
const auto dest =
chunk->Write(dc.out_audio_format,
decoder.timestamp -
- dc.song->start_ms / 1000.0,
+ dc.song->GetStartMS() / 1000.0,
kbit_rate);
if (dest.IsNull()) {
/* the chunk is full, flush it */
- decoder_flush_chunk(decoder);
+ decoder.FlushChunk();
continue;
}
@@ -440,7 +490,7 @@ decoder_data(Decoder &decoder,
full = chunk->Expand(dc.out_audio_format, nbytes);
if (full) {
/* the chunk is full, flush it */
- decoder_flush_chunk(decoder);
+ decoder.FlushChunk();
}
data = (const uint8_t *)data + nbytes;
@@ -532,7 +582,7 @@ decoder_replay_gain(Decoder &decoder,
/* flush the current chunk because the new
replay gain values affect the following
samples */
- decoder_flush_chunk(decoder);
+ decoder.FlushChunk();
}
} else
decoder.replay_gain_serial = 0;