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