decoder/Client: add DecoderCommand/seek virtual methods
This commit is contained in:
parent
66fb352cca
commit
47a0f46ce8
@ -21,7 +21,11 @@
|
||||
#define MPD_DECODER_CLIENT_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "DecoderCommand.hxx"
|
||||
#include "Chrono.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct AudioFormat;
|
||||
|
||||
@ -42,6 +46,44 @@ public:
|
||||
*/
|
||||
virtual void Ready(AudioFormat audio_format,
|
||||
bool seekable, SignedSongTime duration) = 0;
|
||||
|
||||
/**
|
||||
* Determines the pending decoder command.
|
||||
*
|
||||
* @return the current command, or DecoderCommand::NONE if there is no
|
||||
* command pending
|
||||
*/
|
||||
gcc_pure
|
||||
virtual DecoderCommand GetCommand() = 0;
|
||||
|
||||
/**
|
||||
* Called by the decoder when it has performed the requested command
|
||||
* (dc->command). This function resets dc->command and wakes up the
|
||||
* player thread.
|
||||
*/
|
||||
virtual void CommandFinished() = 0;
|
||||
|
||||
/**
|
||||
* Call this when you have received the DecoderCommand::SEEK command.
|
||||
*
|
||||
* @return the destination position for the seek in milliseconds
|
||||
*/
|
||||
gcc_pure
|
||||
virtual SongTime GetSeekTime() = 0;
|
||||
|
||||
/**
|
||||
* Call this when you have received the DecoderCommand::SEEK command.
|
||||
*
|
||||
* @return the destination position for the seek in frames
|
||||
*/
|
||||
gcc_pure
|
||||
virtual uint64_t GetSeekFrame() = 0;
|
||||
|
||||
/**
|
||||
* Call this instead of CommandFinished() when seeking has
|
||||
* failed.
|
||||
*/
|
||||
virtual void SeekError() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -164,50 +164,45 @@ decoder_lock_get_virtual_command(DecoderClient &client)
|
||||
}
|
||||
|
||||
DecoderCommand
|
||||
decoder_get_command(DecoderClient &client)
|
||||
Decoder::GetCommand()
|
||||
{
|
||||
auto &decoder = (Decoder &)client;
|
||||
return decoder_lock_get_virtual_command(decoder);
|
||||
return decoder_lock_get_virtual_command(*this);
|
||||
}
|
||||
|
||||
void
|
||||
decoder_command_finished(DecoderClient &client)
|
||||
Decoder::CommandFinished()
|
||||
{
|
||||
auto &decoder = (Decoder &)client;
|
||||
DecoderControl &dc = decoder.dc;
|
||||
|
||||
const ScopeLock protect(dc.mutex);
|
||||
|
||||
assert(dc.command != DecoderCommand::NONE ||
|
||||
decoder.initial_seek_running);
|
||||
assert(dc.command != DecoderCommand::NONE || initial_seek_running);
|
||||
assert(dc.command != DecoderCommand::SEEK ||
|
||||
decoder.initial_seek_running ||
|
||||
dc.seek_error || decoder.seeking);
|
||||
initial_seek_running ||
|
||||
dc.seek_error || seeking);
|
||||
assert(dc.pipe != nullptr);
|
||||
|
||||
if (decoder.initial_seek_running) {
|
||||
assert(!decoder.seeking);
|
||||
assert(decoder.current_chunk == nullptr);
|
||||
if (initial_seek_running) {
|
||||
assert(!seeking);
|
||||
assert(current_chunk == nullptr);
|
||||
assert(dc.pipe->IsEmpty());
|
||||
|
||||
decoder.initial_seek_running = false;
|
||||
decoder.timestamp = dc.start_time.ToDoubleS();
|
||||
initial_seek_running = false;
|
||||
timestamp = dc.start_time.ToDoubleS();
|
||||
return;
|
||||
}
|
||||
|
||||
if (decoder.seeking) {
|
||||
decoder.seeking = false;
|
||||
if (seeking) {
|
||||
seeking = false;
|
||||
|
||||
/* delete frames from the old song position */
|
||||
|
||||
if (decoder.current_chunk != nullptr) {
|
||||
dc.buffer->Return(decoder.current_chunk);
|
||||
decoder.current_chunk = nullptr;
|
||||
if (current_chunk != nullptr) {
|
||||
dc.buffer->Return(current_chunk);
|
||||
current_chunk = nullptr;
|
||||
}
|
||||
|
||||
dc.pipe->Clear(*dc.buffer);
|
||||
|
||||
decoder.timestamp = dc.seek_time.ToDoubleS();
|
||||
timestamp = dc.seek_time.ToDoubleS();
|
||||
}
|
||||
|
||||
dc.command = DecoderCommand::NONE;
|
||||
@ -215,53 +210,44 @@ decoder_command_finished(DecoderClient &client)
|
||||
}
|
||||
|
||||
SongTime
|
||||
decoder_seek_time(DecoderClient &client)
|
||||
Decoder::GetSeekTime()
|
||||
{
|
||||
auto &decoder = (Decoder &)client;
|
||||
const DecoderControl &dc = decoder.dc;
|
||||
|
||||
assert(dc.pipe != nullptr);
|
||||
|
||||
if (decoder.initial_seek_running)
|
||||
if (initial_seek_running)
|
||||
return dc.start_time;
|
||||
|
||||
assert(dc.command == DecoderCommand::SEEK);
|
||||
|
||||
decoder.seeking = true;
|
||||
seeking = true;
|
||||
|
||||
return dc.seek_time;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
decoder_seek_where_frame(DecoderClient &client)
|
||||
Decoder::GetSeekFrame()
|
||||
{
|
||||
auto &decoder = (Decoder &)client;
|
||||
const DecoderControl &dc = decoder.dc;
|
||||
|
||||
return decoder_seek_time(decoder).ToScale<uint64_t>(dc.in_audio_format.sample_rate);
|
||||
return GetSeekTime().ToScale<uint64_t>(dc.in_audio_format.sample_rate);
|
||||
}
|
||||
|
||||
void
|
||||
decoder_seek_error(DecoderClient &client)
|
||||
Decoder::SeekError()
|
||||
{
|
||||
auto &decoder = (Decoder &)client;
|
||||
DecoderControl &dc = decoder.dc;
|
||||
|
||||
assert(dc.pipe != nullptr);
|
||||
|
||||
if (decoder.initial_seek_running) {
|
||||
if (initial_seek_running) {
|
||||
/* d'oh, we can't seek to the sub-song start position,
|
||||
what now? - no idea, ignoring the problem for now. */
|
||||
decoder.initial_seek_running = false;
|
||||
initial_seek_running = false;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(dc.command == DecoderCommand::SEEK);
|
||||
|
||||
dc.seek_error = true;
|
||||
decoder.seeking = false;
|
||||
seeking = false;
|
||||
|
||||
decoder_command_finished(decoder);
|
||||
CommandFinished();
|
||||
}
|
||||
|
||||
InputStreamPtr
|
||||
|
@ -54,56 +54,6 @@ class DecoderClient;
|
||||
*/
|
||||
class StopDecoder {};
|
||||
|
||||
/**
|
||||
* Determines the pending decoder command.
|
||||
*
|
||||
* @param decoder the decoder object
|
||||
* @return the current command, or DecoderCommand::NONE if there is no
|
||||
* command pending
|
||||
*/
|
||||
gcc_pure
|
||||
DecoderCommand
|
||||
decoder_get_command(DecoderClient &decoder);
|
||||
|
||||
/**
|
||||
* Called by the decoder when it has performed the requested command
|
||||
* (dc->command). This function resets dc->command and wakes up the
|
||||
* player thread.
|
||||
*
|
||||
* @param decoder the decoder object
|
||||
*/
|
||||
void
|
||||
decoder_command_finished(DecoderClient &decoder);
|
||||
|
||||
/**
|
||||
* Call this when you have received the DecoderCommand::SEEK command.
|
||||
*
|
||||
* @param decoder the decoder object
|
||||
* @return the destination position for the seek in milliseconds
|
||||
*/
|
||||
gcc_pure
|
||||
SongTime
|
||||
decoder_seek_time(DecoderClient &decoder);
|
||||
|
||||
/**
|
||||
* Call this when you have received the DecoderCommand::SEEK command.
|
||||
*
|
||||
* @param decoder the decoder object
|
||||
* @return the destination position for the seek in frames
|
||||
*/
|
||||
gcc_pure
|
||||
uint64_t
|
||||
decoder_seek_where_frame(DecoderClient &decoder);
|
||||
|
||||
/**
|
||||
* Call this instead of decoder_command_finished() when seeking has
|
||||
* failed.
|
||||
*
|
||||
* @param decoder the decoder object
|
||||
*/
|
||||
void
|
||||
decoder_seek_error(DecoderClient &decoder);
|
||||
|
||||
/**
|
||||
* Open a new #InputStream and wait until it's ready.
|
||||
*
|
||||
|
@ -59,9 +59,8 @@ struct Decoder final : DecoderClient {
|
||||
bool initial_seek_running = false;
|
||||
|
||||
/**
|
||||
* This flag is set by decoder_seek_time(), and checked by
|
||||
* decoder_command_finished(). It is used to clean up after
|
||||
* seeking.
|
||||
* This flag is set by GetSeekTime(), and checked by
|
||||
* CommandFinished(). It is used to clean up after seeking.
|
||||
*/
|
||||
bool seeking = false;
|
||||
|
||||
@ -120,6 +119,11 @@ struct Decoder final : DecoderClient {
|
||||
/* virtual methods from DecoderClient */
|
||||
void Ready(AudioFormat audio_format,
|
||||
bool seekable, SignedSongTime duration) override;
|
||||
DecoderCommand GetCommand() override;
|
||||
void CommandFinished() override;
|
||||
SongTime GetSeekTime() override;
|
||||
uint64_t GetSeekFrame() override;
|
||||
void SeekError() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -228,10 +228,10 @@ audiofile_stream_decode(DecoderClient &client, InputStream &is)
|
||||
kbit_rate);
|
||||
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
AFframecount frame = decoder_seek_where_frame(client);
|
||||
AFframecount frame = client.GetSeekFrame();
|
||||
afSeekFrame(fh, AF_DEFAULT_TRACK, frame);
|
||||
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
cmd = DecoderCommand::NONE;
|
||||
}
|
||||
} while (cmd == DecoderCommand::NONE);
|
||||
|
@ -372,23 +372,23 @@ dsdiff_decode_chunk(DecoderClient &client, InputStream &is,
|
||||
const unsigned buffer_frames = sizeof(buffer) / frame_size;
|
||||
const size_t buffer_size = buffer_frames * frame_size;
|
||||
|
||||
auto cmd = decoder_get_command(client);
|
||||
auto cmd = client.GetCommand();
|
||||
for (offset_type remaining_bytes = total_bytes;
|
||||
remaining_bytes >= frame_size && cmd != DecoderCommand::STOP;) {
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
uint64_t frame = decoder_seek_where_frame(client);
|
||||
uint64_t frame = client.GetSeekFrame();
|
||||
offset_type offset = FrameToOffset(frame, channels);
|
||||
if (offset >= total_bytes) {
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
break;
|
||||
}
|
||||
|
||||
if (dsdlib_skip_to(&client, is,
|
||||
start_offset + offset)) {
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
remaining_bytes = total_bytes - offset;
|
||||
} else
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
}
|
||||
|
||||
/* see how much aligned data from the remaining chunk
|
||||
|
@ -259,23 +259,23 @@ dsf_decode_chunk(DecoderClient &client, InputStream &is,
|
||||
const size_t block_size = channels * DSF_BLOCK_SIZE;
|
||||
const offset_type start_offset = is.GetOffset();
|
||||
|
||||
auto cmd = decoder_get_command(client);
|
||||
auto cmd = client.GetCommand();
|
||||
for (offset_type i = 0; i < n_blocks && cmd != DecoderCommand::STOP;) {
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
uint64_t frame = decoder_seek_where_frame(client);
|
||||
uint64_t frame = client.GetSeekFrame();
|
||||
offset_type block = FrameToBlock(frame);
|
||||
if (block >= n_blocks) {
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
break;
|
||||
}
|
||||
|
||||
offset_type offset =
|
||||
start_offset + block * block_size;
|
||||
if (dsdlib_skip_to(&client, is, offset)) {
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
i = block;
|
||||
} else
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
}
|
||||
|
||||
/* worst-case buffer size */
|
||||
|
@ -717,11 +717,11 @@ FfmpegDecode(DecoderClient &client, InputStream &input,
|
||||
|
||||
uint64_t min_frame = 0;
|
||||
|
||||
DecoderCommand cmd = decoder_get_command(client);
|
||||
DecoderCommand cmd = client.GetCommand();
|
||||
while (cmd != DecoderCommand::STOP) {
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
int64_t where =
|
||||
ToFfmpegTime(decoder_seek_time(client),
|
||||
ToFfmpegTime(client.GetSeekTime(),
|
||||
av_stream.time_base) +
|
||||
start_time_fallback(av_stream);
|
||||
|
||||
@ -730,11 +730,11 @@ FfmpegDecode(DecoderClient &client, InputStream &input,
|
||||
stamp, not after */
|
||||
if (av_seek_frame(&format_context, audio_stream, where,
|
||||
AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0)
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
else {
|
||||
avcodec_flush_buffers(codec_context);
|
||||
min_frame = decoder_seek_where_frame(client);
|
||||
decoder_command_finished(client);
|
||||
min_frame = client.GetSeekFrame();
|
||||
client.CommandFinished();
|
||||
}
|
||||
}
|
||||
|
||||
@ -757,7 +757,7 @@ FfmpegDecode(DecoderClient &client, InputStream &input,
|
||||
interleaved_buffer);
|
||||
min_frame = 0;
|
||||
} else
|
||||
cmd = decoder_get_command(client);
|
||||
cmd = client.GetCommand();
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(56, 25, 100)
|
||||
av_packet_unref(&packet);
|
||||
|
@ -151,16 +151,15 @@ flac_decoder_loop(FlacDecoder *data, FLAC__StreamDecoder *flac_dec)
|
||||
std::move(data->tag));
|
||||
data->tag.Clear();
|
||||
} else
|
||||
cmd = decoder_get_command(client);
|
||||
cmd = client.GetCommand();
|
||||
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
FLAC__uint64 seek_sample =
|
||||
decoder_seek_where_frame(client);
|
||||
FLAC__uint64 seek_sample = client.GetSeekFrame();
|
||||
if (FLAC__stream_decoder_seek_absolute(flac_dec, seek_sample)) {
|
||||
data->position = 0;
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
} else
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
} else if (cmd == DecoderCommand::STOP)
|
||||
break;
|
||||
|
||||
@ -198,7 +197,7 @@ flac_decoder_loop(FlacDecoder *data, FLAC__StreamDecoder *flac_dec)
|
||||
}
|
||||
|
||||
if (!FLAC__stream_decoder_process_single(flac_dec) &&
|
||||
decoder_get_command(client) == DecoderCommand::NONE) {
|
||||
client.GetCommand() == DecoderCommand::NONE) {
|
||||
/* a failure that was not triggered by a
|
||||
decoder command */
|
||||
flacPrintErroredState(FLAC__stream_decoder_get_state(flac_dec));
|
||||
|
@ -36,7 +36,7 @@ FlacInput::Read(FLAC__byte buffer[], size_t *bytes)
|
||||
if (r == 0) {
|
||||
if (input_stream.LockIsEOF() ||
|
||||
(client != nullptr &&
|
||||
decoder_get_command(*client) != DecoderCommand::NONE))
|
||||
client->GetCommand() != DecoderCommand::NONE))
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
|
||||
else
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
|
||||
@ -84,8 +84,8 @@ FLAC__bool
|
||||
FlacInput::Eof()
|
||||
{
|
||||
return (client != nullptr &&
|
||||
decoder_get_command(*client) != DecoderCommand::NONE &&
|
||||
decoder_get_command(*client) != DecoderCommand::SEEK) ||
|
||||
client->GetCommand() != DecoderCommand::NONE &&
|
||||
client->GetCommand() != DecoderCommand::SEEK) ||
|
||||
input_stream.LockIsEOF();
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ void
|
||||
FlacInput::Error(FLAC__StreamDecoderErrorStatus status)
|
||||
{
|
||||
if (client == nullptr ||
|
||||
decoder_get_command(*client) != DecoderCommand::STOP)
|
||||
client->GetCommand() != DecoderCommand::STOP)
|
||||
LogWarning(flac_domain,
|
||||
FLAC__StreamDecoderErrorStatusString[status]);
|
||||
}
|
||||
|
@ -192,13 +192,13 @@ gme_file_decode(DecoderClient &client, Path path_fs)
|
||||
|
||||
cmd = decoder_data(client, nullptr, buf, sizeof(buf), 0);
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
unsigned where = decoder_seek_time(client).ToMS();
|
||||
unsigned where = client.GetSeekTime().ToMS();
|
||||
gme_err = gme_seek(emu, where);
|
||||
if (gme_err != nullptr) {
|
||||
LogWarning(gme_domain, gme_err);
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
} else
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
}
|
||||
|
||||
if (gme_track_ended(emu))
|
||||
|
@ -985,18 +985,18 @@ MadDecoder::Read()
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
assert(input_stream.IsSeekable());
|
||||
|
||||
unsigned long j =
|
||||
TimeToFrame(decoder_seek_time(*client));
|
||||
const auto t = client->GetSeekTime();
|
||||
unsigned long j = TimeToFrame(t);
|
||||
if (j < highest_frame) {
|
||||
if (Seek(frame_offsets[j])) {
|
||||
current_frame = j;
|
||||
decoder_command_finished(*client);
|
||||
client->CommandFinished();
|
||||
} else
|
||||
decoder_seek_error(*client);
|
||||
client->SeekError();
|
||||
} else {
|
||||
seek_time = decoder_seek_time(*client);
|
||||
seek_time = t;
|
||||
mute_frame = MUTEFRAME_SEEK;
|
||||
decoder_command_finished(*client);
|
||||
client->CommandFinished();
|
||||
}
|
||||
} else if (cmd != DecoderCommand::NONE)
|
||||
return false;
|
||||
@ -1042,7 +1042,7 @@ mp3_decode(DecoderClient &client, InputStream &input_stream)
|
||||
if (!data.DecodeFirstFrame(&tag)) {
|
||||
delete tag;
|
||||
|
||||
if (decoder_get_command(client) == DecoderCommand::NONE)
|
||||
if (client.GetCommand() == DecoderCommand::NONE)
|
||||
LogError(mad_domain,
|
||||
"input/Input does not appear to be a mp3 bit stream");
|
||||
return;
|
||||
|
@ -165,8 +165,8 @@ mod_decode(DecoderClient &client, InputStream &is)
|
||||
0);
|
||||
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
ModPlug_Seek(f, decoder_seek_time(client).ToMS());
|
||||
decoder_command_finished(client);
|
||||
ModPlug_Seek(f, client.GetSeekTime().ToMS());
|
||||
client.CommandFinished();
|
||||
}
|
||||
|
||||
} while (cmd != DecoderCommand::STOP);
|
||||
|
@ -152,7 +152,7 @@ mpcdec_decode(DecoderClient &client, InputStream &is)
|
||||
|
||||
mpc_demux *demux = mpc_demux_init(&reader);
|
||||
if (demux == nullptr) {
|
||||
if (decoder_get_command(client) != DecoderCommand::STOP)
|
||||
if (client.GetCommand() != DecoderCommand::STOP)
|
||||
LogWarning(mpcdec_domain,
|
||||
"Not a valid musepack stream");
|
||||
return;
|
||||
@ -180,16 +180,15 @@ mpcdec_decode(DecoderClient &client, InputStream &is)
|
||||
DecoderCommand cmd = DecoderCommand::NONE;
|
||||
do {
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
mpc_int64_t where =
|
||||
decoder_seek_where_frame(client);
|
||||
mpc_int64_t where = client.GetSeekFrame();
|
||||
bool success;
|
||||
|
||||
success = mpc_demux_seek_sample(demux, where)
|
||||
== MPC_STATUS_OK;
|
||||
if (success)
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
else
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
}
|
||||
|
||||
MPC_SAMPLE_FORMAT sample_buffer[MPC_DECODER_BUFFER_LENGTH];
|
||||
|
@ -260,12 +260,12 @@ mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
|
||||
cmd = decoder_data(client, nullptr, buffer, nbytes, info.bitrate);
|
||||
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
off_t c = decoder_seek_where_frame(client);
|
||||
off_t c = client.GetSeekFrame();
|
||||
c = mpg123_seek(handle, c, SEEK_SET);
|
||||
if (c < 0)
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
else {
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
decoder_timestamp(client, c/(double)audio_format.sample_rate);
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
|
||||
output_buffer = new opus_int16[opus_output_buffer_frames
|
||||
* audio_format.channels];
|
||||
|
||||
auto cmd = decoder_get_command(client);
|
||||
auto cmd = client.GetCommand();
|
||||
if (cmd != DecoderCommand::NONE)
|
||||
throw cmd;
|
||||
}
|
||||
@ -291,10 +291,10 @@ mpd_opus_stream_decode(DecoderClient &client,
|
||||
break;
|
||||
} catch (DecoderCommand cmd) {
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
if (d.Seek(decoder_seek_where_frame(client)))
|
||||
decoder_command_finished(client);
|
||||
if (d.Seek(client.GetSeekFrame()))
|
||||
client.CommandFinished();
|
||||
else
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
} else if (cmd != DecoderCommand::NONE)
|
||||
break;
|
||||
}
|
||||
|
@ -166,18 +166,18 @@ pcm_stream_decode(DecoderClient &client, InputStream &is)
|
||||
|
||||
cmd = !r.IsEmpty()
|
||||
? decoder_data(client, is, r.data, r.size, 0)
|
||||
: decoder_get_command(client);
|
||||
: client.GetCommand();
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
uint64_t frame = decoder_seek_where_frame(client);
|
||||
uint64_t frame = client.GetSeekFrame();
|
||||
offset_type offset = frame * frame_size;
|
||||
|
||||
try {
|
||||
is.LockSeek(offset);
|
||||
buffer.Clear();
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
} catch (const std::runtime_error &e) {
|
||||
LogError(e);
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
}
|
||||
|
||||
cmd = DecoderCommand::NONE;
|
||||
|
@ -373,7 +373,7 @@ sidplay_file_decode(DecoderClient &client, Path path_fs)
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
unsigned data_time = player.time();
|
||||
unsigned target_time =
|
||||
decoder_seek_time(client).ToScale(timebase);
|
||||
client.GetSeekTime().ToScale(timebase);
|
||||
|
||||
/* can't rewind so return to zero and seek forward */
|
||||
if(target_time<data_time) {
|
||||
@ -386,7 +386,7 @@ sidplay_file_decode(DecoderClient &client, Path path_fs)
|
||||
player.play(buffer, ARRAY_SIZE(buffer)) > 0)
|
||||
data_time = player.time();
|
||||
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
}
|
||||
|
||||
if (end > 0 && player.time() >= end)
|
||||
|
@ -225,12 +225,12 @@ sndfile_stream_decode(DecoderClient &client, InputStream &is)
|
||||
buffer, num_frames * frame_size,
|
||||
0);
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
sf_count_t c = decoder_seek_where_frame(client);
|
||||
sf_count_t c = client.GetSeekFrame();
|
||||
c = sf_seek(sf, c, SEEK_SET);
|
||||
if (c < 0)
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
else
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
cmd = DecoderCommand::NONE;
|
||||
}
|
||||
} while (cmd == DecoderCommand::NONE);
|
||||
|
@ -264,7 +264,7 @@ VorbisDecoder::OnOggPacket(const ogg_packet &_packet)
|
||||
if (vorbis_synthesis(&block, &packet) != 0) {
|
||||
/* ignore bad packets, but give the MPD core a
|
||||
chance to stop us */
|
||||
auto cmd = decoder_get_command(client);
|
||||
auto cmd = client.GetCommand();
|
||||
if (cmd != DecoderCommand::NONE)
|
||||
throw cmd;
|
||||
return;
|
||||
@ -322,10 +322,10 @@ vorbis_stream_decode(DecoderClient &client,
|
||||
break;
|
||||
} catch (DecoderCommand cmd) {
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
if (d.Seek(decoder_seek_where_frame(client)))
|
||||
decoder_command_finished(client);
|
||||
if (d.Seek(client.GetSeekFrame()))
|
||||
client.CommandFinished();
|
||||
else
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
} else if (cmd != DecoderCommand::NONE)
|
||||
break;
|
||||
}
|
||||
|
@ -170,19 +170,19 @@ wavpack_decode(DecoderClient &client, WavpackContext *wpc, bool can_seek)
|
||||
|
||||
client.Ready(audio_format, can_seek, total_time);
|
||||
|
||||
DecoderCommand cmd = decoder_get_command(client);
|
||||
DecoderCommand cmd = client.GetCommand();
|
||||
while (cmd != DecoderCommand::STOP) {
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
if (can_seek) {
|
||||
auto where = decoder_seek_where_frame(client);
|
||||
auto where = client.GetSeekFrame();
|
||||
|
||||
if (WavpackSeekSample(wpc, where)) {
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
} else {
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
}
|
||||
} else {
|
||||
decoder_seek_error(client);
|
||||
client.SeekError();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,11 +114,10 @@ wildmidi_file_decode(DecoderClient &client, Path path_fs)
|
||||
cmd = wildmidi_output(client, wm);
|
||||
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
unsigned long seek_where =
|
||||
decoder_seek_where_frame(client);
|
||||
unsigned long seek_where = client.GetSeekFrame();
|
||||
|
||||
WildMidi_FastSeek(wm, &seek_where);
|
||||
decoder_command_finished(client);
|
||||
client.CommandFinished();
|
||||
cmd = DecoderCommand::NONE;
|
||||
}
|
||||
|
||||
|
@ -46,30 +46,30 @@ FakeDecoder::Ready(const AudioFormat audio_format,
|
||||
}
|
||||
|
||||
DecoderCommand
|
||||
decoder_get_command(gcc_unused DecoderClient &client)
|
||||
FakeDecoder::GetCommand()
|
||||
{
|
||||
return DecoderCommand::NONE;
|
||||
}
|
||||
|
||||
void
|
||||
decoder_command_finished(gcc_unused DecoderClient &client)
|
||||
FakeDecoder::CommandFinished()
|
||||
{
|
||||
}
|
||||
|
||||
SongTime
|
||||
decoder_seek_time(gcc_unused DecoderClient &client)
|
||||
FakeDecoder::GetSeekTime()
|
||||
{
|
||||
return SongTime();
|
||||
}
|
||||
|
||||
uint64_t
|
||||
decoder_seek_where_frame(gcc_unused DecoderClient &client)
|
||||
FakeDecoder::GetSeekFrame()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
decoder_seek_error(gcc_unused DecoderClient &client)
|
||||
FakeDecoder::SeekError()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -34,6 +34,11 @@ struct FakeDecoder final : DecoderClient {
|
||||
/* virtual methods from DecoderClient */
|
||||
void Ready(AudioFormat audio_format,
|
||||
bool seekable, SignedSongTime duration) override;
|
||||
DecoderCommand GetCommand() override;
|
||||
void CommandFinished() override;
|
||||
SongTime GetSeekTime() override;
|
||||
uint64_t GetSeekFrame() override;
|
||||
void SeekError() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user