summaryrefslogtreecommitdiff
path: root/src/decoder
diff options
context:
space:
mode:
authorMax Kellermann <max@musicpd.org>2018-02-17 13:10:00 +0100
committerMax Kellermann <max@musicpd.org>2018-02-17 13:10:00 +0100
commit986ec877b04ed33f38068430c60c817efec851bb (patch)
tree2aba3dd1bc0b5eab588a4f07e2108f018d7df604 /src/decoder
parentc43ea74b3005b97b9e494ba62d86d0e02ef39d55 (diff)
decoder/Bridge: truncate last chunk at the exact end_time
Instead of passing whole chunks to the MusicPipe and checking the end_time after each chunk, truncate the last chunk if it would exceed the end_time. This requires keeping track of the absolute PCM frame number. This fixes a problem with gapless CUE song transitions: a small part of the following song was always played twice. Closes #113
Diffstat (limited to 'src/decoder')
-rw-r--r--src/decoder/Bridge.cxx36
-rw-r--r--src/decoder/Bridge.hxx5
2 files changed, 34 insertions, 7 deletions
diff --git a/src/decoder/Bridge.cxx b/src/decoder/Bridge.cxx
index 37fcb2bf9..73a396e23 100644
--- a/src/decoder/Bridge.cxx
+++ b/src/decoder/Bridge.cxx
@@ -300,6 +300,7 @@ DecoderBridge::CommandFinished()
initial_seek_running = false;
timestamp = dc.start_time.ToDoubleS();
+ absolute_frame = dc.start_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
return;
}
@@ -319,6 +320,7 @@ DecoderBridge::CommandFinished()
convert->Reset();
timestamp = dc.seek_time.ToDoubleS();
+ absolute_frame = dc.seek_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
}
dc.command = DecoderCommand::NONE;
@@ -427,6 +429,7 @@ DecoderBridge::SubmitTimestamp(double t)
assert(t >= 0);
timestamp = t;
+ absolute_frame = uint64_t(t * dc.in_audio_format.sample_rate);
}
DecoderCommand
@@ -464,6 +467,29 @@ DecoderBridge::SubmitData(InputStream *is,
return cmd;
}
+ cmd = DecoderCommand::NONE;
+
+ const size_t frame_size = dc.in_audio_format.GetFrameSize();
+ size_t data_frames = length / frame_size;
+
+ if (dc.end_time.IsPositive()) {
+ /* enforce the given end time */
+
+ const uint64_t end_frame =
+ dc.end_time.ToScale<uint64_t>(dc.in_audio_format.sample_rate);
+ if (absolute_frame >= end_frame)
+ return DecoderCommand::STOP;
+
+ const uint64_t remaining_frames = end_frame - absolute_frame;
+ if (data_frames >= remaining_frames) {
+ /* past the end of the range: truncate this
+ data submission and stop the decoder */
+ data_frames = remaining_frames;
+ length = data_frames * frame_size;
+ cmd = DecoderCommand::STOP;
+ }
+ }
+
if (convert != nullptr) {
assert(dc.in_audio_format != dc.out_audio_format);
@@ -521,15 +547,11 @@ DecoderBridge::SubmitData(InputStream *is,
timestamp += (double)nbytes /
dc.out_audio_format.GetTimeToSize();
-
- if (dc.end_time.IsPositive() &&
- timestamp >= dc.end_time.ToDoubleS())
- /* the end of this range has been reached:
- stop decoding */
- return DecoderCommand::STOP;
}
- return DecoderCommand::NONE;
+ absolute_frame += data_frames;
+
+ return cmd;
}
DecoderCommand
diff --git a/src/decoder/Bridge.hxx b/src/decoder/Bridge.hxx
index 3b354c063..c34c95941 100644
--- a/src/decoder/Bridge.hxx
+++ b/src/decoder/Bridge.hxx
@@ -50,6 +50,11 @@ public:
double timestamp = 0;
/**
+ * The time stamp of the next data chunk, in PCM frames.
+ */
+ uint64_t absolute_frame = 0;
+
+ /**
* Is the initial seek (to the start position of the sub-song)
* pending, or has it been performed already?
*/