From 237c3e226b7c2ac391b0e8d354e5fc6f587a41ba Mon Sep 17 00:00:00 2001 From: Jon Bergli Heier Date: Sun, 2 Jan 2011 22:17:26 +0100 Subject: Use a filtering_istream with custom filters to chain file -> decoder -> encoder. --- decoder.h | 17 +++++++++++++++++ encoder.h | 19 ++++++++++++++++++- encoders/lame_encoder.cpp | 8 +++----- encoders/lame_encoder.h | 2 +- music.cpp | 5 ++--- transcode.cpp | 29 +++++++++++++++++------------ transcode.h | 6 +++--- 7 files changed, 61 insertions(+), 25 deletions(-) diff --git a/decoder.h b/decoder.h index b4dcdb6..a7aaad9 100644 --- a/decoder.h +++ b/decoder.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include @@ -13,6 +15,21 @@ class DecoderBase { virtual size_t decode(const uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) = 0; }; +class DecoderFilter : public boost::iostreams::multichar_input_filter { + private: + DecoderBase& decoder; + public: + DecoderFilter(DecoderBase& decoder_) : decoder(decoder_) {}; + template + std::streamsize read(Source& src, char *s, std::streamsize n) { + char src_data[0x2000]; + std::streamsize src_read = boost::iostreams::read(src, src_data, 0x2000); + if(src_read < 0) + src_read = 0; + return decoder.decode((const uint8_t*)src_data, src_read, (uint8_t*)s, n); + }; +}; + namespace decoder { void init(); DecoderBase *get_decoder(const std::string& name); diff --git a/encoder.h b/encoder.h index 9949b52..7021cdc 100644 --- a/encoder.h +++ b/encoder.h @@ -5,15 +5,32 @@ #include #include #include +#include +#include #include class EncoderBase { public: - virtual size_t encode(uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) = 0; + virtual size_t encode(const uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) = 0; virtual size_t flush(uint8_t *output, size_t output_size) = 0; }; +class EncoderFilter : public boost::iostreams::multichar_input_filter { + private: + EncoderBase& encoder; + public: + EncoderFilter(EncoderBase& encoder_) : encoder(encoder_) {}; + template + std::streamsize read(Source& src, char *s, std::streamsize n) { + char src_data[0x2000]; + std::streamsize src_read = boost::iostreams::read(src, src_data, 0x2000); + if(src_read < 0) + src_read = 0; + return encoder.encode((const uint8_t*)src_data, src_read, (uint8_t*)s, n); + }; +}; + namespace encoder { void init(); EncoderBase *get_encoder(const std::string& name); diff --git a/encoders/lame_encoder.cpp b/encoders/lame_encoder.cpp index 4cbfc9c..125ee5e 100644 --- a/encoders/lame_encoder.cpp +++ b/encoders/lame_encoder.cpp @@ -15,12 +15,10 @@ EncoderLame::~EncoderLame() { lame_close(gfp); } -size_t EncoderLame::encode(uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) { - size_t size = lame_encode_buffer_interleaved(gfp, (short*)input, input_size / 4, output, output_size); - return size; +size_t EncoderLame::encode(const uint8_t *input, size_t input_size, uint8_t *output, size_t output_size) { + return lame_encode_buffer_interleaved(gfp, (short*)input, input_size / 4, output, output_size); } size_t EncoderLame::flush(uint8_t *output, size_t output_size) { - size_t size = lame_encode_flush(gfp, output, output_size); - return size; + return lame_encode_flush(gfp, output, output_size); } diff --git a/encoders/lame_encoder.h b/encoders/lame_encoder.h index 47f9666..1843361 100644 --- a/encoders/lame_encoder.h +++ b/encoders/lame_encoder.h @@ -12,7 +12,7 @@ class EncoderLame : public EncoderBase { public: EncoderLame(); ~EncoderLame(); - size_t encode(uint8_t *input, size_t input_size, uint8_t *output, size_t output_size); + 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); }; diff --git a/music.cpp b/music.cpp index ec2f537..9892526 100644 --- a/music.cpp +++ b/music.cpp @@ -132,16 +132,15 @@ void MusicTrack::render(HTTP::Connection::p req, HTTPResponse& res) { Tag *t = new ID3Tag(path.string()); delete t; - fs::ifstream is(path, std::ios::binary | std::ios::in); - if(req->args.count("decoder") && req->args.count("encoder")) { DecoderBase *d = decoder::get_decoder(req->args["decoder"]); EncoderBase *e = encoder::get_encoder(req->args["encoder"]); - Transcoder t(is, res, *d, *e); + Transcoder t(path.string(), res, *d, *e); t.run(); delete d; delete e; } else { + fs::ifstream is(path, std::ios::in | std::ios::binary); is.seekg(0, std::ios::end); res.add_header("content-length", boost::str(boost::format("%d") % is.tellg())); is.seekg(0, std::ios::beg); diff --git a/transcode.cpp b/transcode.cpp index 249ffb3..5244627 100644 --- a/transcode.cpp +++ b/transcode.cpp @@ -1,20 +1,25 @@ #include "transcode.h" -Transcoder::Transcoder(std::istream& i, HTTPResponse& r, DecoderBase& d, EncoderBase& e) : is(i), res(r), decoder(d), encoder(e) { +#include +#include + +Transcoder::Transcoder(std::string p, HTTPResponse& r, DecoderBase& d, EncoderBase& 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(EncoderFilter(encoder), buffer_size); + s.push(DecoderFilter(decoder), buffer_size); + s.push(is, buffer_size); + char data[0x1000]; - bool encoding_fone = false; - while(!encoding_fone) { - size_t decoded_size = 0; - char decoded_data[0x1000]; - if(is.good()) { - is.read(data, 0x1000); - decoded_size = decoder.decode((uint8_t*)data, is.gcount(), (uint8_t*)decoded_data, 0x1000); - } - char encoded_data[0x1000]; - size_t encoded_size = encoder.encode((uint8_t*)decoded_data, decoded_size, (uint8_t*)encoded_data, 0x1000); - res.write(encoded_data, encoded_size); + std::streamsize size = 1; + while(size) { + s.read(data, 0x1000); + size = s.gcount(); + if(size > 0) + res.write(data, size); } } diff --git a/transcode.h b/transcode.h index 2a63b17..d0e781d 100644 --- a/transcode.h +++ b/transcode.h @@ -5,17 +5,17 @@ #include "encoder.h" #include "http.h" -#include +#include class Transcoder { private: - std::istream& is; + std::string path; HTTPResponse& res; DecoderBase& decoder; EncoderBase& encoder; public: - Transcoder(std::istream& i, HTTPResponse& r, DecoderBase& d, EncoderBase& e); + Transcoder(std::string p, HTTPResponse& r, DecoderBase& d, EncoderBase& e); void run(); }; -- cgit v1.2.3