From a616ded3842994840ce0cfa365d259f602493779 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sat, 12 Jan 2013 22:36:22 +0100 Subject: [PATCH] Defer fetching inputs' color spaces and gamma to finalize(). MLT needs this, as it doesn't know the type of input when building the filter chain. --- effect_chain.cpp | 25 ++++++++++++++++---- effect_chain.h | 1 + effect_chain_test.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/effect_chain.cpp b/effect_chain.cpp index dd7a652..cb7c52c 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -51,10 +51,7 @@ EffectChain::~EffectChain() Input *EffectChain::add_input(Input *input) { inputs.push_back(input); - - Node *node = add_node(input); - node->output_color_space = input->get_color_space(); - node->output_gamma_curve = input->get_gamma_curve(); + add_node(input); return input; } @@ -648,6 +645,21 @@ void EffectChain::topological_sort_visit_node(Node *node, std::set *visi sorted_list->push_back(node); } +void EffectChain::find_color_spaces_for_inputs() +{ + for (unsigned i = 0; i < nodes.size(); ++i) { + Node *node = nodes[i]; + if (node->disabled) { + continue; + } + if (node->incoming_links.size() == 0) { + Input *input = static_cast(node->effect); + node->output_color_space = input->get_color_space(); + node->output_gamma_curve = input->get_gamma_curve(); + } + } +} + // Propagate gamma and color space information as far as we can in the graph. // The rules are simple: Anything where all the inputs agree, get that as // output as well. Anything else keeps having *_INVALID. @@ -992,9 +1004,12 @@ void EffectChain::finalize() } output_dot("step1-rewritten.dot"); - propagate_gamma_and_color_space(); + find_color_spaces_for_inputs(); output_dot("step2-propagated.dot"); + propagate_gamma_and_color_space(); + output_dot("step3-propagated.dot"); + fix_internal_color_spaces(); fix_output_color_space(); output_dot("step4-output-colorspacefix.dot"); diff --git a/effect_chain.h b/effect_chain.h index c38f347..6ceb0c3 100644 --- a/effect_chain.h +++ b/effect_chain.h @@ -167,6 +167,7 @@ private: void topological_sort_visit_node(Node *node, std::set *visited_nodes, std::vector *sorted_list); // Used during finalize(). + void find_color_spaces_for_inputs(); void propagate_gamma_and_color_space(); Node *find_output_node(); diff --git a/effect_chain_test.cpp b/effect_chain_test.cpp index 21cb2be..ace160f 100644 --- a/effect_chain_test.cpp +++ b/effect_chain_test.cpp @@ -185,6 +185,61 @@ TEST(EffectChainTest, RewritingWorksAndColorspaceConversionsAreInserted) { expect_equal(expected_data, out_data, 3, 2); } +// A fake input that can change its output colorspace and gamma between instantiation +// and finalize. +class UnknownColorspaceInput : public FlatInput { +public: + UnknownColorspaceInput(ImageFormat format, MovitPixelFormat pixel_format, GLenum type, unsigned width, unsigned height) + : FlatInput(format, pixel_format, type, width, height), + overridden_color_space(format.color_space), + overridden_gamma_curve(format.gamma_curve) {} + virtual std::string effect_type_id() const { return "UnknownColorspaceInput"; } + + void set_color_space(Colorspace colorspace) { + overridden_color_space = colorspace; + } + void set_gamma_curve(GammaCurve gamma_curve) { + overridden_gamma_curve = gamma_curve; + } + Colorspace get_color_space() const { return overridden_color_space; } + GammaCurve get_gamma_curve() const { return overridden_gamma_curve; } + +private: + Colorspace overridden_color_space; + GammaCurve overridden_gamma_curve; +}; + +TEST(EffectChainTester, HandlesInputChangingColorspace) { + const int size = 4; + + float data[size] = { + 0.0, + 0.5, + 0.7, + 1.0, + }; + float out_data[size]; + + EffectChainTester tester(NULL, 4, 1, FORMAT_GRAYSCALE); + + // First say that we have sRGB, linear input. + ImageFormat format; + format.color_space = COLORSPACE_sRGB; + format.gamma_curve = GAMMA_LINEAR; + + UnknownColorspaceInput *input = new UnknownColorspaceInput(format, FORMAT_GRAYSCALE, GL_FLOAT, 4, 1); + input->set_pixel_data(data); + tester.get_chain()->add_input(input); + + // Now we change to Rec. 601 input. + input->set_color_space(COLORSPACE_REC_601_625); + input->set_gamma_curve(GAMMA_REC_601); + + // Now ask for Rec. 601 output. Thus, our chain should now be a no-op. + tester.run(out_data, GL_RED, COLORSPACE_REC_601_625, GAMMA_REC_601); + expect_equal(data, out_data, 4, 1); +} + // Like RewritingToInvertEffect, but splicing in a MirrorEffect instead, // which does not need linear light or sRGB primaries. class RewritingToMirrorEffect : public Effect { -- 2.39.2