X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=futatabi%2Fycbcr_converter.cpp;h=0edd7e66151e3b7856d918725f87913e4f309df0;hb=refs%2Fheads%2Fmaster;hp=694ba97eb06531fc4b6d882df93f9aa06d4b4c0f;hpb=9b7d691b4cc5db7dbfc18c82e86c1207fcac4722;p=nageru diff --git a/futatabi/ycbcr_converter.cpp b/futatabi/ycbcr_converter.cpp index 694ba97..0edd7e6 100644 --- a/futatabi/ycbcr_converter.cpp +++ b/futatabi/ycbcr_converter.cpp @@ -1,12 +1,16 @@ #include "ycbcr_converter.h" +#include "exif_parser.h" +#include "flags.h" #include "jpeg_frame.h" +#include #include +#include #include -using namespace std; using namespace movit; +using namespace std; namespace { @@ -52,43 +56,47 @@ 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; // Planar Y'CbCr decoding chain. - planar_chain.reset(new EffectChain(1280, 720, resource_pool)); - ycbcr_planar_input = (YCbCrInput *)planar_chain->add_input(new YCbCrInput(inout_format, ycbcr_format, 1280, 720, YCBCR_INPUT_PLANAR)); + planar_chain.reset(new EffectChain(global_flags.width, global_flags.height, resource_pool)); + ycbcr_planar_input = (YCbCrInput *)planar_chain->add_input(new YCbCrInput(inout_format, ycbcr_format, global_flags.width, global_flags.height, YCBCR_INPUT_PLANAR)); setup_outputs(output_mode, inout_format, ycbcr_output_format, planar_chain.get()); planar_chain->set_dither_bits(8); planar_chain->finalize(); // Semiplanar Y'CbCr decoding chain (for images coming from VA-API). - semiplanar_chain.reset(new EffectChain(1280, 720, resource_pool)); - ycbcr_semiplanar_input = (YCbCrInput *)semiplanar_chain->add_input(new YCbCrInput(inout_format, ycbcr_format, 1280, 720, YCBCR_INPUT_SPLIT_Y_AND_CBCR)); + semiplanar_chain.reset(new EffectChain(global_flags.width, global_flags.height, resource_pool)); + ycbcr_semiplanar_input = (YCbCrInput *)semiplanar_chain->add_input(new YCbCrInput(inout_format, ycbcr_format, global_flags.width, global_flags.height, YCBCR_INPUT_SPLIT_Y_AND_CBCR)); setup_outputs(output_mode, inout_format, ycbcr_output_format, semiplanar_chain.get()); 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(1280, 720, resource_pool)); - fade_chain.input[0] = (movit::YCbCrInput *)fade_chain.chain->add_input( - new YCbCrInput(inout_format, ycbcr_format, 1280, 720, - first_input_is_semiplanar ? YCBCR_INPUT_SPLIT_Y_AND_CBCR : YCBCR_INPUT_PLANAR)); - fade_chain.input[1] = (movit::YCbCrInput *)fade_chain.chain->add_input( - new YCbCrInput(inout_format, ycbcr_format, 1280, 720, - 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.chain.reset(new EffectChain(global_flags.width, global_flags.height, resource_pool)); + 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] = (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.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(); @@ -99,20 +107,24 @@ YCbCrConverter::YCbCrConverter(YCbCrConverter::OutputMode output_mode, ResourceP // directly from the GPU anyway). for (bool second_input_is_semiplanar : { false, true }) { FadeChain &fade_chain = interleaved_fade_chains[second_input_is_semiplanar]; - fade_chain.chain.reset(new EffectChain(1280, 720, resource_pool)); + 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( - new YCbCrInput(inout_format, ycbcr_format, 1280, 720, - YCBCR_INPUT_INTERLEAVED)); + 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( - new YCbCrInput(inout_format, ycbcr_format, 1280, 720, - 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.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.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(); @@ -137,11 +149,15 @@ EffectChain *YCbCrConverter::prepare_chain_for_fade(shared_ptr 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, std::shared_ptr 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 secondary_frame, float fade_alpha) { const FadeChain &fade_chain = interleaved_fade_chains[secondary_frame->is_semiplanar]; { @@ -150,8 +166,8 @@ EffectChain *YCbCrConverter::prepare_chain_for_fade_from_texture(GLuint tex, std format_copy.chroma_subsampling_y = 1; fade_chain.input[0]->change_ycbcr_format(format_copy); - fade_chain.input[0]->set_width(1280); // FIXME - fade_chain.input[0]->set_height(720); + fade_chain.input[0]->set_width(width); // Doesn't really matter. + fade_chain.input[0]->set_height(height); fade_chain.input[0]->set_texture_num(0, tex); glTextureParameteri(tex, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -162,6 +178,9 @@ EffectChain *YCbCrConverter::prepare_chain_for_fade_from_texture(GLuint tex, std 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(); } @@ -175,15 +194,11 @@ void setup_input_for_frame(shared_ptr frame, const YCbCrFormat &ycbcr_for input->set_width(frame->width); input->set_height(frame->height); - input->set_pixel_data(0, frame->y.get()); - input->set_pitch(0, frame->pitch_y); + input->set_texture_num(0, *frame->y); if (frame->is_semiplanar) { - input->set_pixel_data(1, frame->cbcr.get()); - input->set_pitch(1, frame->pitch_chroma); + input->set_texture_num(1, *frame->cbcr); } else { - input->set_pixel_data(1, frame->cb.get()); - input->set_pixel_data(2, frame->cr.get()); - input->set_pitch(1, frame->pitch_chroma); - input->set_pitch(2, frame->pitch_chroma); + input->set_texture_num(1, *frame->cb); + input->set_texture_num(2, *frame->cr); } }