From 6faf81502a4f1636537fc14f3229e8b2bfb2209f Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Thu, 6 Jan 2011 01:02:41 +0200 Subject: [PATCH] Streamtools: Refactor rescaling code Refactor the rescaling code. Combo scaling is now supported. --- streamtools/Makefile | 6 +- streamtools/dumpconvert.cpp | 129 +++++------ streamtools/packet-processor.cpp | 112 ++++++---- streamtools/packet-processor.hpp | 31 ++- streamtools/rescalers/base.cpp | 253 ++++++++++++++++++++++ streamtools/{resizer => rescalers}/bilinear.cpp | 4 +- streamtools/rescalers/factory.hpp | 16 ++ streamtools/rescalers/hqx.cpp | 118 ++++++++++ streamtools/{resizer => rescalers}/lanczos.cpp | 23 +- streamtools/{resizer => rescalers}/letterbox.cpp | 4 +- streamtools/{resizer => rescalers}/letterbox2.cpp | 4 +- streamtools/rescalers/linear-separable.cpp | 109 ++++++++++ streamtools/rescalers/linear-separable.hpp | 39 ++++ streamtools/{resizer => rescalers}/nearest.cpp | 6 +- streamtools/rescalers/public.hpp | 46 ++++ streamtools/rescalers/simple.cpp | 37 ++++ streamtools/rescalers/simple.hpp | 21 ++ streamtools/rescalers/xdrop9.cpp | 25 +++ streamtools/resize-linear-separable.cpp | 145 ------------- streamtools/resize-linear-separable.hpp | 44 ---- streamtools/resize.cpp | 115 +--------- streamtools/resize.hpp | 100 +++------ streamtools/resizer/hqx.cpp | 115 ---------- streamtools/resizer/test.cpp | 30 --- streamtools/resizer/xdrop9.cpp | 32 --- streamtools/testresizer.cpp | 19 +- 26 files changed, 877 insertions(+), 706 deletions(-) create mode 100644 streamtools/rescalers/base.cpp rename streamtools/{resizer => rescalers}/bilinear.cpp (74%) create mode 100644 streamtools/rescalers/factory.hpp create mode 100644 streamtools/rescalers/hqx.cpp rename streamtools/{resizer => rescalers}/lanczos.cpp (60%) rename streamtools/{resizer => rescalers}/letterbox.cpp (73%) rename streamtools/{resizer => rescalers}/letterbox2.cpp (74%) create mode 100644 streamtools/rescalers/linear-separable.cpp create mode 100644 streamtools/rescalers/linear-separable.hpp rename streamtools/{resizer => rescalers}/nearest.cpp (82%) create mode 100644 streamtools/rescalers/public.hpp create mode 100644 streamtools/rescalers/simple.cpp create mode 100644 streamtools/rescalers/simple.hpp create mode 100644 streamtools/rescalers/xdrop9.cpp delete mode 100644 streamtools/resize-linear-separable.cpp delete mode 100644 streamtools/resize-linear-separable.hpp rewrite streamtools/resize.hpp (60%) delete mode 100644 streamtools/resizer/hqx.cpp delete mode 100644 streamtools/resizer/test.cpp delete mode 100644 streamtools/resizer/xdrop9.cpp diff --git a/streamtools/Makefile b/streamtools/Makefile index ecf51f3..12c0e26 100644 --- a/streamtools/Makefile +++ b/streamtools/Makefile @@ -3,9 +3,7 @@ all: screenshot.exe dumppackets.exe picturestodump.exe audiotodump.exe demuxdum COMPILER=g++ CXXFLAGS=-g -O2 -Wall -I. -std=c++0x CXXFLAGS2=$(CXXFLAGS) -Werror -RESIZE_DRIVERS=resize.o resize-linear-separable.o $(patsubst %.cpp,%.o,$(wildcard resizer/*.cpp)) -I420_DRIVER_FILES=output-drv-rawi420.o rgbtorgb.o -X264_DRIVER_FILES=output-drv-x264.o rgbtorgb.o +RESIZE_DRIVERS=resize.o $(patsubst %.cpp,%.o,$(wildcard rescalers/*.cpp)) OUTPUT_DRIVERS=rgbtorgb.o $(RESIZE_DRIVERS) dedup.o $(patsubst %.cpp,%.o,$(wildcard outputs/*.cpp)) ifdef WITH_HQX ADD_LIBS=-lhqx @@ -48,7 +46,7 @@ cutdump.exe: cutdump.o newpacket.o timeparse.o main.o guessresolution.exe: guessresolution.o newpacket.o main.o $(COMPILER) $(CXXFLAGS2) -o $@ $^ $(LIBS) -playdump.exe: playdump.o newpacket.o timecounter.o resize.o resampler.o digital-filter.o opl.o misc.o hardsubs.o timeparse.o main.o +playdump.exe: playdump.o newpacket.o timecounter.o resampler.o digital-filter.o opl.o misc.o hardsubs.o timeparse.o main.o $(RESIZE_DRIVERS) $(COMPILER) $(CXXFLAGS2) -o $@ $^ $(LIBS) dumpconvert.exe: dumpconvert.o $(OUTPUT_DRIVERS) packet-processor.o resampler.o digital-filter.o misc.o opl.o timecounter.o hardsubs.o newpacket.o timeparse.o main.o framerate-reducer.o temporal-antialias.o diff --git a/streamtools/dumpconvert.cpp b/streamtools/dumpconvert.cpp index 9a70655..22d417e 100644 --- a/streamtools/dumpconvert.cpp +++ b/streamtools/dumpconvert.cpp @@ -8,25 +8,27 @@ #include "timeparse.hpp" #include -#define DEFAULT_RESIZE_TYPE "lanczos2" - int real_main(int argc, char** argv) { - int64_t _audio_delay = 0; - int64_t _subtitle_delay = 0; - uint32_t _audio_rate = 44100; - uint32_t _width = 0; - uint32_t _height = 0; - uint32_t _rate_num = 0; - uint32_t _rate_denum = 0; - uint32_t _dedup_max = 0; - framerate_reducer* dropper; int dropmode = 0; double antialias_factor = 0; - std::string resize_type = DEFAULT_RESIZE_TYPE; - std::map, std::string> special_resizers; bool sep = false; bool seen_filenames = false; + struct packet_processor_parameters params; + + //Initialize parameters. + params.audio_delay = 0; + params.subtitle_delay = 0; + params.audio_rate = 44100; + params.demux = NULL; + params.width = 0; + params.height = 0; + params.rate_num = 0; + params.rate_denum = 0; + params.dedup_max = 0; + params.frame_dropper = NULL; + params.outgroup = NULL; + for(int i = 1; i < argc; i++) { std::string arg = argv[i]; @@ -44,99 +46,74 @@ int real_main(int argc, char** argv) if(isstringprefix(arg, "--video-width=")) { std::string value = settingvalue(arg); char* x; - _width = strtoul(value.c_str(), &x, 10); - if(*x || !_width) { + params.width = strtoul(value.c_str(), &x, 10); + if(*x || !params.width) { std::cerr << "--video-width: Bad width" << std::endl; return 1; } } else if(isstringprefix(arg, "--video-height=")) { std::string value = settingvalue(arg); char* x; - _height = strtoul(value.c_str(), &x, 10); - if(*x || !_height) { + params.height = strtoul(value.c_str(), &x, 10); + if(*x || !params.height) { std::cerr << "--video-height: Bad height" << std::endl; return 1; } } else if(isstringprefix(arg, "--video-scale-algo=")) { - std::string tmptype = settingvalue(arg); - uint32_t width = 0; - uint32_t height = 0; - size_t p = tmptype.find_first_of(" "); - if(p > tmptype.length()) - resize_type = settingvalue(arg); - else { - std::string tmptype_tail = tmptype.substr(p + 1); - tmptype = tmptype.substr(0, p); - const char* x = tmptype_tail.c_str(); - char* end; - width = (uint32_t)strtoul(x, &end, 10); - if(*end != ' ') - throw std::runtime_error("Bad resolution for resolution-dependent scaler (width)."); - x = end + 1; - height = (uint32_t)strtoul(x, &end, 10); - if(*end != '\0') - throw std::runtime_error("Bad resolution for resolution-dependent scaler (height)."); - special_resizers[std::make_pair(width, height)] = tmptype; - } - } else if(isstringprefix(arg, "--video-scale-algo-")) { - std::string tmptype = settingvalue(arg); - uint32_t width = 0; - uint32_t height = 0; - - special_resizers[std::make_pair(width, height)] = tmptype; + //Processed later. } else if(arg == "--video-framerate=auto") { - if(_rate_denum) { + if(params.rate_denum) { std::cerr << "Conflicts with earlier explicit fps: " << arg << "." << std::endl; return 1; } - _rate_num = 1; + params.rate_num = 1; } else if(isstringprefix(arg, "--video-framerate=")) { std::string value = settingvalue(arg); char* x; - if(_rate_num || _rate_denum) { + if(params.rate_num || params.rate_denum) { std::cerr << "Conflicts with earlier fps: " << arg << "." << std::endl; return 1; } - _rate_num = strtoul(value.c_str(), &x, 10); - if((*x != '\0' && *x != '/') || !_rate_num) { + params.rate_num = strtoul(value.c_str(), &x, 10); + if((*x != '\0' && *x != '/') || !params.rate_num) { std::cerr << "--video-framerate: Bad value (n)" << std::endl; return 1; } if(*x) { x++; - _rate_denum = strtoul(x, &x, 10); - if(*x || !_rate_denum) { + params.rate_denum = strtoul(x, &x, 10); + if(*x || !params.rate_denum) { std::cerr << "--video-framerate: Bad value (d)" << std::endl; return 1; } } else - _rate_denum = 1; + params.rate_denum = 1; } else if(isstringprefix(arg, "--video-max-dedup=")) { std::string value = settingvalue(arg); char* x; - _dedup_max = strtoul(value.c_str(), &x, 10); + params.dedup_max = strtoul(value.c_str(), &x, 10); if(*x) { std::cerr << "--video-dedup-max: Bad value" << std::endl; return 1; } - if(_rate_denum) { + if(params.rate_denum) { std::cerr << "Conflicts with earlier explicit fps: " << arg << "." << std::endl; return 1; } - _rate_num = 1; + params.rate_num = 1; } else if(isstringprefix(arg, "--audio-delay=")) { std::string value = settingvalue(arg); if(value.length() && value[0] == '-') - _audio_delay = -(int64_t)parse_timespec(value.substr(1)); + params.audio_delay = -(int64_t)parse_timespec(value.substr(1)); else - _audio_delay = -(int64_t)parse_timespec(value); + params.audio_delay = -(int64_t)parse_timespec(value); } else if(isstringprefix(arg, "--subtitle-delay=")) { std::string value = settingvalue(arg); if(value.length() && value[0] == '-') - _subtitle_delay = -(int64_t)parse_timespec(value.substr(1)); + params.subtitle_delay = -(int64_t)parse_timespec(value.substr(1)); else - _subtitle_delay = -(int64_t)parse_timespec(value); + params.subtitle_delay = -(int64_t)parse_timespec(value); } else if(isstringprefix(arg, "--video-temporalantialias=")) { std::string value = settingvalue(arg); char* x; @@ -179,7 +156,7 @@ int real_main(int argc, char** argv) std::cout << "\tSet video scaling algo to ." << std::endl; std::cout << "--video-scale-algo= " << std::endl; std::cout << "\tSet video scaling algo for x frames to ." << std::endl; - std::cout << "\tSupported algorithms: " << get_resizer_list() << std::endl; + std::cout << "\tSupported algorithms: " << get_rescaler_string() << std::endl; std::cout << "--video-scale-framerate=[/]" << std::endl; std::cout << "\tSet video framerate to /." << std::endl; std::cout << "--video-scale-framerate=auto" << std::endl; @@ -194,25 +171,26 @@ int real_main(int argc, char** argv) } - if(!_rate_num && !_rate_denum) { - _rate_num = 60; - _rate_denum = 1; + if(!params.rate_num && !params.rate_denum) { + params.rate_num = 60; + params.rate_denum = 1; } if(dropmode == 0) - dropper = new framerate_reducer_dropframes(); + params.frame_dropper = new framerate_reducer_dropframes(); else - dropper = new framerate_reducer_temporalantialias(antialias_factor, _rate_num, _rate_denum); + params.frame_dropper = new framerate_reducer_temporalantialias(antialias_factor, params.rate_num, + params.rate_denum); - audio_settings asettings(_audio_rate); - video_settings vsettings(_width, _height, _rate_num, _rate_denum); + audio_settings asettings(params.audio_rate); + video_settings vsettings(params.width, params.height, params.rate_num, params.rate_denum); subtitle_settings ssettings; - output_driver_group* local_group = new output_driver_group(); + params.outgroup = new output_driver_group(); - local_group->set_audio_settings(asettings); - local_group->set_video_settings(vsettings); - local_group->set_subtitle_settings(ssettings); + params.outgroup->set_audio_settings(asettings); + params.outgroup->set_video_settings(vsettings); + params.outgroup->set_subtitle_settings(ssettings); sep = false; for(int i = 1; i < argc; i++) { @@ -239,12 +217,11 @@ int real_main(int argc, char** argv) parameters = file.substr(x + 1); file = file.substr(0, x); } - local_group->add_driver(type, file, parameters); + params.outgroup->add_driver(type, file, parameters); } } - packet_processor& p = create_packet_processor(_audio_delay, _subtitle_delay, _audio_rate, _width, _height, - _rate_num, _rate_denum, _dedup_max, resize_type, special_resizers, argc, argv, dropper, *local_group); + packet_processor& p = create_packet_processor(¶ms, argc, argv); sep = false; uint64_t timebase = 0; for(int i = 1; i < argc; i++) { @@ -259,9 +236,9 @@ int real_main(int argc, char** argv) } } p.send_end_of_stream(); - local_group->do_audio_end_callback(); - delete local_group; + params.outgroup->do_audio_end_callback(); + delete params.outgroup; delete &p; - delete dropper; + delete params.frame_dropper; return 0; } diff --git a/streamtools/packet-processor.cpp b/streamtools/packet-processor.cpp index 258a573..e4ca35a 100644 --- a/streamtools/packet-processor.cpp +++ b/streamtools/packet-processor.cpp @@ -1,32 +1,34 @@ #include "packet-processor.hpp" #include "outputs/public.hpp" #include - -packet_processor::packet_processor(int64_t _audio_delay, int64_t _subtitle_delay, uint32_t _audio_rate, - packet_demux& _demux, uint32_t _width, uint32_t _height, uint32_t _rate_num, uint32_t _rate_denum, - uint32_t _dedup_max, resizer& _using_resizer, - std::map, resizer*> _special_resizers, std::list _hardsubs, - framerate_reducer* _frame_dropper, output_driver_group& _group) - : using_resizer(_using_resizer), demux(_demux), dedupper(_dedup_max, _width, _height), - audio_timer(_audio_rate), video_timer(_rate_num, _rate_denum), group(_group) +#include +#include +#include +#include +#include "misc.hpp" + +packet_processor::packet_processor(struct packet_processor_parameters* params) + : rescalers(*params->rescalers), demux(*params->demux), + dedupper(params->dedup_max, params->width, params->height), + audio_timer(params->audio_rate), video_timer(params->rate_num, params->rate_denum), + group(*params->outgroup) { - audio_delay = _audio_delay; - subtitle_delay = _subtitle_delay; - special_resizers = _special_resizers; - audio_rate = _audio_rate; - width = _width; - height = _height; - rate_num = _rate_num; - rate_denum = _rate_denum; - frame_dropper = _frame_dropper; - hardsubs = _hardsubs; + audio_delay = params->audio_delay; + subtitle_delay = params->subtitle_delay; + audio_rate = params->audio_rate; + width = params->width; + height = params->height; + rate_num = params->rate_num; + rate_denum = params->rate_denum; + frame_dropper = params->frame_dropper; + hardsubs = params->hardsubs; sequence_length = 0; min_shift = 0; saved_video_frame = NULL; - if(min_shift > _audio_delay) - min_shift = _audio_delay; - if(min_shift > _subtitle_delay) - min_shift = _subtitle_delay; + if(min_shift > params->audio_delay) + min_shift = params->audio_delay; + if(min_shift > params->subtitle_delay) + min_shift = params->subtitle_delay; } packet_processor::~packet_processor() @@ -34,7 +36,7 @@ packet_processor::~packet_processor() for(std::list::iterator i = hardsubs.begin(); i != hardsubs.end(); ++i) delete *i; delete &demux; - delete &using_resizer; + delete &rescalers; } int64_t packet_processor::get_real_time(struct packet& p) @@ -105,27 +107,17 @@ void packet_processor::handle_packet(struct packet& q) break; } if(rate_denum > 0) { - resizer* rs = &using_resizer; image_frame_rgbx* f = new image_frame_rgbx(q); uint64_t ts = q.rp_timestamp; delete &q; - //If special resizer has been defined, use that. - std::pair size = std::make_pair(f->get_width(), f->get_height()); - if(special_resizers.count(size)) - rs = special_resizers[size]; - image_frame_rgbx& r = f->resize(width, height, *rs); + image_frame_rgbx& r = f->resize(width, height, rescalers); if(&r != f) delete f; frame_dropper->push(ts, r); } else { - resizer* rs = &using_resizer; - //Handle frame immediately. image_frame_rgbx f(q); - std::pair size = std::make_pair(f.get_width(), f.get_height()); - if(special_resizers.count(size)) - rs = special_resizers[size]; - image_frame_rgbx& r = f.resize(width, height, *rs); + image_frame_rgbx& r = f.resize(width, height, rescalers); //Subtitles. for(std::list::iterator i = hardsubs.begin(); i != hardsubs.end(); ++i) @@ -213,23 +205,47 @@ uint64_t send_stream(packet_processor& p, read_channel& rc, uint64_t timebase) return p.get_last_timestamp(); } -packet_processor& create_packet_processor(int64_t _audio_delay, int64_t _subtitle_delay, uint32_t _audio_rate, - uint32_t _width, uint32_t _height, uint32_t _rate_num, uint32_t _rate_denum, uint32_t _dedup_max, - const std::string& resize_type, std::map, std::string> _special_resizers, - int argc, char** argv, framerate_reducer* frame_dropper, output_driver_group& group) +packet_processor& create_packet_processor(struct packet_processor_parameters* params, int argc, char** argv) { + bool default_reset = false; + std::set > resets; hardsub_settings stsettings; - std::map, resizer*> special_resizers; - resizer& _using_resizer = resizer_factory::make_by_type(resize_type); mixer& mix = *new mixer(); - packet_demux& ademux = *new packet_demux(mix, _audio_rate); - process_audio_resampler_options(ademux, "--audio-mixer-", argc, argv); + params->demux = new packet_demux(mix, params->audio_rate); + process_audio_resampler_options(*params->demux, "--audio-mixer-", argc, argv); std::list subtitles = process_hardsubs_options(stsettings, "--video-hardsub-", argc, argv); - for(std::map, std::string>::iterator i = _special_resizers.begin(); - i != _special_resizers.end(); ++i) - special_resizers[i->first] = &resizer_factory::make_by_type(i->second); + //Deal with the rescalers. + params->rescalers = new rescaler_group(get_default_rescaler()); + for(int i = 1; i < argc; i++) { + std::string arg = argv[i]; + try { + if(isstringprefix(arg, "--video-scale-algo=")) { + std::string value = settingvalue(arg); + struct parsed_scaler ps = parse_rescaler_expression(value); + std::pair x = std::make_pair(ps.swidth, ps.sheight); + if(ps.is_special) { + if(resets.count(x)) { + std::ostringstream str; + str << "Special rescaler for " << ps.swidth << "*" << ps.sheight + << "already specified." << std::endl; + throw std::runtime_error(str.str()); + } + params->rescalers->set_special_rescaler(ps.swidth, ps.sheight, *ps.use_rescaler); + resets.insert(x); + } else { + if(default_reset) + throw std::runtime_error("Default rescaler already specified"); + params->rescalers->set_default_rescaler(*ps.use_rescaler); + default_reset = true; + } + } + } catch(std::exception& e) { + std::ostringstream str; + str << "Error processing option: " << arg << ":" << e.what() << std::endl; + throw std::runtime_error(str.str()); + } + } - return *new packet_processor(_audio_delay, _subtitle_delay, _audio_rate, ademux, _width, _height, _rate_num, - _rate_denum, _dedup_max, _using_resizer, special_resizers, subtitles, frame_dropper, group); + return *new packet_processor(params); } diff --git a/streamtools/packet-processor.hpp b/streamtools/packet-processor.hpp index c5a83fb..be3b43b 100644 --- a/streamtools/packet-processor.hpp +++ b/streamtools/packet-processor.hpp @@ -11,14 +11,28 @@ #include "framerate-reducer.hpp" #include "outputs/public.hpp" +struct packet_processor_parameters +{ + int64_t audio_delay; + int64_t subtitle_delay; + uint32_t audio_rate; + packet_demux* demux; + uint32_t width; + uint32_t height; + uint32_t rate_num; + uint32_t rate_denum; + uint32_t dedup_max; + framerate_reducer* frame_dropper; + output_driver_group* outgroup; + //These are filled by create_packet_processor(). + rescaler_group* rescalers; + std::list hardsubs; +}; class packet_processor { public: - packet_processor(int64_t _audio_delay, int64_t _subtitle_delay, uint32_t _audio_rate, packet_demux& _demux, - uint32_t _width, uint32_t _height, uint32_t _rate_num, uint32_t _rate_denum, uint32_t _dedup_max, - resizer& _using_resizer, std::map, resizer*> _special_resizers, - std::list _hardsubs, framerate_reducer* frame_dropper, output_driver_group& _group); + packet_processor(struct packet_processor_parameters* params); ~packet_processor(); void send_packet(struct packet& p, uint64_t timebase); uint64_t get_last_timestamp(); @@ -29,8 +43,7 @@ private: int64_t audio_delay; int64_t subtitle_delay; uint32_t audio_rate; - resizer& using_resizer; - std::map, resizer*> special_resizers; + rescaler_group& rescalers; packet_demux& demux; uint32_t width; uint32_t height; @@ -51,10 +64,8 @@ private: //Returns new timebase. uint64_t send_stream(packet_processor& p, read_channel& rc, uint64_t timebase); -packet_processor& create_packet_processor(int64_t _audio_delay, int64_t _subtitle_delay, uint32_t _audio_rate, - uint32_t _width, uint32_t _height, uint32_t _rate_num, uint32_t _rate_denum, uint32_t _dedup_max, - const std::string& resize_type, std::map, std::string> _special_resizers, - int argc, char** argv, framerate_reducer* frame_dropper, output_driver_group& _group); +packet_processor& create_packet_processor(struct packet_processor_parameters* params, + int argc, char** argv); #endif diff --git a/streamtools/rescalers/base.cpp b/streamtools/rescalers/base.cpp new file mode 100644 index 0000000..2095a63 --- /dev/null +++ b/streamtools/rescalers/base.cpp @@ -0,0 +1,253 @@ +#include "rescalers/public.hpp" +#include "rescalers/factory.hpp" +#include +#include +#include +#include + +#define DEFAULT_RESCALER "lanczos2" + +namespace +{ + std::map* factories; +} + +namespace +{ + class composite_rescaler_failure : public std::runtime_error + { + public: + composite_rescaler_failure(const std::string& what) + : std::runtime_error(what) + { + } + }; +} + +rescaler::~rescaler() +{ +} + + +rescaler_factory::~rescaler_factory() +{ +} + +rescaler_factory::rescaler_factory(const std::string& type) +{ + if(!factories) + factories = new std::map(); + (*factories)[type] = this; +} + +rescaler& rescaler::make(const std::string& type) +{ + if(!factories || !factories->count(type)) { + std::ostringstream str; + str << "Unknown rescaler type '" << type << "'"; + throw std::runtime_error(str.str()); + } + return (*factories)[type]->make(type); +} + +std::string get_rescaler_string() +{ + bool first = true; + if(!factories) + return ""; + std::string c; + std::map& f = *factories; + for(auto i = f.begin(); i != f.end(); ++i) { + if(first) + c = i->first; + else + c = c + " " + i->first; + first = false; + } + return c; +} + +std::list get_rescaler_list() +{ + std::list l; + std::map& f = *factories; + for(auto i = f.begin(); i != f.end(); ++i) + l.push_back(i->first); + return l; +} + +namespace +{ + class composite_rescaler_c : public rescaler + { + public: + composite_rescaler_c(rescaler& _s1, uint32_t _iwidth, uint32_t _iheight, rescaler& _s2); + ~composite_rescaler_c(); + void operator()(uint8_t* target, uint32_t twidth, uint32_t theight, + const uint8_t* source, uint32_t swidth, uint32_t sheight); + private: + rescaler& s1; + rescaler& s2; + uint32_t iwidth; + uint32_t iheight; + }; + + composite_rescaler_c::composite_rescaler_c(rescaler& _s1, uint32_t _iwidth, uint32_t _iheight, rescaler& _s2) + : s1(_s1), s2(_s2) + { + iwidth = _iwidth; + iheight = _iheight; + } + + composite_rescaler_c::~composite_rescaler_c() + { + delete &s1; + delete &s2; + } + + void composite_rescaler_c::operator()(uint8_t* target, uint32_t twidth, uint32_t theight, + const uint8_t* source, uint32_t swidth, uint32_t sheight) + { + std::vector intermediate(4 * (size_t)iwidth * iheight); + try { + s1(&intermediate[0], iwidth, iheight, source, swidth, sheight); + } catch(composite_rescaler_failure& e) { + throw; + } catch(std::exception& e) { + std::ostringstream str; + str << "Failed to rescale from " << swidth << "*" << sheight << " to " << iwidth << "*" + << iheight << ": " << e.what(); + throw composite_rescaler_failure(str.str()); + } + try { + s2(target, twidth, theight, &intermediate[0], iwidth, iheight); + } catch(composite_rescaler_failure& e) { + throw; + } catch(std::exception& e) { + std::ostringstream str; + str << "Failed to rescale from " << iwidth << "*" << iheight << " to " << twidth << "*" + << theight << ": " << e.what(); + throw composite_rescaler_failure(str.str()); + } + } +} + +rescaler& composite_rescaler(rescaler& s1, uint32_t iwidth, uint32_t iheight, rescaler& s2) +{ + return *new composite_rescaler_c(s1, iwidth, iheight, s2); +} + +rescaler_group::rescaler_group(rescaler& _default_rescaler) +{ + default_rescaler = &_default_rescaler; +} + +rescaler_group::~rescaler_group() +{ + delete default_rescaler; + for(auto i = special_rescalers.begin(); i != special_rescalers.end(); ++i) + delete(i->second); +} + +void rescaler_group::set_default_rescaler(rescaler& _default_rescaler) +{ + if(default_rescaler == &_default_rescaler) + return; + delete default_rescaler; + default_rescaler = &_default_rescaler; +} + +void rescaler_group::set_special_rescaler(uint32_t width, uint32_t height, rescaler& rescaler) +{ + std::pair key = std::make_pair(width, height); + if(special_rescalers.count(key) && special_rescalers[key] != &rescaler) + delete special_rescalers[key]; + special_rescalers[key] = &rescaler; +} + +void rescaler_group::operator()(uint8_t* target, uint32_t twidth, uint32_t theight, + const uint8_t* source, uint32_t swidth, uint32_t sheight) +{ + std::pair key = std::make_pair(swidth, sheight); + if(special_rescalers.count(key)) + (*special_rescalers[key])(target, twidth, theight, source, swidth, sheight); + else + (*default_rescaler)(target, twidth, theight, source, swidth, sheight); +} + +namespace +{ + rescaler* chain_rescalers(rescaler* previous, std::string nscaler, uint32_t width, uint32_t height) + { + if(!previous) + return &rescaler::make(nscaler); + return &composite_rescaler(rescaler::make(nscaler), width, height, *previous); + } +} + +struct parsed_scaler parse_rescaler_expression(const std::string& expr) +{ + std::string _expr = expr; + struct parsed_scaler s; + s.use_rescaler = NULL; + s.is_special = false; + std::string rescaler_name; + s.swidth = 0; + s.sheight = 0; + unsigned state = 0; //Number of words mod 3. + size_t baseoff = 0; //Next position to process. + char* x; + while(baseoff != std::string::npos) { + size_t nextspace = _expr.find(' ', baseoff); + //Split the word. + std::string word; + if(nextspace == std::string::npos) { + word = _expr.substr(baseoff); + baseoff = nextspace; + } else { + word = _expr.substr(baseoff, nextspace - baseoff); + baseoff = nextspace + 1; + } + if(word == "") + continue; //Ignore empty words. + switch(state % 3) { + case 0: + //This is rescaler name. + rescaler_name = word; + s.use_rescaler = chain_rescalers(s.use_rescaler, rescaler_name, s.swidth, s.sheight); + s.is_special = false; + break; + case 1: + //Width. + s.swidth = strtoul(word.c_str(), &x, 10); + if(*x || !s.swidth) { + std::ostringstream str; + str << "Bad width '" << word << "' for scaler."; + throw std::runtime_error(str.str()); + } + break; + case 2: + //Height. + s.sheight = strtoul(word.c_str(), &x, 10); + if(*x || !s.sheight) { + std::ostringstream str; + str << "Bad height '" << word << "' for scaler."; + throw std::runtime_error(str.str()); + } + s.is_special = true; + break; + } + state++; + } + if(state == 0) + throw std::runtime_error("Empty rescaler specification not allowed."); + if(state % 3 == 2) + throw std::runtime_error("With and height must be specified together"); + return s; +} + +rescaler& get_default_rescaler() +{ + return *(parse_rescaler_expression(DEFAULT_RESCALER).use_rescaler); +} + diff --git a/streamtools/resizer/bilinear.cpp b/streamtools/rescalers/bilinear.cpp similarity index 74% rename from streamtools/resizer/bilinear.cpp rename to streamtools/rescalers/bilinear.cpp index ef4ac92..a67f4a2 100644 --- a/streamtools/resizer/bilinear.cpp +++ b/streamtools/rescalers/bilinear.cpp @@ -1,4 +1,4 @@ -#include "resize-linear-separable.hpp" +#include "rescalers/linear-separable.hpp" #include #include #include @@ -20,5 +20,5 @@ namespace } } - simple_resizer_linear_separable r_bilinear("bilinear", compute_coefficients_bilinear); + simple_rescaler_linear_separable r_bilinear("bilinear", make_bound_method(compute_coefficients_bilinear)); } diff --git a/streamtools/rescalers/factory.hpp b/streamtools/rescalers/factory.hpp new file mode 100644 index 0000000..6920c92 --- /dev/null +++ b/streamtools/rescalers/factory.hpp @@ -0,0 +1,16 @@ +#ifndef _rescalers__factory__hpp__included__ +#define _rescalers__factory__hpp__included__ + +#include +#include +#include "rescalers/public.hpp" + +class rescaler_factory +{ +public: + rescaler_factory(const std::string& type); + virtual ~rescaler_factory(); + virtual rescaler& make(const std::string& type) = 0; +}; + +#endif diff --git a/streamtools/rescalers/hqx.cpp b/streamtools/rescalers/hqx.cpp new file mode 100644 index 0000000..a7bd797 --- /dev/null +++ b/streamtools/rescalers/hqx.cpp @@ -0,0 +1,118 @@ +#ifdef WITH_HQX +#include "rescalers/simple.hpp" +#include +extern "C" { +#include +} +#include +#include + + +#define RMETHOD_HQX2 0 +#define RMETHOD_HQX3 1 +#define RMETHOD_HQX4 2 +#define RMETHOD_HQX22 3 +#define RMETHOD_HQX32 4 +#define RMETHOD_HQX42 5 +#define RMETHOD_HQX2d 6 +#define RMETHOD_HQX3d 7 +#define RMETHOD_HQX4d 8 + +namespace +{ + bool initflag = false; + + void psize_dummy(uint32_t* src, uint32_t* dest, int width, int height) + { + memcpy(dest, src, 4 * width * height); + } + + void psize_double(uint32_t* src, uint32_t* dest, int width, int height) + { + for(size_t y = 0; (int)y < height; y++) + for(size_t x = 0; (int)x < width; x++) { + size_t dbaseindex = 4 * y * width + 2 * x; + size_t sbaseindex = y * width + x; + dest[dbaseindex] = dest[dbaseindex + 1] = dest[dbaseindex + 2 * width] = + dest[dbaseindex + 2 * width + 1] = src[sbaseindex]; + } + } + + typedef void(*rescale_t)(uint32_t*, uint32_t*, int, int); + int factors[] = {2, 3, 4, 4, 6, 8, 4, 6, 8}; + int pfactors[] = {1, 1, 1, 2, 2, 2, 2, 2, 2}; + rescale_t hqxfun[] = {hq2x_32, hq3x_32, hq4x_32, hq2x_32, hq3x_32, hq4x_32, + hq2x_32, hq3x_32, hq4x_32}; + rescale_t psizefun[] = {psize_dummy, psize_dummy, psize_dummy, hq2x_32, hq2x_32, + hq2x_32, psize_double, psize_double, psize_double}; + + //Read the frame data in src (swidth x sheight) and rescale it to dest (dwidth x dheight). + void rescale_frame(unsigned char* dest, unsigned dwidth, unsigned dheight, const unsigned char* src, + unsigned swidth, unsigned sheight, int algo) + { + unsigned char magic[4] = {255, 255, 255, 0}; + uint32_t* magic2 = (uint32_t*)magic; + uint32_t magic3 = ~*magic2; + uint32_t shiftscale = 0; + if(*magic2 > 0xFFFFFF) + shiftscale = 8; //Big-endian. + + if(!initflag) + hqxInit(); + initflag = true; + + if(dwidth % factors[algo] || dheight % factors[algo]) + throw std::runtime_error("hqx: Target image size must be multiple of scale factor"); + if(dwidth / factors[algo] != swidth || dheight / factors[algo] != sheight) + throw std::runtime_error("hqx: Ratio of source and destination sizes must be the scale factor"); + + uint32_t buffer1_width = dwidth / factors[algo]; + uint32_t buffer2_width = dwidth / pfactors[algo]; + uint32_t buffer3_width = dwidth; + uint32_t buffer1_height = dheight / factors[algo]; + uint32_t buffer2_height = dheight / pfactors[algo]; + uint32_t buffer3_height = dheight; + uint32_t* buffer1 = new uint32_t[buffer1_width * buffer1_height]; + uint32_t* buffer2 = new uint32_t[buffer2_width * buffer2_height]; + uint32_t* buffer3 = new uint32_t[buffer3_width * buffer3_height]; + uint32_t* __restrict__ _src = (uint32_t*)src; + + for(uint32_t y = 0; y < buffer1_height; y++) + for(uint32_t x = 0; x < buffer1_width; x++) + //Mask off high bits because HQX will crash otherwise. + buffer1[y * buffer1_width + x] = (_src[y * swidth + x] >> shiftscale) & 0xFFFFFF; + + //Do the rescale steps. + hqxfun[algo](buffer1, buffer2, buffer1_width, buffer1_height); + psizefun[algo](buffer2, buffer3, buffer2_width, buffer2_height); + + //Final copy out of buffer3 to destination. + for(size_t i = 0; i < buffer3_width * buffer3_height; i++) + buffer3[i] = (buffer3[i] << shiftscale) | magic3; + memcpy(dest, buffer3, 4 * dwidth * dheight); + + delete buffer1; + delete buffer2; + delete buffer3; + } + + simple_rescaler r_hqx2("hqx2", bind_last(make_bound_method(rescale_frame), RMETHOD_HQX2)); + simple_rescaler r_hqx3("hqx3", bind_last(make_bound_method(rescale_frame), RMETHOD_HQX3)); + simple_rescaler r_hqx4("hqx4", bind_last(make_bound_method(rescale_frame), RMETHOD_HQX4)); + simple_rescaler r_hqx22("hqx22", bind_last(make_bound_method(rescale_frame), RMETHOD_HQX22)); + simple_rescaler r_hqx32("hqx32", bind_last(make_bound_method(rescale_frame), RMETHOD_HQX32)); + simple_rescaler r_hqx42("hqx42", bind_last(make_bound_method(rescale_frame), RMETHOD_HQX42)); + simple_rescaler r_hqx2d("hqx2d", bind_last(make_bound_method(rescale_frame), RMETHOD_HQX2d)); + simple_rescaler r_hqx3d("hqx3d", bind_last(make_bound_method(rescale_frame), RMETHOD_HQX3d)); + simple_rescaler r_hqx4d("hqx4d", bind_last(make_bound_method(rescale_frame), RMETHOD_HQX4d)); +} +#endif diff --git a/streamtools/resizer/lanczos.cpp b/streamtools/rescalers/lanczos.cpp similarity index 60% rename from streamtools/resizer/lanczos.cpp rename to streamtools/rescalers/lanczos.cpp index d20ffe0..96add40 100644 --- a/streamtools/resizer/lanczos.cpp +++ b/streamtools/rescalers/lanczos.cpp @@ -1,4 +1,4 @@ -#include "resize-linear-separable.hpp" +#include "rescalers/linear-separable.hpp" #include #include #include @@ -15,10 +15,10 @@ namespace position_t twidth, unsigned& count, unsigned& base, int a) { if(a == 0) - throw std::runtime_error("Parameter alpha must be positive in lanczos resizer"); + throw std::runtime_error("Parameter alpha must be positive in lanczos rescaler"); if(2 * a + 1 <= a) - throw std::runtime_error("Parameter alpha way too large in lanczos resizer"); + throw std::runtime_error("Parameter alpha way too large in lanczos rescaler"); if(2 * a + 1 > MAXCOEFFICIENTS) throw std::runtime_error("Parameter alpha value would require more coefficients than " @@ -73,10 +73,15 @@ namespace } } - simple_resizer_linear_separable r_average("average", compute_coefficients_average); - simple_resizer_linear_separable r_lanczos1("lanczos1", compute_coefficients_lanczos, 1); - simple_resizer_linear_separable r_lanczos2("lanczos2", compute_coefficients_lanczos, 2); - simple_resizer_linear_separable r_lanczos3("lanczos3", compute_coefficients_lanczos, 3); - simple_resizer_linear_separable r_lanczos4("lanczos4", compute_coefficients_lanczos, 4); - simple_resizer_linear_separable r_lanczos5("lanczos5", compute_coefficients_lanczos, 5); + simple_rescaler_linear_separable r_average("average", make_bound_method(compute_coefficients_average)); + simple_rescaler_linear_separable r_lanczos1("lanczos1", bind_last(make_bound_method(compute_coefficients_lanczos), 1)); + simple_rescaler_linear_separable r_lanczos2("lanczos2", bind_last(make_bound_method(compute_coefficients_lanczos), 2)); + simple_rescaler_linear_separable r_lanczos3("lanczos3", bind_last(make_bound_method(compute_coefficients_lanczos), 3)); + simple_rescaler_linear_separable r_lanczos4("lanczos4", bind_last(make_bound_method(compute_coefficients_lanczos), 4)); + simple_rescaler_linear_separable r_lanczos5("lanczos5", bind_last(make_bound_method(compute_coefficients_lanczos), 5)); } diff --git a/streamtools/resizer/letterbox.cpp b/streamtools/rescalers/letterbox.cpp similarity index 73% rename from streamtools/resizer/letterbox.cpp rename to streamtools/rescalers/letterbox.cpp index e31151d..36ffeea 100644 --- a/streamtools/resizer/letterbox.cpp +++ b/streamtools/rescalers/letterbox.cpp @@ -1,4 +1,4 @@ -#include "resize-linear-separable.hpp" +#include "rescalers/linear-separable.hpp" #include #include #include @@ -18,5 +18,5 @@ namespace } } - simple_resizer_linear_separable r_letterbox("letterbox", compute_coefficients_letterbox); + simple_rescaler_linear_separable r_letterbox("letterbox", make_bound_method(compute_coefficients_letterbox)); } diff --git a/streamtools/resizer/letterbox2.cpp b/streamtools/rescalers/letterbox2.cpp similarity index 74% rename from streamtools/resizer/letterbox2.cpp rename to streamtools/rescalers/letterbox2.cpp index e0ff5a0..19c7258 100644 --- a/streamtools/resizer/letterbox2.cpp +++ b/streamtools/rescalers/letterbox2.cpp @@ -1,4 +1,4 @@ -#include "resize-linear-separable.hpp" +#include "rescalers/linear-separable.hpp" #include #include #include @@ -19,5 +19,5 @@ namespace } } - simple_resizer_linear_separable r_letterbox("letterbox2", compute_coefficients_letterbox); + simple_rescaler_linear_separable r_letterbox("letterbox2", make_bound_method(compute_coefficients_letterbox)); } diff --git a/streamtools/rescalers/linear-separable.cpp b/streamtools/rescalers/linear-separable.cpp new file mode 100644 index 0000000..de05e9e --- /dev/null +++ b/streamtools/rescalers/linear-separable.cpp @@ -0,0 +1,109 @@ +#include "rescalers/linear-separable.hpp" + +#define MAXCOEFFICIENTS 256 + +void rescaler_linear_separable::operator()(uint8_t* target, uint32_t twidth, uint32_t theight, + const uint8_t* source, uint32_t swidth, uint32_t sheight) +{ + float coeffs[MAXCOEFFICIENTS]; + unsigned count; + unsigned base; + float* interm; + + interm = new float[4 * twidth * sheight]; + + for(unsigned x = 0; x < twidth; x++) { + count = 0xDEADBEEF; + base = 0xDEADBEEF; + compute_coeffs(coeffs, (position_t)x * swidth, twidth, swidth, twidth, count, base); + /* Normalize the coefficients. */ + float sum = 0; + for(unsigned i = 0; i < count; i++) + sum += coeffs[i]; + for(unsigned i = 0; i < count; i++) + coeffs[i] /= sum; + for(unsigned y = 0; y < sheight; y++) { + float vr = 0, vg = 0, vb = 0, va = 0; + for(unsigned k = 0; k < count; k++) { + uint32_t sampleaddr = 4 * y * swidth + 4 * (k + base); + vr += coeffs[k] * source[sampleaddr + 0]; + vg += coeffs[k] * source[sampleaddr + 1]; + vb += coeffs[k] * source[sampleaddr + 2]; + va += coeffs[k] * source[sampleaddr + 3]; + } + interm[y * 4 * twidth + 4 * x + 0] = vr; + interm[y * 4 * twidth + 4 * x + 1] = vg; + interm[y * 4 * twidth + 4 * x + 2] = vb; + interm[y * 4 * twidth + 4 * x + 3] = va; + } + } + + for(unsigned y = 0; y < theight; y++) { + count = 0; + base = 0; + compute_coeffs(coeffs, (position_t)y * sheight, theight, sheight, theight, count, base); + /* Normalize the coefficients. */ + float sum = 0; + for(unsigned i = 0; i < count; i++) + sum += coeffs[i]; + for(unsigned i = 0; i < count; i++) + coeffs[i] /= sum; + for(unsigned x = 0; x < twidth; x++) { + float vr = 0, vg = 0, vb = 0, va = 0; + for(unsigned k = 0; k < count; k++) { + vr += coeffs[k] * interm[(base + k) * 4 * twidth + x * 4 + 0]; + vg += coeffs[k] * interm[(base + k) * 4 * twidth + x * 4 + 1]; + vb += coeffs[k] * interm[(base + k) * 4 * twidth + x * 4 + 2]; + va += coeffs[k] * interm[(base + k) * 4 * twidth + x * 4 + 3]; + } + int wr = (int)vr; + int wg = (int)vg; + int wb = (int)vb; + int wa = (int)va; + wr = (wr < 0) ? 0 : ((wr > 255) ? 255 : wr); + wg = (wg < 0) ? 0 : ((wg > 255) ? 255 : wg); + wb = (wb < 0) ? 0 : ((wb > 255) ? 255 : wb); + wa = (wa < 0) ? 0 : ((wa > 255) ? 255 : wa); + + target[y * 4 * twidth + 4 * x] = (unsigned char)wr; + target[y * 4 * twidth + 4 * x + 1] = (unsigned char)wg; + target[y * 4 * twidth + 4 * x + 2] = (unsigned char)wb; + target[y * 4 * twidth + 4 * x + 3] = (unsigned char)wa; + } + } + delete[] interm; +} + + +namespace +{ + class simple_rescaler_linear_separable_c : public rescaler_linear_separable + { + public: + simple_rescaler_linear_separable_c(bound_coeff_function_t _coeffs_fn) + { + coeffs_fn = _coeffs_fn; + } + + void compute_coeffs(float* coeffs, position_t num, position_t denum, position_t osize, + position_t nsize, unsigned& base, unsigned& coeffcount) + { + coeffs_fn(coeffs, num, denum, osize, nsize, base, coeffcount); + } + + private: + bound_coeff_function_t coeffs_fn; + }; +} + +simple_rescaler_linear_separable::simple_rescaler_linear_separable(const std::string& type, + bound_coeff_function_t _coeffs_fn) + : rescaler_factory(type) +{ + coeffs_fn = _coeffs_fn; +} + +rescaler& simple_rescaler_linear_separable::make(const std::string& type) +{ + return *new simple_rescaler_linear_separable_c(coeffs_fn); +} diff --git a/streamtools/rescalers/linear-separable.hpp b/streamtools/rescalers/linear-separable.hpp new file mode 100644 index 0000000..7e09464 --- /dev/null +++ b/streamtools/rescalers/linear-separable.hpp @@ -0,0 +1,39 @@ +#ifndef _rescalers__linear_separable__hpp__included__ +#define _rescalers__linear_separable__hpp__included__ + +#include "rescalers/factory.hpp" +#include "bound-method.hpp" + +#define MAXCOEFFICIENTS 256 + +typedef signed long long position_t; + +typedef bound_method + bound_coeff_function_t; + + +class rescaler_linear_separable : public rescaler +{ +public: + void operator()(uint8_t* target, uint32_t twidth, uint32_t theight, + const uint8_t* source, uint32_t swidth, uint32_t sheight); +protected: + //Fill coeffs, base and coeffcount. Coeffs is set of floating-point coefficients for pixels + //starting from pixel number base (zero-based) and numbering coeffcount. Take care not to refer + //to pixel outside range [0,width). Twidth is target width. + //num / denum gives position of pixel being approximated. The coordinate range is [0, width), + //width giving the width of original data. + virtual void compute_coeffs(float* coeffs, position_t num, position_t denum, position_t width, + position_t twidth, unsigned& base, unsigned& coeffcount) = 0; +}; + +class simple_rescaler_linear_separable : public rescaler_factory +{ +public: + simple_rescaler_linear_separable(const std::string& type, bound_coeff_function_t _coeffs_fn); + rescaler& make(const std::string& type); +private: + bound_coeff_function_t coeffs_fn; +}; + +#endif diff --git a/streamtools/resizer/nearest.cpp b/streamtools/rescalers/nearest.cpp similarity index 82% rename from streamtools/resizer/nearest.cpp rename to streamtools/rescalers/nearest.cpp index 2a9487b..ea58494 100644 --- a/streamtools/resizer/nearest.cpp +++ b/streamtools/rescalers/nearest.cpp @@ -1,4 +1,4 @@ -#include "resize.hpp" +#include "rescalers/simple.hpp" #include #include #include @@ -12,7 +12,7 @@ namespace return (uint32_t)(((uint64_t)value * trange + srange / 2) / srange); } - void do_resize(uint8_t* target, uint32_t twidth, uint32_t theight, + void do_rescale(uint8_t* target, uint32_t twidth, uint32_t theight, const uint8_t* source, uint32_t swidth, uint32_t sheight) { uint32_t* __restrict__ src = (uint32_t*)source; @@ -26,5 +26,5 @@ namespace } } - simple_resizer factory("nearest", do_resize); + simple_rescaler factory("nearest", make_bound_method(do_rescale)); } diff --git a/streamtools/rescalers/public.hpp b/streamtools/rescalers/public.hpp new file mode 100644 index 0000000..32e1a75 --- /dev/null +++ b/streamtools/rescalers/public.hpp @@ -0,0 +1,46 @@ +#ifndef _rescalers__public__hpp__included__ +#define _rescalers__public__hpp__included__ + +#include +#include +#include +#include + +class rescaler +{ +public: + virtual ~rescaler(); + virtual void operator()(uint8_t* target, uint32_t twidth, uint32_t theight, + const uint8_t* source, uint32_t swidth, uint32_t sheight) = 0; + static rescaler& make(const std::string& type); +}; + +struct parsed_scaler +{ + bool is_special; + uint32_t swidth; //Meaningful only if is_special is set. + uint32_t sheight; //Meaningful only if is_special is set. + rescaler* use_rescaler; +}; + +std::string get_rescaler_string(); +std::list get_rescaler_list(); +rescaler& composite_rescaler(rescaler& s1, uint32_t iwidth, uint32_t iheight, rescaler& s2); +struct parsed_scaler parse_rescaler_expression(const std::string& expr); +rescaler& get_default_rescaler(); + +class rescaler_group +{ +public: + rescaler_group(rescaler& _default_rescaler); + ~rescaler_group(); + void set_default_rescaler(rescaler& _default_rescaler); + void set_special_rescaler(uint32_t width, uint32_t height, rescaler& rescaler); + void operator()(uint8_t* target, uint32_t twidth, uint32_t theight, + const uint8_t* source, uint32_t swidth, uint32_t sheight); +private: + rescaler* default_rescaler; + std::map, rescaler*> special_rescalers; +}; + +#endif diff --git a/streamtools/rescalers/simple.cpp b/streamtools/rescalers/simple.cpp new file mode 100644 index 0000000..3c488a4 --- /dev/null +++ b/streamtools/rescalers/simple.cpp @@ -0,0 +1,37 @@ +#include "rescalers/public.hpp" +#include "rescalers/factory.hpp" +#include "rescalers/simple.hpp" +#include +#include + +namespace +{ + class simple_rescaler_c : public rescaler + { + public: + simple_rescaler_c(bound_scaler_t _rescale_fn) + { + rescale_fn = _rescale_fn; + } + + void operator()(uint8_t* target, uint32_t twidth, uint32_t theight, + const uint8_t* source, uint32_t swidth, uint32_t sheight) + { + rescale_fn(target, twidth, theight, source, swidth, sheight); + } + + private: + bound_scaler_t rescale_fn; + }; +} + +simple_rescaler::simple_rescaler(const std::string& type, bound_scaler_t _fn) + : rescaler_factory(type) +{ + fn = _fn; +} + +rescaler& simple_rescaler::make(const std::string& type) +{ + return *new simple_rescaler_c(fn); +} diff --git a/streamtools/rescalers/simple.hpp b/streamtools/rescalers/simple.hpp new file mode 100644 index 0000000..5181092 --- /dev/null +++ b/streamtools/rescalers/simple.hpp @@ -0,0 +1,21 @@ +#ifndef _rescalers__simple__hpp__included__ +#define _rescalers__simple__hpp__included__ + +#include +#include +#include "bound-method.hpp" +#include "rescalers/factory.hpp" + +//The parameters in order are target, twidth, theight, source, swidth and sheight. +typedef bound_method bound_scaler_t; + +class simple_rescaler : public rescaler_factory +{ +public: + simple_rescaler(const std::string& type, bound_scaler_t _fn); + rescaler& make(const std::string& type); +private: + bound_scaler_t fn; +}; + +#endif diff --git a/streamtools/rescalers/xdrop9.cpp b/streamtools/rescalers/xdrop9.cpp new file mode 100644 index 0000000..6899db2 --- /dev/null +++ b/streamtools/rescalers/xdrop9.cpp @@ -0,0 +1,25 @@ +#include "rescalers/simple.hpp" +#include +#include +#include + +namespace +{ + void do_rescale(uint8_t* target, uint32_t twidth, uint32_t theight, + const uint8_t* source, uint32_t swidth, uint32_t sheight) + { + uint32_t* __restrict__ src = (uint32_t*)source; + uint32_t* __restrict__ dest = (uint32_t*)target; + + if(theight != sheight || twidth % 8 || swidth % 9 || swidth / 9 * 8 != twidth) + throw std::runtime_error("xdrop9: Incorrect scale factor"); + + for(uint32_t y = 0; y < theight; y++) + for(uint32_t x = 0; x < twidth; x++) { + uint32_t _x = x / 8 * 9 + x % 8; + dest[y * twidth + x] = src[y * swidth + _x]; + } + } + + simple_rescaler factory("xdrop9", make_bound_method(do_rescale)); +} diff --git a/streamtools/resize-linear-separable.cpp b/streamtools/resize-linear-separable.cpp deleted file mode 100644 index 98effbc..0000000 --- a/streamtools/resize-linear-separable.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "resize-linear-separable.hpp" - -#define MAXCOEFFICIENTS 256 - -void resizer_linear_separable::operator()(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight) -{ - float coeffs[MAXCOEFFICIENTS]; - unsigned count; - unsigned base; - float* interm; - - interm = new float[3 * twidth * sheight]; - - for(unsigned x = 0; x < twidth; x++) { - count = 0xDEADBEEF; - base = 0xDEADBEEF; - compute_coeffs(coeffs, (position_t)x * swidth, twidth, swidth, twidth, count, base); - /* Normalize the coefficients. */ - float sum = 0; - for(unsigned i = 0; i < count; i++) - sum += coeffs[i]; - for(unsigned i = 0; i < count; i++) - coeffs[i] /= sum; - for(unsigned y = 0; y < sheight; y++) { - float vr = 0, vg = 0, vb = 0; - for(unsigned k = 0; k < count; k++) { - uint32_t sampleaddr = 4 * y * swidth + 4 * (k + base); - vr += coeffs[k] * source[sampleaddr + 0]; - vg += coeffs[k] * source[sampleaddr + 1]; - vb += coeffs[k] * source[sampleaddr + 2]; - } - interm[y * 3 * twidth + 3 * x + 0] = vr; - interm[y * 3 * twidth + 3 * x + 1] = vg; - interm[y * 3 * twidth + 3 * x + 2] = vb; - } - } - - for(unsigned y = 0; y < theight; y++) { - count = 0; - base = 0; - compute_coeffs(coeffs, (position_t)y * sheight, theight, sheight, theight, count, base); - /* Normalize the coefficients. */ - float sum = 0; - for(unsigned i = 0; i < count; i++) - sum += coeffs[i]; - for(unsigned i = 0; i < count; i++) - coeffs[i] /= sum; - for(unsigned x = 0; x < twidth; x++) { - float vr = 0, vg = 0, vb = 0; - for(unsigned k = 0; k < count; k++) { - vr += coeffs[k] * interm[(base + k) * 3 * twidth + x * 3 + 0]; - vg += coeffs[k] * interm[(base + k) * 3 * twidth + x * 3 + 1]; - vb += coeffs[k] * interm[(base + k) * 3 * twidth + x * 3 + 2]; - } - int wr = (int)vr; - int wg = (int)vg; - int wb = (int)vb; - wr = (wr < 0) ? 0 : ((wr > 255) ? 255 : wr); - wg = (wg < 0) ? 0 : ((wg > 255) ? 255 : wg); - wb = (wb < 0) ? 0 : ((wb > 255) ? 255 : wb); - - target[y * 4 * twidth + 4 * x] = (unsigned char)wr; - target[y * 4 * twidth + 4 * x + 1] = (unsigned char)wg; - target[y * 4 * twidth + 4 * x + 2] = (unsigned char)wb; - target[y * 4 * twidth + 4 * x + 3] = 0; - } - } - delete[] interm; -} - - -namespace -{ - class simple_resizer_linear_separable_c : public resizer_linear_separable - { - public: - simple_resizer_linear_separable_c(void(*_coeffs_fn)(float* coeffs, position_t num, - position_t denum, position_t osize, position_t nsize, unsigned& base, unsigned& coeffcount)) - { - coeffs_fn = _coeffs_fn; - } - - void compute_coeffs(float* coeffs, position_t num, position_t denum, position_t osize, - position_t nsize, unsigned& base, unsigned& coeffcount) - { - coeffs_fn(coeffs, num, denum, osize, nsize, base, coeffcount); - } - - private: - void(*coeffs_fn)(float* coeffs, position_t num, position_t denum, position_t osize, - position_t nsize, unsigned& base, unsigned& coeffcount); - }; - - class simple_resizer_linear_separable_c2 : public resizer_linear_separable - { - public: - simple_resizer_linear_separable_c2(void(*_coeffs_fn)(float* coeffs, position_t num, - position_t denum, position_t osize, position_t nsize, unsigned& base, unsigned& coeffcount, - int algo), int _algo) - { - coeffs_fn = _coeffs_fn; - algo = _algo; - } - - void compute_coeffs(float* coeffs, position_t num, position_t denum, position_t osize, - position_t nsize, unsigned& base, unsigned& coeffcount) - { - coeffs_fn(coeffs, num, denum, osize, nsize, base, coeffcount, algo); - } - - private: - void(*coeffs_fn)(float* coeffs, position_t num, position_t denum, position_t osize, - position_t nsize, unsigned& base, unsigned& coeffcount, int algo); - int algo; - }; -} - -simple_resizer_linear_separable::simple_resizer_linear_separable(const std::string& type, - void(*_coeffs_fn)(float* coeffs, position_t num, position_t denum, position_t osize, - position_t nsize, unsigned& base, unsigned& coeffcount)) - : resizer_factory(type) -{ - coeffs_fn = _coeffs_fn; - coeffs_fn2 = NULL; - algo = 0; -} - -simple_resizer_linear_separable::simple_resizer_linear_separable(const std::string& type, - void(*_coeffs_fn)(float* coeffs, position_t num, position_t denum, position_t osize, - position_t nsize, unsigned& base, unsigned& coeffcount, int algo), int _algo) - : resizer_factory(type) -{ - coeffs_fn = NULL; - coeffs_fn2 = _coeffs_fn; - algo = _algo; -} - -resizer& simple_resizer_linear_separable::make(const std::string& type) -{ - if(coeffs_fn) - return *new simple_resizer_linear_separable_c(coeffs_fn); - else - return *new simple_resizer_linear_separable_c2(coeffs_fn2, algo); -} diff --git a/streamtools/resize-linear-separable.hpp b/streamtools/resize-linear-separable.hpp deleted file mode 100644 index 8c3144c..0000000 --- a/streamtools/resize-linear-separable.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _resize_linear_separable__hpp__included__ -#define _resize_linear_separable__hpp__included__ - -#include "resize.hpp" - -#define MAXCOEFFICIENTS 256 - -typedef signed long long position_t; - - - -class resizer_linear_separable : public resizer -{ -public: - void operator()(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight); -protected: - //Fill coeffs, base and coeffcount. Coeffs is set of floating-point coefficients for pixels - //starting from pixel number base (zero-based) and numbering coeffcount. Take care not to refer - //to pixel outside range [0,width). Twidth is target width. - //num / denum gives position of pixel being approximated. The coordinate range is [0, width), - //width giving the width of original data. - virtual void compute_coeffs(float* coeffs, position_t num, position_t denum, position_t width, - position_t twidth, unsigned& base, unsigned& coeffcount) = 0; -}; - -class simple_resizer_linear_separable : public resizer_factory -{ -public: - simple_resizer_linear_separable(const std::string& type, void(*coeffs_fn)(float* coeffs, position_t num, - position_t denum, position_t width, position_t twidth, unsigned& base, unsigned& coeffcount)); - simple_resizer_linear_separable(const std::string& type, void(*coeffs_fn)(float* coeffs, position_t num, - position_t denum, position_t width, position_t twidth, unsigned& base, unsigned& coeffcount, - int algo), int algo); - resizer& make(const std::string& type); -private: - void(*coeffs_fn)(float* coeffs, position_t newsize, position_t oldsize, position_t width, position_t twidth, - unsigned& base, unsigned& coeffcount); - void(*coeffs_fn2)(float* coeffs, position_t newsize, position_t oldsize, position_t width, - position_t twidth, unsigned& base, unsigned& coeffcount, int algo); - int algo; -}; - -#endif diff --git a/streamtools/resize.cpp b/streamtools/resize.cpp index 29cced1..be94175 100644 --- a/streamtools/resize.cpp +++ b/streamtools/resize.cpp @@ -196,7 +196,7 @@ size_t image_frame_rgbx::get_data_size() const return 4 * width * height; } -image_frame_rgbx& image_frame_rgbx::resize(uint32_t nwidth, uint32_t nheight, resizer& using_resizer) +image_frame_rgbx& image_frame_rgbx::resize(uint32_t nwidth, uint32_t nheight, rescaler_group& rescalers) { if(width == nwidth && height == nheight) return *this; @@ -206,118 +206,7 @@ image_frame_rgbx& image_frame_rgbx::resize(uint32_t nwidth, uint32_t nheight, re memset(newf->get_pixels(), 0, newf->get_data_size()); return *newf; } - using_resizer(newf->get_pixels(), nwidth, nheight, get_pixels(), width, height); + rescalers(newf->get_pixels(), nwidth, nheight, get_pixels(), width, height); return *newf; } -resizer::~resizer() -{ -} - -std::map* resizer_factory::factories; - -resizer_factory::~resizer_factory() -{ -} - -resizer_factory::resizer_factory(const std::string& type) -{ - if(!factories) - factories = new std::map(); - (*factories)[type] = this; -} - -resizer& resizer_factory::make_by_type(const std::string& type) -{ - if(!factories || !factories->count(type)) - throw std::runtime_error("Unknown output driver type"); - return (*factories)[type]->make(type); -} - -std::string get_resizer_list() -{ - bool first = true; - if(!resizer_factory::factories) - return ""; - std::string c; - std::map& f = *resizer_factory::factories; - for(std::map::iterator i = f.begin(); i != f.end(); ++i) { - if(first) - c = i->first; - else - c = c + " " + i->first; - first = false; - } - return c; -} - -namespace -{ - class simple_resizer_c : public resizer - { - public: - simple_resizer_c(void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight)) - { - resize_fn = _resize_fn; - } - - void operator()(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight) - { - resize_fn(target, twidth, theight, source, swidth, sheight); - } - - private: - void(*resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight); - }; - - class simple_resizer_c2 : public resizer - { - public: - simple_resizer_c2(void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo), int _algo) - { - resize_fn = _resize_fn; - algo = _algo; - } - - void operator()(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight) - { - resize_fn(target, twidth, theight, source, swidth, sheight, algo); - } - - private: - void(*resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo); - int algo; - }; -} - -simple_resizer::simple_resizer(const std::string& type, void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight)) - : resizer_factory(type) -{ - resize_fn = _resize_fn; - resize_fn2 = NULL; - algo = 0; -} - -simple_resizer::simple_resizer(const std::string& type, void(*_resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo), int _algo) - : resizer_factory(type) -{ - resize_fn = NULL; - resize_fn2 = _resize_fn; - algo = _algo; -} - -resizer& simple_resizer::make(const std::string& type) -{ - if(resize_fn) - return *new simple_resizer_c(resize_fn); - else - return *new simple_resizer_c2(resize_fn2, algo); -} diff --git a/streamtools/resize.hpp b/streamtools/resize.hpp dissimilarity index 60% index 9ef50ca..cacbb1c 100644 --- a/streamtools/resize.hpp +++ b/streamtools/resize.hpp @@ -1,68 +1,32 @@ -#ifndef _resize__hpp__included__ -#define _resize__hpp__included__ - -#include -#include -#include "newpacket.hpp" - -class resizer -{ -public: - virtual ~resizer(); - virtual void operator()(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight) = 0; -}; - -class resizer_factory -{ -public: - resizer_factory(const std::string& type); - virtual ~resizer_factory(); - static resizer& make_by_type(const std::string& type); - virtual resizer& make(const std::string& type) = 0; -private: - static std::map* factories; - friend std::string get_resizer_list(); -}; - -class simple_resizer : public resizer_factory -{ -public: - simple_resizer(const std::string& type, void(*resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight)); - simple_resizer(const std::string& type, void(*resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight, int algo), int algo); - resizer& make(const std::string& type); -private: - void(*resize_fn)(uint8_t* target, uint32_t twidth, uint32_t theight, const uint8_t* source, uint32_t swidth, - uint32_t sheight); - void(*resize_fn2)(uint8_t* target, uint32_t twidth, uint32_t theight, const uint8_t* source, uint32_t swidth, - uint32_t sheight, int algo); - int algo; -}; - - -struct image_frame_rgbx -{ -public: - image_frame_rgbx(uint32_t width, uint32_t height); - image_frame_rgbx(struct packet& p); - ~image_frame_rgbx(); - image_frame_rgbx(const image_frame_rgbx& x); - image_frame_rgbx& operator=(const image_frame_rgbx& x); - uint32_t get_height() const; - uint32_t get_width() const; - unsigned char* get_pixels(); //RGBx data. - const unsigned char* get_pixels() const; //RGBx data. - size_t get_data_size() const; //Bytes. - //This returns the frame itself if it is already of suitable size. - image_frame_rgbx& resize(uint32_t nwidth, uint32_t nheight, resizer& using_resizer); -private: - uint32_t width; - uint32_t height; - unsigned char* imagedata; //RGBx. -}; - -std::string get_resizer_list(); - -#endif +#ifndef _resize__hpp__included__ +#define _resize__hpp__included__ + +#include +#include +#include "newpacket.hpp" +#include "rescalers/public.hpp" + +struct image_frame_rgbx +{ +public: + image_frame_rgbx(uint32_t width, uint32_t height); + image_frame_rgbx(struct packet& p); + ~image_frame_rgbx(); + image_frame_rgbx(const image_frame_rgbx& x); + image_frame_rgbx& operator=(const image_frame_rgbx& x); + uint32_t get_height() const; + uint32_t get_width() const; + unsigned char* get_pixels(); //RGBx data. + const unsigned char* get_pixels() const; //RGBx data. + size_t get_data_size() const; //Bytes. + //This returns the frame itself if it is already of suitable size. + image_frame_rgbx& resize(uint32_t nwidth, uint32_t nheight, rescaler_group& rescalers); +private: + uint32_t width; + uint32_t height; + unsigned char* imagedata; //RGBx. +}; + +std::string get_resizer_list(); + +#endif diff --git a/streamtools/resizer/hqx.cpp b/streamtools/resizer/hqx.cpp deleted file mode 100644 index 9609fdb..0000000 --- a/streamtools/resizer/hqx.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#ifdef WITH_HQX -#include "resize.hpp" -#include -extern "C" { -#include -} -#include -#include - - -#define RMETHOD_HQX2 0 -#define RMETHOD_HQX3 1 -#define RMETHOD_HQX4 2 -#define RMETHOD_HQX22 3 -#define RMETHOD_HQX32 4 -#define RMETHOD_HQX42 5 -#define RMETHOD_HQX2d 6 -#define RMETHOD_HQX3d 7 -#define RMETHOD_HQX4d 8 - -namespace -{ - bool initflag = false; - - inline uint32_t nnscale(uint32_t value, uint32_t trange, uint32_t srange) - { - //x / trange is as good approximation for value / srange as possible. - //=> x is as good approximation for value * trange / srange as possible. - return (uint32_t)(((uint64_t)value * trange + srange / 2) / srange); - } - - void psize_dummy(uint32_t* src, uint32_t* dest, int width, int height) - { - memcpy(dest, src, 4 * width * height); - } - - void psize_double(uint32_t* src, uint32_t* dest, int width, int height) - { - for(size_t y = 0; (int)y < height; y++) - for(size_t x = 0; (int)x < width; x++) { - size_t dbaseindex = 4 * y * width + 2 * x; - size_t sbaseindex = y * width + x; - dest[dbaseindex] = dest[dbaseindex + 1] = dest[dbaseindex + 2 * width] = - dest[dbaseindex + 2 * width + 1] = src[sbaseindex]; - } - } - - typedef void(*resize_t)(uint32_t*, uint32_t*, int, int); - int factors[] = {2, 3, 4, 4, 6, 8, 4, 6, 8}; - int pfactors[] = {1, 1, 1, 2, 2, 2, 2, 2, 2}; - resize_t hqxfun[] = {hq2x_32, hq3x_32, hq4x_32, hq2x_32, hq3x_32, hq4x_32, - hq2x_32, hq3x_32, hq4x_32}; - resize_t psizefun[] = {psize_dummy, psize_dummy, psize_dummy, hq2x_32, hq2x_32, - hq2x_32, psize_double, psize_double, psize_double}; - - //Read the frame data in src (swidth x sheight) and resize it to dest (dwidth x dheight). - void resize_frame(unsigned char* dest, unsigned dwidth, unsigned dheight, const unsigned char* src, - unsigned swidth, unsigned sheight, int algo) - { - char magic[4] = {(char)255, (char)255, (char)255, 0}; - uint32_t* magic2 = (uint32_t*)magic; - uint32_t shiftscale = 0; - if(*magic2 > 0xFFFFFF) - shiftscale = 8; //Big-endian. - - if(!initflag) - hqxInit(); - initflag = true; - - if(dwidth % factors[algo] || dheight % factors[algo]) - throw std::runtime_error("hqx: Target image size must be multiple of scale factor"); - - uint32_t buffer1_width = dwidth / factors[algo]; - uint32_t buffer2_width = dwidth / pfactors[algo]; - uint32_t buffer3_width = dwidth; - uint32_t buffer1_height = dheight / factors[algo]; - uint32_t buffer2_height = dheight / pfactors[algo]; - uint32_t buffer3_height = dheight; - uint32_t* buffer1 = new uint32_t[buffer1_width * buffer1_height]; - uint32_t* buffer2 = new uint32_t[buffer2_width * buffer2_height]; - uint32_t* buffer3 = new uint32_t[buffer3_width * buffer3_height]; - uint32_t* __restrict__ _src = (uint32_t*)src; - - for(uint32_t y = 0; y < buffer1_height; y++) - for(uint32_t x = 0; x < buffer1_width; x++) { - uint32_t _x = nnscale(x, swidth, buffer1_width); - uint32_t _y = nnscale(y, sheight, buffer1_height); - buffer1[y * buffer1_width + x] = _src[_y * swidth + _x] >> shiftscale; - } - - //Do the resize steps. - hqxfun[algo](buffer1, buffer2, buffer1_width, buffer1_height); - psizefun[algo](buffer2, buffer3, buffer2_width, buffer2_height); - - //Final copy out of buffer3 to destination. - for(size_t i = 0; i < buffer3_width * buffer3_height; i++) - buffer3[i] <<= shiftscale; - memcpy(dest, buffer3, 4 * dwidth * dheight); - - delete buffer1; - delete buffer2; - delete buffer3; - } - - simple_resizer r_hqx2("hqx2", resize_frame, RMETHOD_HQX2); - simple_resizer r_hqx3("hqx3", resize_frame, RMETHOD_HQX3); - simple_resizer r_hqx4("hqx4", resize_frame, RMETHOD_HQX4); - simple_resizer r_hqx22("hqx22", resize_frame, RMETHOD_HQX22); - simple_resizer r_hqx32("hqx32", resize_frame, RMETHOD_HQX32); - simple_resizer r_hqx42("hqx42", resize_frame, RMETHOD_HQX42); - simple_resizer r_hqx2d("hqx2d", resize_frame, RMETHOD_HQX2d); - simple_resizer r_hqx3d("hqx3d", resize_frame, RMETHOD_HQX3d); - simple_resizer r_hqx4d("hqx4d", resize_frame, RMETHOD_HQX4d); -} -#endif diff --git a/streamtools/resizer/test.cpp b/streamtools/resizer/test.cpp deleted file mode 100644 index 79b2c65..0000000 --- a/streamtools/resizer/test.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include -#include "resize.hpp" - -namespace -{ - inline uint32_t nnscale(uint32_t value, uint32_t trange, uint32_t srange) - { - //x / trange is as good approximation for value / srange as possible. - //=> x is as good approximation for value * trange / srange as possible. - return (uint32_t)(((uint64_t)value * trange + srange / 2) / srange); - } - - void do_resize(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight) - { - uint32_t* __restrict__ src = (uint32_t*)source; - uint32_t* __restrict__ dest = (uint32_t*)target; - - for(uint32_t y = 0; y < sheight; y++) - for(uint32_t x = 0; x < swidth; x++) { - uint32_t _x = nnscale(x, twidth, swidth); - uint32_t _y = nnscale(y, theight, sheight); - dest[_y * twidth + _x] = src[y * swidth + x]; - } - } - - simple_resizer factory("test", do_resize); -} diff --git a/streamtools/resizer/xdrop9.cpp b/streamtools/resizer/xdrop9.cpp deleted file mode 100644 index 321c0f8..0000000 --- a/streamtools/resizer/xdrop9.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "resize.hpp" -#include -#include -#include - -namespace -{ - inline uint32_t nnscale(uint32_t value, uint32_t trange, uint32_t srange) - { - //x / trange is as good approximation for value / srange as possible. - //=> x is as good approximation for value * trange / srange as possible. - return (uint32_t)(((uint64_t)value * trange + srange / 2) / srange); - } - - void do_resize(uint8_t* target, uint32_t twidth, uint32_t theight, - const uint8_t* source, uint32_t swidth, uint32_t sheight) - { - uint32_t* __restrict__ src = (uint32_t*)source; - uint32_t* __restrict__ dest = (uint32_t*)target; - uint32_t pwidth = swidth * 8 / 9 + swidth % 9; - - for(uint32_t y = 0; y < theight; y++) - for(uint32_t x = 0; x < twidth; x++) { - uint32_t _x = nnscale(x, pwidth, twidth); - uint32_t _y = nnscale(y, sheight, theight); - _x = _x / 8 * 9 + _x % 8; - dest[y * twidth + x] = src[_y * swidth + _x]; - } - } - - simple_resizer factory("xdrop9", do_resize); -} diff --git a/streamtools/testresizer.cpp b/streamtools/testresizer.cpp index a06a235..ff1a7bb 100644 --- a/streamtools/testresizer.cpp +++ b/streamtools/testresizer.cpp @@ -1,6 +1,7 @@ #include "SDL_image.h" #include "SDL.h" #include "resize.hpp" +#include "rescalers/public.hpp" #include #include #include @@ -10,6 +11,18 @@ #include "newpacket.hpp" #include +namespace +{ + bool do_quit_on(SDL_Event* e) + { + if(e->type == SDL_QUIT) + return true; + if(e->type == SDL_KEYUP && e->key.keysym.sym == 'q') + return true; + return false; + } +} + int real_main(int argc, char** argv) { if(argc < 5) { @@ -53,8 +66,8 @@ int real_main(int argc, char** argv) SDL_UnlockSurface(img); SDL_FreeSurface(img); - resizer& r = resizer_factory::make_by_type(argv[2]); - image_frame_rgbx& dest = src.resize(twidth, theight, r); + rescaler_group grp(*(parse_rescaler_expression(argv[2]).use_rescaler)); + image_frame_rgbx& dest = src.resize(twidth, theight, grp); //Now, display the image. SDL_Surface* swsurf = NULL; @@ -93,7 +106,7 @@ int real_main(int argc, char** argv) SDL_BlitSurface(swsurf, NULL, hwsurf, NULL); SDL_Flip(hwsurf); SDL_Event e; - while(SDL_PollEvent(&e) != 1 || e.type != SDL_QUIT); + while(SDL_PollEvent(&e) != 1 || !do_quit_on(&e)); if(&dest != &src) delete &dest; -- 2.11.4.GIT