decoder/ogg: ignore the BOS packet after seek to the beginning of song

Previously, MPD would skip the current song after attempting to seek
to its beginnig, because that was a seek to offset 0.  At offset 0,
MPD will see the BOS packet again, which results in throwing
StopDecoder in MPDOpusDecoder::OnOggEnd().

Closes https://github.com/MusicPlayerDaemon/MPD/issues/470
This commit is contained in:
Max Kellermann 2019-03-17 23:14:59 +01:00
parent b76d78e6ae
commit 6d12c22653
3 changed files with 18 additions and 0 deletions

1
NEWS
View File

@ -7,6 +7,7 @@ ver 0.21.6 (not yet released)
- cdio_paranoia: fix build failure due to missing #include - cdio_paranoia: fix build failure due to missing #include
* decoder * decoder
- opus: fix replay gain when there are no other tags - opus: fix replay gain when there are no other tags
- opus: fix seeking to beginning of song
* output * output
- pulse: work around error with unusual channel count - pulse: work around error with unusual channel count
- osx: fix build failure - osx: fix build failure

View File

@ -20,6 +20,7 @@
#include "OggVisitor.hxx" #include "OggVisitor.hxx"
#include <stdexcept> #include <stdexcept>
#include <utility>
void void
OggVisitor::EndStream() OggVisitor::EndStream()
@ -51,7 +52,13 @@ OggVisitor::ReadNextPage()
inline void inline void
OggVisitor::HandlePacket(const ogg_packet &packet) OggVisitor::HandlePacket(const ogg_packet &packet)
{ {
const bool _post_seek = std::exchange(post_seek, false);
if (packet.b_o_s) { if (packet.b_o_s) {
if (_post_seek)
/* ignore the BOS packet after seeking */
return;
EndStream(); EndStream();
has_stream = true; has_stream = true;
OnOggBeginning(packet); OnOggBeginning(packet);
@ -97,4 +104,6 @@ OggVisitor::PostSeek()
/* find the next Ogg page and feed it into the stream */ /* find the next Ogg page and feed it into the stream */
sync.ExpectPageSeekIn(stream); sync.ExpectPageSeekIn(stream);
post_seek = true;
} }

View File

@ -39,6 +39,14 @@ class OggVisitor {
bool has_stream = false; bool has_stream = false;
/**
* This is true after seeking; its one-time effect is to
* ignore the BOS packet, just in case we have been seeking to
* the beginning of the file, because that would disrupt
* playback.
*/
bool post_seek = false;
public: public:
explicit OggVisitor(Reader &reader) explicit OggVisitor(Reader &reader)
:sync(reader), stream(0) {} :sync(reader), stream(0) {}