diff options
author | Max Kellermann <max@musicpd.org> | 2018-02-17 13:10:00 +0100 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2018-02-17 13:10:00 +0100 |
commit | 986ec877b04ed33f38068430c60c817efec851bb (patch) | |
tree | 2aba3dd1bc0b5eab588a4f07e2108f018d7df604 /src/decoder | |
parent | c43ea74b3005b97b9e494ba62d86d0e02ef39d55 (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.cxx | 36 | ||||
-rw-r--r-- | src/decoder/Bridge.hxx | 5 |
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? */ |