]> git.sesse.net Git - nageru/blobdiff - theme.cpp
Nitpick: Add a little const.
[nageru] / theme.cpp
index 7ece56a928330bc1baad55ac357e06ebf231b963..ce1389f7cc4ea635ec0c2fbe4a295c8a8c3832fc 100644 (file)
--- a/theme.cpp
+++ b/theme.cpp
@@ -222,7 +222,7 @@ int EffectChain_add_video_input(lua_State* L)
        // doesn't care about the object anymore. (If we change this, we'd need
        // to also unregister the signal connection on __gc.)
        int ret = wrap_lua_object_nonowned<LiveInputWrapper>(
-               L, "LiveInputWrapper", theme, chain, bmusb::PixelFormat_8BitRGBA,
+               L, "LiveInputWrapper", theme, chain, bmusb::PixelFormat_8BitBGRA,
                /*override_bounce=*/false, deinterlace);
        if (ret == 1) {
                Theme *theme = get_theme_updata(L);
@@ -360,6 +360,23 @@ int VideoInput_rewind(lua_State* L)
        return 0;
 }
 
+int VideoInput_change_rate(lua_State* L)
+{
+       assert(lua_gettop(L) == 2);
+       FFmpegCapture **video_input = (FFmpegCapture **)luaL_checkudata(L, 1, "VideoInput");
+       double new_rate = luaL_checknumber(L, 2);
+       (*video_input)->change_rate(new_rate);
+       return 0;
+}
+
+int VideoInput_get_signal_num(lua_State* L)
+{
+       assert(lua_gettop(L) == 1);
+       FFmpegCapture **video_input = (FFmpegCapture **)luaL_checkudata(L, 1, "VideoInput");
+       lua_pushnumber(L, -1 - (*video_input)->get_card_index());
+       return 1;
+}
+
 int WhiteBalanceEffect_new(lua_State* L)
 {
        assert(lua_gettop(L) == 0);
@@ -562,6 +579,8 @@ const luaL_Reg ImageInput_funcs[] = {
 const luaL_Reg VideoInput_funcs[] = {
        { "new", VideoInput_new },
        { "rewind", VideoInput_rewind },
+       { "change_rate", VideoInput_change_rate },
+       { "get_signal_num", VideoInput_get_signal_num },
        { NULL, NULL }
 };
 
@@ -682,8 +701,10 @@ LiveInputWrapper::LiveInputWrapper(Theme *theme, EffectChain *chain, bmusb::Pixe
                num_inputs = 1;
        }
 
-       if (pixel_format == bmusb::PixelFormat_8BitRGBA) {
+       if (pixel_format == bmusb::PixelFormat_8BitBGRA) {
                for (unsigned i = 0; i < num_inputs; ++i) {
+                       // We upload our textures ourselves, and Movit swaps
+                       // R and B in the shader if we specify BGRA, so lie and say RGBA.
                        if (global_flags.can_disable_srgb_decoder) {
                                rgba_inputs.push_back(new sRGBSwitchingFlatInput(inout_format, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, GL_UNSIGNED_BYTE, global_flags.width, global_flags.height));
                        } else {
@@ -697,13 +718,11 @@ LiveInputWrapper::LiveInputWrapper(Theme *theme, EffectChain *chain, bmusb::Pixe
                        chain->add_effect(deinterlace_effect, reverse_inputs);
                }
        } else {
-               assert(pixel_format == bmusb::PixelFormat_8BitYCbCr || pixel_format == bmusb::PixelFormat_10BitYCbCr);
-               // The Blackmagic driver docs claim that the device outputs Y'CbCr
-               // according to Rec. 601, but practical testing indicates it definitely
-               // is Rec. 709 (at least up to errors attributable to rounding errors).
-               // 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;
+               assert(pixel_format == bmusb::PixelFormat_8BitYCbCr ||
+                      pixel_format == bmusb::PixelFormat_10BitYCbCr ||
+                      pixel_format == bmusb::PixelFormat_8BitYCbCrPlanar);
+
+               // Most of these settings will be overridden later if using PixelFormat_8BitYCbCrPlanar.
                input_ycbcr_format.chroma_subsampling_x = (pixel_format == bmusb::PixelFormat_10BitYCbCr) ? 1 : 2;
                input_ycbcr_format.chroma_subsampling_y = 1;
                input_ycbcr_format.num_levels = (pixel_format == bmusb::PixelFormat_10BitYCbCr) ? 1024 : 256;
@@ -711,12 +730,19 @@ LiveInputWrapper::LiveInputWrapper(Theme *theme, EffectChain *chain, bmusb::Pixe
                input_ycbcr_format.cr_x_position = 0.0;
                input_ycbcr_format.cb_y_position = 0.5;
                input_ycbcr_format.cr_y_position = 0.5;
-               input_ycbcr_format.luma_coefficients = YCBCR_REC_709;
-               input_ycbcr_format.full_range = false;
+               input_ycbcr_format.luma_coefficients = YCBCR_REC_709;  // Will be overridden later even if not planar.
+               input_ycbcr_format.full_range = false;  // Will be overridden later even if not planar.
 
                for (unsigned i = 0; i < num_inputs; ++i) {
                        // When using 10-bit input, we're converting to interleaved through v210Converter.
-                       YCbCrInputSplitting splitting = (pixel_format == bmusb::PixelFormat_10BitYCbCr) ? YCBCR_INPUT_INTERLEAVED : YCBCR_INPUT_SPLIT_Y_AND_CBCR;
+                       YCbCrInputSplitting splitting;
+                       if (pixel_format == bmusb::PixelFormat_10BitYCbCr) {
+                               splitting = YCBCR_INPUT_INTERLEAVED;
+                       } else if (pixel_format == bmusb::PixelFormat_8BitYCbCr) {
+                               splitting = YCBCR_INPUT_SPLIT_Y_AND_CBCR;
+                       } else {
+                               splitting = YCBCR_INPUT_PLANAR;
+                       }
                        if (override_bounce) {
                                ycbcr_inputs.push_back(new NonBouncingYCbCrInput(inout_format, input_ycbcr_format, global_flags.width, global_flags.height, splitting));
                        } else {
@@ -757,6 +783,31 @@ void LiveInputWrapper::connect_signal_raw(int signal_num)
                height = userdata->last_height[first_frame.field_number];
        }
 
+       movit::YCbCrLumaCoefficients ycbcr_coefficients = theme->input_state->ycbcr_coefficients[signal_num];
+       bool full_range = theme->input_state->full_range[signal_num];
+
+       if (theme->input_state->ycbcr_coefficients_auto[signal_num]) {
+               full_range = false;
+
+               // The Blackmagic driver docs claim that the device outputs Y'CbCr
+               // according to Rec. 601, but this seems to indicate the subsampling
+               // positions only, as they publish Y'CbCr → RGB formulas that are
+               // different for HD and SD (corresponding to Rec. 709 and 601, respectively),
+               // and a Lenovo X1 gen 3 I used to test definitely outputs Rec. 709
+               // (at least up to rounding error). Other devices seem to use Rec. 601
+               // even on HD resolutions. Nevertheless, Rec. 709 _is_ the right choice
+               // for HD, so we default to that if the user hasn't set anything.
+               if (height >= 720) {
+                       ycbcr_coefficients = YCBCR_REC_709;
+               } else {
+                       ycbcr_coefficients = YCBCR_REC_601;
+               }
+       }
+
+       // This is a global, but it doesn't really matter.
+       input_ycbcr_format.luma_coefficients = ycbcr_coefficients;
+       input_ycbcr_format.full_range = full_range;
+
        BufferedFrame last_good_frame = first_frame;
        for (unsigned i = 0; i < max(ycbcr_inputs.size(), rgba_inputs.size()); ++i) {
                BufferedFrame frame = theme->input_state->buffered_frames[signal_num][i];
@@ -780,18 +831,28 @@ void LiveInputWrapper::connect_signal_raw(int signal_num)
                case bmusb::PixelFormat_8BitYCbCr:
                        ycbcr_inputs[i]->set_texture_num(0, userdata->tex_y[frame.field_number]);
                        ycbcr_inputs[i]->set_texture_num(1, userdata->tex_cbcr[frame.field_number]);
-                       ycbcr_inputs[i]->set_width(this_width);
-                       ycbcr_inputs[i]->set_height(this_height);
+                       ycbcr_inputs[i]->change_ycbcr_format(input_ycbcr_format);
+                       ycbcr_inputs[i]->set_width(width);
+                       ycbcr_inputs[i]->set_height(height);
+                       break;
+               case bmusb::PixelFormat_8BitYCbCrPlanar:
+                       ycbcr_inputs[i]->set_texture_num(0, userdata->tex_y[frame.field_number]);
+                       ycbcr_inputs[i]->set_texture_num(1, userdata->tex_cb[frame.field_number]);
+                       ycbcr_inputs[i]->set_texture_num(2, userdata->tex_cr[frame.field_number]);
+                       ycbcr_inputs[i]->change_ycbcr_format(userdata->ycbcr_format);
+                       ycbcr_inputs[i]->set_width(width);
+                       ycbcr_inputs[i]->set_height(height);
                        break;
                case bmusb::PixelFormat_10BitYCbCr:
                        ycbcr_inputs[i]->set_texture_num(0, userdata->tex_444[frame.field_number]);
-                       ycbcr_inputs[i]->set_width(this_width);
-                       ycbcr_inputs[i]->set_height(this_height);
+                       ycbcr_inputs[i]->change_ycbcr_format(input_ycbcr_format);
+                       ycbcr_inputs[i]->set_width(width);
+                       ycbcr_inputs[i]->set_height(height);
                        break;
-               case bmusb::PixelFormat_8BitRGBA:
+               case bmusb::PixelFormat_8BitBGRA:
                        rgba_inputs[i]->set_texture_num(userdata->tex_rgba[frame.field_number]);
-                       rgba_inputs[i]->set_width(this_width);
-                       rgba_inputs[i]->set_height(this_height);
+                       rgba_inputs[i]->set_width(width);
+                       rgba_inputs[i]->set_height(height);
                        break;
                default:
                        assert(false);
@@ -1072,6 +1133,11 @@ vector<string> Theme::get_transition_names(float t)
 
 int Theme::map_signal(int signal_num)
 {
+       // Negative numbers map to raw signals.
+       if (signal_num < 0) {
+               return -1 - signal_num;
+       }
+
        unique_lock<mutex> lock(map_m);
        if (signal_to_card_mapping.count(signal_num)) {
                return signal_to_card_mapping[signal_num];