diff --git a/NEWS b/NEWS index 2f1907cd7..f810c88e1 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ ver 0.16.5 (2010/??/??) * decoder: - ffmpeg: higher precision timestamps - ffmpeg: don't require key frame for seeking + - fix CUE track seeking * WIN32: close sockets properly diff --git a/src/decoder_api.c b/src/decoder_api.c index fe34ea34a..99c02db87 100644 --- a/src/decoder_api.c +++ b/src/decoder_api.c @@ -78,15 +78,40 @@ decoder_initialized(struct decoder *decoder, &af_string)); } -enum decoder_command decoder_get_command(G_GNUC_UNUSED struct decoder * decoder) +/** + * Returns the current decoder command. May return a "virtual" + * synthesized command, e.g. to seek to the beginning of the CUE + * track. + */ +G_GNUC_PURE +static enum decoder_command +decoder_get_virtual_command(struct decoder *decoder) { const struct decoder_control *dc = decoder->dc; - assert(dc->pipe != NULL); + if (decoder->initial_seek_running) + return DECODE_COMMAND_SEEK; + + if (decoder->initial_seek_pending) { + if (dc->command == DECODE_COMMAND_NONE) { + decoder->initial_seek_pending = false; + decoder->initial_seek_running = true; + return DECODE_COMMAND_SEEK; + } + + decoder->initial_seek_pending = false; + } + return dc->command; } +enum decoder_command +decoder_get_command(struct decoder *decoder) +{ + return decoder_get_virtual_command(decoder); +} + void decoder_command_finished(struct decoder *decoder) { @@ -94,11 +119,24 @@ decoder_command_finished(struct decoder *decoder) decoder_lock(dc); - assert(dc->command != DECODE_COMMAND_NONE); + assert(dc->command != DECODE_COMMAND_NONE || + decoder->initial_seek_running); assert(dc->command != DECODE_COMMAND_SEEK || + decoder->initial_seek_running || dc->seek_error || decoder->seeking); assert(dc->pipe != NULL); + if (decoder->initial_seek_running) { + assert(!decoder->seeking); + assert(decoder->chunk == NULL); + assert(music_pipe_empty(dc->pipe)); + + decoder->initial_seek_running = false; + decoder->timestamp = dc->song->start_ms / 1000.; + decoder_unlock(dc); + return; + } + if (decoder->seeking) { decoder->seeking = false; @@ -124,9 +162,13 @@ double decoder_seek_where(G_GNUC_UNUSED struct decoder * decoder) { const struct decoder_control *dc = decoder->dc; - assert(dc->command == DECODE_COMMAND_SEEK); assert(dc->pipe != NULL); + if (decoder->initial_seek_running) + return dc->song->start_ms / 1000.; + + assert(dc->command == DECODE_COMMAND_SEEK); + decoder->seeking = true; return dc->seek_where; @@ -136,9 +178,15 @@ void decoder_seek_error(struct decoder * decoder) { struct decoder_control *dc = decoder->dc; - assert(dc->command == DECODE_COMMAND_SEEK); assert(dc->pipe != NULL); + if (decoder->initial_seek_running) + /* d'oh, we can't seek to the sub-song start position, + what now? - no idea, ignoring the problem for now. */ + return; + + assert(dc->command == DECODE_COMMAND_SEEK); + dc->seek_error = true; decoder->seeking = false; @@ -270,7 +318,7 @@ decoder_data(struct decoder *decoder, assert(length % audio_format_frame_size(&dc->in_audio_format) == 0); decoder_lock(dc); - cmd = dc->command; + cmd = decoder_get_virtual_command(decoder); decoder_unlock(dc); if (cmd == DECODE_COMMAND_STOP || cmd == DECODE_COMMAND_SEEK || @@ -401,6 +449,9 @@ decoder_tag(G_GNUC_UNUSED struct decoder *decoder, struct input_stream *is, /* send only the decoder tag */ cmd = do_send_tag(decoder, is, tag); + if (cmd == DECODE_COMMAND_NONE) + cmd = decoder_get_virtual_command(decoder); + return cmd; } diff --git a/src/decoder_internal.h b/src/decoder_internal.h index 2347fdf4e..5818632e5 100644 --- a/src/decoder_internal.h +++ b/src/decoder_internal.h @@ -36,6 +36,20 @@ struct decoder { */ double timestamp; + /** + * Is the initial seek (to the start position of the sub-song) + * pending, or has it been performed already? + */ + bool initial_seek_pending; + + /** + * Is the initial seek currently running? During this time, + * the decoder command is SEEK. This flag is set by + * decoder_get_virtual_command(), when the virtual SEEK + * command is generated for the first time. + */ + bool initial_seek_running; + /** * This flag is set by decoder_seek_where(), and checked by * decoder_command_finished(). It is used to clean up after diff --git a/src/decoder_thread.c b/src/decoder_thread.c index 10a796967..ce849df47 100644 --- a/src/decoder_thread.c +++ b/src/decoder_thread.c @@ -369,6 +369,8 @@ decoder_run_song(struct decoder_control *dc, { struct decoder decoder = { .dc = dc, + .initial_seek_pending = song->start_ms > 0, + .initial_seek_running = false, }; int ret; diff --git a/src/player_thread.c b/src/player_thread.c index a89e59908..be08aa32d 100644 --- a/src/player_thread.c +++ b/src/player_thread.c @@ -881,16 +881,6 @@ static void do_play(struct decoder_control *dc) if (!player_check_decoder_startup(&player)) break; - /* seek to the beginning of the range */ - const struct song *song = decoder_current_song(dc); - if (song != NULL && song->start_ms > 0 && - /* we must not send a seek command until - the decoder is initialized - completely */ - !player.decoder_starting && - !dc_seek(dc, song->start_ms / 1000.0)) - player_dc_stop(&player); - player_lock(); continue; }