diff options
-rw-r--r-- | decoder.cpp | 13 | ||||
-rw-r--r-- | decoder.h | 58 | ||||
-rw-r--r-- | decoders/mpg123_decoder.cpp | 8 | ||||
-rw-r--r-- | decoders/mpg123_decoder.h | 11 | ||||
-rw-r--r-- | encoder.cpp | 13 | ||||
-rw-r--r-- | encoder.h | 56 | ||||
-rw-r--r-- | encoders/lame_encoder.cpp | 10 | ||||
-rw-r--r-- | encoders/lame_encoder.h | 10 | ||||
-rw-r--r-- | main.cpp | 4 | ||||
-rw-r--r-- | music.cpp | 17 | ||||
-rw-r--r-- | transcode.cpp | 18 | ||||
-rw-r--r-- | transcode.h | 22 |
12 files changed, 72 insertions, 168 deletions
diff --git a/decoder.cpp b/decoder.cpp index c362745..9330c6e 100644 --- a/decoder.cpp +++ b/decoder.cpp @@ -6,19 +6,14 @@ #include <map> -DecoderFilter::DecoderFilter(DecoderBase::p decoder_) { - decoder = decoder_; -} - -typedef boost::function<DecoderBase::p ()> DecoderFactory; +typedef boost::function<Decoder::p (const std::string&)> DecoderFactory; std::map<std::string, DecoderFactory> decoder_factories; -void decoder::init() { +void Decoder::init() { mpg123_init(); // initialize the mpg123 library decoder_factories["mpg123"] = boost::factory<boost::shared_ptr<DecoderMpg123> >(); } -//! Construct a filter with the given decoder. -DecoderFilter::p decoder::get_decoder(const std::string& name) { - return DecoderFilter::p(new DecoderFilter(decoder_factories[name]())); +Decoder::p Decoder::get(const std::string& name, const std::string& filename) { + return decoder_factories[name](filename); } @@ -1,56 +1,32 @@ #ifndef DECODER_H #define DECODER_H -#include <boost/iostreams/concepts.hpp> -#include <boost/iostreams/operations.hpp> #include <boost/shared_ptr.hpp> -#include <boost/function.hpp> #include <string> -class DecoderBase { - friend class DecoderFilter; - - protected: - typedef boost::function<std::size_t (char*, std::size_t)> ReadFunc; - - virtual size_t decode(ReadFunc read, uint8_t *output, size_t output_size) = 0; - +//! Interface for classes outputting raw audio. +class RawAudioSource { public: - typedef boost::shared_ptr<DecoderBase> p; - virtual ~DecoderBase() {} -}; - -//! Input filter to hold a decoder in a filter chain. -class DecoderFilter : public boost::iostreams::multichar_input_filter { - private: - DecoderBase::p decoder; + typedef boost::shared_ptr<RawAudioSource> p; - //! Functor binding a source to a read function. - template<class T> - struct ReadFunc { - T& s; - - ReadFunc(T& s_) : s(s_) {} - - std::size_t operator()(char* buf, std::size_t buf_size) { - return boost::iostreams::read(s, buf, buf_size); - } - }; - - public: - typedef boost::shared_ptr<DecoderFilter> p; - DecoderFilter(DecoderBase::p decoder_); + //! Virtual destructor. + virtual ~RawAudioSource() {} - template<typename Source> - std::streamsize read(Source& src, char *s, std::streamsize n) { - return decoder->decode(ReadFunc<Source>(src), (uint8_t*)s, n); - } + //! Read into provided buffer. + virtual std::size_t read(char* buf, std::size_t buf_size) = 0; }; -namespace decoder { - void init(); - DecoderFilter::p get_decoder(const std::string& name); +//! Decoder base class. +class Decoder : public RawAudioSource { + public: + typedef boost::shared_ptr<Decoder> p; + + //! Initialize decoders. + static void init(); + + //! Construct and return requested decoder. + static p get(const std::string& name, const std::string& filename); }; #endif diff --git a/decoders/mpg123_decoder.cpp b/decoders/mpg123_decoder.cpp index 0618320..8b3d9b4 100644 --- a/decoders/mpg123_decoder.cpp +++ b/decoders/mpg123_decoder.cpp @@ -5,7 +5,7 @@ #include <iostream> #include <stdexcept> -DecoderMpg123::DecoderMpg123() { +DecoderMpg123::DecoderMpg123(const std::string& filename) : ifile(filename.c_str()) { int error; handle = mpg123_new("generic", &error); if(error) { @@ -49,10 +49,10 @@ size_t DecoderMpg123::decode(const uint8_t *input, size_t input_size, uint8_t *o return output_written; } -size_t DecoderMpg123::decode(ReadFunc read, uint8_t *output, size_t output_size) { +std::size_t DecoderMpg123::read(char* buf, std::size_t buf_size) { char src_data[0x2000]; - std::streamsize src_read = read(src_data, 0x2000); + std::streamsize src_read = ifile.get(src_data, 0x2000).gcount(); if(src_read < 0) src_read = 0; - return decode((const uint8_t*)src_data, src_read, (uint8_t*)output, output_size); + return decode((const uint8_t*)src_data, src_read, (uint8_t*)buf, buf_size); } diff --git a/decoders/mpg123_decoder.h b/decoders/mpg123_decoder.h index 5a637af..f71dbe7 100644 --- a/decoders/mpg123_decoder.h +++ b/decoders/mpg123_decoder.h @@ -3,20 +3,21 @@ #include "decoder.h" +#include <fstream> #include <mpg123.h> -class DecoderMpg123 : public DecoderBase { +class DecoderMpg123 : public Decoder { private: mpg123_handle *handle; + std::ifstream ifile; size_t decode(const uint8_t *input, size_t input_size, uint8_t *output, size_t output_size); - protected: - virtual size_t decode(ReadFunc read, uint8_t *output, size_t output_size); - public: - DecoderMpg123(); + DecoderMpg123(const std::string& filename); ~DecoderMpg123(); + + virtual std::size_t read(char* buf, std::size_t buf_size); }; #endif diff --git a/encoder.cpp b/encoder.cpp index 0f2a5fe..9d352dc 100644 --- a/encoder.cpp +++ b/encoder.cpp @@ -6,18 +6,13 @@ #include <map> -EncoderFilter::EncoderFilter(EncoderBase::p encoder_) { - encoder = encoder_; -} - -typedef boost::function<EncoderBase::p ()> EncoderFactory; +typedef boost::function<Encoder::p (RawAudioSource::p)> EncoderFactory; std::map<std::string, EncoderFactory> encoder_factories; -void encoder::init() { +void Encoder::init() { encoder_factories["lame"] = boost::factory<boost::shared_ptr<EncoderLame> >(); } -//! Construct a filter with the given encoder. -EncoderFilter::p encoder::get_encoder(const std::string& name) { - return EncoderFilter::p(new EncoderFilter(encoder_factories[name]())); +Encoder::p Encoder::get(const std::string& name, RawAudioSource::p source) { + return encoder_factories[name](source); } @@ -1,57 +1,27 @@ #ifndef ENCODER_H #define ENCODER_H -#include <boost/iostreams/concepts.hpp> -#include <boost/iostreams/operations.hpp> +#include "decoder.h" + #include <boost/shared_ptr.hpp> -#include <boost/function.hpp> -#include <iostream> #include <string> -class EncoderBase { - friend class EncoderFilter; - - protected: - typedef boost::function<std::size_t (char*, std::size_t)> ReadFunc; +class Encoder { + public: + typedef boost::shared_ptr<Encoder> p; - virtual size_t encode(ReadFunc read, uint8_t *output, size_t output_size) = 0; + //! Virtual destructor. + virtual ~Encoder() {} - public: - typedef boost::shared_ptr<EncoderBase> p; - virtual ~EncoderBase() {} -}; - -//! Input filter to hold an encoder in a filter chain. -class EncoderFilter : public boost::iostreams::multichar_input_filter { - private: - EncoderBase::p encoder; + //! Initialize encoders. + static void init(); - //! Functor binding a source to a read function. - template<class T> - struct ReadFunc { - T& s; - - ReadFunc(T& s_) : s(s_) {} - - std::size_t operator()(char* buf, std::size_t buf_size) { - return boost::iostreams::read(s, buf, buf_size); - } - }; - - public: - typedef boost::shared_ptr<EncoderFilter> p; - EncoderFilter(EncoderBase::p encoder_); + //! Construct and return requested encoder. + static p get(const std::string& name, RawAudioSource::p source); - template<typename Source> - std::streamsize read(Source& src, char *s, std::streamsize n) { - return encoder->encode(ReadFunc<Source>(src), (uint8_t*)s, n); - }; -}; - -namespace encoder { - void init(); - EncoderFilter::p get_encoder(const std::string& name); + //! Read into provided buffer. + virtual std::size_t read(char* buf, std::size_t buf_size) = 0; }; #endif diff --git a/encoders/lame_encoder.cpp b/encoders/lame_encoder.cpp index 7bf2ebc..be6f684 100644 --- a/encoders/lame_encoder.cpp +++ b/encoders/lame_encoder.cpp @@ -2,7 +2,7 @@ #include <stdexcept> -EncoderLame::EncoderLame() { +EncoderLame::EncoderLame(RawAudioSource::p source_) : source(source_) { gfp = lame_init(); int error = lame_init_params(gfp); @@ -23,15 +23,15 @@ size_t EncoderLame::flush(uint8_t *output, size_t output_size) { return lame_encode_flush(gfp, output, output_size); } -size_t EncoderLame::encode(ReadFunc read, uint8_t *output, size_t output_size) { +std::size_t EncoderLame::read(char* buf, std::size_t buf_size) { char src_data[0x2000]; - std::streamsize src_read = read(src_data, 0x2000); + std::streamsize src_read = source->read(src_data, 0x2000); if(src_read < 0) src_read = 0; - std::streamsize size = encode((const uint8_t*)src_data, src_read, (uint8_t*)output, output_size); + std::streamsize size = encode((const uint8_t*)src_data, src_read, (uint8_t*)buf, buf_size); // no more data, flush encoder if(src_read == 0 && size == 0) { - size = flush((uint8_t*)output, output_size); + size = flush((uint8_t*)buf, buf_size); } return size; diff --git a/encoders/lame_encoder.h b/encoders/lame_encoder.h index 98ebc9f..3d1137d 100644 --- a/encoders/lame_encoder.h +++ b/encoders/lame_encoder.h @@ -5,19 +5,19 @@ #include <lame/lame.h> -class EncoderLame : public EncoderBase { +class EncoderLame : public Encoder { private: lame_global_flags *gfp; + RawAudioSource::p source; size_t encode(const uint8_t *input, size_t input_size, uint8_t *output, size_t output_size); size_t flush(uint8_t *output, size_t output_size); - protected: - virtual size_t encode(ReadFunc read, uint8_t *output, size_t output_size); - public: - EncoderLame(); + EncoderLame(RawAudioSource::p source_); ~EncoderLame(); + + virtual std::size_t read(char* buf, std::size_t buf_size); }; #endif @@ -25,8 +25,8 @@ int main(int argc, char **argv) { try { config::init(); music::init(config::vm["audist.music_root"].as<std::string>()); - decoder::init(); - encoder::init(); + Decoder::init(); + Encoder::init(); boost::asio::io_service io_service; @@ -1,7 +1,6 @@ #include "music.h" #include "decoder.h" #include "encoder.h" -#include "transcode.h" #include "tag.h" #include "config.h" @@ -238,10 +237,18 @@ void MusicTrack::render(HTTP::Connection::p req) { req->add_header("content-type", "application/octet-stream"); if(req->args.count("decoder") && req->args.count("encoder")) { - DecoderFilter::p d = decoder::get_decoder(req->args["decoder"]); - EncoderFilter::p e = encoder::get_encoder(req->args["encoder"]); - Transcoder t(path.string(), req, d, e); - t.run(); + Decoder::p decoder = Decoder::get(req->args["decoder"], path.string()); + Encoder::p encoder = Encoder::get(req->args["encoder"], decoder); + + // TODO: Make an encoder-to-istream adapter to get rid of this: + char data[0x1000]; + std::streamsize size = 1; + while(size) { + size = encoder->read(data, 0x1000); + if(size > 0) + req->send_data(data, size); + } + } else { fs::ifstream is(path, std::ios::in | std::ios::binary); is.seekg(0, std::ios::end); diff --git a/transcode.cpp b/transcode.cpp deleted file mode 100644 index 394f604..0000000 --- a/transcode.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "transcode.h" - -#include <boost/iostreams/device/file.hpp> -#include <boost/iostreams/filtering_stream.hpp> - -Transcoder::Transcoder(std::string p, HTTP::Connection::p r, DecoderFilter::p d, EncoderFilter::p e) : path(p), res(r), decoder(d), encoder(e) { -} - -void Transcoder::run() { - const std::streamsize buffer_size = 0x1000; - boost::iostreams::file_source is(path, std::ios::in | std::ios::binary); - boost::iostreams::filtering_istream s; - s.push(*encoder.get(), buffer_size); - s.push(*decoder.get(), buffer_size); - s.push(is, buffer_size); - - res->send_data(s); -} diff --git a/transcode.h b/transcode.h deleted file mode 100644 index 56f16c1..0000000 --- a/transcode.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef TRANSCODE_H -#define TRANSCODE_H - -#include "decoder.h" -#include "encoder.h" -#include "http_connection.h" - -#include <string> - -class Transcoder { - private: - std::string path; - HTTP::Connection::p res; - DecoderFilter::p decoder; - EncoderFilter::p encoder; - - public: - Transcoder(std::string p, HTTP::Connection::p r, DecoderFilter::p d, EncoderFilter::p e); - void run(); -}; - -#endif |