aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2009-12-25 23:12:10 +0100
committerMax Kellermann <max@duempel.org>2009-12-27 16:08:53 +0100
commit5787f737044e90b74e22d2179cd0d1b47fd17c76 (patch)
tree0455e67ab93ba5ba0bb221a1833f0aab50ff4db0 /src
parent201316cd67d374357c1aabc8a4aa2210fe20f1e8 (diff)
downloadmpd-5787f737044e90b74e22d2179cd0d1b47fd17c76.tar.gz
mpd-5787f737044e90b74e22d2179cd0d1b47fd17c76.tar.xz
mpd-5787f737044e90b74e22d2179cd0d1b47fd17c76.zip
decoder, player: support song ranges
Seek the decoder to the start of the range before beginning with playback. Stop the decoder when the end of the range has been reached. Add the start position to the seek position. Expose the duration of the range, not the full song file.
Diffstat (limited to 'src')
-rw-r--r--src/decoder_api.c11
-rw-r--r--src/player_thread.c34
2 files changed, 40 insertions, 5 deletions
diff --git a/src/decoder_api.c b/src/decoder_api.c
index dde27727b..704f6dbf7 100644
--- a/src/decoder_api.c
+++ b/src/decoder_api.c
@@ -328,8 +328,9 @@ decoder_data(struct decoder *decoder,
}
dest = music_chunk_write(chunk, &dc->out_audio_format,
- decoder->timestamp, kbit_rate,
- &nbytes);
+ decoder->timestamp -
+ dc->song->start_ms / 1000.0,
+ kbit_rate, &nbytes);
if (dest == NULL) {
/* the chunk is full, flush it */
decoder_flush_chunk(decoder);
@@ -366,6 +367,12 @@ decoder_data(struct decoder *decoder,
decoder->timestamp += (double)nbytes /
audio_format_time_to_size(&dc->in_audio_format);
+
+ if (dc->song->end_ms > 0 &&
+ decoder->timestamp >= dc->song->end_ms / 1000.0)
+ /* the end of this range has been reached:
+ stop decoding */
+ return DECODE_COMMAND_STOP;
}
return DECODE_COMMAND_NONE;
diff --git a/src/player_thread.c b/src/player_thread.c
index 1a92a3182..5823b433e 100644
--- a/src/player_thread.c
+++ b/src/player_thread.c
@@ -228,6 +228,26 @@ player_wait_for_decoder(struct player *player)
}
/**
+ * Returns the real duration of the song, comprising the duration
+ * indicated by the decoder plugin.
+ */
+static double
+real_song_duration(const struct song *song, double decoder_duration)
+{
+ assert(song != NULL);
+
+ if (decoder_duration <= 0.0)
+ /* the decoder plugin didn't provide information; fall
+ back to song_get_duration() */
+ return song_get_duration(song);
+
+ if (song->end_ms > 0 && song->end_ms / 1000.0 < decoder_duration)
+ return (song->end_ms - song->start_ms) / 1000.0;
+
+ return decoder_duration - song->start_ms / 1000.0;
+}
+
+/**
* The decoder has acknowledged the "START" command (see
* player_wait_for_decoder()). This function checks if the decoder
* initialization has completed yet.
@@ -265,7 +285,7 @@ player_check_decoder_startup(struct player *player)
return true;
player_lock();
- pc.total_time = dc->total_time;
+ pc.total_time = real_song_duration(dc->song, dc->total_time);
pc.audio_format = dc->in_audio_format;
player_unlock();
@@ -351,13 +371,14 @@ player_send_silence(struct player *player)
*/
static bool player_seek_decoder(struct player *player)
{
+ struct song *song = pc.next_song;
struct decoder_control *dc = player->dc;
double where;
bool ret;
assert(pc.next_song != NULL);
- if (decoder_current_song(dc) != pc.next_song) {
+ if (decoder_current_song(dc) != song) {
/* the decoder is already decoding the "next" song -
stop it and start the previous song again */
@@ -399,7 +420,7 @@ static bool player_seek_decoder(struct player *player)
if (where < 0.0)
where = 0.0;
- ret = dc_seek(dc, where);
+ ret = dc_seek(dc, where + song->start_ms / 1000.0);
if (!ret) {
/* decoder failure */
player_command_finished();
@@ -801,11 +822,18 @@ static void do_play(struct decoder_control *dc)
if (player.decoder_starting) {
/* wait until the decoder is initialized completely */
bool success;
+ const struct song *song;
success = player_check_decoder_startup(&player);
if (!success)
break;
+ /* seek to the beginning of the range */
+ song = decoder_current_song(dc);
+ if (song != NULL && song->start_ms > 0 &&
+ !dc_seek(dc, song->start_ms / 1000.0))
+ player_dc_stop(&player);
+
player_lock();
continue;
}