summaryrefslogtreecommitdiff
path: root/src/decoder
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2020-07-01 21:15:59 +0200
committerMax Kellermann <max@musicpd.org>2020-07-01 21:21:06 +0200
commit7befab7e830f830ffbda43959d136c57a392a608 (patch)
tree7f3f580e9629b9c67239b4bab2bed87551a14767 /src/decoder
parent4244e61214db8d421a09be353b2374f21fc33f2d (diff)
decoder/opus: keep track of the granulepos
Will be needed for End Trimming (RFC7845 4.4, https://github.com/MusicPlayerDaemon/MPD/issues/867).
Diffstat (limited to 'src/decoder')
-rw-r--r--src/decoder/plugins/OpusDecoderPlugin.cxx29
1 files changed, 27 insertions, 2 deletions
diff --git a/src/decoder/plugins/OpusDecoderPlugin.cxx b/src/decoder/plugins/OpusDecoderPlugin.cxx
index 34e8a9d7e..ed4ec3d01 100644
--- a/src/decoder/plugins/OpusDecoderPlugin.cxx
+++ b/src/decoder/plugins/OpusDecoderPlugin.cxx
@@ -98,6 +98,13 @@ class MPDOpusDecoder final : public OggDecoder {
size_t frame_size;
+ /**
+ * The granulepos of the next sample to be submitted to
+ * DecoderClient::SubmitData(). Negative if unkown.
+ * Initialized by OnOggBeginning().
+ */
+ ogg_int64_t granulepos;
+
public:
explicit MPDOpusDecoder(DecoderReader &reader)
:OggDecoder(reader) {}
@@ -114,6 +121,13 @@ public:
bool Seek(uint64_t where_frame);
private:
+ void AddGranulepos(ogg_int64_t n) noexcept {
+ assert(n >= 0);
+
+ if (granulepos >= 0)
+ granulepos += n;
+ }
+
void HandleTags(const ogg_packet &packet);
void HandleAudio(const ogg_packet &packet);
@@ -154,6 +168,7 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
!audio_valid_channel_count(channels))
throw std::runtime_error("Malformed BOS packet");
+ granulepos = 0;
skip = pre_skip;
assert(opus_decoder == nullptr);
@@ -261,12 +276,14 @@ MPDOpusDecoder::HandleAudio(const ogg_packet &packet)
/* apply the "skip" value */
if (skip >= (unsigned)nframes) {
skip -= nframes;
+ AddGranulepos(nframes);
return;
}
const opus_int16 *data = output_buffer;
data += skip * previous_channels;
nframes -= skip;
+ AddGranulepos(skip);
skip = 0;
/* submit decoded samples to the DecoderClient */
@@ -277,9 +294,12 @@ MPDOpusDecoder::HandleAudio(const ogg_packet &packet)
if (cmd != DecoderCommand::NONE)
throw cmd;
- if (packet.granulepos > 0)
- client.SubmitTimestamp(FloatDuration(packet.granulepos - pre_skip)
+ if (packet.granulepos > 0) {
+ granulepos = packet.granulepos;
+ client.SubmitTimestamp(FloatDuration(granulepos - pre_skip)
/ opus_sample_rate);
+ } else
+ AddGranulepos(nframes);
}
bool
@@ -291,6 +311,11 @@ MPDOpusDecoder::Seek(uint64_t where_frame)
const ogg_int64_t where_granulepos(where_frame);
+ /* we don't know the exact granulepos after seeking, so let's
+ set it to -1 - it will be set after the next packet which
+ declares its granulepos */
+ granulepos = -1;
+
try {
SeekGranulePos(where_granulepos);