summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--src/decoder/OggFind.cxx38
-rw-r--r--src/decoder/OggFind.hxx40
-rw-r--r--src/decoder/OpusDecoderPlugin.cxx22
4 files changed, 101 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 351978440..469aa129f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -531,6 +531,7 @@ if HAVE_OPUS
libdecoder_plugins_a_SOURCES += \
src/decoder/OggUtil.cxx \
src/decoder/OggUtil.hxx \
+ src/decoder/OggFind.cxx src/decoder/OggFind.hxx \
src/decoder/OpusReader.hxx \
src/decoder/OpusHead.hxx \
src/decoder/OpusHead.cxx \
diff --git a/src/decoder/OggFind.cxx b/src/decoder/OggFind.cxx
new file mode 100644
index 000000000..4f4fd1e96
--- /dev/null
+++ b/src/decoder/OggFind.cxx
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "OggFind.hxx"
+#include "OggUtil.hxx"
+
+bool
+OggFindEOS(ogg_sync_state &oy, ogg_stream_state &os, ogg_packet &packet,
+ decoder *decoder, input_stream *is)
+{
+ while (true) {
+ int r = ogg_stream_packetout(&os, &packet);
+ if (r == 0) {
+ if (!OggExpectPageIn(oy, os, decoder, is))
+ return false;
+
+ continue;
+ } else if (r > 0 && packet.e_o_s)
+ return true;
+ }
+}
diff --git a/src/decoder/OggFind.hxx b/src/decoder/OggFind.hxx
new file mode 100644
index 000000000..6a55f9b34
--- /dev/null
+++ b/src/decoder/OggFind.hxx
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_OGG_FIND_HXX
+#define MPD_OGG_FIND_HXX
+
+#include "check.h"
+
+#include <ogg/ogg.h>
+
+struct decoder;
+struct input_stream;
+
+/**
+ * Skip all pages/packets until an end-of-stream (EOS) packet for the
+ * specified stream is found.
+ *
+ * @return true if the EOS packet was found
+ */
+bool
+OggFindEOS(ogg_sync_state &oy, ogg_stream_state &os, ogg_packet &packet,
+ decoder *decoder, input_stream *is);
+
+#endif
diff --git a/src/decoder/OpusDecoderPlugin.cxx b/src/decoder/OpusDecoderPlugin.cxx
index c4d6c2d12..9c2f86d05 100644
--- a/src/decoder/OpusDecoderPlugin.cxx
+++ b/src/decoder/OpusDecoderPlugin.cxx
@@ -22,6 +22,7 @@
#include "OpusHead.hxx"
#include "OpusTags.hxx"
#include "OggUtil.hxx"
+#include "OggFind.hxx"
#include "decoder_api.h"
#include "OggCodec.hxx"
#include "audio_check.h"
@@ -291,6 +292,23 @@ mpd_opus_stream_decode(struct decoder *decoder,
}
static bool
+SeekFindEOS(ogg_sync_state &oy, ogg_stream_state &os, ogg_packet &packet,
+ decoder *decoder, input_stream *is)
+{
+ if (is->size > 0 && is->size - is->offset < 65536)
+ return OggFindEOS(oy, os, packet, decoder, is);
+
+ if (!input_stream_cheap_seeking(is))
+ return false;
+
+ ogg_sync_reset(&oy);
+
+ return input_stream_lock_seek(is, -65536, SEEK_END, nullptr) &&
+ OggExpectPageSeekIn(oy, os, decoder, is) &&
+ OggFindEOS(oy, os, packet, decoder, is);
+}
+
+static bool
mpd_opus_scan_stream(struct input_stream *is,
const struct tag_handler *handler, void *handler_ctx)
{
@@ -351,6 +369,10 @@ mpd_opus_scan_stream(struct input_stream *is,
}
}
+ if (packet.e_o_s || SeekFindEOS(oy, os, packet, nullptr, is))
+ tag_handler_invoke_duration(handler, handler_ctx,
+ packet.granulepos / opus_sample_rate);
+
ogg_stream_clear(&os);
ogg_sync_clear(&oy);