diff --git a/src/decoder/DecoderAPI.cxx b/src/decoder/DecoderAPI.cxx
index 926a3955e..7349b00db 100644
--- a/src/decoder/DecoderAPI.cxx
+++ b/src/decoder/DecoderAPI.cxx
@@ -237,6 +237,24 @@ decoder_seek_where_ms(Decoder &decoder)
 	return unsigned(dc.seek_where * 1000);
 }
 
+uint64_t
+decoder_seek_where_frame(Decoder &decoder)
+{
+	const DecoderControl &dc = decoder.dc;
+
+	assert(dc.pipe != nullptr);
+
+	if (decoder.initial_seek_running)
+		return uint64_t(dc.start_ms) * dc.in_audio_format.sample_rate
+			/ 1000;
+
+	assert(dc.command == DecoderCommand::SEEK);
+
+	decoder.seeking = true;
+
+	return uint64_t(dc.seek_where * dc.in_audio_format.sample_rate);
+}
+
 void decoder_seek_error(Decoder & decoder)
 {
 	DecoderControl &dc = decoder.dc;
diff --git a/src/decoder/DecoderAPI.hxx b/src/decoder/DecoderAPI.hxx
index ddcead4b1..2464ee6fa 100644
--- a/src/decoder/DecoderAPI.hxx
+++ b/src/decoder/DecoderAPI.hxx
@@ -40,6 +40,8 @@
 
 // IWYU pragma: end_exports
 
+#include <stdint.h>
+
 class Error;
 
 /**
@@ -98,6 +100,16 @@ gcc_pure
 unsigned
 decoder_seek_where_ms(Decoder &decoder);
 
+/**
+ * Call this when you have received the DecoderCommand::SEEK command.
+ *
+ * @param decoder the decoder object
+ * @return the destination position for the seek in frames
+ */
+gcc_pure
+uint64_t
+decoder_seek_where_frame(Decoder &decoder);
+
 /**
  * Call this instead of decoder_command_finished() when seeking has
  * failed.
diff --git a/test/FakeDecoderAPI.cxx b/test/FakeDecoderAPI.cxx
index afa90b4ca..54e75eb49 100644
--- a/test/FakeDecoderAPI.cxx
+++ b/test/FakeDecoderAPI.cxx
@@ -67,6 +67,12 @@ decoder_seek_where_ms(gcc_unused Decoder &decoder)
 	return 1;
 }
 
+uint64_t
+decoder_seek_where_frame(gcc_unused Decoder &decoder)
+{
+	return 1;
+}
+
 void
 decoder_seek_error(gcc_unused Decoder &decoder)
 {