aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS1
-rw-r--r--src/decoder_api.c63
-rw-r--r--src/decoder_internal.h14
-rw-r--r--src/decoder_thread.c2
-rw-r--r--src/player_thread.c10
5 files changed, 74 insertions, 16 deletions
diff --git a/NEWS b/NEWS
index 2f1907cd..f810c88e 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 fe34ea34..99c02db8 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 2347fdf4..5818632e 100644
--- a/src/decoder_internal.h
+++ b/src/decoder_internal.h
@@ -37,6 +37,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
* seeking.
diff --git a/src/decoder_thread.c b/src/decoder_thread.c
index 10a79696..ce849df4 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 a89e5990..be08aa32 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;
}