summaryrefslogtreecommitdiff
path: root/src/decoder
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2019-08-02 22:18:45 +0200
committerMax Kellermann <max@musicpd.org>2019-08-03 08:32:27 +0200
commit3e3d8c7f9d095daac987a9688b1917e556ae8649 (patch)
tree6fd3baceff25003b5b30b746c11399de53020eeb /src/decoder
parent9b99a9897a96cbc7e7c3697d5c3c4e70ffcf0047 (diff)
decoder/mad: pad the input buffer with zero bytes and end of file
libmad requires padding the input buffer with "MAD_BUFFER_GUARD" zero bytes at the end of the file, or else it is unable to decode the last frame. This fixes yet another bug which prevented this plugin from decoding the last frame, see https://github.com/MusicPlayerDaemon/MPD/issues/601
Diffstat (limited to 'src/decoder')
-rw-r--r--src/decoder/plugins/MadDecoderPlugin.cxx16
1 files changed, 15 insertions, 1 deletions
diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx
index 33a9be644..626fec855 100644
--- a/src/decoder/plugins/MadDecoderPlugin.cxx
+++ b/src/decoder/plugins/MadDecoderPlugin.cxx
@@ -132,6 +132,14 @@ class MadDecoder {
bool found_replay_gain = false;
bool found_first_frame = false;
bool decoded_first_frame = false;
+
+ /**
+ * If this flag is true, then end-of-file was seen and a
+ * padding of 8 zero bytes were appended to #input_buffer, to
+ * allow libmad to decode the last frame.
+ */
+ bool was_eof = false;
+
DecoderClient *const client;
InputStream &input_stream;
enum mad_layer layer = mad_layer(0);
@@ -247,7 +255,12 @@ MadDecoder::FillBuffer() noexcept
size_t nbytes = decoder_read(client, input_stream,
dest, max_read_size);
if (nbytes == 0) {
- return false;
+ if (was_eof || max_read_size < MAD_BUFFER_GUARD)
+ return false;
+
+ was_eof = true;
+ nbytes = MAD_BUFFER_GUARD;
+ memset(dest, 0, nbytes);
}
mad_stream_buffer(&stream, input_buffer, rest_size + nbytes);
@@ -922,6 +935,7 @@ MadDecoder::Read() noexcept
if (j < highest_frame) {
if (Seek(frame_offsets[j])) {
current_frame = j;
+ was_eof = false;
client->CommandFinished();
} else
client->SeekError();