decoder/Client: pass std::span to SubmitData()

This commit is contained in:
Max Kellermann 2022-07-11 18:03:06 +02:00
parent 329c448d30
commit c34f6ed8c0
30 changed files with 138 additions and 116 deletions

View File

@ -451,18 +451,18 @@ DecoderBridge::SubmitTimestamp(FloatDuration t) noexcept
}
DecoderCommand
DecoderBridge::SubmitData(InputStream *is,
const void *data, size_t length,
uint16_t kbit_rate) noexcept
DecoderBridge::SubmitAudio(InputStream *is,
std::span<const std::byte> audio,
uint16_t kbit_rate) noexcept
{
assert(dc.state == DecoderState::DECODE);
assert(dc.pipe != nullptr);
assert(length % dc.in_audio_format.GetFrameSize() == 0);
assert(audio.size() % dc.in_audio_format.GetFrameSize() == 0);
DecoderCommand cmd = LockGetVirtualCommand();
if (cmd == DecoderCommand::STOP || cmd == DecoderCommand::SEEK ||
length == 0)
audio.empty())
return cmd;
assert(!initial_seek_pending);
@ -486,7 +486,7 @@ DecoderBridge::SubmitData(InputStream *is,
cmd = DecoderCommand::NONE;
const size_t frame_size = dc.in_audio_format.GetFrameSize();
size_t data_frames = length / frame_size;
size_t data_frames = audio.size() / frame_size;
if (dc.end_time.IsPositive()) {
/* enforce the given end time */
@ -501,7 +501,7 @@ DecoderBridge::SubmitData(InputStream *is,
/* past the end of the range: truncate this
data submission and stop the decoder */
data_frames = remaining_frames;
length = data_frames * frame_size;
audio = audio.first(data_frames * frame_size);
cmd = DecoderCommand::STOP;
}
}
@ -510,9 +510,7 @@ DecoderBridge::SubmitData(InputStream *is,
assert(dc.in_audio_format != dc.out_audio_format);
try {
auto result = convert->Convert({(const std::byte *)data, length});
data = result.data();
length = result.size();
audio = convert->Convert(audio);
} catch (...) {
/* the PCM conversion has failed - stop
playback, since we have no better way to
@ -524,7 +522,7 @@ DecoderBridge::SubmitData(InputStream *is,
assert(dc.in_audio_format == dc.out_audio_format);
}
while (length > 0) {
while (!audio.empty()) {
bool full;
auto *chunk = GetChunk();
@ -544,11 +542,11 @@ DecoderBridge::SubmitData(InputStream *is,
continue;
}
const size_t nbytes = std::min(dest.size(), length);
const size_t nbytes = std::min(dest.size(), audio.size());
/* copy the buffer */
memcpy(dest.data(), data, nbytes);
memcpy(dest.data(), audio.data(), nbytes);
/* expand the music pipe chunk */
@ -558,8 +556,7 @@ DecoderBridge::SubmitData(InputStream *is,
FlushChunk();
}
data = (const uint8_t *)data + nbytes;
length -= nbytes;
audio = audio.subspan(nbytes);
timestamp += dc.out_audio_format.SizeToTime<FloatDuration>(nbytes);
}

View File

@ -177,9 +177,9 @@ public:
size_t Read(InputStream &is,
void *buffer, size_t length) noexcept override;
void SubmitTimestamp(FloatDuration t) noexcept override;
DecoderCommand SubmitData(InputStream *is,
const void *data, size_t length,
uint16_t kbit_rate) noexcept override;
DecoderCommand SubmitAudio(InputStream *is,
std::span<const std::byte> audio,
uint16_t kbit_rate) noexcept override;
DecoderCommand SubmitTag(InputStream *is, Tag &&tag) noexcept override;
void SubmitReplayGain(const ReplayGainInfo *replay_gain_info) noexcept override;
void SubmitMixRamp(MixRampInfo &&mix_ramp) noexcept override;

View File

@ -24,7 +24,9 @@
#include "Chrono.hxx"
#include "input/Ptr.hxx"
#include <cstddef>
#include <cstdint>
#include <span>
struct AudioFormat;
struct Tag;
@ -41,7 +43,7 @@ public:
* that it has read the song's meta data.
*
* @param audio_format the audio format which is going to be
* sent to SubmitData()
* sent to SubmitAudio()
* @param seekable true if the song is seekable
* @param duration the total duration of this song; negative if
* unknown
@ -128,14 +130,32 @@ public:
* @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) noexcept = 0;
virtual DecoderCommand SubmitAudio(InputStream *is,
std::span<const std::byte> audio,
uint16_t kbit_rate) noexcept = 0;
DecoderCommand SubmitData(InputStream &is,
const void *data, size_t length,
uint16_t kbit_rate) noexcept {
return SubmitData(&is, data, length, kbit_rate);
DecoderCommand SubmitAudio(InputStream &is,
std::span<const std::byte> audio,
uint16_t kbit_rate) noexcept {
return SubmitAudio(&is, audio, kbit_rate);
}
template<typename T, std::size_t extent>
DecoderCommand SubmitAudio(InputStream *is,
std::span<T, extent> audio,
uint16_t kbit_rate) noexcept {
const std::span<const std::byte> audio_bytes =
std::as_bytes(audio);
return SubmitAudio(is, audio_bytes, kbit_rate);
}
template<typename T, std::size_t extent>
DecoderCommand SubmitAudio(InputStream &is,
std::span<T, extent> audio,
uint16_t kbit_rate) noexcept {
const std::span<const std::byte> audio_bytes =
std::as_bytes(audio);
return SubmitAudio(is, audio_bytes, kbit_rate);
}
/**

View File

@ -71,9 +71,9 @@ adplug_file_decode(DecoderClient &client, Path path_fs)
int16_t buffer[2048];
constexpr unsigned frames_per_buffer = std::size(buffer) / 2;
opl.update(buffer, frames_per_buffer);
cmd = client.SubmitData(nullptr,
buffer, sizeof(buffer),
0);
cmd = client.SubmitAudio(nullptr,
std::span{buffer},
0);
} while (cmd == DecoderCommand::NONE);
delete player;

View File

@ -212,7 +212,7 @@ audiofile_stream_decode(DecoderClient &client, InputStream &is)
const auto kbit_rate = (uint16_t)
(is.GetSize() * uint64_t(8) / total_time.ToMS());
const auto frame_size = (unsigned)
const auto frame_size = (std::size_t)
afGetVirtualFrameSize(fh, AF_DEFAULT_TRACK, true);
client.Ready(audio_format, true, total_time);
@ -226,9 +226,9 @@ audiofile_stream_decode(DecoderClient &client, InputStream &is)
if (nframes <= 0)
break;
cmd = client.SubmitData(nullptr,
chunk, nframes * frame_size,
kbit_rate);
cmd = client.SubmitAudio(nullptr,
std::span{chunk, std::size_t(nframes) * frame_size},
kbit_rate);
if (cmd == DecoderCommand::SEEK) {
AFframecount frame = client.GetSeekFrame();

View File

@ -417,8 +417,8 @@ dsdiff_decode_chunk(DecoderClient &client, InputStream &is,
if (lsbitfirst)
bit_reverse_buffer(buffer, buffer + nbytes);
cmd = client.SubmitData(is, buffer, nbytes,
kbit_rate);
cmd = client.SubmitAudio(is, std::span{buffer, nbytes},
kbit_rate);
}
return true;

View File

@ -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 = client.SubmitData(is,
interleaved_buffer, block_size,
kbit_rate);
cmd = client.SubmitAudio(is,
std::span{interleaved_buffer, block_size},
kbit_rate);
++i;
}

View File

@ -354,7 +354,7 @@ faad_stream_decode(DecoderClient &client, InputStream &is,
/* decode it */
NeAACDecFrameInfo frame_info;
const void *const decoded =
const auto decoded = (const int16_t *)
faad_decoder_decode(decoder, buffer, &frame_info);
if (frame_info.error > 0) {
@ -391,9 +391,9 @@ faad_stream_decode(DecoderClient &client, InputStream &is,
/* send PCM samples to MPD */
cmd = client.SubmitData(is, decoded,
(size_t)frame_info.samples * 2,
bit_rate);
const std::span audio{decoded, (size_t)frame_info.samples};
cmd = client.SubmitAudio(is, audio, bit_rate);
} while (cmd != DecoderCommand::STOP);
}

View File

@ -205,7 +205,7 @@ PtsToPcmFrame(uint64_t pts, const AVStream &stream,
}
/**
* Invoke DecoderClient::SubmitData() with the contents of an
* Invoke DecoderClient::SubmitAudio() with the contents of an
* #AVFrame.
*/
static DecoderCommand
@ -227,9 +227,8 @@ FfmpegSendFrame(DecoderClient &client, InputStream *is,
skip_bytes = 0;
}
return client.SubmitData(is,
output_buffer.data(), output_buffer.size(),
codec_context.bit_rate / 1000);
return client.SubmitAudio(is, output_buffer,
codec_context.bit_rate / 1000);
}
static DecoderCommand

View File

@ -46,7 +46,7 @@ struct FlacDecoder : public FlacInput {
/**
* The kbit_rate parameter for the next
* DecoderBridge::SubmitData() call.
* DecoderBridge::SubmitAudio() call.
*/
uint16_t kbit_rate;
@ -62,7 +62,7 @@ struct FlacDecoder : public FlacInput {
/**
* Decoded PCM data obtained by our libFLAC write callback.
* If this is non-empty, then DecoderBridge::SubmitData()
* If this is non-empty, then DecoderBridge::SubmitAudio()
* should be called.
*/
std::span<const std::byte> chunk = {};

View File

@ -152,10 +152,8 @@ FlacSubmitToClient(DecoderClient &client, FlacDecoder &d) noexcept
}
if (!d.chunk.empty()) {
auto cmd = client.SubmitData(d.GetInputStream(),
d.chunk.data(),
d.chunk.size(),
d.kbit_rate);
auto cmd = client.SubmitAudio(d.GetInputStream(), d.chunk,
d.kbit_rate);
d.chunk = {};
if (cmd != DecoderCommand::NONE)
return cmd;

View File

@ -179,7 +179,7 @@ fluidsynth_file_decode(DecoderClient &client, Path path_fs)
if (ret != 0)
break;
cmd = client.SubmitData(nullptr, buffer, sizeof(buffer), 0);
cmd = client.SubmitAudio(nullptr, std::span{buffer}, 0);
if (cmd != DecoderCommand::NONE)
break;
}

View File

@ -216,7 +216,7 @@ gme_file_decode(DecoderClient &client, Path path_fs)
return;
}
cmd = client.SubmitData(nullptr, buf, sizeof(buf), 0);
cmd = client.SubmitAudio(nullptr, std::span{buf}, 0);
if (cmd == DecoderCommand::SEEK) {
unsigned where = client.GetSeekTime().ToMS();
gme_err = gme_seek(emu, where);

View File

@ -185,13 +185,13 @@ private:
/**
* Sends the synthesized current frame via
* DecoderClient::SubmitData().
* DecoderClient::SubmitAudio().
*/
DecoderCommand SubmitPCM(size_t start, size_t n) noexcept;
/**
* Synthesize the current frame and send it via
* DecoderClient::SubmitData().
* DecoderClient::SubmitAudio().
*/
DecoderCommand SynthAndSubmit() noexcept;
@ -805,9 +805,9 @@ MadDecoder::SubmitPCM(size_t i, size_t pcm_length) noexcept
MAD_NCHANNELS(&frame.header));
num_samples *= MAD_NCHANNELS(&frame.header);
return client->SubmitData(input_stream, output_buffer,
sizeof(output_buffer[0]) * num_samples,
frame.header.bitrate / 1000);
return client->SubmitAudio(input_stream,
std::span{output_buffer, num_samples},
frame.header.bitrate / 1000);
}
inline DecoderCommand

View File

@ -171,7 +171,9 @@ 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 = client.SubmitData(nullptr, buffer, ret, 0);
cmd = client.SubmitAudio(nullptr,
std::span{buffer, std::size_t(ret)},
0);
}
Player_Stop();

View File

@ -116,9 +116,9 @@ mod_decode(DecoderClient &client, InputStream &is)
if (ret <= 0)
break;
cmd = client.SubmitData(nullptr,
audio_buffer, ret,
0);
cmd = client.SubmitAudio(nullptr,
std::span{audio_buffer, std::size_t(ret)},
0);
if (cmd == DecoderCommand::SEEK) {
ModPlug_Seek(f, client.GetSeekTime().ToMS());

View File

@ -241,9 +241,9 @@ mpcdec_decode(DecoderClient &client, InputStream &is)
long bit_rate = unsigned(frame.bits) * audio_format.sample_rate
/ (1000 * frame.samples);
cmd = client.SubmitData(is,
chunk, ret * sizeof(chunk[0]),
bit_rate);
cmd = client.SubmitAudio(is,
std::span{chunk, ret},
bit_rate);
} while (cmd != DecoderCommand::STOP);
}

View File

@ -253,7 +253,8 @@ mpd_mpg123_file_decode(DecoderClient &client, Path path_fs)
/* send to MPD */
cmd = client.SubmitData(nullptr, buffer, nbytes, info.bitrate);
cmd = client.SubmitAudio(nullptr, std::span{buffer, nbytes},
info.bitrate);
if (cmd == DecoderCommand::SEEK) {
off_t c = client.GetSeekFrame();

View File

@ -69,7 +69,6 @@ static void
mod_decode(DecoderClient &client, InputStream &is)
{
int ret;
char audio_buffer[OPENMPT_FRAME_SIZE];
const auto buffer = mod_loadfile(&openmpt_domain, &client, is);
if (buffer == nullptr) {
@ -99,7 +98,8 @@ mod_decode(DecoderClient &client, InputStream &is)
mod.ctl_set("render.resampler.emulate_amiga", std::to_string((unsigned)openmpt_emulate_amiga));
#endif
static constexpr AudioFormat audio_format(OPENMPT_SAMPLE_RATE, SampleFormat::FLOAT, 2);
static constexpr unsigned channels = 2;
static constexpr AudioFormat audio_format(OPENMPT_SAMPLE_RATE, SampleFormat::FLOAT, channels);
assert(audio_format.IsValid());
client.Ready(audio_format, is.IsSeekable(),
@ -107,13 +107,16 @@ mod_decode(DecoderClient &client, InputStream &is)
DecoderCommand cmd;
do {
ret = mod.read_interleaved_stereo(OPENMPT_SAMPLE_RATE, OPENMPT_FRAME_SIZE / 2 / sizeof(float), (float*)audio_buffer);
float audio_buffer[OPENMPT_FRAME_SIZE / sizeof(float)];
ret = mod.read_interleaved_stereo(OPENMPT_SAMPLE_RATE,
OPENMPT_FRAME_SIZE / channels / sizeof(float),
audio_buffer);
if (ret <= 0)
break;
cmd = client.SubmitData(nullptr,
audio_buffer, ret * 2 * sizeof(float),
0);
cmd = client.SubmitAudio(nullptr,
std::span{audio_buffer, ret * channels},
0);
if (cmd == DecoderCommand::SEEK) {
mod.set_position_seconds(client.GetSeekTime().ToS());

View File

@ -114,11 +114,9 @@ class MPDOpusDecoder final : public OggDecoder {
*/
unsigned previous_channels = 0;
size_t frame_size;
/**
* The granulepos of the next sample to be submitted to
* DecoderClient::SubmitData(). Negative if unkown.
* DecoderClient::SubmitAudio(). Negative if unkown.
* Initialized by OnOggBeginning().
*/
ogg_int64_t granulepos;
@ -238,7 +236,6 @@ MPDOpusDecoder::OnOggBeginning(const ogg_packet &packet)
const AudioFormat audio_format(opus_sample_rate,
SampleFormat::S16, channels);
client.Ready(audio_format, eos_granulepos > 0, duration);
frame_size = audio_format.GetFrameSize();
if (output_buffer == nullptr)
/* note: if we ever support changing the channel count
@ -365,10 +362,10 @@ MPDOpusDecoder::HandleAudio(const ogg_packet &packet)
}
/* submit decoded samples to the DecoderClient */
const size_t nbytes = nframes * frame_size;
auto cmd = client.SubmitData(input_stream,
data, nbytes,
kbits);
const size_t n_samples = nframes * previous_channels;
auto cmd = client.SubmitAudio(input_stream,
std::span{data, n_samples},
kbits);
if (cmd != DecoderCommand::NONE)
throw cmd;

View File

@ -187,7 +187,7 @@ 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
DecoderClient::SubmitData() */
DecoderClient::SubmitAudio() */
r = r.first(r.size() - r.size() % in_frame_size);
buffer.Consume(r.size());
@ -209,7 +209,7 @@ pcm_stream_decode(DecoderClient &client, InputStream &is)
}
cmd = !r.empty()
? client.SubmitData(is, r.data(), r.size(), 0)
? client.SubmitAudio(is, r, 0)
: client.GetCommand();
if (cmd == DecoderCommand::SEEK) {
uint64_t frame = client.GetSeekFrame();

View File

@ -419,15 +419,16 @@ sidplay_file_decode(DecoderClient &client, Path path_fs)
#ifdef HAVE_SIDPLAYFP
/* libsidplayfp returns the number of samples */
const size_t nbytes = result * sizeof(buffer[0]);
const size_t n_samples = result;
#else
/* libsidplay2 returns the number of bytes */
const size_t nbytes = result;
const size_t n_samples = result / sizeof(buffer[0]);
#endif
client.SubmitTimestamp(FloatDuration(player.time()) / timebase);
cmd = client.SubmitData(nullptr, buffer, nbytes, 0);
cmd = client.SubmitAudio(nullptr, std::span{buffer, n_samples},
0);
if (cmd == DecoderCommand::SEEK) {
unsigned data_time = player.time();

View File

@ -227,9 +227,9 @@ sndfile_stream_decode(DecoderClient &client, InputStream &is)
if (num_frames <= 0)
break;
cmd = client.SubmitData(is,
buffer, num_frames * frame_size,
0);
cmd = client.SubmitAudio(is,
std::span{buffer, num_frames * frame_size},
0);
if (cmd == DecoderCommand::SEEK) {
sf_count_t c = client.GetSeekFrame();
c = sf_seek(sf, c, SEEK_SET);

View File

@ -233,10 +233,10 @@ VorbisDecoder::SubmitSomePcm()
vorbis_synthesis_read(&dsp, n_frames);
const size_t nbytes = n_frames * frame_size;
auto cmd = client.SubmitData(input_stream,
buffer, nbytes,
0);
const std::size_t n_samples = n_frames * channels;
auto cmd = client.SubmitAudio(input_stream,
std::span{buffer, n_samples},
0);
if (cmd != DecoderCommand::NONE)
throw cmd;

View File

@ -234,9 +234,12 @@ wavpack_decode(DecoderClient &client, WavpackContext *wpc, bool can_seek)
int bitrate = lround(WavpackGetInstantBitrate(wpc) / 1000);
format_samples(buffer, n_frames * audio_format.channels);
cmd = client.SubmitData(nullptr, buffer,
n_frames * output_frame_size,
bitrate);
cmd = client.SubmitAudio(nullptr,
{
(const std::byte *)buffer,
n_frames * output_frame_size,
},
bitrate);
}
}

View File

@ -94,7 +94,9 @@ wildmidi_output(DecoderClient &client, midi *wm)
if (length <= 0)
return DecoderCommand::STOP;
return client.SubmitData(nullptr, buffer, length, 0);
return client.SubmitAudio(nullptr,
std::span{buffer, std::size_t(length)},
0);
}
static void

View File

@ -63,23 +63,21 @@ ChromaprintDecoderClient::Ready(AudioFormat audio_format, bool,
}
DecoderCommand
ChromaprintDecoderClient::SubmitData(InputStream *,
const void *_data, size_t length,
uint16_t) noexcept
ChromaprintDecoderClient::SubmitAudio(InputStream *,
std::span<const std::byte> audio,
uint16_t) noexcept
{
assert(ready);
if (length > remaining_bytes)
if (audio.size() > remaining_bytes)
remaining_bytes = 0;
else
remaining_bytes -= length;
std::span<const std::byte> src{(const std::byte *)_data, length};
remaining_bytes -= audio.size();
if (convert)
src = convert->Convert(src);
audio = convert->Convert(audio);
chromaprint.Feed(FromBytesStrict<const int16_t>(src));
chromaprint.Feed(FromBytesStrict<const int16_t>(audio));
return GetCommand();
}

View File

@ -93,9 +93,9 @@ public:
void *buffer, size_t length) noexcept override;
void SubmitTimestamp(FloatDuration) noexcept override {}
DecoderCommand SubmitData(InputStream *is,
const void *data, size_t length,
uint16_t kbit_rate) noexcept override;
DecoderCommand SubmitAudio(InputStream *is,
std::span<const std::byte> audio,
uint16_t kbit_rate) noexcept override;
DecoderCommand SubmitTag(InputStream *, Tag &&) noexcept override {
return GetCommand();

View File

@ -91,16 +91,17 @@ DumpDecoderClient::SubmitTimestamp([[maybe_unused]] FloatDuration t) noexcept
}
DecoderCommand
DumpDecoderClient::SubmitData([[maybe_unused]] InputStream *is,
const void *data, size_t datalen,
[[maybe_unused]] uint16_t kbit_rate) noexcept
DumpDecoderClient::SubmitAudio([[maybe_unused]] InputStream *is,
std::span<const std::byte> audio,
[[maybe_unused]] uint16_t kbit_rate) noexcept
{
if (kbit_rate != prev_kbit_rate) {
prev_kbit_rate = kbit_rate;
fprintf(stderr, "%u kbit/s\n", kbit_rate);
}
[[maybe_unused]] ssize_t nbytes = write(STDOUT_FILENO, data, datalen);
[[maybe_unused]] ssize_t nbytes = write(STDOUT_FILENO,
audio.data(), audio.size());
return GetCommand();
}

View File

@ -51,9 +51,9 @@ public:
size_t Read(InputStream &is,
void *buffer, size_t length) noexcept override;
void SubmitTimestamp(FloatDuration t) noexcept override;
DecoderCommand SubmitData(InputStream *is,
const void *data, size_t length,
uint16_t kbit_rate) noexcept override;
DecoderCommand SubmitAudio(InputStream *is,
std::span<const std::byte> audio,
uint16_t kbit_rate) noexcept override;
DecoderCommand SubmitTag(InputStream *is, Tag &&tag) noexcept override;
void SubmitReplayGain(const ReplayGainInfo *replay_gain_info) noexcept override;
void SubmitMixRamp(MixRampInfo &&mix_ramp) noexcept override;