decoder/Client: add Submit methods
Replaces decoder_data() and others.
This commit is contained in:
parent
47a0f46ce8
commit
a88040e4d5
@ -28,6 +28,10 @@
|
||||
#include <stdint.h>
|
||||
|
||||
struct AudioFormat;
|
||||
struct Tag;
|
||||
struct ReplayGainInfo;
|
||||
class MixRampInfo;
|
||||
class InputStream;
|
||||
|
||||
/**
|
||||
* An interface between the decoder plugin and the MPD core.
|
||||
@ -84,6 +88,64 @@ public:
|
||||
* failed.
|
||||
*/
|
||||
virtual void SeekError() = 0;
|
||||
|
||||
/**
|
||||
* Sets the time stamp for the next data chunk [seconds]. The MPD
|
||||
* core automatically counts it up, and a decoder plugin only needs to
|
||||
* use this function if it thinks that adding to the time stamp based
|
||||
* on the buffer size won't work.
|
||||
*/
|
||||
virtual void SubmitTimestamp(double t) = 0;
|
||||
|
||||
/**
|
||||
* This function is called by the decoder plugin when it has
|
||||
* successfully decoded block of input data.
|
||||
*
|
||||
* @param is an input stream which is buffering while we are waiting
|
||||
* for the player
|
||||
* @param data the source buffer
|
||||
* @param length the number of bytes in the buffer
|
||||
* @return the current command, or DecoderCommand::NONE if there is no
|
||||
* command pending
|
||||
*/
|
||||
virtual DecoderCommand SubmitData(InputStream *is,
|
||||
const void *data, size_t length,
|
||||
uint16_t kbit_rate) = 0;
|
||||
|
||||
DecoderCommand SubmitData(InputStream &is,
|
||||
const void *data, size_t length,
|
||||
uint16_t kbit_rate) {
|
||||
return SubmitData(&is, data, length, kbit_rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called by the decoder plugin when it has
|
||||
* successfully decoded a tag.
|
||||
*
|
||||
* @param is an input stream which is buffering while we are waiting
|
||||
* for the player
|
||||
* @param tag the tag to send
|
||||
* @return the current command, or DecoderCommand::NONE if there is no
|
||||
* command pending
|
||||
*/
|
||||
virtual DecoderCommand SubmitTag(InputStream *is, Tag &&tag) = 0 ;
|
||||
|
||||
DecoderCommand SubmitTag(InputStream &is, Tag &&tag) {
|
||||
return SubmitTag(&is, std::move(tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set replay gain values for the following chunks.
|
||||
*
|
||||
* @param replay_gain_info the replay_gain_info object; may be nullptr
|
||||
* to invalidate the previous replay gain values
|
||||
*/
|
||||
virtual void SubmitReplayGain(const ReplayGainInfo *replay_gain_info) = 0;
|
||||
|
||||
/**
|
||||
* Store MixRamp tags.
|
||||
*/
|
||||
virtual void SubmitMixRamp(MixRampInfo &&mix_ramp) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -382,12 +382,11 @@ decoder_skip(DecoderClient *client, InputStream &is, size_t size)
|
||||
}
|
||||
|
||||
void
|
||||
decoder_timestamp(DecoderClient &client, double t)
|
||||
Decoder::SubmitTimestamp(double t)
|
||||
{
|
||||
assert(t >= 0);
|
||||
|
||||
auto &decoder = (Decoder &)client;
|
||||
decoder.timestamp = t;
|
||||
timestamp = t;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -446,56 +445,52 @@ update_stream_tag(DecoderClient &client, InputStream *is)
|
||||
}
|
||||
|
||||
DecoderCommand
|
||||
decoder_data(DecoderClient &client,
|
||||
InputStream *is,
|
||||
const void *data, size_t length,
|
||||
uint16_t kbit_rate)
|
||||
Decoder::SubmitData(InputStream *is,
|
||||
const void *data, size_t length,
|
||||
uint16_t kbit_rate)
|
||||
{
|
||||
auto &decoder = (Decoder &)client;
|
||||
DecoderControl &dc = decoder.dc;
|
||||
|
||||
assert(dc.state == DecoderState::DECODE);
|
||||
assert(dc.pipe != nullptr);
|
||||
assert(length % dc.in_audio_format.GetFrameSize() == 0);
|
||||
|
||||
DecoderCommand cmd = decoder_lock_get_virtual_command(decoder);
|
||||
DecoderCommand cmd = decoder_lock_get_virtual_command(*this);
|
||||
|
||||
if (cmd == DecoderCommand::STOP || cmd == DecoderCommand::SEEK ||
|
||||
length == 0)
|
||||
return cmd;
|
||||
|
||||
assert(!decoder.initial_seek_pending);
|
||||
assert(!decoder.initial_seek_running);
|
||||
assert(!initial_seek_pending);
|
||||
assert(!initial_seek_running);
|
||||
|
||||
/* send stream tags */
|
||||
|
||||
if (update_stream_tag(decoder, is)) {
|
||||
if (decoder.decoder_tag != nullptr) {
|
||||
if (update_stream_tag(*this, is)) {
|
||||
if (decoder_tag != nullptr) {
|
||||
/* merge with tag from decoder plugin */
|
||||
Tag *tag = Tag::Merge(*decoder.decoder_tag,
|
||||
*decoder.stream_tag);
|
||||
cmd = do_send_tag(decoder, *tag);
|
||||
Tag *tag = Tag::Merge(*decoder_tag,
|
||||
*stream_tag);
|
||||
cmd = do_send_tag(*this, *tag);
|
||||
delete tag;
|
||||
} else
|
||||
/* send only the stream tag */
|
||||
cmd = do_send_tag(decoder, *decoder.stream_tag);
|
||||
cmd = do_send_tag(*this, *stream_tag);
|
||||
|
||||
if (cmd != DecoderCommand::NONE)
|
||||
return cmd;
|
||||
}
|
||||
|
||||
if (decoder.convert != nullptr) {
|
||||
if (convert != nullptr) {
|
||||
assert(dc.in_audio_format != dc.out_audio_format);
|
||||
|
||||
try {
|
||||
auto result = decoder.convert->Convert({data, length});
|
||||
auto result = convert->Convert({data, length});
|
||||
data = result.data;
|
||||
length = result.size;
|
||||
} catch (const std::runtime_error &e) {
|
||||
/* the PCM conversion has failed - stop
|
||||
playback, since we have no better way to
|
||||
bail out */
|
||||
decoder.error = std::current_exception();
|
||||
error = std::current_exception();
|
||||
return DecoderCommand::STOP;
|
||||
}
|
||||
} else {
|
||||
@ -503,10 +498,9 @@ decoder_data(DecoderClient &client,
|
||||
}
|
||||
|
||||
while (length > 0) {
|
||||
MusicChunk *chunk;
|
||||
bool full;
|
||||
|
||||
chunk = decoder.GetChunk();
|
||||
auto *chunk = GetChunk();
|
||||
if (chunk == nullptr) {
|
||||
assert(dc.command != DecoderCommand::NONE);
|
||||
return dc.command;
|
||||
@ -514,12 +508,12 @@ decoder_data(DecoderClient &client,
|
||||
|
||||
const auto dest =
|
||||
chunk->Write(dc.out_audio_format,
|
||||
SongTime::FromS(decoder.timestamp) -
|
||||
SongTime::FromS(timestamp) -
|
||||
dc.song->GetStartTime(),
|
||||
kbit_rate);
|
||||
if (dest.IsEmpty()) {
|
||||
/* the chunk is full, flush it */
|
||||
decoder.FlushChunk();
|
||||
FlushChunk();
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -534,17 +528,17 @@ decoder_data(DecoderClient &client,
|
||||
full = chunk->Expand(dc.out_audio_format, nbytes);
|
||||
if (full) {
|
||||
/* the chunk is full, flush it */
|
||||
decoder.FlushChunk();
|
||||
FlushChunk();
|
||||
}
|
||||
|
||||
data = (const uint8_t *)data + nbytes;
|
||||
length -= nbytes;
|
||||
|
||||
decoder.timestamp += (double)nbytes /
|
||||
timestamp += (double)nbytes /
|
||||
dc.out_audio_format.GetTimeToSize();
|
||||
|
||||
if (dc.end_time.IsPositive() &&
|
||||
decoder.timestamp >= dc.end_time.ToDoubleS())
|
||||
timestamp >= dc.end_time.ToDoubleS())
|
||||
/* the end of this range has been reached:
|
||||
stop decoding */
|
||||
return DecoderCommand::STOP;
|
||||
@ -554,11 +548,8 @@ decoder_data(DecoderClient &client,
|
||||
}
|
||||
|
||||
DecoderCommand
|
||||
decoder_tag(DecoderClient &client, InputStream *is,
|
||||
Tag &&tag)
|
||||
Decoder::SubmitTag(InputStream *is, Tag &&tag)
|
||||
{
|
||||
auto &decoder = (Decoder &)client;
|
||||
gcc_unused const DecoderControl &dc = decoder.dc;
|
||||
DecoderCommand cmd;
|
||||
|
||||
assert(dc.state == DecoderState::DECODE);
|
||||
@ -566,16 +557,16 @@ decoder_tag(DecoderClient &client, InputStream *is,
|
||||
|
||||
/* save the tag */
|
||||
|
||||
delete decoder.decoder_tag;
|
||||
decoder.decoder_tag = new Tag(std::move(tag));
|
||||
delete decoder_tag;
|
||||
decoder_tag = new Tag(std::move(tag));
|
||||
|
||||
/* check for a new stream tag */
|
||||
|
||||
update_stream_tag(decoder, is);
|
||||
update_stream_tag(*this, is);
|
||||
|
||||
/* check if we're seeking */
|
||||
|
||||
if (decoder_prepare_initial_seek(decoder))
|
||||
if (decoder_prepare_initial_seek(*this))
|
||||
/* during initial seek, no music chunk must be created
|
||||
until seeking is finished; skip the rest of the
|
||||
function here */
|
||||
@ -583,28 +574,24 @@ decoder_tag(DecoderClient &client, InputStream *is,
|
||||
|
||||
/* send tag to music pipe */
|
||||
|
||||
if (decoder.stream_tag != nullptr) {
|
||||
if (stream_tag != nullptr) {
|
||||
/* merge with tag from input stream */
|
||||
Tag *merged;
|
||||
|
||||
merged = Tag::Merge(*decoder.stream_tag,
|
||||
*decoder.decoder_tag);
|
||||
cmd = do_send_tag(decoder, *merged);
|
||||
merged = Tag::Merge(*stream_tag, *decoder_tag);
|
||||
cmd = do_send_tag(*this, *merged);
|
||||
delete merged;
|
||||
} else
|
||||
/* send only the decoder tag */
|
||||
cmd = do_send_tag(decoder, *decoder.decoder_tag);
|
||||
cmd = do_send_tag(*this, *decoder_tag);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void
|
||||
decoder_replay_gain(DecoderClient &client,
|
||||
const ReplayGainInfo *replay_gain_info)
|
||||
Decoder::SubmitReplayGain(const ReplayGainInfo *new_replay_gain_info)
|
||||
{
|
||||
auto &decoder = (Decoder &)client;
|
||||
|
||||
if (replay_gain_info != nullptr) {
|
||||
if (new_replay_gain_info != nullptr) {
|
||||
static unsigned serial;
|
||||
if (++serial == 0)
|
||||
serial = 1;
|
||||
@ -614,32 +601,29 @@ decoder_replay_gain(DecoderClient &client,
|
||||
if (rgm != REPLAY_GAIN_ALBUM)
|
||||
rgm = REPLAY_GAIN_TRACK;
|
||||
|
||||
const auto &tuple = replay_gain_info->tuples[rgm];
|
||||
const auto &tuple = new_replay_gain_info->tuples[rgm];
|
||||
const auto scale =
|
||||
tuple.CalculateScale(replay_gain_preamp,
|
||||
replay_gain_missing_preamp,
|
||||
replay_gain_limit);
|
||||
decoder.dc.replay_gain_db = 20.0 * log10f(scale);
|
||||
dc.replay_gain_db = 20.0 * log10f(scale);
|
||||
}
|
||||
|
||||
decoder.replay_gain_info = *replay_gain_info;
|
||||
decoder.replay_gain_serial = serial;
|
||||
replay_gain_info = *new_replay_gain_info;
|
||||
replay_gain_serial = serial;
|
||||
|
||||
if (decoder.current_chunk != nullptr) {
|
||||
if (current_chunk != nullptr) {
|
||||
/* flush the current chunk because the new
|
||||
replay gain values affect the following
|
||||
samples */
|
||||
decoder.FlushChunk();
|
||||
FlushChunk();
|
||||
}
|
||||
} else
|
||||
decoder.replay_gain_serial = 0;
|
||||
replay_gain_serial = 0;
|
||||
}
|
||||
|
||||
void
|
||||
decoder_mixramp(DecoderClient &client, MixRampInfo &&mix_ramp)
|
||||
Decoder::SubmitMixRamp(MixRampInfo &&mix_ramp)
|
||||
{
|
||||
auto &decoder = (Decoder &)client;
|
||||
DecoderControl &dc = decoder.dc;
|
||||
|
||||
dc.SetMixRamp(std::move(mix_ramp));
|
||||
}
|
||||
|
@ -104,73 +104,4 @@ decoder_read_full(DecoderClient *decoder, InputStream &is,
|
||||
bool
|
||||
decoder_skip(DecoderClient *decoder, InputStream &is, size_t size);
|
||||
|
||||
/**
|
||||
* Sets the time stamp for the next data chunk [seconds]. The MPD
|
||||
* core automatically counts it up, and a decoder plugin only needs to
|
||||
* use this function if it thinks that adding to the time stamp based
|
||||
* on the buffer size won't work.
|
||||
*/
|
||||
void
|
||||
decoder_timestamp(DecoderClient &decoder, double t);
|
||||
|
||||
/**
|
||||
* This function is called by the decoder plugin when it has
|
||||
* successfully decoded block of input data.
|
||||
*
|
||||
* @param decoder the decoder object
|
||||
* @param is an input stream which is buffering while we are waiting
|
||||
* for the player
|
||||
* @param data the source buffer
|
||||
* @param length the number of bytes in the buffer
|
||||
* @return the current command, or DecoderCommand::NONE if there is no
|
||||
* command pending
|
||||
*/
|
||||
DecoderCommand
|
||||
decoder_data(DecoderClient &decoder, InputStream *is,
|
||||
const void *data, size_t length,
|
||||
uint16_t kbit_rate);
|
||||
|
||||
static inline DecoderCommand
|
||||
decoder_data(DecoderClient &decoder, InputStream &is,
|
||||
const void *data, size_t length,
|
||||
uint16_t kbit_rate)
|
||||
{
|
||||
return decoder_data(decoder, &is, data, length, kbit_rate);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called by the decoder plugin when it has
|
||||
* successfully decoded a tag.
|
||||
*
|
||||
* @param is an input stream which is buffering while we are waiting
|
||||
* for the player
|
||||
* @param tag the tag to send
|
||||
* @return the current command, or DecoderCommand::NONE if there is no
|
||||
* command pending
|
||||
*/
|
||||
DecoderCommand
|
||||
decoder_tag(DecoderClient &decoder, InputStream *is, Tag &&tag);
|
||||
|
||||
static inline DecoderCommand
|
||||
decoder_tag(DecoderClient &decoder, InputStream &is, Tag &&tag)
|
||||
{
|
||||
return decoder_tag(decoder, &is, std::move(tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set replay gain values for the following chunks.
|
||||
*
|
||||
* @param replay_gain_info the replay_gain_info object; may be nullptr
|
||||
* to invalidate the previous replay gain values
|
||||
*/
|
||||
void
|
||||
decoder_replay_gain(DecoderClient &decoder,
|
||||
const ReplayGainInfo *replay_gain_info);
|
||||
|
||||
/**
|
||||
* Store MixRamp tags.
|
||||
*/
|
||||
void
|
||||
decoder_mixramp(DecoderClient &decoder, MixRampInfo &&mix_ramp);
|
||||
|
||||
#endif
|
||||
|
@ -124,6 +124,13 @@ struct Decoder final : DecoderClient {
|
||||
SongTime GetSeekTime() override;
|
||||
uint64_t GetSeekFrame() override;
|
||||
void SeekError() override;
|
||||
void SubmitTimestamp(double t) override;
|
||||
DecoderCommand SubmitData(InputStream *is,
|
||||
const void *data, size_t length,
|
||||
uint16_t kbit_rate) override;
|
||||
DecoderCommand SubmitTag(InputStream *is, Tag &&tag) override ;
|
||||
void SubmitReplayGain(const ReplayGainInfo *replay_gain_info) override;
|
||||
void SubmitMixRamp(MixRampInfo &&mix_ramp) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -245,14 +245,14 @@ decoder_run_stream_fallback(Decoder &decoder, InputStream &is)
|
||||
|
||||
/**
|
||||
* Attempt to load replay gain data, and pass it to
|
||||
* decoder_replay_gain().
|
||||
* DecoderClient::SubmitReplayGain().
|
||||
*/
|
||||
static void
|
||||
LoadReplayGain(Decoder &decoder, InputStream &is)
|
||||
LoadReplayGain(DecoderClient &client, InputStream &is)
|
||||
{
|
||||
ReplayGainInfo info;
|
||||
if (replay_gain_ape_read(is, info))
|
||||
decoder_replay_gain(decoder, &info);
|
||||
client.SubmitReplayGain(&info);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,9 +73,9 @@ adplug_file_decode(DecoderClient &client, Path path_fs)
|
||||
int16_t buffer[2048];
|
||||
constexpr unsigned frames_per_buffer = ARRAY_SIZE(buffer) / 2;
|
||||
opl.update(buffer, frames_per_buffer);
|
||||
cmd = decoder_data(client, nullptr,
|
||||
buffer, sizeof(buffer),
|
||||
0);
|
||||
cmd = client.SubmitData(nullptr,
|
||||
buffer, sizeof(buffer),
|
||||
0);
|
||||
} while (cmd == DecoderCommand::NONE);
|
||||
|
||||
delete player;
|
||||
|
@ -223,9 +223,9 @@ audiofile_stream_decode(DecoderClient &client, InputStream &is)
|
||||
if (nframes <= 0)
|
||||
break;
|
||||
|
||||
cmd = decoder_data(client, nullptr,
|
||||
chunk, nframes * frame_size,
|
||||
kbit_rate);
|
||||
cmd = client.SubmitData(nullptr,
|
||||
chunk, nframes * frame_size,
|
||||
kbit_rate);
|
||||
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
AFframecount frame = client.GetSeekFrame();
|
||||
|
@ -408,8 +408,8 @@ dsdiff_decode_chunk(DecoderClient &client, InputStream &is,
|
||||
if (lsbitfirst)
|
||||
bit_reverse_buffer(buffer, buffer + nbytes);
|
||||
|
||||
cmd = decoder_data(client, is, buffer, nbytes,
|
||||
sample_rate / 1000);
|
||||
cmd = client.SubmitData(is, buffer, nbytes,
|
||||
sample_rate / 1000);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -289,9 +289,9 @@ dsf_decode_chunk(DecoderClient &client, InputStream &is,
|
||||
uint8_t interleaved_buffer[MAX_CHANNELS * DSF_BLOCK_SIZE];
|
||||
InterleaveDsfBlock(interleaved_buffer, buffer, channels);
|
||||
|
||||
cmd = decoder_data(client, is,
|
||||
interleaved_buffer, block_size,
|
||||
sample_rate / 1000);
|
||||
cmd = client.SubmitData(is,
|
||||
interleaved_buffer, block_size,
|
||||
sample_rate / 1000);
|
||||
++i;
|
||||
}
|
||||
|
||||
|
@ -393,9 +393,9 @@ faad_stream_decode(DecoderClient &client, InputStream &is,
|
||||
|
||||
/* send PCM samples to MPD */
|
||||
|
||||
cmd = decoder_data(client, is, decoded,
|
||||
(size_t)frame_info.samples * 2,
|
||||
bit_rate);
|
||||
cmd = client.SubmitData(is, decoded,
|
||||
(size_t)frame_info.samples * 2,
|
||||
bit_rate);
|
||||
} while (cmd != DecoderCommand::STOP);
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,8 @@ PtsToPcmFrame(uint64_t pts, const AVStream &stream,
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke decoder_data() with the contents of an #AVFrame.
|
||||
* Invoke DecoderClient::SubmitData() with the contents of an
|
||||
* #AVFrame.
|
||||
*/
|
||||
static DecoderCommand
|
||||
FfmpegSendFrame(DecoderClient &client, InputStream &is,
|
||||
@ -250,9 +251,9 @@ FfmpegSendFrame(DecoderClient &client, InputStream &is,
|
||||
skip_bytes = 0;
|
||||
}
|
||||
|
||||
return decoder_data(client, is,
|
||||
output_buffer.data, output_buffer.size,
|
||||
codec_context.bit_rate / 1000);
|
||||
return client.SubmitData(is,
|
||||
output_buffer.data, output_buffer.size,
|
||||
codec_context.bit_rate / 1000);
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 0)
|
||||
@ -330,9 +331,8 @@ ffmpeg_send_packet(DecoderClient &client, InputStream &is,
|
||||
if (cur_frame < min_frame)
|
||||
skip_bytes = pcm_frame_size * (min_frame - cur_frame);
|
||||
} else
|
||||
decoder_timestamp(client,
|
||||
FfmpegTimeToDouble(pts,
|
||||
stream.time_base));
|
||||
client.SubmitTimestamp(FfmpegTimeToDouble(pts,
|
||||
stream.time_base));
|
||||
}
|
||||
|
||||
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57, 37, 0)
|
||||
@ -540,10 +540,10 @@ FfmpegParseMetaData(DecoderClient &client,
|
||||
FfmpegParseMetaData(format_context, audio_stream, rg, mr);
|
||||
|
||||
if (rg.IsDefined())
|
||||
decoder_replay_gain(client, &rg);
|
||||
client.SubmitReplayGain(&rg);
|
||||
|
||||
if (mr.IsDefined())
|
||||
decoder_mixramp(client, std::move(mr));
|
||||
client.SubmitMixRamp(std::move(mr));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -576,7 +576,7 @@ FfmpegScanTag(const AVFormatContext &format_context, int audio_stream,
|
||||
|
||||
/**
|
||||
* Check if a new stream tag was received and pass it to
|
||||
* decoder_tag().
|
||||
* DecoderClient::SubmitTag().
|
||||
*/
|
||||
static void
|
||||
FfmpegCheckTag(DecoderClient &client, InputStream &is,
|
||||
@ -593,7 +593,7 @@ FfmpegCheckTag(DecoderClient &client, InputStream &is,
|
||||
TagBuilder tag;
|
||||
FfmpegScanTag(format_context, audio_stream, tag);
|
||||
if (!tag.IsEmpty())
|
||||
decoder_tag(client, is, tag.Commit());
|
||||
client.SubmitTag(is, tag.Commit());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -77,9 +77,9 @@ FlacDecoder::OnVorbisComment(const FLAC__StreamMetadata_VorbisComment &vc)
|
||||
{
|
||||
ReplayGainInfo rgi;
|
||||
if (flac_parse_replay_gain(rgi, vc))
|
||||
decoder_replay_gain(*GetClient(), &rgi);
|
||||
GetClient()->SubmitReplayGain(&rgi);
|
||||
|
||||
decoder_mixramp(*GetClient(), flac_parse_mixramp(vc));
|
||||
GetClient()->SubmitMixRamp(flac_parse_mixramp(vc));
|
||||
|
||||
tag = flac_vorbis_comments_to_tag(&vc);
|
||||
}
|
||||
@ -148,9 +148,9 @@ FlacDecoder::OnWrite(const FLAC__Frame &frame,
|
||||
unsigned bit_rate = nbytes * 8 * frame.header.sample_rate /
|
||||
(1000 * frame.header.blocksize);
|
||||
|
||||
auto cmd = decoder_data(*GetClient(), GetInputStream(),
|
||||
data.data, data.size,
|
||||
bit_rate);
|
||||
auto cmd = GetClient()->SubmitData(GetInputStream(),
|
||||
data.data, data.size,
|
||||
bit_rate);
|
||||
switch (cmd) {
|
||||
case DecoderCommand::NONE:
|
||||
case DecoderCommand::START:
|
||||
|
@ -147,8 +147,8 @@ flac_decoder_loop(FlacDecoder *data, FLAC__StreamDecoder *flac_dec)
|
||||
while (true) {
|
||||
DecoderCommand cmd;
|
||||
if (!data->tag.IsEmpty()) {
|
||||
cmd = decoder_tag(client, data->GetInputStream(),
|
||||
std::move(data->tag));
|
||||
cmd = client.SubmitTag(data->GetInputStream(),
|
||||
std::move(data->tag));
|
||||
data->tag.Clear();
|
||||
} else
|
||||
cmd = client.GetCommand();
|
||||
|
@ -176,8 +176,7 @@ fluidsynth_file_decode(DecoderClient &client, Path path_fs)
|
||||
if (ret != 0)
|
||||
break;
|
||||
|
||||
cmd = decoder_data(client, nullptr, buffer, sizeof(buffer),
|
||||
0);
|
||||
cmd = client.SubmitData(nullptr, buffer, sizeof(buffer), 0);
|
||||
if (cmd != DecoderCommand::NONE)
|
||||
break;
|
||||
}
|
||||
|
@ -190,7 +190,7 @@ gme_file_decode(DecoderClient &client, Path path_fs)
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = decoder_data(client, nullptr, buf, sizeof(buf), 0);
|
||||
cmd = client.SubmitData(nullptr, buf, sizeof(buf), 0);
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
unsigned where = client.GetSeekTime().ToMS();
|
||||
gme_err = gme_seek(emu, where);
|
||||
|
@ -182,13 +182,14 @@ struct MadDecoder {
|
||||
void UpdateTimerNextFrame();
|
||||
|
||||
/**
|
||||
* Sends the synthesized current frame via decoder_data().
|
||||
* Sends the synthesized current frame via
|
||||
* DecoderClient::SubmitData().
|
||||
*/
|
||||
DecoderCommand SendPCM(unsigned i, unsigned pcm_length);
|
||||
|
||||
/**
|
||||
* Synthesize the current frame and send it via
|
||||
* decoder_data().
|
||||
* DecoderClient::SubmitData().
|
||||
*/
|
||||
DecoderCommand SyncAndSend();
|
||||
|
||||
@ -361,11 +362,11 @@ MadDecoder::ParseId3(size_t tagsize, Tag **mpd_tag)
|
||||
ReplayGainInfo rgi;
|
||||
|
||||
if (parse_id3_replay_gain_info(rgi, id3_tag)) {
|
||||
decoder_replay_gain(*client, &rgi);
|
||||
client->SubmitReplayGain(&rgi);
|
||||
found_replay_gain = true;
|
||||
}
|
||||
|
||||
decoder_mixramp(*client, parse_id3_mixramp(id3_tag));
|
||||
client->SubmitMixRamp(parse_id3_mixramp(id3_tag));
|
||||
}
|
||||
|
||||
id3_tag_delete(id3_tag);
|
||||
@ -806,7 +807,7 @@ MadDecoder::DecodeFirstFrame(Tag **tag)
|
||||
rgi.Clear();
|
||||
rgi.tuples[REPLAY_GAIN_TRACK].gain = lame.track_gain;
|
||||
rgi.tuples[REPLAY_GAIN_TRACK].peak = lame.peak;
|
||||
decoder_replay_gain(*client, &rgi);
|
||||
client->SubmitReplayGain(&rgi);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -903,9 +904,9 @@ MadDecoder::SendPCM(unsigned i, unsigned pcm_length)
|
||||
MAD_NCHANNELS(&frame.header));
|
||||
num_samples *= MAD_NCHANNELS(&frame.header);
|
||||
|
||||
auto cmd = decoder_data(*client, input_stream, output_buffer,
|
||||
sizeof(output_buffer[0]) * num_samples,
|
||||
bit_rate / 1000);
|
||||
auto cmd = client->SubmitData(input_stream, output_buffer,
|
||||
sizeof(output_buffer[0]) * num_samples,
|
||||
bit_rate / 1000);
|
||||
if (cmd != DecoderCommand::NONE)
|
||||
return cmd;
|
||||
}
|
||||
@ -1010,8 +1011,8 @@ MadDecoder::Read()
|
||||
ret = DecodeNextFrameHeader(&tag);
|
||||
|
||||
if (tag != nullptr) {
|
||||
decoder_tag(*client, input_stream,
|
||||
std::move(*tag));
|
||||
client->SubmitTag(input_stream,
|
||||
std::move(*tag));
|
||||
delete tag;
|
||||
}
|
||||
} while (ret == DECODE_CONT);
|
||||
@ -1057,7 +1058,7 @@ mp3_decode(DecoderClient &client, InputStream &input_stream)
|
||||
data.total_time);
|
||||
|
||||
if (tag != nullptr) {
|
||||
decoder_tag(client, input_stream, std::move(*tag));
|
||||
client.SubmitTag(input_stream, std::move(*tag));
|
||||
delete tag;
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ mikmod_decoder_file_decode(DecoderClient &client, Path path_fs)
|
||||
DecoderCommand cmd = DecoderCommand::NONE;
|
||||
while (cmd == DecoderCommand::NONE && Player_Active()) {
|
||||
ret = VC_WriteBytes(buffer, sizeof(buffer));
|
||||
cmd = decoder_data(client, nullptr, buffer, ret, 0);
|
||||
cmd = client.SubmitData(nullptr, buffer, ret, 0);
|
||||
}
|
||||
|
||||
Player_Stop();
|
||||
|
@ -160,9 +160,9 @@ mod_decode(DecoderClient &client, InputStream &is)
|
||||
if (ret <= 0)
|
||||
break;
|
||||
|
||||
cmd = decoder_data(client, nullptr,
|
||||
audio_buffer, ret,
|
||||
0);
|
||||
cmd = client.SubmitData(nullptr,
|
||||
audio_buffer, ret,
|
||||
0);
|
||||
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
ModPlug_Seek(f, client.GetSeekTime().ToMS());
|
||||
|
@ -172,7 +172,7 @@ mpcdec_decode(DecoderClient &client, InputStream &is)
|
||||
rgi.tuples[REPLAY_GAIN_TRACK].gain = MPC_OLD_GAIN_REF - (info.gain_title / 256.);
|
||||
rgi.tuples[REPLAY_GAIN_TRACK].peak = pow(10, info.peak_title / 256. / 20) / 32767;
|
||||
|
||||
decoder_replay_gain(client, &rgi);
|
||||
client.SubmitReplayGain(&rgi);
|
||||
|
||||
client.Ready(audio_format, is.IsSeekable(),
|
||||
SongTime::FromS(mpc_streaminfo_get_length(&info)));
|
||||
@ -213,9 +213,9 @@ mpcdec_decode(DecoderClient &client, InputStream &is)
|
||||
long bit_rate = unsigned(frame.bits) * audio_format.sample_rate
|
||||
/ (1000 * frame.samples);
|
||||
|
||||
cmd = decoder_data(client, is,
|
||||
chunk, ret * sizeof(chunk[0]),
|
||||
bit_rate);
|
||||
cmd = client.SubmitData(is,
|
||||
chunk, ret * sizeof(chunk[0]),
|
||||
bit_rate);
|
||||
} while (cmd != DecoderCommand::STOP);
|
||||
|
||||
mpc_demux_exit(demux);
|
||||
|
@ -129,7 +129,7 @@ mpd_mpg123_id3v2_tag(DecoderClient &client, const mpg123_id3v2 &id3v2)
|
||||
for (size_t i = 0, n = id3v2.comments; i < n; ++i)
|
||||
AddTagItem(tag, TAG_COMMENT, id3v2.comment_list[i].text);
|
||||
|
||||
decoder_tag(client, nullptr, tag.Commit());
|
||||
client.SubmitTag(nullptr, tag.Commit());
|
||||
}
|
||||
|
||||
static void
|
||||
@ -154,10 +154,10 @@ mpd_mpg123_id3v2_extras(DecoderClient &client, const mpg123_id3v2 &id3v2)
|
||||
}
|
||||
|
||||
if (found_replay_gain)
|
||||
decoder_replay_gain(client, &replay_gain);
|
||||
client.SubmitReplayGain(&replay_gain);
|
||||
|
||||
if (found_mixramp)
|
||||
decoder_mixramp(client, std::move(mix_ramp));
|
||||
client.SubmitMixRamp(std::move(mix_ramp));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -257,7 +257,7 @@ mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
|
||||
|
||||
/* send to MPD */
|
||||
|
||||
cmd = decoder_data(client, nullptr, buffer, nbytes, info.bitrate);
|
||||
cmd = client.SubmitData(nullptr, buffer, nbytes, info.bitrate);
|
||||
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
off_t c = client.GetSeekFrame();
|
||||
@ -266,7 +266,7 @@ mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
|
||||
client.SeekError();
|
||||
else {
|
||||
client.CommandFinished();
|
||||
decoder_timestamp(client, c/(double)audio_format.sample_rate);
|
||||
client.SubmitTimestamp(c / (double)audio_format.sample_rate);
|
||||
}
|
||||
|
||||
cmd = DecoderCommand::NONE;
|
||||
|
@ -212,10 +212,10 @@ MPDOpusDecoder::HandleTags(const ogg_packet &packet)
|
||||
&rgi,
|
||||
add_tag_handler, &tag_builder) &&
|
||||
!tag_builder.IsEmpty()) {
|
||||
decoder_replay_gain(client, &rgi);
|
||||
client.SubmitReplayGain(&rgi);
|
||||
|
||||
Tag tag = tag_builder.Commit();
|
||||
auto cmd = decoder_tag(client, input_stream, std::move(tag));
|
||||
auto cmd = client.SubmitTag(input_stream, std::move(tag));
|
||||
if (cmd != DecoderCommand::NONE)
|
||||
throw cmd;
|
||||
}
|
||||
@ -237,16 +237,15 @@ MPDOpusDecoder::HandleAudio(const ogg_packet &packet)
|
||||
|
||||
if (nframes > 0) {
|
||||
const size_t nbytes = nframes * frame_size;
|
||||
auto cmd = decoder_data(client, input_stream,
|
||||
output_buffer, nbytes,
|
||||
0);
|
||||
auto cmd = client.SubmitData(input_stream,
|
||||
output_buffer, nbytes,
|
||||
0);
|
||||
if (cmd != DecoderCommand::NONE)
|
||||
throw cmd;
|
||||
|
||||
if (packet.granulepos > 0)
|
||||
decoder_timestamp(client,
|
||||
double(packet.granulepos)
|
||||
/ opus_sample_rate);
|
||||
client.SubmitTimestamp(double(packet.granulepos)
|
||||
/ opus_sample_rate);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,8 @@ pcm_stream_decode(DecoderClient &client, InputStream &is)
|
||||
|
||||
auto r = buffer.Read();
|
||||
/* round down to the nearest frame size, because we
|
||||
must not pass partial frames to decoder_data() */
|
||||
must not pass partial frames to
|
||||
DecoderClient::SubmitData() */
|
||||
r.size -= r.size % frame_size;
|
||||
buffer.Consume(r.size);
|
||||
|
||||
@ -165,7 +166,7 @@ pcm_stream_decode(DecoderClient &client, InputStream &is)
|
||||
(uint16_t *)(r.data + r.size));
|
||||
|
||||
cmd = !r.IsEmpty()
|
||||
? decoder_data(client, is, r.data, r.size, 0)
|
||||
? client.SubmitData(is, r.data, r.size, 0)
|
||||
: client.GetCommand();
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
uint64_t frame = client.GetSeekFrame();
|
||||
|
@ -366,9 +366,9 @@ sidplay_file_decode(DecoderClient &client, Path path_fs)
|
||||
const size_t nbytes = result;
|
||||
#endif
|
||||
|
||||
decoder_timestamp(client, (double)player.time() / timebase);
|
||||
client.SubmitTimestamp((double)player.time() / timebase);
|
||||
|
||||
cmd = decoder_data(client, nullptr, buffer, nbytes, 0);
|
||||
cmd = client.SubmitData(nullptr, buffer, nbytes, 0);
|
||||
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
unsigned data_time = player.time();
|
||||
|
@ -221,9 +221,9 @@ sndfile_stream_decode(DecoderClient &client, InputStream &is)
|
||||
if (num_frames <= 0)
|
||||
break;
|
||||
|
||||
cmd = decoder_data(client, is,
|
||||
buffer, num_frames * frame_size,
|
||||
0);
|
||||
cmd = client.SubmitData(is,
|
||||
buffer, num_frames * frame_size,
|
||||
0);
|
||||
if (cmd == DecoderCommand::SEEK) {
|
||||
sf_count_t c = client.GetSeekFrame();
|
||||
c = sf_seek(sf, c, SEEK_SET);
|
||||
|
@ -156,7 +156,7 @@ vorbis_send_comments(DecoderClient &client, InputStream &is,
|
||||
if (!tag)
|
||||
return;
|
||||
|
||||
decoder_tag(client, is, std::move(*tag));
|
||||
client.SubmitTag(is, std::move(*tag));
|
||||
delete tag;
|
||||
}
|
||||
|
||||
@ -211,9 +211,9 @@ VorbisDecoder::SubmitSomePcm()
|
||||
vorbis_synthesis_read(&dsp, n_frames);
|
||||
|
||||
const size_t nbytes = n_frames * frame_size;
|
||||
auto cmd = decoder_data(client, input_stream,
|
||||
buffer, nbytes,
|
||||
0);
|
||||
auto cmd = client.SubmitData(input_stream,
|
||||
buffer, nbytes,
|
||||
0);
|
||||
if (cmd != DecoderCommand::NONE)
|
||||
throw cmd;
|
||||
|
||||
@ -252,7 +252,7 @@ VorbisDecoder::OnOggPacket(const ogg_packet &_packet)
|
||||
|
||||
ReplayGainInfo rgi;
|
||||
if (vorbis_comments_to_replay_gain(rgi, vc.user_comments))
|
||||
decoder_replay_gain(client, &rgi);
|
||||
client.SubmitReplayGain(&rgi);
|
||||
} else {
|
||||
if (!dsp_initialized) {
|
||||
dsp_initialized = true;
|
||||
@ -277,8 +277,7 @@ VorbisDecoder::OnOggPacket(const ogg_packet &_packet)
|
||||
|
||||
#ifndef HAVE_TREMOR
|
||||
if (packet.granulepos > 0)
|
||||
decoder_timestamp(client,
|
||||
vorbis_granule_time(&dsp, packet.granulepos));
|
||||
client.SubmitTimestamp(vorbis_granule_time(&dsp, packet.granulepos));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -196,9 +196,9 @@ wavpack_decode(DecoderClient &client, WavpackContext *wpc, bool can_seek)
|
||||
format_samples(bytes_per_sample, chunk,
|
||||
samples_got * audio_format.channels);
|
||||
|
||||
cmd = decoder_data(client, nullptr, chunk,
|
||||
samples_got * output_sample_size,
|
||||
bitrate);
|
||||
cmd = client.SubmitData(nullptr, chunk,
|
||||
samples_got * output_sample_size,
|
||||
bitrate);
|
||||
}
|
||||
}
|
||||
|
||||
@ -563,7 +563,7 @@ wavpack_filedecode(DecoderClient &client, Path path_fs)
|
||||
|
||||
ReplayGainInfo rgi;
|
||||
if (wavpack_replaygain(rgi, wpc))
|
||||
decoder_replay_gain(client, &rgi);
|
||||
client.SubmitReplayGain(&rgi);
|
||||
|
||||
wavpack_decode(client, wpc, true);
|
||||
|
||||
|
@ -75,7 +75,7 @@ wildmidi_output(DecoderClient &client, midi *wm)
|
||||
if (length <= 0)
|
||||
return DecoderCommand::STOP;
|
||||
|
||||
return decoder_data(client, nullptr, buffer, length, 0);
|
||||
return client.SubmitData(nullptr, buffer, length, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -127,16 +127,14 @@ decoder_skip(DecoderClient *client, InputStream &is, size_t size)
|
||||
}
|
||||
|
||||
void
|
||||
decoder_timestamp(gcc_unused DecoderClient &client,
|
||||
gcc_unused double t)
|
||||
FakeDecoder::SubmitTimestamp(gcc_unused double t)
|
||||
{
|
||||
}
|
||||
|
||||
DecoderCommand
|
||||
decoder_data(gcc_unused DecoderClient &client,
|
||||
gcc_unused InputStream *is,
|
||||
const void *data, size_t datalen,
|
||||
gcc_unused uint16_t kbit_rate)
|
||||
FakeDecoder::SubmitData(gcc_unused InputStream *is,
|
||||
const void *data, size_t datalen,
|
||||
gcc_unused uint16_t kbit_rate)
|
||||
{
|
||||
static uint16_t prev_kbit_rate;
|
||||
if (kbit_rate != prev_kbit_rate) {
|
||||
@ -149,9 +147,8 @@ decoder_data(gcc_unused DecoderClient &client,
|
||||
}
|
||||
|
||||
DecoderCommand
|
||||
decoder_tag(gcc_unused DecoderClient &client,
|
||||
gcc_unused InputStream *is,
|
||||
Tag &&tag)
|
||||
FakeDecoder::SubmitTag(gcc_unused InputStream *is,
|
||||
Tag &&tag)
|
||||
{
|
||||
fprintf(stderr, "TAG: duration=%f\n", tag.duration.ToDoubleS());
|
||||
|
||||
@ -162,8 +159,7 @@ decoder_tag(gcc_unused DecoderClient &client,
|
||||
}
|
||||
|
||||
void
|
||||
decoder_replay_gain(gcc_unused DecoderClient &client,
|
||||
const ReplayGainInfo *rgi)
|
||||
FakeDecoder::SubmitReplayGain(const ReplayGainInfo *rgi)
|
||||
{
|
||||
const ReplayGainTuple *tuple = &rgi->tuples[REPLAY_GAIN_ALBUM];
|
||||
if (tuple->IsDefined())
|
||||
@ -177,7 +173,7 @@ decoder_replay_gain(gcc_unused DecoderClient &client,
|
||||
}
|
||||
|
||||
void
|
||||
decoder_mixramp(gcc_unused DecoderClient &client, gcc_unused MixRampInfo &&mix_ramp)
|
||||
FakeDecoder::SubmitMixRamp(gcc_unused MixRampInfo &&mix_ramp)
|
||||
{
|
||||
fprintf(stderr, "MixRamp: start='%s' end='%s'\n",
|
||||
mix_ramp.GetStart(), mix_ramp.GetEnd());
|
||||
|
@ -39,6 +39,13 @@ struct FakeDecoder final : DecoderClient {
|
||||
SongTime GetSeekTime() override;
|
||||
uint64_t GetSeekFrame() override;
|
||||
void SeekError() override;
|
||||
void SubmitTimestamp(double t) override;
|
||||
DecoderCommand SubmitData(InputStream *is,
|
||||
const void *data, size_t length,
|
||||
uint16_t kbit_rate) override;
|
||||
DecoderCommand SubmitTag(InputStream *is, Tag &&tag) override ;
|
||||
void SubmitReplayGain(const ReplayGainInfo *replay_gain_info) override;
|
||||
void SubmitMixRamp(MixRampInfo &&mix_ramp) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user