encoder/Interface: move instance methods to abstract class

Rename struct Encoder to PreparedEncoder, and add a new (abstract)
class Encoder which represents one encoder instance.
This commit is contained in:
Max Kellermann
2016-05-04 09:31:21 +02:00
parent 69bf835059
commit e7edc02647
18 changed files with 777 additions and 996 deletions

View File

@@ -23,7 +23,6 @@
#include "AudioFormat.hxx"
#include "pcm/PcmBuffer.hxx"
#include "config/ConfigError.hxx"
#include "util/Manual.hxx"
#include "util/DynamicFifoBuffer.hxx"
#include "util/Error.hxx"
#include "util/Domain.hxx"
@@ -34,13 +33,10 @@
#error libFLAC is too old
#endif
struct flac_encoder {
Encoder encoder;
class FlacEncoder final : public Encoder {
const AudioFormat audio_format;
AudioFormat audio_format;
unsigned compression;
FLAC__StreamEncoder *fse;
FLAC__StreamEncoder *const fse;
PcmBuffer expand_buffer;
@@ -48,29 +44,76 @@ struct flac_encoder {
* This buffer will hold encoded data from libFLAC until it is
* picked up with flac_encoder_read().
*/
Manual<DynamicFifoBuffer<uint8_t>> output_buffer;
DynamicFifoBuffer<uint8_t> output_buffer;
flac_encoder():encoder(flac_encoder_plugin) {}
public:
FlacEncoder(AudioFormat _audio_format, FLAC__StreamEncoder *_fse)
:Encoder(false),
audio_format(_audio_format), fse(_fse),
output_buffer(8192) {}
~FlacEncoder() override {
FLAC__stream_encoder_delete(fse);
}
bool Init(Error &error);
/* virtual methods from class Encoder */
bool End(Error &) override {
(void) FLAC__stream_encoder_finish(fse);
return true;
}
bool Flush(Error &) override {
(void) FLAC__stream_encoder_finish(fse);
return true;
}
bool Write(const void *data, size_t length, Error &) override;
size_t Read(void *dest, size_t length) override {
return output_buffer.Read((uint8_t *)dest, length);
}
private:
static FLAC__StreamEncoderWriteStatus WriteCallback(const FLAC__StreamEncoder *,
const FLAC__byte data[],
size_t bytes,
gcc_unused unsigned samples,
gcc_unused unsigned current_frame,
void *client_data) {
auto &encoder = *(FlacEncoder *)client_data;
encoder.output_buffer.Append((const uint8_t *)data, bytes);
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
};
struct PreparedFlacEncoder {
PreparedEncoder encoder;
unsigned compression;
PreparedFlacEncoder():encoder(flac_encoder_plugin) {}
bool Configure(const ConfigBlock &block, Error &error);
};
static constexpr Domain flac_encoder_domain("vorbis_encoder");
static bool
flac_encoder_configure(struct flac_encoder *encoder, const ConfigBlock &block,
gcc_unused Error &error)
bool
PreparedFlacEncoder::Configure(const ConfigBlock &block, Error &)
{
encoder->compression = block.GetBlockValue("compression", 5u);
compression = block.GetBlockValue("compression", 5u);
return true;
}
static Encoder *
static PreparedEncoder *
flac_encoder_init(const ConfigBlock &block, Error &error)
{
flac_encoder *encoder = new flac_encoder();
auto *encoder = new PreparedFlacEncoder();
/* load configuration from "block" */
if (!flac_encoder_configure(encoder, block, error)) {
if (!encoder->Configure(block, error)) {
/* configuration has failed, roll back and return error */
delete encoder;
return nullptr;
@@ -80,9 +123,9 @@ flac_encoder_init(const ConfigBlock &block, Error &error)
}
static void
flac_encoder_finish(Encoder *_encoder)
flac_encoder_finish(PreparedEncoder *_encoder)
{
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
auto *encoder = (PreparedFlacEncoder *)_encoder;
/* the real libFLAC cleanup was already performed by
flac_encoder_close(), so no real work here */
@@ -90,71 +133,67 @@ flac_encoder_finish(Encoder *_encoder)
}
static bool
flac_encoder_setup(struct flac_encoder *encoder, unsigned bits_per_sample,
flac_encoder_setup(FLAC__StreamEncoder *fse, unsigned compression,
const AudioFormat &audio_format, unsigned bits_per_sample,
Error &error)
{
if ( !FLAC__stream_encoder_set_compression_level(encoder->fse,
encoder->compression)) {
if (!FLAC__stream_encoder_set_compression_level(fse, compression)) {
error.Format(config_domain,
"error setting flac compression to %d",
encoder->compression);
compression);
return false;
}
if ( !FLAC__stream_encoder_set_channels(encoder->fse,
encoder->audio_format.channels)) {
if (!FLAC__stream_encoder_set_channels(fse, audio_format.channels)) {
error.Format(config_domain,
"error setting flac channels num to %d",
encoder->audio_format.channels);
audio_format.channels);
return false;
}
if ( !FLAC__stream_encoder_set_bits_per_sample(encoder->fse,
bits_per_sample)) {
if (!FLAC__stream_encoder_set_bits_per_sample(fse, bits_per_sample)) {
error.Format(config_domain,
"error setting flac bit format to %d",
bits_per_sample);
return false;
}
if ( !FLAC__stream_encoder_set_sample_rate(encoder->fse,
encoder->audio_format.sample_rate)) {
if (!FLAC__stream_encoder_set_sample_rate(fse,
audio_format.sample_rate)) {
error.Format(config_domain,
"error setting flac sample rate to %d",
encoder->audio_format.sample_rate);
audio_format.sample_rate);
return false;
}
return true;
}
static FLAC__StreamEncoderWriteStatus
flac_write_callback(gcc_unused const FLAC__StreamEncoder *fse,
const FLAC__byte data[],
size_t bytes,
gcc_unused unsigned samples,
gcc_unused unsigned current_frame, void *client_data)
bool
FlacEncoder::Init(Error &error)
{
struct flac_encoder *encoder = (struct flac_encoder *) client_data;
/* this immediately outputs data through callback */
//transfer data to buffer
encoder->output_buffer->Append((const uint8_t *)data, bytes);
auto init_status =
FLAC__stream_encoder_init_stream(fse,
WriteCallback,
nullptr, nullptr, nullptr,
this);
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
if (init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
error.Format(flac_encoder_domain,
"failed to initialize encoder: %s\n",
FLAC__StreamEncoderInitStatusString[init_status]);
return false;
}
return true;
}
static void
flac_encoder_close(Encoder *_encoder)
static Encoder *
flac_encoder_open(PreparedEncoder *_encoder, AudioFormat &audio_format, Error &error)
{
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
FLAC__stream_encoder_delete(encoder->fse);
encoder->expand_buffer.Clear();
encoder->output_buffer.Destruct();
}
static bool
flac_encoder_open(Encoder *_encoder, AudioFormat &audio_format, Error &error)
{
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
auto *encoder = (PreparedFlacEncoder *)_encoder;
unsigned bits_per_sample;
/* FIXME: flac should support 32bit as well */
@@ -176,51 +215,26 @@ flac_encoder_open(Encoder *_encoder, AudioFormat &audio_format, Error &error)
audio_format.format = SampleFormat::S24_P32;
}
encoder->audio_format = audio_format;
/* allocate the encoder */
encoder->fse = FLAC__stream_encoder_new();
if (encoder->fse == nullptr) {
error.Set(flac_encoder_domain, "flac_new() failed");
return false;
auto fse = FLAC__stream_encoder_new();
if (fse == nullptr) {
error.Set(flac_encoder_domain, "FLAC__stream_encoder_new() failed");
return nullptr;
}
if (!flac_encoder_setup(encoder, bits_per_sample, error)) {
FLAC__stream_encoder_delete(encoder->fse);
return false;
if (!flac_encoder_setup(fse, encoder->compression,
audio_format, bits_per_sample, error)) {
FLAC__stream_encoder_delete(fse);
return nullptr;
}
encoder->output_buffer.Construct(8192);
/* this immediately outputs data through callback */
{
FLAC__StreamEncoderInitStatus init_status;
init_status = FLAC__stream_encoder_init_stream(encoder->fse,
flac_write_callback,
nullptr, nullptr, nullptr, encoder);
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
error.Format(flac_encoder_domain,
"failed to initialize encoder: %s\n",
FLAC__StreamEncoderInitStatusString[init_status]);
flac_encoder_close(_encoder);
return false;
}
auto *e = new FlacEncoder(audio_format, fse);
if (!e->Init(error)) {
delete e;
return nullptr;
}
return true;
}
static bool
flac_encoder_flush(Encoder *_encoder, gcc_unused Error &error)
{
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
(void) FLAC__stream_encoder_finish(encoder->fse);
return true;
return e;
}
static inline void
@@ -241,31 +255,27 @@ pcm16_to_flac(int32_t *out, const int16_t *in, unsigned num_samples)
}
}
static bool
flac_encoder_write(Encoder *_encoder,
const void *data, size_t length,
gcc_unused Error &error)
bool
FlacEncoder::Write(const void *data, size_t length, Error &error)
{
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
unsigned num_frames, num_samples;
void *exbuffer;
const void *buffer = nullptr;
/* format conversion */
num_frames = length / encoder->audio_format.GetFrameSize();
num_samples = num_frames * encoder->audio_format.channels;
const unsigned num_frames = length / audio_format.GetFrameSize();
const unsigned num_samples = num_frames * audio_format.channels;
switch (encoder->audio_format.format) {
switch (audio_format.format) {
case SampleFormat::S8:
exbuffer = encoder->expand_buffer.Get(length * 4);
exbuffer = expand_buffer.Get(length * 4);
pcm8_to_flac((int32_t *)exbuffer, (const int8_t *)data,
num_samples);
buffer = exbuffer;
break;
case SampleFormat::S16:
exbuffer = encoder->expand_buffer.Get(length * 2);
exbuffer = expand_buffer.Get(length * 2);
pcm16_to_flac((int32_t *)exbuffer, (const int16_t *)data,
num_samples);
buffer = exbuffer;
@@ -284,7 +294,7 @@ flac_encoder_write(Encoder *_encoder,
/* feed samples to encoder */
if (!FLAC__stream_encoder_process_interleaved(encoder->fse,
if (!FLAC__stream_encoder_process_interleaved(fse,
(const FLAC__int32 *)buffer,
num_frames)) {
error.Set(flac_encoder_domain, "flac encoder process failed");
@@ -294,16 +304,8 @@ flac_encoder_write(Encoder *_encoder,
return true;
}
static size_t
flac_encoder_read(Encoder *_encoder, void *dest, size_t length)
{
struct flac_encoder *encoder = (struct flac_encoder *)_encoder;
return encoder->output_buffer->Read((uint8_t *)dest, length);
}
static const char *
flac_encoder_get_mime_type(gcc_unused Encoder *_encoder)
flac_encoder_get_mime_type(gcc_unused PreparedEncoder *_encoder)
{
return "audio/flac";
}
@@ -313,13 +315,6 @@ const EncoderPlugin flac_encoder_plugin = {
flac_encoder_init,
flac_encoder_finish,
flac_encoder_open,
flac_encoder_close,
flac_encoder_flush,
flac_encoder_flush,
nullptr,
nullptr,
flac_encoder_write,
flac_encoder_read,
flac_encoder_get_mime_type,
};