encoder/lame: Read() returns the internal buffer

Eliminate memcpy() calls.
This commit is contained in:
Max Kellermann 2022-07-12 10:47:52 +02:00
parent 0d09f307b2
commit c266fb7758
2 changed files with 21 additions and 44 deletions

View File

@ -30,15 +30,13 @@
#include <cassert> #include <cassert>
#include <stdexcept> #include <stdexcept>
#include <string.h>
class LameEncoder final : public Encoder { class LameEncoder final : public Encoder {
const AudioFormat audio_format; const AudioFormat audio_format;
lame_global_flags *const gfp; lame_global_flags *const gfp;
ReusableArray<unsigned char, 32768> output_buffer; ReusableArray<std::byte, 32768> output_buffer;
unsigned char *output_begin = nullptr, *output_end = nullptr; std::span<const std::byte> output{};
public: public:
LameEncoder(const AudioFormat _audio_format, LameEncoder(const AudioFormat _audio_format,
@ -172,7 +170,7 @@ LameEncoder::Write(std::span<const std::byte> _src)
{ {
const auto src = FromBytesStrict<const int16_t>(_src); const auto src = FromBytesStrict<const int16_t>(_src);
assert(output_begin == output_end); assert(output.empty());
const std::size_t num_samples = src.size(); const std::size_t num_samples = src.size();
const std::size_t num_frames = num_samples / audio_format.channels; const std::size_t num_frames = num_samples / audio_format.channels;
@ -186,27 +184,19 @@ LameEncoder::Write(std::span<const std::byte> _src)
int bytes_out = lame_encode_buffer_interleaved(gfp, int bytes_out = lame_encode_buffer_interleaved(gfp,
const_cast<short *>(src.data()), const_cast<short *>(src.data()),
num_frames, num_frames,
dest, output_buffer_size); (unsigned char *)dest,
output_buffer_size);
if (bytes_out < 0) if (bytes_out < 0)
throw std::runtime_error("lame encoder failed"); throw std::runtime_error("lame encoder failed");
output_begin = dest; output = {dest, std::size_t(bytes_out)};
output_end = dest + bytes_out;
} }
std::span<const std::byte> std::span<const std::byte>
LameEncoder::Read(std::span<std::byte> buffer) noexcept LameEncoder::Read(std::span<std::byte>) noexcept
{ {
const auto begin = output_begin; return std::exchange(output, std::span<const std::byte>{});
assert(begin <= output_end);
const std::size_t remainning = output_end - begin;
const std::size_t nbytes = std::min(remainning, buffer.size());
memcpy(buffer.data(), begin, nbytes);
output_begin = begin + nbytes;
return buffer.first(nbytes);
} }
const EncoderPlugin lame_encoder_plugin = { const EncoderPlugin lame_encoder_plugin = {

View File

@ -31,16 +31,13 @@
#include <cassert> #include <cassert>
#include <stdexcept> #include <stdexcept>
#include <string.h>
class TwolameEncoder final : public Encoder { class TwolameEncoder final : public Encoder {
const AudioFormat audio_format; const AudioFormat audio_format;
twolame_options *options; twolame_options *options;
unsigned char output_buffer[32768]; std::byte output_buffer[32768];
std::size_t output_buffer_length = 0; std::size_t fill = 0;
std::size_t output_buffer_position = 0;
/** /**
* Call libtwolame's flush function when the output_buffer is * Call libtwolame's flush function when the output_buffer is
@ -192,46 +189,36 @@ TwolameEncoder::Write(std::span<const std::byte> _src)
{ {
const auto src = FromBytesStrict<const int16_t>(_src); const auto src = FromBytesStrict<const int16_t>(_src);
assert(output_buffer_position == output_buffer_length); assert(fill == 0);
const std::size_t num_frames = src.size() / audio_format.channels; const std::size_t num_frames = src.size() / audio_format.channels;
int bytes_out = twolame_encode_buffer_interleaved(options, int bytes_out = twolame_encode_buffer_interleaved(options,
src.data(), num_frames, src.data(), num_frames,
output_buffer, (unsigned char *)output_buffer,
sizeof(output_buffer)); sizeof(output_buffer));
if (bytes_out < 0) if (bytes_out < 0)
throw std::runtime_error("twolame encoder failed"); throw std::runtime_error("twolame encoder failed");
output_buffer_length = (std::size_t)bytes_out; fill = (std::size_t)bytes_out;
output_buffer_position = 0;
} }
std::span<const std::byte> std::span<const std::byte>
TwolameEncoder::Read(std::span<std::byte> buffer) noexcept TwolameEncoder::Read(std::span<std::byte>) noexcept
{ {
assert(output_buffer_position <= output_buffer_length); assert(fill <= sizeof(output_buffer));
if (output_buffer_position == output_buffer_length && flush) { if (fill == 0 && flush) {
int ret = twolame_encode_flush(options, output_buffer, int ret = twolame_encode_flush(options,
(unsigned char *)output_buffer,
sizeof(output_buffer)); sizeof(output_buffer));
if (ret > 0) { if (ret > 0)
output_buffer_length = (size_t)ret; fill = (std::size_t)ret;
output_buffer_position = 0;
}
flush = false; flush = false;
} }
return std::span{output_buffer}.first(std::exchange(fill, 0));
const std::size_t remainning = output_buffer_length - output_buffer_position;
const std::size_t nbytes = std::min(remainning, buffer.size());
memcpy(buffer.data(), output_buffer + output_buffer_position, nbytes);
output_buffer_position += nbytes;
return buffer.first(nbytes);
} }
const EncoderPlugin twolame_encoder_plugin = { const EncoderPlugin twolame_encoder_plugin = {