diff --git a/NEWS b/NEWS
index 1deecbe56..7acf48cc9 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ ver 0.18.12 (not yet released)
   - audiofile: improve responsiveness
   - audiofile: fix WAV stream playback
   - dsdiff, dsf: fix stream playback
+  - faad: estimate song duration for remote files
   - sndfile: improve responsiveness
 * randomize next song when enabling "random" mode while not playing
 * randomize next song when adding to single-song queue
diff --git a/src/decoder/FaadDecoderPlugin.cxx b/src/decoder/FaadDecoderPlugin.cxx
index 07c10fa69..b446ac5be 100644
--- a/src/decoder/FaadDecoderPlugin.cxx
+++ b/src/decoder/FaadDecoderPlugin.cxx
@@ -122,6 +122,12 @@ adts_find_frame(DecoderBuffer *buffer)
 static float
 adts_song_duration(DecoderBuffer *buffer)
 {
+	const InputStream &is = decoder_buffer_get_stream(buffer);
+	const bool estimate = !is.CheapSeeking();
+	const auto file_size = is.GetSize();
+	if (estimate && file_size <= 0)
+		return -1;
+
 	unsigned sample_rate = 0;
 
 	/* Read all frames to ensure correct time and bitrate */
@@ -145,6 +151,22 @@ adts_song_duration(DecoderBuffer *buffer)
 		}
 
 		decoder_buffer_consume(buffer, frame_length);
+
+		if (estimate && frames == 128) {
+			/* if this is a remote file, don't slurp the
+			   whole file just for checking the song
+			   duration; instead, stop after some time and
+			   extrapolate the song duration from what we
+			   have until now */
+
+			const auto offset = is.GetOffset()
+				- decoder_buffer_available(buffer);
+			if (offset <= 0)
+				return -1;
+
+			frames = (frames * file_size) / offset;
+			break;
+		}
 	}
 
 	if (sample_rate == 0)