]> git.sesse.net Git - nageru/blobdiff - futatabi/ycbcr_converter.cpp
Make Futatabi fades apply white balance.
[nageru] / futatabi / ycbcr_converter.cpp
index ef402a57d3926a974317db8e3b0bb52faafc1f7a..2d2f32f6077e72ae4cd5894634227b853161bfd6 100644 (file)
@@ -1,13 +1,16 @@
 #include "ycbcr_converter.h"
 
+#include "exif_parser.h"
 #include "flags.h"
 #include "jpeg_frame.h"
 
+#include <array>
 #include <movit/mix_effect.h>
+#include <movit/white_balance_effect.h>
 #include <movit/ycbcr_input.h>
 
-using namespace std;
 using namespace movit;
+using namespace std;
 
 namespace {
 
@@ -53,12 +56,12 @@ YCbCrConverter::YCbCrConverter(YCbCrConverter::OutputMode output_mode, ResourceP
        // sources with no conversion, so we ought to have had false here.
        // However, in the off chance that we're actually getting real MJPEG,
        // we don't want to crush its blacks (or whites) by clamping. All of
-       // our processing is fades, so if we're in limited-range input, we'll
-       // stay in limited-range output. (Fading between limited-range and
-       // full-range sources will be broken, of course.) There will be some
-       // slight confusion in the parts of the algorithms dealing with RGB,
-       // but they're small and we'll manage.
-       ycbcr_format.full_range = true;
+       // our processing is fades or other linear operations, so if we're in
+       // limited-range input, we'll stay in limited-range output. (Fading
+       // between limited-range and full-range sources will be broken,
+       // of course.) There will be some slight confusion in the parts of the
+       // algorithms dealing with RGB, but they're small and we'll manage.
+       ycbcr_format.full_range = false;
 
        YCbCrFormat ycbcr_output_format = ycbcr_format;
        ycbcr_output_format.chroma_subsampling_x = 1;
@@ -77,19 +80,23 @@ YCbCrConverter::YCbCrConverter(YCbCrConverter::OutputMode output_mode, ResourceP
        semiplanar_chain->set_dither_bits(8);
        semiplanar_chain->finalize();
 
-       // Fade chains.
+       // Fade chains. These include white balance adjustments.
        for (bool first_input_is_semiplanar : { false, true }) {
                for (bool second_input_is_semiplanar : { false, true }) {
                        FadeChain &fade_chain = fade_chains[first_input_is_semiplanar][second_input_is_semiplanar];
                        fade_chain.chain.reset(new EffectChain(global_flags.width, global_flags.height, resource_pool));
-                       fade_chain.input[0] = (movit::YCbCrInput *)fade_chain.chain->add_input(
+                       fade_chain.input[0] = (YCbCrInput *)fade_chain.chain->add_input(
                                new YCbCrInput(inout_format, ycbcr_format, global_flags.width, global_flags.height,
                                               first_input_is_semiplanar ? YCBCR_INPUT_SPLIT_Y_AND_CBCR : YCBCR_INPUT_PLANAR));
-                       fade_chain.input[1] = (movit::YCbCrInput *)fade_chain.chain->add_input(
+                       fade_chain.input[1] = (YCbCrInput *)fade_chain.chain->add_input(
                                new YCbCrInput(inout_format, ycbcr_format, global_flags.width, global_flags.height,
                                               second_input_is_semiplanar ? YCBCR_INPUT_SPLIT_Y_AND_CBCR : YCBCR_INPUT_PLANAR));
-                       fade_chain.mix_effect = (movit::MixEffect *)fade_chain.chain->add_effect(
-                               new MixEffect, fade_chain.input[0], fade_chain.input[1]);
+                       fade_chain.wb_effect[0] = (WhiteBalanceEffect *)fade_chain.chain->add_effect(
+                               new WhiteBalanceEffect, fade_chain.input[0]);
+                       fade_chain.wb_effect[1] = (WhiteBalanceEffect *)fade_chain.chain->add_effect(
+                               new WhiteBalanceEffect, fade_chain.input[1]);
+                       fade_chain.mix_effect = (MixEffect *)fade_chain.chain->add_effect(
+                               new MixEffect, fade_chain.wb_effect[0], fade_chain.wb_effect[1]);
                        setup_outputs(output_mode, inout_format, ycbcr_output_format, fade_chain.chain.get());
                        fade_chain.chain->set_dither_bits(8);
                        fade_chain.chain->finalize();
@@ -103,17 +110,21 @@ YCbCrConverter::YCbCrConverter(YCbCrConverter::OutputMode output_mode, ResourceP
                fade_chain.chain.reset(new EffectChain(global_flags.width, global_flags.height, resource_pool));
 
                ycbcr_format.chroma_subsampling_x = 1;
-               fade_chain.input[0] = (movit::YCbCrInput *)fade_chain.chain->add_input(
+               fade_chain.input[0] = (YCbCrInput *)fade_chain.chain->add_input(
                        new YCbCrInput(inout_format, ycbcr_format, global_flags.width, global_flags.height,
                                       YCBCR_INPUT_INTERLEAVED));
 
                ycbcr_format.chroma_subsampling_x = 2;
-               fade_chain.input[1] = (movit::YCbCrInput *)fade_chain.chain->add_input(
+               fade_chain.input[1] = (YCbCrInput *)fade_chain.chain->add_input(
                        new YCbCrInput(inout_format, ycbcr_format, global_flags.width, global_flags.height,
                                       second_input_is_semiplanar ? YCBCR_INPUT_SPLIT_Y_AND_CBCR : YCBCR_INPUT_PLANAR));
 
-               fade_chain.mix_effect = (movit::MixEffect *)fade_chain.chain->add_effect(
-                       new MixEffect, fade_chain.input[0], fade_chain.input[1]);
+               fade_chain.wb_effect[0] = (WhiteBalanceEffect *)fade_chain.chain->add_effect(
+                       new WhiteBalanceEffect, fade_chain.input[0]);
+               fade_chain.wb_effect[1] = (WhiteBalanceEffect *)fade_chain.chain->add_effect(
+                       new WhiteBalanceEffect, fade_chain.input[1]);
+               fade_chain.mix_effect = (MixEffect *)fade_chain.chain->add_effect(
+                       new MixEffect, fade_chain.wb_effect[0], fade_chain.wb_effect[1]);
                setup_outputs(output_mode, inout_format, ycbcr_output_format, fade_chain.chain.get());
                fade_chain.chain->set_dither_bits(8);
                fade_chain.chain->finalize();
@@ -138,11 +149,15 @@ EffectChain *YCbCrConverter::prepare_chain_for_fade(shared_ptr<Frame> frame, sha
        setup_input_for_frame(secondary_frame, ycbcr_format, fade_chain.input[1]);
        bool ok = fade_chain.mix_effect->set_float("strength_first", 1.0f - fade_alpha);
        ok |= fade_chain.mix_effect->set_float("strength_second", fade_alpha);
+       RGBTriplet neutral_color0 = get_neutral_color(frame->exif_data);
+       RGBTriplet neutral_color1 = get_neutral_color(secondary_frame->exif_data);
+       ok |= fade_chain.wb_effect[0]->set_vec3("neutral_color", (float *)&neutral_color0);
+       ok |= fade_chain.wb_effect[1]->set_vec3("neutral_color", (float *)&neutral_color1);
        assert(ok);
        return fade_chain.chain.get();
 }
 
-EffectChain *YCbCrConverter::prepare_chain_for_fade_from_texture(GLuint tex, unsigned width, unsigned height, std::shared_ptr<Frame> secondary_frame, float fade_alpha)
+EffectChain *YCbCrConverter::prepare_chain_for_fade_from_texture(GLuint tex, RGBTriplet tex_neutral_color, unsigned width, unsigned height, std::shared_ptr<Frame> secondary_frame, float fade_alpha)
 {
        const FadeChain &fade_chain = interleaved_fade_chains[secondary_frame->is_semiplanar];
        {
@@ -163,6 +178,9 @@ EffectChain *YCbCrConverter::prepare_chain_for_fade_from_texture(GLuint tex, uns
        setup_input_for_frame(secondary_frame, ycbcr_format, fade_chain.input[1]);
        bool ok = fade_chain.mix_effect->set_float("strength_first", 1.0f - fade_alpha);
        ok |= fade_chain.mix_effect->set_float("strength_second", fade_alpha);
+       RGBTriplet neutral_color1 = get_neutral_color(secondary_frame->exif_data);
+       ok |= fade_chain.wb_effect[0]->set_vec3("neutral_color", (float *)&tex_neutral_color);
+       ok |= fade_chain.wb_effect[1]->set_vec3("neutral_color", (float *)&neutral_color1);
        assert(ok);
        return fade_chain.chain.get();
 }