diff options
Diffstat (limited to 'src/DecoderAPI.cxx')
-rw-r--r-- | src/DecoderAPI.cxx | 92 |
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; |