Commit 5787f737 authored by Max Kellermann's avatar Max Kellermann

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.
parent 201316cd
...@@ -328,8 +328,9 @@ decoder_data(struct decoder *decoder, ...@@ -328,8 +328,9 @@ decoder_data(struct decoder *decoder,
} }
dest = music_chunk_write(chunk, &dc->out_audio_format, dest = music_chunk_write(chunk, &dc->out_audio_format,
decoder->timestamp, kbit_rate, decoder->timestamp -
&nbytes); dc->song->start_ms / 1000.0,
kbit_rate, &nbytes);
if (dest == NULL) { if (dest == NULL) {
/* the chunk is full, flush it */ /* the chunk is full, flush it */
decoder_flush_chunk(decoder); decoder_flush_chunk(decoder);
...@@ -366,6 +367,12 @@ decoder_data(struct decoder *decoder, ...@@ -366,6 +367,12 @@ decoder_data(struct decoder *decoder,
decoder->timestamp += (double)nbytes / decoder->timestamp += (double)nbytes /
audio_format_time_to_size(&dc->in_audio_format); 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; return DECODE_COMMAND_NONE;
......
...@@ -228,6 +228,26 @@ player_wait_for_decoder(struct player *player) ...@@ -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 * The decoder has acknowledged the "START" command (see
* player_wait_for_decoder()). This function checks if the decoder * player_wait_for_decoder()). This function checks if the decoder
* initialization has completed yet. * initialization has completed yet.
...@@ -265,7 +285,7 @@ player_check_decoder_startup(struct player *player) ...@@ -265,7 +285,7 @@ player_check_decoder_startup(struct player *player)
return true; return true;
player_lock(); 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; pc.audio_format = dc->in_audio_format;
player_unlock(); player_unlock();
...@@ -351,13 +371,14 @@ player_send_silence(struct player *player) ...@@ -351,13 +371,14 @@ player_send_silence(struct player *player)
*/ */
static bool player_seek_decoder(struct player *player) static bool player_seek_decoder(struct player *player)
{ {
struct song *song = pc.next_song;
struct decoder_control *dc = player->dc; struct decoder_control *dc = player->dc;
double where; double where;
bool ret; bool ret;
assert(pc.next_song != NULL); 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 - /* the decoder is already decoding the "next" song -
stop it and start the previous song again */ stop it and start the previous song again */
...@@ -399,7 +420,7 @@ static bool player_seek_decoder(struct player *player) ...@@ -399,7 +420,7 @@ static bool player_seek_decoder(struct player *player)
if (where < 0.0) if (where < 0.0)
where = 0.0; where = 0.0;
ret = dc_seek(dc, where); ret = dc_seek(dc, where + song->start_ms / 1000.0);
if (!ret) { if (!ret) {
/* decoder failure */ /* decoder failure */
player_command_finished(); player_command_finished();
...@@ -801,11 +822,18 @@ static void do_play(struct decoder_control *dc) ...@@ -801,11 +822,18 @@ static void do_play(struct decoder_control *dc)
if (player.decoder_starting) { if (player.decoder_starting) {
/* wait until the decoder is initialized completely */ /* wait until the decoder is initialized completely */
bool success; bool success;
const struct song *song;
success = player_check_decoder_startup(&player); success = player_check_decoder_startup(&player);
if (!success) if (!success)
break; 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(); player_lock();
continue; continue;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment