From: Steinar H. Gunderson Date: Mon, 8 Oct 2012 22:53:36 +0000 (+0200) Subject: Pull EffectChain a step closer to input resolution independence. X-Git-Tag: 1.0~334 X-Git-Url: https://git.sesse.net/?p=movit;a=commitdiff_plain;h=4a9b478d0cc333e7b47a766d3d27ffe67c08f15a Pull EffectChain a step closer to input resolution independence. --- diff --git a/effect_chain.cpp b/effect_chain.cpp index b04727b..87d0663 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -1,6 +1,7 @@ #define GL_GLEXT_PROTOTYPES 1 #include +#include #include #include @@ -17,9 +18,9 @@ #include "input.h" #include "opengl.h" -EffectChain::EffectChain(unsigned width, unsigned height) - : width(width), - height(height), +EffectChain::EffectChain(float aspect_nom, float aspect_denom) + : aspect_nom(aspect_nom), + aspect_denom(aspect_denom), finalized(false) {} Input *EffectChain::add_input(Input *input) @@ -436,6 +437,19 @@ void EffectChain::output_dot(const char *filename) fclose(fp); } +unsigned EffectChain::fit_rectangle_to_aspect(unsigned width, unsigned height) +{ + if (float(width) * aspect_denom >= float(height) * aspect_nom) { + // Same aspect, or W/H > aspect (image is wider than the frame). + // In either case, keep width. + return width; + } else { + // W/H < aspect (image is taller than the frame), so keep height, + // and adjust width correspondingly. + return lrintf(height * aspect_nom / aspect_denom); + } +} + void EffectChain::find_output_size(Phase *phase) { Node *output_node = phase->effects.back(); @@ -447,30 +461,33 @@ void EffectChain::find_output_size(Phase *phase) return; } - // If not, look at the input phases, if any. We select the largest one - // (really assuming they all have the same aspect currently), by pixel count. - if (!phase->inputs.empty()) { - unsigned best_width = 0, best_height = 0; - for (unsigned i = 0; i < phase->inputs.size(); ++i) { - Node *input = phase->inputs[i]; - assert(input->phase->output_width != 0); - assert(input->phase->output_height != 0); - if (input->phase->output_width * input->phase->output_height > best_width * best_height) { - best_width = input->phase->output_width; - best_height = input->phase->output_height; - } + // If not, look at the input phases and textures. + // We select the largest one (by fit into the current aspect). + unsigned best_width = 0; + for (unsigned i = 0; i < phase->inputs.size(); ++i) { + Node *input = phase->inputs[i]; + assert(input->phase->output_width != 0); + assert(input->phase->output_height != 0); + unsigned width = fit_rectangle_to_aspect(input->phase->output_width, input->phase->output_height); + if (width > best_width) { + best_width = width; } - assert(best_width != 0); - assert(best_height != 0); - phase->output_width = best_width; - phase->output_height = best_height; - return; } + for (unsigned i = 0; i < phase->effects.size(); ++i) { + Effect *effect = phase->effects[i]->effect; + if (effect->num_inputs() != 0) { + continue; + } - // OK, no inputs. Just use the global width/height. - // TODO: We probably want to use the texture's size eventually. - phase->output_width = width; - phase->output_height = height; + Input *input = static_cast(effect); + unsigned width = fit_rectangle_to_aspect(input->get_width(), input->get_height()); + if (width > best_width) { + best_width = width; + } + } + assert(best_width != 0); + phase->output_width = best_width; + phase->output_height = best_width * aspect_denom / aspect_nom; } void EffectChain::sort_nodes_topologically() @@ -858,6 +875,10 @@ void EffectChain::render_to_screen() { assert(finalized); + // Save original viewport. + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + // Basic state. glDisable(GL_BLEND); check_error(); @@ -936,7 +957,7 @@ void EffectChain::render_to_screen() // Last phase goes directly to the screen. glBindFramebuffer(GL_FRAMEBUFFER, 0); check_error(); - glViewport(0, 0, width, height); + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); } else { Node *output_node = phases[phase]->effects.back(); glFramebufferTexture2D( diff --git a/effect_chain.h b/effect_chain.h index cf96293..b3e03d5 100644 --- a/effect_chain.h +++ b/effect_chain.h @@ -54,7 +54,7 @@ struct Phase { class EffectChain { public: - EffectChain(unsigned width, unsigned height); + EffectChain(float aspect_nom, float aspect_denom); // E.g., 16.0f, 9.0f for 16:9. // User API: // input, effects, output, finalize need to come in that specific order. @@ -107,6 +107,10 @@ public: void insert_node_between(Node *sender, Node *middle, Node *receiver); private: + // Fits a rectangle of the given size to the current aspect ratio + // (aspect_nom/aspect_denom) and returns the new width and height. + unsigned fit_rectangle_to_aspect(unsigned width, unsigned height); + // Determine the preferred output size of a given phase. // Requires that all input phases (if any) already have output sizes set. void find_output_size(Phase *phase); @@ -146,7 +150,7 @@ private: void fix_internal_gamma_by_inserting_nodes(unsigned step); void fix_output_gamma(); - unsigned width, height; + float aspect_nom, aspect_denom; ImageFormat output_format; std::vector nodes; diff --git a/flat_input.h b/flat_input.h index 2e14488..90c0386 100644 --- a/flat_input.h +++ b/flat_input.h @@ -27,6 +27,8 @@ public: // Uploads the texture if it has changed since last time. void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num); + unsigned get_width() const { return width; } + unsigned get_height() const { return height; } ColorSpace get_color_space() const { return image_format.color_space; } GammaCurve get_gamma_curve() const { return image_format.gamma_curve; } diff --git a/input.h b/input.h index 8687690..ef94add 100644 --- a/input.h +++ b/input.h @@ -29,6 +29,8 @@ public: // to activate it.) virtual bool can_output_linear_gamma() const = 0; + virtual unsigned get_width() const = 0; + virtual unsigned get_height() const = 0; virtual ColorSpace get_color_space() const = 0; virtual GammaCurve get_gamma_curve() const = 0; }; diff --git a/main.cpp b/main.cpp index 1fbb6a2..0340cac 100644 --- a/main.cpp +++ b/main.cpp @@ -166,7 +166,7 @@ int main(int argc, char **argv) inout_format.color_space = COLORSPACE_sRGB; inout_format.gamma_curve = GAMMA_sRGB; - FlatInput *input = new FlatInput(inout_format, FORMAT_BGRA, WIDTH, HEIGHT); + FlatInput *input = new FlatInput(inout_format, FORMAT_BGRA, img_w, img_h); chain.add_input(input); Effect *lift_gamma_gain_effect = chain.add_effect(new LiftGammaGainEffect()); Effect *saturation_effect = chain.add_effect(new SaturationEffect()); diff --git a/ycbcr_input.h b/ycbcr_input.h index 43d1f1d..379279f 100644 --- a/ycbcr_input.h +++ b/ycbcr_input.h @@ -45,6 +45,8 @@ public: // Uploads the texture if it has changed since last time. void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num); + unsigned get_width() const { return width; } + unsigned get_height() const { return height; } ColorSpace get_color_space() const { return image_format.color_space; } GammaCurve get_gamma_curve() const { return image_format.gamma_curve; }