encoder/Interface: pass std::span to Write() and Read()
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#define MPD_ENCODER_INTERFACE_HXX
|
||||
|
||||
#include <cstddef>
|
||||
#include <span>
|
||||
|
||||
struct AudioFormat;
|
||||
struct Tag;
|
||||
@@ -91,18 +92,19 @@ public:
|
||||
* @param data the buffer containing PCM samples
|
||||
* @param length the length of the buffer in bytes
|
||||
*/
|
||||
virtual void Write(const void *data, std::size_t length) = 0;
|
||||
virtual void Write(std::span<const std::byte> src) = 0;
|
||||
|
||||
/**
|
||||
* Reads encoded data from the encoder.
|
||||
*
|
||||
* Call this repeatedly until no more data is returned.
|
||||
*
|
||||
* @param dest the destination buffer to copy to
|
||||
* @param length the maximum length of the destination buffer
|
||||
* @return the number of bytes written to #dest
|
||||
* @param buffer a buffer that can be used to write data into
|
||||
*
|
||||
* @return the portion of the buffer that was filled (but may
|
||||
* also point to a different buffer, e.g. one owned by this object)
|
||||
*/
|
||||
virtual std::size_t Read(void *dest, std::size_t length) noexcept = 0;
|
||||
virtual std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept = 0;
|
||||
};
|
||||
|
||||
class PreparedEncoder {
|
||||
|
@@ -28,12 +28,12 @@ EncoderToOutputStream(OutputStream &os, Encoder &encoder)
|
||||
/* read from the encoder */
|
||||
|
||||
std::byte buffer[32768];
|
||||
size_t nbytes = encoder.Read(buffer, sizeof(buffer));
|
||||
if (nbytes == 0)
|
||||
const auto r = encoder.Read(std::span{buffer});
|
||||
if (r.empty())
|
||||
return;
|
||||
|
||||
/* write everything to the stream */
|
||||
|
||||
os.Write(buffer, nbytes);
|
||||
os.Write(r.data(), r.size());
|
||||
}
|
||||
}
|
||||
|
@@ -71,10 +71,10 @@ public:
|
||||
|
||||
void SendTag(const Tag &tag) override;
|
||||
|
||||
void Write(const void *data, size_t length) override;
|
||||
void Write(std::span<const std::byte> src) override;
|
||||
|
||||
size_t Read(void *dest, size_t length) noexcept override {
|
||||
return output_buffer.Read((std::byte *)dest, length);
|
||||
std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept override {
|
||||
return buffer.first(output_buffer.Read(buffer.data(), buffer.size()));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -267,27 +267,27 @@ pcm16_to_flac(int32_t *out, const int16_t *in, std::size_t num_samples) noexcept
|
||||
}
|
||||
|
||||
void
|
||||
FlacEncoder::Write(const void *data, size_t length)
|
||||
FlacEncoder::Write(std::span<const std::byte> src)
|
||||
{
|
||||
void *exbuffer;
|
||||
const void *buffer = nullptr;
|
||||
|
||||
/* format conversion */
|
||||
|
||||
const std::size_t num_frames = length / audio_format.GetFrameSize();
|
||||
const std::size_t num_frames = src.size() / audio_format.GetFrameSize();
|
||||
const std::size_t num_samples = num_frames * audio_format.channels;
|
||||
|
||||
switch (audio_format.format) {
|
||||
case SampleFormat::S8:
|
||||
exbuffer = expand_buffer.Get(length * 4);
|
||||
pcm8_to_flac((int32_t *)exbuffer, (const int8_t *)data,
|
||||
exbuffer = expand_buffer.Get(src.size() * 4);
|
||||
pcm8_to_flac((int32_t *)exbuffer, (const int8_t *)src.data(),
|
||||
num_samples);
|
||||
buffer = exbuffer;
|
||||
break;
|
||||
|
||||
case SampleFormat::S16:
|
||||
exbuffer = expand_buffer.Get(length * 2);
|
||||
pcm16_to_flac((int32_t *)exbuffer, (const int16_t *)data,
|
||||
exbuffer = expand_buffer.Get(src.size() * 2);
|
||||
pcm16_to_flac((int32_t *)exbuffer, (const int16_t *)src.data(),
|
||||
num_samples);
|
||||
buffer = exbuffer;
|
||||
break;
|
||||
@@ -296,7 +296,7 @@ FlacEncoder::Write(const void *data, size_t length)
|
||||
case SampleFormat::S32:
|
||||
/* nothing need to be done; format is the same for
|
||||
both mpd and libFLAC */
|
||||
buffer = data;
|
||||
buffer = src.data();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "util/NumberParser.hxx"
|
||||
#include "util/ReusableArray.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/SpanCast.hxx"
|
||||
|
||||
#include <lame/lame.h>
|
||||
|
||||
@@ -167,14 +168,14 @@ LameEncoder::~LameEncoder() noexcept
|
||||
}
|
||||
|
||||
void
|
||||
LameEncoder::Write(std::span<const std::byte> src)
|
||||
LameEncoder::Write(std::span<const std::byte> _src)
|
||||
{
|
||||
const auto *src = (const int16_t*)data;
|
||||
const auto src = FromBytesStrict<const int16_t>(_src);
|
||||
|
||||
assert(output_begin == output_end);
|
||||
|
||||
const std::size_t num_frames = length / audio_format.GetFrameSize();
|
||||
const std::size_t num_samples = length / audio_format.GetSampleSize();
|
||||
const std::size_t num_samples = src.size();
|
||||
const std::size_t num_frames = num_samples / audio_format.channels;
|
||||
|
||||
/* worst-case formula according to LAME documentation */
|
||||
const std::size_t output_buffer_size = 5 * num_samples / 4 + 7200;
|
||||
@@ -183,7 +184,7 @@ LameEncoder::Write(std::span<const std::byte> src)
|
||||
/* this is for only 16-bit audio */
|
||||
|
||||
int bytes_out = lame_encode_buffer_interleaved(gfp,
|
||||
const_cast<short *>(src),
|
||||
const_cast<short *>(src.data()),
|
||||
num_frames,
|
||||
dest, output_buffer_size);
|
||||
|
||||
@@ -194,19 +195,18 @@ LameEncoder::Write(std::span<const std::byte> src)
|
||||
output_end = dest + bytes_out;
|
||||
}
|
||||
|
||||
size_t
|
||||
LameEncoder::Read(void *dest, size_t length) noexcept
|
||||
std::span<const std::byte>
|
||||
LameEncoder::Read(std::span<std::byte> buffer) noexcept
|
||||
{
|
||||
const auto begin = output_begin;
|
||||
assert(begin <= output_end);
|
||||
const std::size_t remainning = output_end - begin;
|
||||
if (length > remainning)
|
||||
length = remainning;
|
||||
const std::size_t nbytes = std::min(remainning, buffer.size());
|
||||
|
||||
memcpy(dest, begin, length);
|
||||
memcpy(buffer.data(), begin, nbytes);
|
||||
|
||||
output_begin = begin + length;
|
||||
return length;
|
||||
output_begin = begin + nbytes;
|
||||
return buffer.first(nbytes);
|
||||
}
|
||||
|
||||
const EncoderPlugin lame_encoder_plugin = {
|
||||
|
@@ -29,12 +29,12 @@ public:
|
||||
:Encoder(false) {}
|
||||
|
||||
/* virtual methods from class Encoder */
|
||||
void Write(const void *data, size_t length) override {
|
||||
buffer.Append({(const std::byte *)data, length});
|
||||
void Write(std::span<const std::byte> src) override {
|
||||
buffer.Append(src);
|
||||
}
|
||||
|
||||
size_t Read(void *dest, size_t length) noexcept override {
|
||||
return buffer.Read((std::byte *)dest, length);
|
||||
std::span<const std::byte> Read(std::span<std::byte> b) noexcept override {
|
||||
return b.first(buffer.Read(b.data(), b.size()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -50,7 +50,7 @@ public:
|
||||
flush = true;
|
||||
}
|
||||
|
||||
size_t Read(void *dest, size_t length) noexcept override {
|
||||
std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept override {
|
||||
ogg_page page;
|
||||
bool success = stream.PageOut(page);
|
||||
if (!success) {
|
||||
@@ -60,10 +60,11 @@ public:
|
||||
}
|
||||
|
||||
if (!success)
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
|
||||
return ReadPage(page, dest, length);
|
||||
return buffer.first(ReadPage(page, buffer.data(),
|
||||
buffer.size()));
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -61,7 +61,7 @@ public:
|
||||
|
||||
/* virtual methods from class Encoder */
|
||||
void End() override;
|
||||
void Write(const void *data, size_t length) override;
|
||||
void Write(std::span<const std::byte> src) override;
|
||||
|
||||
void PreTag() override;
|
||||
void SendTag(const Tag &tag) override;
|
||||
@@ -272,10 +272,8 @@ OpusEncoder::WriteSilence(unsigned fill_frames)
|
||||
}
|
||||
|
||||
void
|
||||
OpusEncoder::Write(const void *_data, size_t length)
|
||||
OpusEncoder::Write(std::span<const std::byte> src)
|
||||
{
|
||||
const auto *data = (const std::byte *)_data;
|
||||
|
||||
if (lookahead > 0) {
|
||||
/* generate some silence at the beginning of the
|
||||
stream */
|
||||
@@ -286,14 +284,12 @@ OpusEncoder::Write(const void *_data, size_t length)
|
||||
lookahead = 0;
|
||||
}
|
||||
|
||||
while (length > 0) {
|
||||
size_t nbytes = buffer_size - buffer_position;
|
||||
if (nbytes > length)
|
||||
nbytes = length;
|
||||
while (!src.empty()) {
|
||||
const std::size_t nbytes = std::min(buffer_size - buffer_position,
|
||||
src.size());
|
||||
|
||||
memcpy(buffer + buffer_position, data, nbytes);
|
||||
data += nbytes;
|
||||
length -= nbytes;
|
||||
memcpy(buffer + buffer_position, src.data(), nbytes);
|
||||
src = src.subspan(nbytes);
|
||||
buffer_position += nbytes;
|
||||
|
||||
if (buffer_position == buffer_size)
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "pcm/AudioFormat.hxx"
|
||||
#include "util/DynamicFifoBuffer.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/SpanCast.hxx"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -75,10 +76,10 @@ public:
|
||||
|
||||
void Flush() override;
|
||||
|
||||
void Write(const void *data, size_t length) override;
|
||||
void Write(std::span<const std::byte> src) override;
|
||||
|
||||
size_t Read(void *dest, size_t length) noexcept override {
|
||||
return output_buffer.Read((std::byte *)dest, length);
|
||||
std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept override {
|
||||
return buffer.first(output_buffer.Read(buffer.data(), buffer.size()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -165,24 +166,24 @@ ShineEncoder::WriteChunk(bool flush)
|
||||
}
|
||||
|
||||
void
|
||||
ShineEncoder::Write(const void *_data, size_t length)
|
||||
ShineEncoder::Write(std::span<const std::byte> _src)
|
||||
{
|
||||
const auto *data = (const int16_t*)_data;
|
||||
length /= sizeof(*data) * audio_format.channels;
|
||||
const auto src = FromBytesStrict<const int16_t>(_src);
|
||||
const std::size_t nframes = src.size() / audio_format.channels;
|
||||
size_t written = 0;
|
||||
|
||||
if (input_pos > SHINE_MAX_SAMPLES)
|
||||
input_pos = 0;
|
||||
|
||||
/* write all data to de-interleaved buffers */
|
||||
while (written < length) {
|
||||
while (written < nframes) {
|
||||
for (;
|
||||
written < length && input_pos < frame_size;
|
||||
written < nframes && input_pos < frame_size;
|
||||
written++, input_pos++) {
|
||||
const size_t base =
|
||||
written * audio_format.channels;
|
||||
stereo[0][input_pos] = data[base];
|
||||
stereo[1][input_pos] = data[base + 1];
|
||||
stereo[0][input_pos] = src[base];
|
||||
stereo[1][input_pos] = src[base + 1];
|
||||
}
|
||||
/* write if chunk is filled */
|
||||
WriteChunk(false);
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include "pcm/AudioFormat.hxx"
|
||||
#include "util/NumberParser.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/SpanCast.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
@@ -67,8 +68,8 @@ public:
|
||||
flush = true;
|
||||
}
|
||||
|
||||
void Write(const void *data, size_t length) override;
|
||||
size_t Read(void *dest, size_t length) noexcept override;
|
||||
void Write(std::span<const std::byte> src) override;
|
||||
std::span<const std::byte> Read(std::span<std::byte> buffer) noexcept override;
|
||||
};
|
||||
|
||||
class PreparedTwolameEncoder final : public PreparedEncoder {
|
||||
@@ -187,16 +188,16 @@ TwolameEncoder::~TwolameEncoder() noexcept
|
||||
}
|
||||
|
||||
void
|
||||
TwolameEncoder::Write(const void *data, size_t length)
|
||||
TwolameEncoder::Write(std::span<const std::byte> _src)
|
||||
{
|
||||
const auto *src = (const int16_t*)data;
|
||||
const auto src = FromBytesStrict<const int16_t>(_src);
|
||||
|
||||
assert(output_buffer_position == output_buffer_length);
|
||||
|
||||
const std::size_t num_frames = length / audio_format.GetFrameSize();
|
||||
const std::size_t num_frames = src.size() / audio_format.channels;
|
||||
|
||||
int bytes_out = twolame_encode_buffer_interleaved(options,
|
||||
src, num_frames,
|
||||
src.data(), num_frames,
|
||||
output_buffer,
|
||||
sizeof(output_buffer));
|
||||
if (bytes_out < 0)
|
||||
@@ -206,8 +207,8 @@ TwolameEncoder::Write(const void *data, size_t length)
|
||||
output_buffer_position = 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
TwolameEncoder::Read(void *dest, size_t length) noexcept
|
||||
std::span<const std::byte>
|
||||
TwolameEncoder::Read(std::span<std::byte> buffer) noexcept
|
||||
{
|
||||
assert(output_buffer_position <= output_buffer_length);
|
||||
|
||||
@@ -224,14 +225,13 @@ TwolameEncoder::Read(void *dest, size_t length) noexcept
|
||||
|
||||
|
||||
const std::size_t remainning = output_buffer_length - output_buffer_position;
|
||||
if (length > remainning)
|
||||
length = remainning;
|
||||
const std::size_t nbytes = std::min(remainning, buffer.size());
|
||||
|
||||
memcpy(dest, output_buffer + output_buffer_position, length);
|
||||
memcpy(buffer.data(), output_buffer + output_buffer_position, nbytes);
|
||||
|
||||
output_buffer_position += length;
|
||||
output_buffer_position += nbytes;
|
||||
|
||||
return length;
|
||||
return buffer.first(nbytes);
|
||||
}
|
||||
|
||||
const EncoderPlugin twolame_encoder_plugin = {
|
||||
|
@@ -55,7 +55,7 @@ public:
|
||||
void PreTag() override;
|
||||
void SendTag(const Tag &tag) override;
|
||||
|
||||
void Write(const void *data, size_t length) override;
|
||||
void Write(std::span<const std::byte> src) override;
|
||||
|
||||
private:
|
||||
void HeaderOut(vorbis_comment &vc);
|
||||
@@ -245,14 +245,14 @@ interleaved_to_vorbis_buffer(float **dest, const float *src,
|
||||
}
|
||||
|
||||
void
|
||||
VorbisEncoder::Write(const void *data, size_t length)
|
||||
VorbisEncoder::Write(std::span<const std::byte> src)
|
||||
{
|
||||
std::size_t num_frames = length / audio_format.GetFrameSize();
|
||||
std::size_t num_frames = src.size() / audio_format.GetFrameSize();
|
||||
|
||||
/* this is for only 16-bit audio */
|
||||
|
||||
interleaved_to_vorbis_buffer(vorbis_analysis_buffer(&vd, num_frames),
|
||||
(const float *)data,
|
||||
(const float *)(const void *)src.data(),
|
||||
num_frames,
|
||||
audio_format.channels);
|
||||
|
||||
|
@@ -36,10 +36,10 @@ public:
|
||||
explicit WaveEncoder(AudioFormat &audio_format) noexcept;
|
||||
|
||||
/* virtual methods from class Encoder */
|
||||
void Write(const void *data, size_t length) override;
|
||||
void Write(std::span<const std::byte> src) override;
|
||||
|
||||
size_t Read(void *dest, size_t length) noexcept override {
|
||||
return buffer.Read((std::byte *)dest, length);
|
||||
std::span<const std::byte> Read(std::span<std::byte> b) noexcept override {
|
||||
return b.first(buffer.Read(b.data(), b.size()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -183,8 +183,9 @@ pcm24_to_wave(uint8_t *dst8, const uint32_t *src32, size_t length) noexcept
|
||||
}
|
||||
|
||||
void
|
||||
WaveEncoder::Write(const void *src, size_t length)
|
||||
WaveEncoder::Write(std::span<const std::byte> src)
|
||||
{
|
||||
std::size_t length = src.size();
|
||||
std::byte *dst = buffer.Write(length);
|
||||
|
||||
if (IsLittleEndian()) {
|
||||
@@ -192,29 +193,33 @@ WaveEncoder::Write(const void *src, size_t length)
|
||||
case 8:
|
||||
case 16:
|
||||
case 32:// optimized cases
|
||||
memcpy(dst, src, length);
|
||||
memcpy(dst, src.data(), length);
|
||||
break;
|
||||
case 24:
|
||||
length = pcm24_to_wave((uint8_t *)dst,
|
||||
(const uint32_t *)src, length);
|
||||
(const uint32_t *)(const void *)src.data(),
|
||||
length);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (bits) {
|
||||
case 8:
|
||||
memcpy(dst, src, length);
|
||||
memcpy(dst, src.data(), length);
|
||||
break;
|
||||
case 16:
|
||||
length = pcm16_to_wave((uint16_t *)dst,
|
||||
(const uint16_t *)src, length);
|
||||
(const uint16_t *)(const void *)src.data(),
|
||||
length);
|
||||
break;
|
||||
case 24:
|
||||
length = pcm24_to_wave((uint8_t *)dst,
|
||||
(const uint32_t *)src, length);
|
||||
(const uint32_t *)(const void *)src.data(),
|
||||
length);
|
||||
break;
|
||||
case 32:
|
||||
length = pcm32_to_wave((uint32_t *)dst,
|
||||
(const uint32_t *)src, length);
|
||||
(const uint32_t *)(const void *)src.data(),
|
||||
length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user