encoder/Interface: convert PreparedEncoder to abstract class

This commit is contained in:
Max Kellermann 2016-05-04 18:29:31 +02:00
parent e7edc02647
commit b376536a3b
15 changed files with 110 additions and 301 deletions

View File

@ -26,6 +26,7 @@
#include <assert.h>
#include <stddef.h>
struct AudioFormat;
struct Tag;
class Encoder {
@ -112,19 +113,9 @@ public:
virtual size_t Read(void *dest, size_t length) = 0;
};
struct PreparedEncoder {
const EncoderPlugin &plugin;
explicit PreparedEncoder(const EncoderPlugin &_plugin)
:plugin(_plugin) {}
/**
* Frees an #Encoder object.
*/
void Dispose() {
plugin.finish(this);
}
class PreparedEncoder {
public:
virtual ~PreparedEncoder() {}
/**
* Opens the object. You must call this prior to using it.
@ -139,24 +130,16 @@ struct PreparedEncoder {
* may modify the struct to adapt it to its abilities
* @return true on success
*/
Encoder *Open(AudioFormat &audio_format, Error &error) {
return plugin.open(this, audio_format, error);
}
virtual Encoder *Open(AudioFormat &audio_format, Error &error) = 0;
/**
* Get mime type of encoded content.
*
* @return an constant string, nullptr on failure
*/
virtual const char *GetMimeType() const {
return nullptr;
}
};
/**
* Get mime type of encoded content.
*
* @return an constant string, nullptr on failure
*/
static inline const char *
encoder_get_mime_type(PreparedEncoder *encoder)
{
/* this method is optional */
return encoder->plugin.get_mime_type != nullptr
? encoder->plugin.get_mime_type(encoder)
: nullptr;
}
#endif

View File

@ -20,9 +20,7 @@
#ifndef MPD_ENCODER_PLUGIN_HXX
#define MPD_ENCODER_PLUGIN_HXX
struct PreparedEncoder;
class Encoder;
struct AudioFormat;
class PreparedEncoder;
struct ConfigBlock;
class Error;
@ -31,14 +29,6 @@ struct EncoderPlugin {
PreparedEncoder *(*init)(const ConfigBlock &block,
Error &error);
void (*finish)(PreparedEncoder *encoder);
Encoder *(*open)(PreparedEncoder *encoder,
AudioFormat &audio_format,
Error &error);
const char *(*get_mime_type)(PreparedEncoder *encoder);
};
/**

View File

@ -88,14 +88,18 @@ private:
}
};
struct PreparedFlacEncoder {
PreparedEncoder encoder;
class PreparedFlacEncoder final : public PreparedEncoder {
unsigned compression;
PreparedFlacEncoder():encoder(flac_encoder_plugin) {}
public:
bool Configure(const ConfigBlock &block, Error &error);
/* virtual methods from class PreparedEncoder */
Encoder *Open(AudioFormat &audio_format, Error &) override;
const char *GetMimeType() const override {
return "audio/flac";
}
};
static constexpr Domain flac_encoder_domain("vorbis_encoder");
@ -119,17 +123,7 @@ flac_encoder_init(const ConfigBlock &block, Error &error)
return nullptr;
}
return &encoder->encoder;
}
static void
flac_encoder_finish(PreparedEncoder *_encoder)
{
auto *encoder = (PreparedFlacEncoder *)_encoder;
/* the real libFLAC cleanup was already performed by
flac_encoder_close(), so no real work here */
delete encoder;
return encoder;
}
static bool
@ -190,10 +184,9 @@ FlacEncoder::Init(Error &error)
return true;
}
static Encoder *
flac_encoder_open(PreparedEncoder *_encoder, AudioFormat &audio_format, Error &error)
Encoder *
PreparedFlacEncoder::Open(AudioFormat &audio_format, Error &error)
{
auto *encoder = (PreparedFlacEncoder *)_encoder;
unsigned bits_per_sample;
/* FIXME: flac should support 32bit as well */
@ -222,7 +215,7 @@ flac_encoder_open(PreparedEncoder *_encoder, AudioFormat &audio_format, Error &e
return nullptr;
}
if (!flac_encoder_setup(fse, encoder->compression,
if (!flac_encoder_setup(fse, compression,
audio_format, bits_per_sample, error)) {
FLAC__stream_encoder_delete(fse);
return nullptr;
@ -304,17 +297,8 @@ FlacEncoder::Write(const void *data, size_t length, Error &error)
return true;
}
static const char *
flac_encoder_get_mime_type(gcc_unused PreparedEncoder *_encoder)
{
return "audio/flac";
}
const EncoderPlugin flac_encoder_plugin = {
"flac",
flac_encoder_init,
flac_encoder_finish,
flac_encoder_open,
flac_encoder_get_mime_type,
};

View File

@ -53,15 +53,19 @@ public:
size_t Read(void *dest, size_t length) override;
};
struct PreparedLameEncoder final {
PreparedEncoder encoder;
class PreparedLameEncoder final : public PreparedEncoder {
float quality;
int bitrate;
PreparedLameEncoder():encoder(lame_encoder_plugin) {}
public:
bool Configure(const ConfigBlock &block, Error &error);
/* virtual methods from class PreparedEncoder */
Encoder *Open(AudioFormat &audio_format, Error &) override;
const char *GetMimeType() const override {
return "audio/mpeg";
}
};
static constexpr Domain lame_encoder_domain("lame_encoder");
@ -126,17 +130,7 @@ lame_encoder_init(const ConfigBlock &block, Error &error)
return nullptr;
}
return &encoder->encoder;
}
static void
lame_encoder_finish(PreparedEncoder *_encoder)
{
auto *encoder = (PreparedLameEncoder *)_encoder;
/* the real liblame cleanup was already performed by
lame_encoder_close(), so no real work here */
delete encoder;
return encoder;
}
static bool
@ -193,12 +187,9 @@ lame_encoder_setup(lame_global_flags *gfp, float quality, int bitrate,
return true;
}
static Encoder *
lame_encoder_open(PreparedEncoder *_encoder, AudioFormat &audio_format,
Error &error)
Encoder *
PreparedLameEncoder::Open(AudioFormat &audio_format, Error &error)
{
auto *encoder = (PreparedLameEncoder *)_encoder;
audio_format.format = SampleFormat::S16;
audio_format.channels = 2;
@ -208,7 +199,7 @@ lame_encoder_open(PreparedEncoder *_encoder, AudioFormat &audio_format,
return nullptr;
}
if (!lame_encoder_setup(gfp, encoder->quality, encoder->bitrate,
if (!lame_encoder_setup(gfp, quality, bitrate,
audio_format, error)) {
lame_close(gfp);
return nullptr;
@ -269,16 +260,7 @@ LameEncoder::Read(void *dest, size_t length)
return length;
}
static const char *
lame_encoder_get_mime_type(gcc_unused PreparedEncoder *_encoder)
{
return "audio/mpeg";
}
const EncoderPlugin lame_encoder_plugin = {
"lame",
lame_encoder_init,
lame_encoder_finish,
lame_encoder_open,
lame_encoder_get_mime_type,
};

View File

@ -23,8 +23,6 @@
#include "util/DynamicFifoBuffer.hxx"
#include "Compiler.h"
#include <assert.h>
class NullEncoder final : public Encoder {
DynamicFifoBuffer<uint8_t> buffer;
@ -44,40 +42,22 @@ public:
}
};
struct PreparedNullEncoder final {
PreparedEncoder encoder;
PreparedNullEncoder()
:encoder(null_encoder_plugin) {}
class PreparedNullEncoder final : public PreparedEncoder {
public:
/* virtual methods from class PreparedEncoder */
Encoder *Open(AudioFormat &, Error &) override {
return new NullEncoder();
}
};
static PreparedEncoder *
null_encoder_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
auto *encoder = new PreparedNullEncoder();
return &encoder->encoder;
}
static void
null_encoder_finish(PreparedEncoder *_encoder)
{
auto *encoder = (PreparedNullEncoder *)_encoder;
delete encoder;
}
static Encoder *
null_encoder_open(gcc_unused PreparedEncoder *encoder,
gcc_unused AudioFormat &audio_format,
gcc_unused Error &error)
{
return new NullEncoder();
return new PreparedNullEncoder();
}
const EncoderPlugin null_encoder_plugin = {
"null",
null_encoder_init,
null_encoder_finish,
null_encoder_open,
nullptr,
};

View File

@ -77,20 +77,20 @@ private:
void GenerateTags();
};
struct PreparedOpusEncoder {
/** the base class */
PreparedEncoder encoder;
/* configuration */
class PreparedOpusEncoder final : public PreparedEncoder {
opus_int32 bitrate;
int complexity;
int signal;
PreparedOpusEncoder():encoder(opus_encoder_plugin) {}
public:
bool Configure(const ConfigBlock &block, Error &error);
Encoder *Open(AudioFormat &audio_format, Error &error);
/* virtual methods from class PreparedEncoder */
Encoder *Open(AudioFormat &audio_format, Error &) override;
const char *GetMimeType() const override {
return "audio/ogg";
}
};
static constexpr Domain opus_encoder_domain("opus_encoder");
@ -146,17 +146,7 @@ opus_encoder_init(const ConfigBlock &block, Error &error)
return nullptr;
}
return &encoder->encoder;
}
static void
opus_encoder_finish(PreparedEncoder *_encoder)
{
auto *encoder = (PreparedOpusEncoder *)_encoder;
/* the real libopus cleanup was already performed by
opus_encoder_close(), so no real work here */
delete encoder;
return encoder;
}
OpusEncoder::OpusEncoder(AudioFormat &_audio_format, ::OpusEncoder *_enc)
@ -214,15 +204,6 @@ PreparedOpusEncoder::Open(AudioFormat &audio_format, Error &error)
return new OpusEncoder(audio_format, enc);
}
static Encoder *
opus_encoder_open(PreparedEncoder *_encoder,
AudioFormat &audio_format,
Error &error)
{
auto &encoder = *(PreparedOpusEncoder *)_encoder;
return encoder.Open(audio_format, error);
}
OpusEncoder::~OpusEncoder()
{
stream.Deinitialize();
@ -405,18 +386,9 @@ OpusEncoder::Read(void *dest, size_t length)
return stream.PageOut(dest, length);
}
static const char *
opus_encoder_get_mime_type(gcc_unused PreparedEncoder *_encoder)
{
return "audio/ogg";
}
}
const EncoderPlugin opus_encoder_plugin = {
"opus",
opus_encoder_init,
opus_encoder_finish,
opus_encoder_open,
opus_encoder_get_mime_type,
};

View File

@ -84,16 +84,18 @@ public:
}
};
struct PreparedShineEncoder {
PreparedEncoder encoder;
class PreparedShineEncoder final : public PreparedEncoder {
shine_config_t config;
PreparedShineEncoder():encoder(shine_encoder_plugin) {}
public:
bool Configure(const ConfigBlock &block, Error &error);
bool Setup(Error &error);
/* virtual methods from class PreparedEncoder */
Encoder *Open(AudioFormat &audio_format, Error &) override;
const char *GetMimeType() const override {
return "audio/mpeg";
}
};
inline bool
@ -117,15 +119,7 @@ shine_encoder_init(const ConfigBlock &block, Error &error)
return nullptr;
}
return &encoder->encoder;
}
static void
shine_encoder_finish(PreparedEncoder *_encoder)
{
auto *encoder = (PreparedShineEncoder *)_encoder;
delete encoder;
return encoder;
}
static shine_t
@ -159,13 +153,10 @@ SetupShine(shine_config_t config, AudioFormat &audio_format,
return shine;
}
static Encoder *
shine_encoder_open(PreparedEncoder *_encoder, AudioFormat &audio_format,
Error &error)
Encoder *
PreparedShineEncoder::Open(AudioFormat &audio_format, Error &error)
{
auto *encoder = (PreparedShineEncoder *)_encoder;
auto shine = SetupShine(encoder->config, audio_format, error);
auto shine = SetupShine(config, audio_format, error);
if (!shine)
return nullptr;
@ -238,16 +229,7 @@ ShineEncoder::Flush(gcc_unused Error &error)
return true;
}
static const char *
shine_encoder_get_mime_type(gcc_unused PreparedEncoder *_encoder)
{
return "audio/mpeg";
}
const EncoderPlugin shine_encoder_plugin = {
"shine",
shine_encoder_init,
shine_encoder_finish,
shine_encoder_open,
shine_encoder_get_mime_type,
};

View File

@ -72,15 +72,19 @@ public:
size_t Read(void *dest, size_t length) override;
};
struct PreparedTwolameEncoder final {
PreparedEncoder encoder;
class PreparedTwolameEncoder final : public PreparedEncoder {
float quality;
int bitrate;
PreparedTwolameEncoder():encoder(twolame_encoder_plugin) {}
public:
bool Configure(const ConfigBlock &block, Error &error);
/* virtual methods from class PreparedEncoder */
Encoder *Open(AudioFormat &audio_format, Error &) override;
const char *GetMimeType() const override {
return "audio/mpeg";
}
};
static constexpr Domain twolame_encoder_domain("twolame_encoder");
@ -148,17 +152,7 @@ twolame_encoder_init(const ConfigBlock &block, Error &error_r)
return nullptr;
}
return &encoder->encoder;
}
static void
twolame_encoder_finish(PreparedEncoder *_encoder)
{
auto *encoder = (PreparedTwolameEncoder *)_encoder;
/* the real libtwolame cleanup was already performed by
twolame_encoder_close(), so no real work here */
delete encoder;
return encoder;
}
static bool
@ -210,12 +204,9 @@ twolame_encoder_setup(twolame_options *options, float quality, int bitrate,
return true;
}
static Encoder *
twolame_encoder_open(PreparedEncoder *_encoder, AudioFormat &audio_format,
Error &error)
Encoder *
PreparedTwolameEncoder::Open(AudioFormat &audio_format, Error &error)
{
auto *encoder = (PreparedTwolameEncoder *)_encoder;
audio_format.format = SampleFormat::S16;
audio_format.channels = 2;
@ -225,7 +216,7 @@ twolame_encoder_open(PreparedEncoder *_encoder, AudioFormat &audio_format,
return nullptr;
}
if (!twolame_encoder_setup(options, encoder->quality, encoder->bitrate,
if (!twolame_encoder_setup(options, quality, bitrate,
audio_format, error)) {
twolame_close(&options);
return nullptr;
@ -291,16 +282,7 @@ TwolameEncoder::Read(void *dest, size_t length)
return length;
}
static const char *
twolame_encoder_get_mime_type(gcc_unused PreparedEncoder *_encoder)
{
return "audio/mpeg";
}
const EncoderPlugin twolame_encoder_plugin = {
"twolame",
twolame_encoder_init,
twolame_encoder_finish,
twolame_encoder_open,
twolame_encoder_get_mime_type,
};

View File

@ -73,18 +73,19 @@ private:
void Clear();
};
struct PreparedVorbisEncoder {
/** the base class */
PreparedEncoder encoder;
/* configuration */
class PreparedVorbisEncoder final : public PreparedEncoder {
float quality;
int bitrate;
PreparedVorbisEncoder():encoder(vorbis_encoder_plugin) {}
public:
bool Configure(const ConfigBlock &block, Error &error);
/* virtual methods from class PreparedEncoder */
Encoder *Open(AudioFormat &audio_format, Error &) override;
const char *GetMimeType() const override {
return "audio/ogg";
}
};
static constexpr Domain vorbis_encoder_domain("vorbis_encoder");
@ -148,17 +149,7 @@ vorbis_encoder_init(const ConfigBlock &block, Error &error)
return nullptr;
}
return &encoder->encoder;
}
static void
vorbis_encoder_finish(PreparedEncoder *_encoder)
{
auto *encoder = (PreparedVorbisEncoder *)_encoder;
/* the real libvorbis/libogg cleanup was already performed by
vorbis_encoder_close(), so no real work here */
delete encoder;
return encoder;
}
bool
@ -228,15 +219,11 @@ VorbisEncoder::SendHeader()
vorbis_comment_clear(&vc);
}
static Encoder *
vorbis_encoder_open(PreparedEncoder *_encoder,
AudioFormat &audio_format,
Error &error)
Encoder *
PreparedVorbisEncoder::Open(AudioFormat &audio_format, Error &error)
{
auto &encoder = *(PreparedVorbisEncoder *)_encoder;
auto *e = new VorbisEncoder();
if (!e->Open(encoder.quality, encoder.bitrate, audio_format, error)) {
if (!e->Open(quality, bitrate, audio_format, error)) {
delete e;
return nullptr;
}
@ -348,16 +335,7 @@ VorbisEncoder::Write(const void *data, size_t length, gcc_unused Error &error)
return true;
}
static const char *
vorbis_encoder_get_mime_type(gcc_unused PreparedEncoder *_encoder)
{
return "audio/ogg";
}
const EncoderPlugin vorbis_encoder_plugin = {
"vorbis",
vorbis_encoder_init,
vorbis_encoder_finish,
vorbis_encoder_open,
vorbis_encoder_get_mime_type,
};

View File

@ -44,10 +44,15 @@ public:
}
};
struct PreparedWaveEncoder {
PreparedEncoder encoder;
class PreparedWaveEncoder final : public PreparedEncoder {
/* virtual methods from class PreparedEncoder */
Encoder *Open(AudioFormat &audio_format, Error &) override {
return new WaveEncoder(audio_format);
}
PreparedWaveEncoder():encoder(wave_encoder_plugin) {}
const char *GetMimeType() const override {
return "audio/wav";
}
};
struct WaveHeader {
@ -96,16 +101,7 @@ static PreparedEncoder *
wave_encoder_init(gcc_unused const ConfigBlock &block,
gcc_unused Error &error)
{
auto *encoder = new PreparedWaveEncoder();
return &encoder->encoder;
}
static void
wave_encoder_finish(PreparedEncoder *_encoder)
{
auto *encoder = (PreparedWaveEncoder *)_encoder;
delete encoder;
return new PreparedWaveEncoder();
}
WaveEncoder::WaveEncoder(AudioFormat &audio_format)
@ -151,14 +147,6 @@ WaveEncoder::WaveEncoder(AudioFormat &audio_format)
buffer.Append(sizeof(*header));
}
static Encoder *
wave_encoder_open(gcc_unused PreparedEncoder *_encoder,
AudioFormat &audio_format,
gcc_unused Error &error)
{
return new WaveEncoder(audio_format);
}
static size_t
pcm16_to_wave(uint16_t *dst16, const uint16_t *src16, size_t length)
{
@ -239,16 +227,7 @@ WaveEncoder::Write(const void *src, size_t length,
return true;
}
static const char *
wave_encoder_get_mime_type(gcc_unused PreparedEncoder *_encoder)
{
return "audio/wav";
}
const EncoderPlugin wave_encoder_plugin = {
"wave",
wave_encoder_init,
wave_encoder_finish,
wave_encoder_open,
wave_encoder_get_mime_type,
};

View File

@ -76,8 +76,7 @@ class RecorderOutput {
:base(recorder_output_plugin) {}
~RecorderOutput() {
if (prepared_encoder != nullptr)
prepared_encoder->Dispose();
delete prepared_encoder;
}
bool Initialize(const ConfigBlock &block, Error &error_r) {

View File

@ -45,7 +45,7 @@ class EventLoop;
class ServerSocket;
class HttpdClient;
class Page;
struct PreparedEncoder;
class PreparedEncoder;
class Encoder;
struct Tag;

View File

@ -63,9 +63,7 @@ HttpdOutput::~HttpdOutput()
if (metadata != nullptr)
metadata->Unref();
if (prepared_encoder != nullptr)
prepared_encoder->Dispose();
delete prepared_encoder;
}
inline bool
@ -128,7 +126,7 @@ HttpdOutput::Configure(const ConfigBlock &block, Error &error)
return false;
/* determine content type */
content_type = encoder_get_mime_type(prepared_encoder);
content_type = prepared_encoder->GetMimeType();
if (content_type == nullptr)
content_type = "application/octet-stream";

View File

@ -111,7 +111,7 @@ int main(int argc, char **argv)
EncoderToOutputStream(os, *encoder);
delete encoder;
p_encoder->Dispose();
delete p_encoder;
return EXIT_SUCCESS;
} catch (const std::exception &e) {

View File

@ -103,7 +103,7 @@ main(gcc_unused int argc, gcc_unused char **argv)
EncoderToOutputStream(os, *encoder);
delete encoder;
p_encoder->Dispose();
delete p_encoder;
return EXIT_SUCCESS;
} catch (const std::exception &e) {