aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-08-29 20:52:39 +0200
committerMax Kellermann <max@duempel.org>2014-08-29 21:40:15 +0200
commitd9d97bd17bf0d9469dcf00120d3d3fdab87299bc (patch)
treed7abd9d0cbc6e417aaf4427740bf47207f47d7fa
parent94f6380d693b8bece655885d37495a3a73c78b62 (diff)
downloadmpd-d9d97bd17bf0d9469dcf00120d3d3fdab87299bc.tar.gz
mpd-d9d97bd17bf0d9469dcf00120d3d3fdab87299bc.tar.xz
mpd-d9d97bd17bf0d9469dcf00120d3d3fdab87299bc.zip
DecoderAPI: pass SignedSongTime to decoder_initialized()
-rw-r--r--src/decoder/DecoderAPI.cxx6
-rw-r--r--src/decoder/DecoderAPI.hxx5
-rw-r--r--src/decoder/plugins/AdPlugDecoderPlugin.cxx2
-rw-r--r--src/decoder/plugins/AudiofileDecoderPlugin.cxx14
-rw-r--r--src/decoder/plugins/DsdiffDecoderPlugin.cxx6
-rw-r--r--src/decoder/plugins/DsfDecoderPlugin.cxx4
-rw-r--r--src/decoder/plugins/FaadDecoderPlugin.cxx83
-rw-r--r--src/decoder/plugins/FfmpegDecoderPlugin.cxx8
-rw-r--r--src/decoder/plugins/FlacCommon.cxx6
-rw-r--r--src/decoder/plugins/FlacDecoderPlugin.cxx8
-rw-r--r--src/decoder/plugins/FluidsynthDecoderPlugin.cxx3
-rw-r--r--src/decoder/plugins/GmeDecoderPlugin.cxx6
-rw-r--r--src/decoder/plugins/MadDecoderPlugin.cxx39
-rw-r--r--src/decoder/plugins/MikmodDecoderPlugin.cxx3
-rw-r--r--src/decoder/plugins/ModplugDecoderPlugin.cxx2
-rw-r--r--src/decoder/plugins/Mp4v2DecoderPlugin.cxx3
-rw-r--r--src/decoder/plugins/MpcdecDecoderPlugin.cxx2
-rw-r--r--src/decoder/plugins/Mpg123DecoderPlugin.cxx8
-rw-r--r--src/decoder/plugins/OpusDecoderPlugin.cxx7
-rw-r--r--src/decoder/plugins/PcmDecoderPlugin.cxx8
-rw-r--r--src/decoder/plugins/SidplayDecoderPlugin.cxx30
-rw-r--r--src/decoder/plugins/SndfileDecoderPlugin.cxx5
-rw-r--r--src/decoder/plugins/VorbisDecoderPlugin.cxx17
-rw-r--r--src/decoder/plugins/WavpackDecoderPlugin.cxx5
-rw-r--r--src/decoder/plugins/WildmidiDecoderPlugin.cxx7
-rw-r--r--test/FakeDecoderAPI.cxx4
26 files changed, 159 insertions, 132 deletions
diff --git a/src/decoder/DecoderAPI.cxx b/src/decoder/DecoderAPI.cxx
index 354fed9a3..3d45cb325 100644
--- a/src/decoder/DecoderAPI.cxx
+++ b/src/decoder/DecoderAPI.cxx
@@ -41,7 +41,7 @@
void
decoder_initialized(Decoder &decoder,
const AudioFormat audio_format,
- bool seekable, float total_time)
+ bool seekable, SignedSongTime duration)
{
DecoderControl &dc = decoder.dc;
struct audio_format_string af_string;
@@ -59,9 +59,7 @@ decoder_initialized(Decoder &decoder,
dc.out_audio_format = getOutputAudioFormat(audio_format);
dc.seekable = seekable;
- dc.total_time = total_time > 0
- ? SignedSongTime::FromS(total_time)
- : SignedSongTime::Negative();
+ dc.total_time = duration;
FormatDebug(decoder_domain, "audio_format=%s, seekable=%s",
audio_format_to_string(dc.in_audio_format, &af_string),
diff --git a/src/decoder/DecoderAPI.hxx b/src/decoder/DecoderAPI.hxx
index ca33e26c7..b756331d9 100644
--- a/src/decoder/DecoderAPI.hxx
+++ b/src/decoder/DecoderAPI.hxx
@@ -53,12 +53,13 @@ class Error;
* @param audio_format the audio format which is going to be sent to
* decoder_data()
* @param seekable true if the song is seekable
- * @param total_time the total number of seconds in this song; -1 if unknown
+ * @param duration the total duration of this song; negative if
+ * unknown
*/
void
decoder_initialized(Decoder &decoder,
AudioFormat audio_format,
- bool seekable, float total_time);
+ bool seekable, SignedSongTime duration);
/**
* Determines the pending decoder command.
diff --git a/src/decoder/plugins/AdPlugDecoderPlugin.cxx b/src/decoder/plugins/AdPlugDecoderPlugin.cxx
index 32a2432f4..6c8edfe02 100644
--- a/src/decoder/plugins/AdPlugDecoderPlugin.cxx
+++ b/src/decoder/plugins/AdPlugDecoderPlugin.cxx
@@ -62,7 +62,7 @@ adplug_file_decode(Decoder &decoder, Path path_fs)
assert(audio_format.IsValid());
decoder_initialized(decoder, audio_format, false,
- player->songlength() / 1000.);
+ SongTime::FromMS(player->songlength()));
int16_t buffer[2048];
const unsigned frames_per_buffer = ARRAY_SIZE(buffer) / 2;
diff --git a/src/decoder/plugins/AudiofileDecoderPlugin.cxx b/src/decoder/plugins/AudiofileDecoderPlugin.cxx
index 412cda1e3..8d04f9596 100644
--- a/src/decoder/plugins/AudiofileDecoderPlugin.cxx
+++ b/src/decoder/plugins/AudiofileDecoderPlugin.cxx
@@ -64,13 +64,11 @@ struct AudioFileInputStream {
};
gcc_pure
-static double
+static SongTime
audiofile_get_duration(AFfilehandle fh)
{
- double frame_count = afGetFrameCount(fh, AF_DEFAULT_TRACK);
- double rate = afGetRate(fh, AF_DEFAULT_TRACK);
-
- return frame_count / rate;
+ return SongTime::FromScale<uint64_t>(afGetFrameCount(fh, AF_DEFAULT_TRACK),
+ afGetRate(fh, AF_DEFAULT_TRACK));
}
static ssize_t
@@ -208,10 +206,10 @@ audiofile_stream_decode(Decoder &decoder, InputStream &is)
return;
}
- const double total_time = audiofile_get_duration(fh);
+ const auto total_time = audiofile_get_duration(fh);
const uint16_t kbit_rate = (uint16_t)
- (is.GetSize() * 8.0 / total_time / 1000.0 + 0.5);
+ (is.GetSize() * uint64_t(8000) / total_time.ToMS());
const unsigned frame_size = (unsigned)
afGetVirtualFrameSize(fh, AF_DEFAULT_TRACK, true);
@@ -258,7 +256,7 @@ audiofile_get_duration(InputStream &is)
if (fh == AF_NULL_FILEHANDLE)
return -1;
- int duration = int(audiofile_get_duration(fh));
+ int duration = audiofile_get_duration(fh).RoundS();
afCloseFile(fh);
return duration;
}
diff --git a/src/decoder/plugins/DsdiffDecoderPlugin.cxx b/src/decoder/plugins/DsdiffDecoderPlugin.cxx
index 112de8b90..617d34ae4 100644
--- a/src/decoder/plugins/DsdiffDecoderPlugin.cxx
+++ b/src/decoder/plugins/DsdiffDecoderPlugin.cxx
@@ -437,8 +437,10 @@ dsdiff_stream_decode(Decoder &decoder, InputStream &is)
/* calculate song time from DSD chunk size and sample frequency */
offset_type chunk_size = metadata.chunk_size;
- float songtime = ((chunk_size / metadata.channels) * 8) /
- (float) metadata.sample_rate;
+
+ uint64_t n_frames = chunk_size / audio_format.channels;
+ auto songtime = SongTime::FromScale<uint64_t>(n_frames,
+ audio_format.sample_rate);
/* success: file was recognized */
decoder_initialized(decoder, audio_format, is.IsSeekable(), songtime);
diff --git a/src/decoder/plugins/DsfDecoderPlugin.cxx b/src/decoder/plugins/DsfDecoderPlugin.cxx
index c92c276fc..b84eadf66 100644
--- a/src/decoder/plugins/DsfDecoderPlugin.cxx
+++ b/src/decoder/plugins/DsfDecoderPlugin.cxx
@@ -318,8 +318,8 @@ dsf_stream_decode(Decoder &decoder, InputStream &is)
}
/* Calculate song time from DSD chunk size and sample frequency */
const auto n_blocks = metadata.n_blocks;
- float songtime = float(n_blocks * DSF_BLOCK_BITS) /
- (float) metadata.sample_rate;
+ auto songtime = SongTime::FromScale<uint64_t>(n_blocks * DSF_BLOCK_SIZE,
+ audio_format.sample_rate);
/* success: file was recognized */
decoder_initialized(decoder, audio_format, is.IsSeekable(), songtime);
diff --git a/src/decoder/plugins/FaadDecoderPlugin.cxx b/src/decoder/plugins/FaadDecoderPlugin.cxx
index 83fab7f9e..5b352c9f4 100644
--- a/src/decoder/plugins/FaadDecoderPlugin.cxx
+++ b/src/decoder/plugins/FaadDecoderPlugin.cxx
@@ -107,13 +107,13 @@ adts_find_frame(DecoderBuffer *buffer)
}
}
-static float
+static SignedSongTime
adts_song_duration(DecoderBuffer *buffer)
{
const InputStream &is = decoder_buffer_get_stream(buffer);
const bool estimate = !is.CheapSeeking();
if (estimate && !is.KnownSize())
- return -1;
+ return SignedSongTime::Negative();
unsigned sample_rate = 0;
@@ -146,7 +146,7 @@ adts_song_duration(DecoderBuffer *buffer)
const auto offset = is.GetOffset()
- decoder_buffer_available(buffer);
if (offset <= 0)
- return -1;
+ return SignedSongTime::Negative();
const auto file_size = is.GetSize();
frames = (frames * file_size) / offset;
@@ -155,20 +155,18 @@ adts_song_duration(DecoderBuffer *buffer)
}
if (sample_rate == 0)
- return -1;
+ return SignedSongTime::Negative();
- float frames_per_second = (float)sample_rate / 1024.0;
- assert(frames_per_second > 0);
-
- return (float)frames / frames_per_second;
+ return SignedSongTime::FromScale<uint64_t>(frames * uint64_t(1024),
+ sample_rate);
}
-static float
+static SignedSongTime
faad_song_duration(DecoderBuffer *buffer, InputStream &is)
{
auto data = ConstBuffer<uint8_t>::FromVoid(decoder_buffer_need(buffer, 5));
if (data.IsNull())
- return -1;
+ return SignedSongTime::Negative();
size_t tagsize = 0;
if (data.size >= 10 && !memcmp(data.data, "ID3", 3)) {
@@ -180,20 +178,20 @@ faad_song_duration(DecoderBuffer *buffer, InputStream &is)
tagsize += 10;
if (!decoder_buffer_skip(buffer, tagsize))
- return -1;
+ return SignedSongTime::Negative();
data = ConstBuffer<uint8_t>::FromVoid(decoder_buffer_need(buffer, 5));
if (data.IsNull())
- return -1;
+ return SignedSongTime::Negative();
}
if (data.size >= 8 && adts_check_frame(data.data) > 0) {
/* obtain the duration from the ADTS header */
if (!is.IsSeekable())
- return -1;
+ return SignedSongTime::Negative();
- float song_length = adts_song_duration(buffer);
+ auto song_length = adts_song_duration(buffer);
is.LockSeek(tagsize, IgnoreError());
@@ -204,14 +202,14 @@ faad_song_duration(DecoderBuffer *buffer, InputStream &is)
/* obtain the duration from the ADIF header */
if (!is.KnownSize())
- return -1;
+ return SignedSongTime::Negative();
size_t skip_size = (data.data[4] & 0x80) ? 9 : 0;
if (8 + skip_size > data.size)
/* not enough data yet; skip parsing this
header */
- return -1;
+ return SignedSongTime::Negative();
unsigned bit_rate = ((data.data[4 + skip_size] & 0x0F) << 19) |
(data.data[5 + skip_size] << 11) |
@@ -220,11 +218,11 @@ faad_song_duration(DecoderBuffer *buffer, InputStream &is)
const auto size = is.GetSize();
if (bit_rate == 0)
- return -1;
+ return SignedSongTime::Negative();
- return size * 8.0 / bit_rate;
+ return SongTime::FromScale(size, bit_rate / 8);
} else
- return -1;
+ return SignedSongTime::Negative();
}
static NeAACDecHandle
@@ -301,19 +299,21 @@ faad_decoder_decode(NeAACDecHandle decoder, DecoderBuffer *buffer,
}
/**
- * Get a song file's total playing time in seconds, as a float.
- * Returns 0 if the duration is unknown, and a negative value if the
- * file is invalid.
+ * Determine a song file's total playing time.
+ *
+ * The first return value specifies whether the file was recognized.
+ * The second return value is the duration.
*/
-static float
-faad_get_file_time_float(InputStream &is)
+static std::pair<bool, SignedSongTime>
+faad_get_file_time(InputStream &is)
{
DecoderBuffer *buffer =
decoder_buffer_new(nullptr, is,
FAAD_MIN_STREAMSIZE * MAX_CHANNELS);
- float length = faad_song_duration(buffer, is);
+ auto duration = faad_song_duration(buffer, is);
+ bool recognized = !duration.IsNegative();
- if (length < 0) {
+ if (!recognized) {
NeAACDecHandle decoder = faad_decoder_new();
decoder_buffer_fill(buffer);
@@ -321,36 +321,21 @@ faad_get_file_time_float(InputStream &is)
AudioFormat audio_format;
if (faad_decoder_init(decoder, buffer, audio_format,
IgnoreError()))
- length = 0;
+ recognized = true;
NeAACDecClose(decoder);
}
decoder_buffer_free(buffer);
- return length;
-}
-
-/**
- * Get a song file's total playing time in seconds, as an int.
- * Returns 0 if the duration is unknown, and a negative value if the
- * file is invalid.
- */
-static int
-faad_get_file_time(InputStream &is)
-{
- float length = faad_get_file_time_float(is);
- if (length < 0)
- return -1;
-
- return int(length + 0.5);
+ return std::make_pair(recognized, duration);
}
static void
faad_stream_decode(Decoder &mpd_decoder, InputStream &is,
DecoderBuffer *buffer, const NeAACDecHandle decoder)
{
- const float total_time = faad_song_duration(buffer, is);
+ const auto total_time = faad_song_duration(buffer, is);
if (adts_find_frame(buffer) == 0)
return;
@@ -449,11 +434,15 @@ static bool
faad_scan_stream(InputStream &is,
const struct tag_handler *handler, void *handler_ctx)
{
- int file_time = faad_get_file_time(is);
- if (file_time < 0)
+ auto result = faad_get_file_time(is);
+ if (!result.first)
return false;
- tag_handler_invoke_duration(handler, handler_ctx, file_time);
+ unsigned duration = result.second.IsNegative()
+ ? 0
+ : result.second.RoundS();
+
+ tag_handler_invoke_duration(handler, handler_ctx, duration);
return true;
}
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index e328da24b..0693ffd43 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -514,9 +514,11 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
return;
}
- int total_time = format_context->duration != (int64_t)AV_NOPTS_VALUE
- ? format_context->duration / AV_TIME_BASE
- : 0;
+ const SignedSongTime total_time =
+ format_context->duration != (int64_t)AV_NOPTS_VALUE
+ ? SignedSongTime::FromScale<uint64_t>(format_context->duration,
+ AV_TIME_BASE)
+ : SignedSongTime::Negative();
decoder_initialized(decoder, audio_format,
input.IsSeekable(), total_time);
diff --git a/src/decoder/plugins/FlacCommon.cxx b/src/decoder/plugins/FlacCommon.cxx
index f06a52cf8..76762bdf9 100644
--- a/src/decoder/plugins/FlacCommon.cxx
+++ b/src/decoder/plugins/FlacCommon.cxx
@@ -136,10 +136,12 @@ flac_got_first_frame(struct flac_data *data, const FLAC__FrameHeader *header)
data->frame_size = data->audio_format.GetFrameSize();
+ const auto duration = SongTime::FromScale<uint64_t>(data->total_frames,
+ data->audio_format.sample_rate);
+
decoder_initialized(data->decoder, data->audio_format,
data->input_stream.IsSeekable(),
- (float)data->total_frames /
- (float)data->audio_format.sample_rate);
+ duration);
data->initialized = true;
diff --git a/src/decoder/plugins/FlacDecoderPlugin.cxx b/src/decoder/plugins/FlacDecoderPlugin.cxx
index 60772398c..eea813401 100644
--- a/src/decoder/plugins/FlacDecoderPlugin.cxx
+++ b/src/decoder/plugins/FlacDecoderPlugin.cxx
@@ -144,10 +144,14 @@ flac_decoder_initialize(struct flac_data *data, FLAC__StreamDecoder *sd,
if (data->initialized) {
/* done */
+
+ const auto duration2 =
+ SongTime::FromScale<uint64_t>(data->total_frames,
+ data->audio_format.sample_rate);
+
decoder_initialized(data->decoder, data->audio_format,
data->input_stream.IsSeekable(),
- (float)data->total_frames /
- (float)data->audio_format.sample_rate);
+ duration2);
return true;
}
diff --git a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
index bdf30baea..f19ac5bf4 100644
--- a/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
+++ b/src/decoder/plugins/FluidsynthDecoderPlugin.cxx
@@ -166,7 +166,8 @@ fluidsynth_file_decode(Decoder &decoder, Path path_fs)
MPD core */
const AudioFormat audio_format(sample_rate, SampleFormat::S16, 2);
- decoder_initialized(decoder, audio_format, false, -1);
+ decoder_initialized(decoder, audio_format, false,
+ SignedSongTime::Negative());
DecoderCommand cmd;
while (fluid_player_get_status(player) == FLUID_PLAYER_PLAYING) {
diff --git a/src/decoder/plugins/GmeDecoderPlugin.cxx b/src/decoder/plugins/GmeDecoderPlugin.cxx
index 5588e2a1e..e1b281f93 100644
--- a/src/decoder/plugins/GmeDecoderPlugin.cxx
+++ b/src/decoder/plugins/GmeDecoderPlugin.cxx
@@ -156,9 +156,9 @@ gme_file_decode(Decoder &decoder, Path path_fs)
return;
}
- const float song_len = ti->length > 0
- ? ti->length / 1000.0
- : -1.0;
+ const SignedSongTime song_len = ti->length > 0
+ ? SignedSongTime::FromMS(ti->length)
+ : SignedSongTime::Negative();
/* initialize the MPD decoder */
diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx
index 7509faabb..3175d4bf6 100644
--- a/src/decoder/plugins/MadDecoderPlugin.cxx
+++ b/src/decoder/plugins/MadDecoderPlugin.cxx
@@ -122,7 +122,7 @@ struct MadDecoder {
mad_timer_t timer;
unsigned char input_buffer[READ_BUFFER_SIZE];
int32_t output_buffer[MP3_DATA_OUTPUT_BUFFER_SIZE];
- float total_time;
+ SignedSongTime total_time;
SongTime elapsed_time;
SongTime seek_time;
enum muteframe mute_frame;
@@ -713,11 +713,10 @@ parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen)
return true;
}
-static inline float
+static inline SongTime
mp3_frame_duration(const struct mad_frame *frame)
{
- return mad_timer_count(frame->header.duration,
- MAD_UNITS_MILLISECONDS) / 1000.0;
+ return ToSongTime(frame->header.duration);
}
inline offset_type
@@ -745,13 +744,19 @@ MadDecoder::FileSizeToSongLength()
if (input_stream.KnownSize()) {
offset_type rest = RestIncludingThisFrame();
- float frame_duration = mp3_frame_duration(&frame);
+ const SongTime frame_duration = mp3_frame_duration(&frame);
+ const SongTime duration =
+ SongTime::FromScale<uint64_t>(rest,
+ frame.header.bitrate / 8);
+ total_time = duration;
- total_time = (rest * 8.0) / frame.header.bitrate;
- max_frames = total_time / frame_duration + FRAMES_CUSHION;
+ max_frames = (frame_duration.IsPositive()
+ ? duration.count() / frame_duration.count()
+ : 0)
+ + FRAMES_CUSHION;
} else {
max_frames = FRAMES_CUSHION;
- total_time = 0;
+ total_time = SignedSongTime::Negative();
}
}
@@ -792,7 +797,7 @@ MadDecoder::DecodeFirstFrame(Tag **tag)
if ((xing.flags & XING_FRAMES) && xing.frames) {
mad_timer_t duration = frame.header.duration;
mad_timer_multiply(&duration, xing.frames);
- total_time = ((float)mad_timer_count(duration, MAD_UNITS_MILLISECONDS)) / 1000;
+ total_time = ToSongTime(duration);
max_frames = xing.frames;
}
@@ -844,13 +849,13 @@ MadDecoder::~MadDecoder()
}
/* this is primarily used for getting total time for tags */
-static int
+static std::pair<bool, SignedSongTime>
mad_decoder_total_file_time(InputStream &is)
{
MadDecoder data(nullptr, is);
return data.DecodeFirstFrame(nullptr)
- ? data.total_time + 0.5
- : -1;
+ ? std::make_pair(true, data.total_time)
+ : std::make_pair(false, SignedSongTime::Negative());
}
long
@@ -1085,11 +1090,15 @@ static bool
mad_decoder_scan_stream(InputStream &is,
const struct tag_handler *handler, void *handler_ctx)
{
- const int total_time = mad_decoder_total_file_time(is);
- if (total_time < 0)
+ const auto result = mad_decoder_total_file_time(is);
+ if (!result.first)
return false;
- tag_handler_invoke_duration(handler, handler_ctx, total_time);
+ unsigned duration = result.second.IsNegative()
+ ? 0
+ : result.second.RoundS();
+
+ tag_handler_invoke_duration(handler, handler_ctx, duration);
return true;
}
diff --git a/src/decoder/plugins/MikmodDecoderPlugin.cxx b/src/decoder/plugins/MikmodDecoderPlugin.cxx
index a1938617d..85633f1fc 100644
--- a/src/decoder/plugins/MikmodDecoderPlugin.cxx
+++ b/src/decoder/plugins/MikmodDecoderPlugin.cxx
@@ -170,7 +170,8 @@ mikmod_decoder_file_decode(Decoder &decoder, Path path_fs)
const AudioFormat audio_format(mikmod_sample_rate, SampleFormat::S16, 2);
assert(audio_format.IsValid());
- decoder_initialized(decoder, audio_format, false, 0);
+ decoder_initialized(decoder, audio_format, false,
+ SignedSongTime::Negative());
Player_Start(handle);
diff --git a/src/decoder/plugins/ModplugDecoderPlugin.cxx b/src/decoder/plugins/ModplugDecoderPlugin.cxx
index c88249fa5..279790b93 100644
--- a/src/decoder/plugins/ModplugDecoderPlugin.cxx
+++ b/src/decoder/plugins/ModplugDecoderPlugin.cxx
@@ -153,7 +153,7 @@ mod_decode(Decoder &decoder, InputStream &is)
decoder_initialized(decoder, audio_format,
is.IsSeekable(),
- ModPlug_GetLength(f) / 1000.0);
+ SongTime::FromMS(ModPlug_GetLength(f)));
DecoderCommand cmd;
do {
diff --git a/src/decoder/plugins/Mp4v2DecoderPlugin.cxx b/src/decoder/plugins/Mp4v2DecoderPlugin.cxx
index ef5284437..d59be7f09 100644
--- a/src/decoder/plugins/Mp4v2DecoderPlugin.cxx
+++ b/src/decoder/plugins/Mp4v2DecoderPlugin.cxx
@@ -149,7 +149,8 @@ mp4_file_decode(Decoder &mpd_decoder, Path path_fs)
/* initialize the MPD core */
const MP4Timestamp scale = MP4GetTrackTimeScale(handle, track);
- const float duration = ((float)MP4GetTrackDuration(handle, track)) / scale + 0.5f;
+ const SongTime duration = SongTime::FromScale<uint64_t>(MP4GetTrackDuration(handle, track),
+ scale);
const MP4SampleId num_samples = MP4GetTrackNumberOfSamples(handle, track);
decoder_initialized(mpd_decoder, audio_format, true, duration);
diff --git a/src/decoder/plugins/MpcdecDecoderPlugin.cxx b/src/decoder/plugins/MpcdecDecoderPlugin.cxx
index 3ad4ff40d..08e060bee 100644
--- a/src/decoder/plugins/MpcdecDecoderPlugin.cxx
+++ b/src/decoder/plugins/MpcdecDecoderPlugin.cxx
@@ -180,7 +180,7 @@ mpcdec_decode(Decoder &mpd_decoder, InputStream &is)
decoder_initialized(mpd_decoder, audio_format,
is.IsSeekable(),
- mpc_streaminfo_get_length(&info));
+ SongTime::FromS(mpc_streaminfo_get_length(&info)));
DecoderCommand cmd = DecoderCommand::NONE;
do {
diff --git a/src/decoder/plugins/Mpg123DecoderPlugin.cxx b/src/decoder/plugins/Mpg123DecoderPlugin.cxx
index 8779a6568..798cc953d 100644
--- a/src/decoder/plugins/Mpg123DecoderPlugin.cxx
+++ b/src/decoder/plugins/Mpg123DecoderPlugin.cxx
@@ -131,9 +131,11 @@ mpd_mpg123_file_decode(Decoder &decoder, Path path_fs)
/* tell MPD core we're ready */
- decoder_initialized(decoder, audio_format, true,
- (float)num_samples /
- (float)audio_format.sample_rate);
+ const auto duration =
+ SongTime::FromScale<uint64_t>(num_samples,
+ audio_format.sample_rate);
+
+ decoder_initialized(decoder, audio_format, true, duration);
if (mpg123_info(handle, &info) != MPG123_OK) {
info.vbr = MPG123_CBR;
diff --git a/src/decoder/plugins/OpusDecoderPlugin.cxx b/src/decoder/plugins/OpusDecoderPlugin.cxx
index 18ccf8183..2de827c7f 100644
--- a/src/decoder/plugins/OpusDecoderPlugin.cxx
+++ b/src/decoder/plugins/OpusDecoderPlugin.cxx
@@ -253,9 +253,10 @@ MPDOpusDecoder::HandleBOS(const ogg_packet &packet)
eos_granulepos = LoadEOSGranulePos(input_stream, &decoder,
opus_serialno);
- const double duration = eos_granulepos >= 0
- ? double(eos_granulepos) / opus_sample_rate
- : -1.0;
+ const auto duration = eos_granulepos >= 0
+ ? SignedSongTime::FromScale<uint64_t>(eos_granulepos,
+ opus_sample_rate)
+ : SignedSongTime::Negative();
const AudioFormat audio_format(opus_sample_rate,
SampleFormat::S16, channels);
diff --git a/src/decoder/plugins/PcmDecoderPlugin.cxx b/src/decoder/plugins/PcmDecoderPlugin.cxx
index 0f41099f2..c07a7b9b1 100644
--- a/src/decoder/plugins/PcmDecoderPlugin.cxx
+++ b/src/decoder/plugins/PcmDecoderPlugin.cxx
@@ -40,12 +40,12 @@ pcm_stream_decode(Decoder &decoder, InputStream &is)
const bool reverse_endian = mime != nullptr &&
strcmp(mime, "audio/x-mpd-cdda-pcm-reverse") == 0;
- const double time_to_size = audio_format.GetTimeToSize();
const auto frame_size = audio_format.GetFrameSize();
- float total_time = -1;
- if (is.KnownSize())
- total_time = is.GetSize() / time_to_size;
+ const auto total_time = is.KnownSize()
+ ? SignedSongTime::FromScale<uint64_t>(is.GetSize() / frame_size,
+ audio_format.sample_rate)
+ : SignedSongTime::Negative();
decoder_initialized(decoder, audio_format,
is.IsSeekable(), total_time);
diff --git a/src/decoder/plugins/SidplayDecoderPlugin.cxx b/src/decoder/plugins/SidplayDecoderPlugin.cxx
index b0a398f56..2adfa6df9 100644
--- a/src/decoder/plugins/SidplayDecoderPlugin.cxx
+++ b/src/decoder/plugins/SidplayDecoderPlugin.cxx
@@ -159,11 +159,11 @@ get_song_num(const char *path_fs)
}
/* get the song length in seconds */
-static int
+static SignedSongTime
get_song_length(Path path_fs)
{
if (songlength_database == nullptr)
- return -1;
+ return SignedSongTime::Negative();
char *sid_file = get_container_name(path_fs);
SidTuneMod tune(sid_file);
@@ -171,7 +171,7 @@ get_song_length(Path path_fs)
if(!tune) {
LogWarning(sidplay_domain,
"failed to load file for calculating md5 sum");
- return -1;
+ return SignedSongTime::Negative();
}
char md5sum[SIDTUNE_MD5_LENGTH+1];
tune.createMD5(md5sum);
@@ -183,7 +183,7 @@ get_song_length(Path path_fs)
"Database", md5sum, &num_items, nullptr);
if(!values || song_num>num_items) {
g_strfreev(values);
- return -1;
+ return SignedSongTime::Negative();
}
int minutes=strtol(values[song_num-1], nullptr, 10);
@@ -199,7 +199,7 @@ get_song_length(Path path_fs)
g_strfreev(values);
- return (minutes*60)+seconds;
+ return SignedSongTime::FromS((minutes * 60) + seconds);
}
static void
@@ -220,8 +220,9 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
const int song_num = get_song_num(path_fs.c_str());
tune.selectSong(song_num);
- int song_len=get_song_length(path_fs);
- if(song_len==-1) song_len=default_songlength;
+ auto duration = get_song_length(path_fs);
+ if (duration.IsNegative() && default_songlength > 0)
+ duration = SongTime::FromS(default_songlength);
/* initialize the player */
@@ -292,12 +293,14 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
const AudioFormat audio_format(48000, SampleFormat::S16, channels);
assert(audio_format.IsValid());
- decoder_initialized(decoder, audio_format, true, (float)song_len);
+ decoder_initialized(decoder, audio_format, true, duration);
/* .. and play */
const unsigned timebase = player.timebase();
- song_len *= timebase;
+ const unsigned end = duration.IsNegative()
+ ? 0u
+ : duration.ToScale<uint64_t>(timebase);
DecoderCommand cmd;
do {
@@ -334,7 +337,7 @@ sidplay_file_decode(Decoder &decoder, Path path_fs)
decoder_command_finished(decoder);
}
- if (song_len > 0 && player.time() >= (unsigned)song_len)
+ if (end > 0 && player.time() >= end)
break;
} while (cmd != DecoderCommand::STOP);
@@ -382,9 +385,10 @@ sidplay_scan_file(Path path_fs,
tag_handler_invoke_tag(handler, handler_ctx, TAG_TRACK, track);
/* time */
- int song_len=get_song_length(path_fs);
- if (song_len >= 0)
- tag_handler_invoke_duration(handler, handler_ctx, song_len);
+ const auto duration = get_song_length(path_fs);
+ if (!duration.IsNegative())
+ tag_handler_invoke_duration(handler, handler_ctx,
+ duration.RoundS());
return true;
}
diff --git a/src/decoder/plugins/SndfileDecoderPlugin.cxx b/src/decoder/plugins/SndfileDecoderPlugin.cxx
index 96e61d088..78897da58 100644
--- a/src/decoder/plugins/SndfileDecoderPlugin.cxx
+++ b/src/decoder/plugins/SndfileDecoderPlugin.cxx
@@ -140,10 +140,11 @@ static SF_VIRTUAL_IO vio = {
/**
* Converts a frame number to a timestamp (in seconds).
*/
-static float
+static SongTime
frame_to_time(sf_count_t frame, const AudioFormat *audio_format)
{
- return (float)frame / (float)audio_format->sample_rate;
+ return SongTime::FromScale<uint64_t>(frame,
+ audio_format->sample_rate);
}
static void
diff --git a/src/decoder/plugins/VorbisDecoderPlugin.cxx b/src/decoder/plugins/VorbisDecoderPlugin.cxx
index e740cede6..8348407d6 100644
--- a/src/decoder/plugins/VorbisDecoderPlugin.cxx
+++ b/src/decoder/plugins/VorbisDecoderPlugin.cxx
@@ -202,6 +202,16 @@ vorbis_init(gcc_unused const config_param &param)
return true;
}
+gcc_pure
+static SignedSongTime
+vorbis_duration(OggVorbis_File &vf)
+{
+ auto total = ov_time_total(&vf, -1);
+ return total >= 0
+ ? SignedSongTime::FromS(total)
+ : SignedSongTime::Negative();
+}
+
static void
vorbis_stream_decode(Decoder &decoder,
InputStream &input_stream)
@@ -237,11 +247,8 @@ vorbis_stream_decode(Decoder &decoder,
return;
}
- float total_time = ov_time_total(&vf, -1);
- if (total_time < 0)
- total_time = 0;
-
- decoder_initialized(decoder, audio_format, vis.seekable, total_time);
+ decoder_initialized(decoder, audio_format, vis.seekable,
+ vorbis_duration(vf));
#ifdef HAVE_TREMOR
char buffer[4096];
diff --git a/src/decoder/plugins/WavpackDecoderPlugin.cxx b/src/decoder/plugins/WavpackDecoderPlugin.cxx
index 870a1a80d..1efd49850 100644
--- a/src/decoder/plugins/WavpackDecoderPlugin.cxx
+++ b/src/decoder/plugins/WavpackDecoderPlugin.cxx
@@ -160,8 +160,9 @@ wavpack_decode(Decoder &decoder, WavpackContext *wpc, bool can_seek)
? format_samples_float
: format_samples_int;
- const float total_time = float(WavpackGetNumSamples(wpc))
- / audio_format.sample_rate;
+ const auto total_time =
+ SongTime::FromScale<uint64_t>(WavpackGetNumSamples(wpc),
+ audio_format.sample_rate);
const int bytes_per_sample = WavpackGetBytesPerSample(wpc);
const int output_sample_size = audio_format.GetFrameSize();
diff --git a/src/decoder/plugins/WildmidiDecoderPlugin.cxx b/src/decoder/plugins/WildmidiDecoderPlugin.cxx
index 08078a792..221f7433b 100644
--- a/src/decoder/plugins/WildmidiDecoderPlugin.cxx
+++ b/src/decoder/plugins/WildmidiDecoderPlugin.cxx
@@ -86,8 +86,11 @@ wildmidi_file_decode(Decoder &decoder, Path path_fs)
return;
}
- decoder_initialized(decoder, audio_format, true,
- info->approx_total_samples / WILDMIDI_SAMPLE_RATE);
+ const auto duration =
+ SongTime::FromScale<uint64_t>(info->approx_total_samples,
+ WILDMIDI_SAMPLE_RATE);
+
+ decoder_initialized(decoder, audio_format, true, duration);
DecoderCommand cmd;
do {
diff --git a/test/FakeDecoderAPI.cxx b/test/FakeDecoderAPI.cxx
index 2516e9e62..dcc78125b 100644
--- a/test/FakeDecoderAPI.cxx
+++ b/test/FakeDecoderAPI.cxx
@@ -30,7 +30,7 @@ void
decoder_initialized(Decoder &decoder,
const AudioFormat audio_format,
gcc_unused bool seekable,
- float duration)
+ SignedSongTime duration)
{
struct audio_format_string af_string;
@@ -39,7 +39,7 @@ decoder_initialized(Decoder &decoder,
fprintf(stderr, "audio_format=%s duration=%f\n",
audio_format_to_string(audio_format, &af_string),
- duration);
+ duration.ToDoubleS());
decoder.initialized = true;
}