From 7befab7e830f830ffbda43959d136c57a392a608 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 1 Jul 2020 21:15:59 +0200 Subject: [PATCH] decoder/opus: keep track of the granulepos Will be needed for End Trimming (RFC7845 4.4, https://github.com/MusicPlayerDaemon/MPD/issues/867). --- src/decoder/plugins/OpusDecoderPlugin.cxx | 29 +++++++++++++++++++++-- 1 file 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);