]> git.sesse.net Git - nageru/blobdiff - theme.cpp
Support switching Y'CbCr coefficients midway, which will allow doing the Right Thing...
[nageru] / theme.cpp
index ef635763515ee854a9bbca8c5be8f956396871ec..7bb187714e6f2ef0041a777ce864a4402525b78b 100644 (file)
--- a/theme.cpp
+++ b/theme.cpp
@@ -261,25 +261,28 @@ int EffectChain_finalize(lua_State* L)
 
        if (is_main_chain) {
                YCbCrFormat output_ycbcr_format;
-               // We actually output 4:2:0 in the end, but chroma subsampling
+               // We actually output 4:2:0 and/or 4:2:2 in the end, but chroma subsampling
                // happens in a pass not run by Movit (see ChromaSubsampler::subsample_chroma()).
                output_ycbcr_format.chroma_subsampling_x = 1;
                output_ycbcr_format.chroma_subsampling_y = 1;
 
-               // Rec. 709 would be the sane thing to do, but it seems many players
-               // (e.g. MPlayer and VLC) just default to BT.601 coefficients no matter
-               // what (see discussions in e.g. https://trac.ffmpeg.org/ticket/4978).
-               // We _do_ set the right flags, though, so that a player that works
-               // properly doesn't have to guess.
-               output_ycbcr_format.luma_coefficients = YCBCR_REC_601;
+               // This will be overridden if HDMI/SDI output is in force.
+               if (global_flags.ycbcr_rec709_coefficients) {
+                       output_ycbcr_format.luma_coefficients = YCBCR_REC_709;
+               } else {
+                       output_ycbcr_format.luma_coefficients = YCBCR_REC_601;
+               }
+
                output_ycbcr_format.full_range = false;
                output_ycbcr_format.num_levels = 256;
 
                chain->add_ycbcr_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, output_ycbcr_format, YCBCR_OUTPUT_SPLIT_Y_AND_CBCR);
+               chain->add_ycbcr_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, output_ycbcr_format, YCBCR_OUTPUT_INTERLEAVED);  // Add a copy where we'll only be using the Y component.
                chain->set_dither_bits(8);
                chain->set_output_origin(OUTPUT_ORIGIN_TOP_LEFT);
+       } else {
+               chain->add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
        }
-       chain->add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
 
        chain->finalize();
        return 0;
@@ -605,8 +608,9 @@ LiveInputWrapper::LiveInputWrapper(Theme *theme, EffectChain *chain, bool overri
        // Perhaps 601 was only to indicate the subsampling positions, not the
        // colorspace itself? Tested with a Lenovo X1 gen 3 as input.
        YCbCrFormat input_ycbcr_format;
-       input_ycbcr_format.chroma_subsampling_x = 2;
+       input_ycbcr_format.chroma_subsampling_x = global_flags.ten_bit_input ? 1 : 2;
        input_ycbcr_format.chroma_subsampling_y = 1;
+       input_ycbcr_format.num_levels = global_flags.ten_bit_input ? 1024 : 256;
        input_ycbcr_format.cb_x_position = 0.0;
        input_ycbcr_format.cr_x_position = 0.0;
        input_ycbcr_format.cb_y_position = 0.5;
@@ -630,10 +634,12 @@ LiveInputWrapper::LiveInputWrapper(Theme *theme, EffectChain *chain, bool overri
                num_inputs = 1;
        }
        for (unsigned i = 0; i < num_inputs; ++i) {
+               // When using 10-bit input, we're converting to interleaved through v210Converter.
+               YCbCrInputSplitting splitting = global_flags.ten_bit_input ? YCBCR_INPUT_INTERLEAVED : YCBCR_INPUT_SPLIT_Y_AND_CBCR;
                if (override_bounce) {
-                       inputs.push_back(new NonBouncingYCbCrInput(inout_format, input_ycbcr_format, global_flags.width, global_flags.height, YCBCR_INPUT_SPLIT_Y_AND_CBCR));
+                       inputs.push_back(new NonBouncingYCbCrInput(inout_format, input_ycbcr_format, global_flags.width, global_flags.height, splitting));
                } else {
-                       inputs.push_back(new YCbCrInput(inout_format, input_ycbcr_format, global_flags.width, global_flags.height, YCBCR_INPUT_SPLIT_Y_AND_CBCR));
+                       inputs.push_back(new YCbCrInput(inout_format, input_ycbcr_format, global_flags.width, global_flags.height, splitting));
                }
                chain->add_input(inputs.back());
        }
@@ -682,8 +688,12 @@ void LiveInputWrapper::connect_signal(int signal_num)
                        userdata = (const PBOFrameAllocator::Userdata *)frame.frame->userdata;
                }
 
-               inputs[i]->set_texture_num(0, userdata->tex_y[frame.field_number]);
-               inputs[i]->set_texture_num(1, userdata->tex_cbcr[frame.field_number]);
+               if (global_flags.ten_bit_input) {
+                       inputs[i]->set_texture_num(0, userdata->tex_444[frame.field_number]);
+               } else {
+                       inputs[i]->set_texture_num(0, userdata->tex_y[frame.field_number]);
+                       inputs[i]->set_texture_num(1, userdata->tex_cbcr[frame.field_number]);
+               }
                inputs[i]->set_width(userdata->last_width[frame.field_number]);
                inputs[i]->set_height(userdata->last_height[frame.field_number]);
 
@@ -965,12 +975,28 @@ int Theme::map_signal(int signal_num)
        if (signal_to_card_mapping.count(signal_num)) {
                return signal_to_card_mapping[signal_num];
        }
-       if (signal_num >= int(num_cards)) {
-               fprintf(stderr, "WARNING: Theme asked for input %d, but we only have %u card(s).\n", signal_num, num_cards);
-               fprintf(stderr, "Mapping to card %d instead.\n", signal_num % num_cards);
+
+       int card_index;
+       if (global_flags.output_card != -1 && num_cards > 1) {
+               // Try to exclude the output card from the default card_index.
+               card_index = signal_num % (num_cards - 1);
+               if (card_index >= global_flags.output_card) {
+                        ++card_index;
+               }
+               if (signal_num >= int(num_cards - 1)) {
+                       fprintf(stderr, "WARNING: Theme asked for input %d, but we only have %u input card(s) (card %d is busy with output).\n",
+                               signal_num, num_cards - 1, global_flags.output_card);
+                       fprintf(stderr, "Mapping to card %d instead.\n", card_index);
+               }
+       } else {
+               card_index = signal_num % num_cards;
+               if (signal_num >= int(num_cards)) {
+                       fprintf(stderr, "WARNING: Theme asked for input %d, but we only have %u card(s).\n", signal_num, num_cards);
+                       fprintf(stderr, "Mapping to card %d instead.\n", card_index);
+               }
        }
-       signal_to_card_mapping[signal_num] = signal_num % num_cards;
-       return signal_num % num_cards;
+       signal_to_card_mapping[signal_num] = card_index;
+       return card_index;
 }
 
 void Theme::set_signal_mapping(int signal_num, int card_num)