summaryrefslogtreecommitdiff
path: root/src/decoder
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2016-05-09 16:46:08 +0200
committerMax Kellermann <max@duempel.org>2016-05-14 11:31:31 +0200
commitbbbda7f8127136e766ce07db597874eacf9175b6 (patch)
treeaa69eb112770f6a1582c86d4b7fcd50ece6a00e3 /src/decoder
parente95890038068f552d92ceb6b62afbfc9e81d0c7a (diff)
decoder/opus: move code to new class OggDecoder
Prepare to reuse the same code for a new Vorbis decoder plugin based on libvorbis instead of libvorbisfile.
Diffstat (limited to 'src/decoder')
-rw-r--r--src/decoder/plugins/OggDecoder.cxx87
-rw-r--r--src/decoder/plugins/OggDecoder.hxx64
-rw-r--r--src/decoder/plugins/OpusDecoderPlugin.cxx89
3 files changed, 159 insertions, 81 deletions
diff --git a/src/decoder/plugins/OggDecoder.cxx b/src/decoder/plugins/OggDecoder.cxx
new file mode 100644
index 000000000..b987c45b0
--- /dev/null
+++ b/src/decoder/plugins/OggDecoder.cxx
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2003-2016 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" /* must be first for large file support */
+#include "OggDecoder.hxx"
+#include "lib/xiph/OggFind.hxx"
+#include "input/InputStream.hxx"
+#include "util/Error.hxx"
+
+/**
+ * Load the end-of-stream packet and restore the previous file
+ * position.
+ */
+bool
+OggDecoder::LoadEndPacket(ogg_packet &packet) const
+{
+ if (!input_stream.CheapSeeking())
+ /* we do this for local files only, because seeking
+ around remote files is expensive and not worth the
+ trouble */
+ return false;
+
+ const auto old_offset = input_stream.GetOffset();
+
+ /* create temporary Ogg objects for seeking and parsing the
+ EOS packet */
+
+ bool result;
+
+ {
+ DecoderReader reader(decoder, input_stream);
+ OggSyncState sync2(reader);
+ OggStreamState stream2(GetSerialNo());
+ result = OggSeekFindEOS(sync2, stream2, packet,
+ input_stream);
+ }
+
+ /* restore the previous file position */
+ input_stream.LockSeek(old_offset, IgnoreError());
+
+ return result;
+}
+
+ogg_int64_t
+OggDecoder::LoadEndGranulePos() const
+{
+ ogg_packet packet;
+ if (!LoadEndPacket(packet))
+ return -1;
+
+ return packet.granulepos;
+}
+
+bool
+OggDecoder::SeekGranulePos(ogg_int64_t where_granulepos, Error &error)
+{
+ assert(IsSeekable());
+
+ /* interpolate the file offset where we expect to find the
+ given granule position */
+ /* TODO: implement binary search */
+ offset_type offset(where_granulepos * input_stream.GetSize()
+ / end_granulepos);
+
+ if (!input_stream.LockSeek(offset, error))
+ return false;
+
+ PostSeek();
+ return true;
+}
+
diff --git a/src/decoder/plugins/OggDecoder.hxx b/src/decoder/plugins/OggDecoder.hxx
new file mode 100644
index 000000000..bb33f69cc
--- /dev/null
+++ b/src/decoder/plugins/OggDecoder.hxx
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2003-2016 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_DECODER_HXX
+#define MPD_OGG_DECODER_HXX
+
+#include "config.h" /* must be first for large file support */
+#include "lib/xiph/OggVisitor.hxx"
+#include "decoder/Reader.hxx"
+
+class Error;
+
+class OggDecoder : public OggVisitor {
+ ogg_int64_t end_granulepos;
+
+protected:
+ Decoder &decoder;
+ InputStream &input_stream;
+
+public:
+ explicit OggDecoder(DecoderReader &reader)
+ :OggVisitor(reader),
+ decoder(reader.GetDecoder()),
+ input_stream(reader.GetInputStream()) {}
+
+ bool Seek(OggSyncState &oy, uint64_t where_frame);
+
+private:
+ /**
+ * Load the end-of-stream packet and restore the previous file
+ * position.
+ */
+ bool LoadEndPacket(ogg_packet &packet) const;
+ ogg_int64_t LoadEndGranulePos() const;
+
+protected:
+ ogg_int64_t UpdateEndGranulePos() {
+ return end_granulepos = LoadEndGranulePos();
+ }
+
+ bool IsSeekable() const {
+ return end_granulepos > 0;
+ }
+
+ bool SeekGranulePos(ogg_int64_t where_granulepos, Error &error);
+};
+
+#endif
diff --git a/src/decoder/plugins/OpusDecoderPlugin.cxx b/src/decoder/plugins/OpusDecoderPlugin.cxx
index 6fe2d7006..25e08f8e1 100644
--- a/src/decoder/plugins/OpusDecoderPlugin.cxx
+++ b/src/decoder/plugins/OpusDecoderPlugin.cxx
@@ -19,12 +19,12 @@
#include "config.h" /* must be first for large file support */
#include "OpusDecoderPlugin.h"
+#include "OggDecoder.hxx"
#include "OpusDomain.hxx"
#include "OpusHead.hxx"
#include "OpusTags.hxx"
#include "lib/xiph/OggPacket.hxx"
#include "lib/xiph/OggFind.hxx"
-#include "lib/xiph/OggVisitor.hxx"
#include "../DecoderAPI.hxx"
#include "decoder/Reader.hxx"
#include "input/Reader.hxx"
@@ -73,10 +73,7 @@ mpd_opus_init(gcc_unused const ConfigBlock &block)
return true;
}
-class MPDOpusDecoder final : public OggVisitor {
- Decoder &decoder;
- InputStream &input_stream;
-
+class MPDOpusDecoder final : public OggDecoder {
OpusDecoder *opus_decoder = nullptr;
opus_int16 *output_buffer = nullptr;
@@ -88,15 +85,11 @@ class MPDOpusDecoder final : public OggVisitor {
*/
unsigned previous_channels = 0;
- ogg_int64_t eos_granulepos;
-
size_t frame_size;
public:
- MPDOpusDecoder(DecoderReader &reader)
- :OggVisitor(reader),
- decoder(reader.GetDecoder()),
- input_stream(reader.GetInputStream()) {}
+ explicit MPDOpusDecoder(DecoderReader &reader)
+ :OggDecoder(reader) {}
~MPDOpusDecoder();
@@ -107,8 +100,6 @@ public:
return previous_channels != 0;
}
- DecoderCommand HandlePackets();
-
bool Seek(uint64_t where_frame);
private:
@@ -139,57 +130,6 @@ MPDOpusDecoder::OnOggPacket(const ogg_packet &packet)
HandleAudio(packet);
}
-/**
- * Load the end-of-stream packet and restore the previous file
- * position.
- */
-static bool
-LoadEOSPacket(InputStream &is, Decoder &decoder, int serialno,
- ogg_packet &packet)
-{
- if (!is.CheapSeeking())
- /* we do this for local files only, because seeking
- around remote files is expensive and not worth the
- trouble */
- return false;
-
- const auto old_offset = is.GetOffset();
-
- /* create temporary Ogg objects for seeking and parsing the
- EOS packet */
-
- bool result;
-
- {
- DecoderReader reader(decoder, is);
- OggSyncState oy(reader);
- OggStreamState os(serialno);
- result = OggSeekFindEOS(oy, os, packet, is);
- }
-
- /* restore the previous file position */
- is.LockSeek(old_offset, IgnoreError());
-
- return result;
-}
-
-/**
- * Load the end-of-stream granulepos and restore the previous file
- * position.
- *
- * @return -1 on error
- */
-gcc_pure
-static ogg_int64_t
-LoadEOSGranulePos(InputStream &is, Decoder &decoder, int serialno)
-{
- ogg_packet packet;
- if (!LoadEOSPacket(is, decoder, serialno, packet))
- return -1;
-
- return packet.granulepos;
-}
-
void
MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
{
@@ -210,8 +150,6 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
throw FormatRuntimeError("Next stream has different channels (%u -> %u)",
previous_channels, channels);
- const auto opus_serialno = GetSerialNo();
-
/* TODO: parse attributes from the OpusHead (sample rate,
channels, ...) */
@@ -229,8 +167,7 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
return;
}
- eos_granulepos = LoadEOSGranulePos(input_stream, decoder,
- opus_serialno);
+ const auto eos_granulepos = UpdateEndGranulePos();
const auto duration = eos_granulepos >= 0
? SignedSongTime::FromScale<uint64_t>(eos_granulepos,
opus_sample_rate)
@@ -254,7 +191,7 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
void
MPDOpusDecoder::OnOggEnd()
{
- if (eos_granulepos < 0 && IsInitialized()) {
+ if (!IsSeekable() && IsInitialized()) {
/* allow chaining of (unseekable) streams */
assert(opus_decoder != nullptr);
assert(output_buffer != nullptr);
@@ -318,23 +255,13 @@ MPDOpusDecoder::HandleAudio(const ogg_packet &packet)
bool
MPDOpusDecoder::Seek(uint64_t where_frame)
{
- assert(eos_granulepos > 0);
+ assert(IsSeekable());
assert(input_stream.IsSeekable());
assert(input_stream.KnownSize());
const ogg_int64_t where_granulepos(where_frame);
- /* interpolate the file offset where we expect to find the
- given granule position */
- /* TODO: implement binary search */
- offset_type offset(where_granulepos * input_stream.GetSize()
- / eos_granulepos);
-
- if (!input_stream.LockSeek(offset, IgnoreError()))
- return false;
-
- PostSeek();
- return true;
+ return SeekGranulePos(where_granulepos, IgnoreError());
}
static void