diff options
author | Max Kellermann <max@duempel.org> | 2013-01-07 23:05:33 +0100 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2013-10-24 23:26:58 +0200 |
commit | c76952534e0ab82b179d360f07beceb634a0a154 (patch) | |
tree | 3e06655eca02aa73af15947e09f8e5b015bf8751 /src/decoder | |
parent | f0060718def9b5f2a6ddc8f6f0659915ce468bfc (diff) | |
download | mpd-c76952534e0ab82b179d360f07beceb634a0a154.tar.gz mpd-c76952534e0ab82b179d360f07beceb634a0a154.tar.xz mpd-c76952534e0ab82b179d360f07beceb634a0a154.zip |
decoder/Opus: implement seeking
Diffstat (limited to 'src/decoder')
-rw-r--r-- | src/decoder/OggFind.cxx | 3 | ||||
-rw-r--r-- | src/decoder/OggFind.hxx | 8 | ||||
-rw-r--r-- | src/decoder/OpusDecoderPlugin.cxx | 44 |
3 files changed, 49 insertions, 6 deletions
diff --git a/src/decoder/OggFind.cxx b/src/decoder/OggFind.cxx index 05d693122..821f75ca8 100644 --- a/src/decoder/OggFind.cxx +++ b/src/decoder/OggFind.cxx @@ -20,7 +20,6 @@ #include "config.h" #include "OggFind.hxx" #include "OggSyncState.hxx" -#include "InputStream.hxx" #include "util/Error.hxx" bool @@ -38,7 +37,7 @@ OggFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet) } } -static bool +bool OggSeekPageAtOffset(OggSyncState &oy, ogg_stream_state &os, InputStream &is, InputStream::offset_type offset, int whence) { diff --git a/src/decoder/OggFind.hxx b/src/decoder/OggFind.hxx index 703510fb5..ad51ccdf3 100644 --- a/src/decoder/OggFind.hxx +++ b/src/decoder/OggFind.hxx @@ -21,6 +21,7 @@ #define MPD_OGG_FIND_HXX #include "check.h" +#include "InputStream.hxx" #include <ogg/ogg.h> @@ -37,6 +38,13 @@ bool OggFindEOS(OggSyncState &oy, ogg_stream_state &os, ogg_packet &packet); /** + * Seek the #InputStream and find the next Ogg page. + */ +bool +OggSeekPageAtOffset(OggSyncState &oy, ogg_stream_state &os, InputStream &is, + InputStream::offset_type offset, int whence); + +/** * Try to find the end-of-stream (EOS) packet. Seek to the end of the * file if necessary. * diff --git a/src/decoder/OpusDecoderPlugin.cxx b/src/decoder/OpusDecoderPlugin.cxx index 2f4f3df5b..fd8ed4e89 100644 --- a/src/decoder/OpusDecoderPlugin.cxx +++ b/src/decoder/OpusDecoderPlugin.cxx @@ -80,6 +80,8 @@ class MPDOpusDecoder { int opus_serialno; + ogg_int64_t eos_granulepos; + size_t frame_size; public: @@ -99,6 +101,8 @@ public: DecoderCommand HandleBOS(const ogg_packet &packet); DecoderCommand HandleTags(const ogg_packet &packet); DecoderCommand HandleAudio(const ogg_packet &packet); + + bool Seek(OggSyncState &oy, double where); }; MPDOpusDecoder::~MPDOpusDecoder() @@ -252,15 +256,16 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet) return DecoderCommand::STOP; } - const ogg_int64_t eos_granulepos = - LoadEOSGranulePos(input_stream, &decoder, opus_serialno); + eos_granulepos = LoadEOSGranulePos(input_stream, &decoder, + opus_serialno); const double duration = eos_granulepos >= 0 ? double(eos_granulepos) / opus_sample_rate : -1.0; const AudioFormat audio_format(opus_sample_rate, SampleFormat::S16, channels); - decoder_initialized(decoder, audio_format, false, duration); + decoder_initialized(decoder, audio_format, + eos_granulepos > 0, duration); frame_size = audio_format.GetFrameSize(); /* allocate an output buffer for 16 bit PCM samples big enough @@ -324,6 +329,29 @@ MPDOpusDecoder::HandleAudio(const ogg_packet &packet) return DecoderCommand::NONE; } +bool +MPDOpusDecoder::Seek(OggSyncState &oy, double where_s) +{ + assert(eos_granulepos > 0); + assert(input_stream.seekable); + assert(input_stream.size > 0); + assert(input_stream.offset >= 0); + + const ogg_int64_t where_granulepos(where_s * opus_sample_rate); + + /* interpolate the file offset where we expect to find the + given granule position */ + /* TODO: implement binary search */ + InputStream::offset_type offset(where_granulepos * input_stream.size + / eos_granulepos); + + if (!OggSeekPageAtOffset(oy, os, input_stream, offset, SEEK_SET)) + return false; + + decoder_timestamp(decoder, where_s); + return true; +} + static void mpd_opus_stream_decode(Decoder &decoder, InputStream &input_stream) @@ -343,12 +371,20 @@ mpd_opus_stream_decode(Decoder &decoder, while (true) { auto cmd = d.HandlePackets(); + if (cmd == DecoderCommand::SEEK) { + if (d.Seek(oy, decoder_seek_where(decoder))) + decoder_command_finished(decoder); + else + decoder_seek_error(decoder); + + continue; + } + if (cmd != DecoderCommand::NONE) break; if (!d.ReadNextPage(oy)) break; - } } |