]> git.sesse.net Git - nageru/blobdiff - nageru/theme.cpp
Expose BlurEffect and UnsharpMaskEffect.
[nageru] / nageru / theme.cpp
index 6c75e114f97ac94899eef4e0a2f9b1c7e323e015..937043f7ca72e96ad60bf7a4611857091bf13730 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdarg.h>
 #include <lauxlib.h>
 #include <lua.hpp>
+#include <movit/blur_effect.h>
 #include <movit/deinterlace_effect.h>
 #include <movit/effect.h>
 #include <movit/effect_chain.h>
@@ -19,6 +20,7 @@
 #include <movit/resample_effect.h>
 #include <movit/resize_effect.h>
 #include <movit/util.h>
+#include <movit/unsharp_mask_effect.h>
 #include <movit/white_balance_effect.h>
 #include <movit/ycbcr.h>
 #include <movit/ycbcr_input.h>
@@ -140,6 +142,10 @@ Effect *instantiate_effect(EffectChain *chain, EffectType effect_type)
                return new MixEffect;
        case LIFT_GAMMA_GAIN_EFFECT:
                return new LiftGammaGainEffect;
+       case BLUR_EFFECT:
+               return new BlurEffect;
+       case UNSHARP_MASK_EFFECT:
+               return new UnsharpMaskEffect;
        default:
                fprintf(stderr, "Unhandled effect type %d\n", effect_type);
                abort();
@@ -260,9 +266,9 @@ void add_outputs_and_finalize(EffectChain *chain, bool is_main_chain)
                }
 
                output_ycbcr_format.full_range = false;
-               output_ycbcr_format.num_levels = 1 << global_flags.x264_bit_depth;
+               output_ycbcr_format.num_levels = 1 << global_flags.bit_depth;
 
-               GLenum type = global_flags.x264_bit_depth > 8 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
+               GLenum type = global_flags.bit_depth > 8 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
 
                chain->add_ycbcr_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, output_ycbcr_format, YCBCR_OUTPUT_SPLIT_Y_AND_CBCR, type);
 
@@ -272,7 +278,7 @@ void add_outputs_and_finalize(EffectChain *chain, bool is_main_chain)
                if (global_flags.use_zerocopy) {
                        chain->add_ycbcr_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, output_ycbcr_format, YCBCR_OUTPUT_INTERLEAVED, type);  // Add a copy where we'll only be using the Y component.
                }
-               chain->set_dither_bits(global_flags.x264_bit_depth > 8 ? 16 : 8);
+               chain->set_dither_bits(global_flags.bit_depth > 8 ? 16 : 8);
                chain->set_output_origin(OUTPUT_ORIGIN_TOP_LEFT);
        } else {
                chain->add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
@@ -308,7 +314,7 @@ int EffectChain_add_live_input(lua_State* L)
        EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
        bool override_bounce = checkbool(L, 2);
        bool deinterlace = checkbool(L, 3);
-       bmusb::PixelFormat pixel_format = global_flags.ten_bit_input ? bmusb::PixelFormat_10BitYCbCr : bmusb::PixelFormat_8BitYCbCr;
+       bmusb::PixelFormat pixel_format = global_flags.bit_depth > 8 ? bmusb::PixelFormat_10BitYCbCr : bmusb::PixelFormat_8BitYCbCr;
 
        // Needs to be nonowned to match add_video_input (see below).
        return wrap_lua_object_nonowned<LiveInputWrapper>(L, "LiveInputWrapper", theme, chain, pixel_format, override_bounce, deinterlace, /*user_connectable=*/true);
@@ -622,6 +628,18 @@ int LiftGammaGainEffect_new(lua_State* L)
        return wrap_lua_object_nonowned<EffectBlueprint>(L, "EffectBlueprint", LIFT_GAMMA_GAIN_EFFECT);
 }
 
+int BlurEffect_new(lua_State* L)
+{
+       assert(lua_gettop(L) == 0);
+       return wrap_lua_object_nonowned<EffectBlueprint>(L, "EffectBlueprint", BLUR_EFFECT);
+}
+
+int UnsharpMaskEffect_new(lua_State* L)
+{
+       assert(lua_gettop(L) == 0);
+       return wrap_lua_object_nonowned<EffectBlueprint>(L, "EffectBlueprint", UNSHARP_MASK_EFFECT);
+}
+
 int InputStateInfo_get_width(lua_State* L)
 {
        assert(lua_gettop(L) == 2);
@@ -997,6 +1015,16 @@ const luaL_Reg LiftGammaGainEffect_funcs[] = {
        { NULL, NULL }
 };
 
+const luaL_Reg BlurEffect_funcs[] = {
+       { "new", BlurEffect_new },
+       { NULL, NULL }
+};
+
+const luaL_Reg UnsharpMaskEffect_funcs[] = {
+       { "new", UnsharpMaskEffect_new },
+       { NULL, NULL }
+};
+
 // End of effects.
 
 const luaL_Reg InputStateInfo_funcs[] = {
@@ -1202,7 +1230,14 @@ void LiveInputWrapper::connect_card(int card_idx, const InputState &input_state)
                        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);
+                       // YCbCrPlanar is used for video streams, where we can have metadata from the mux.
+                       // Prefer that if there's no override. (Overrides are only available when using
+                       // video as SRT cards.)
+                       if (input_state.ycbcr_coefficients_auto[card_idx]) {
+                               ycbcr_inputs[i]->change_ycbcr_format(userdata->ycbcr_format);
+                       } else {
+                               ycbcr_inputs[i]->change_ycbcr_format(input_ycbcr_format);
+                       }
                        ycbcr_inputs[i]->set_width(width);
                        ycbcr_inputs[i]->set_height(height);
                        break;
@@ -1459,8 +1494,8 @@ int Nageru_set_audio_bus_eq_level_db(lua_State *L)
        return 0;
 }
 
-Theme::Theme(const string &filename, const vector<string> &search_dirs, ResourcePool *resource_pool, unsigned num_cards)
-       : resource_pool(resource_pool), num_cards(num_cards), signal_to_card_mapping(global_flags.default_stream_mapping)
+Theme::Theme(const string &filename, const vector<string> &search_dirs, ResourcePool *resource_pool)
+       : resource_pool(resource_pool), signal_to_card_mapping(global_flags.default_stream_mapping)
 {
        // Defaults.
        channel_names[0] = "Live";
@@ -1551,6 +1586,8 @@ Theme::Theme(const string &filename, const vector<string> &search_dirs, Resource
        register_class("ResizeEffect", ResizeEffect_funcs, RESIZE_EFFECT);
        register_class("MultiplyEffect", MultiplyEffect_funcs, MULTIPLY_EFFECT);
        register_class("MixEffect", MixEffect_funcs, MIX_EFFECT);
+       register_class("BlurEffect", BlurEffect_funcs, BLUR_EFFECT);
+       register_class("UnsharpMaskEffect", UnsharpMaskEffect_funcs, UNSHARP_MASK_EFFECT);
        register_class("LiftGammaGainEffect", LiftGammaGainEffect_funcs, LIFT_GAMMA_GAIN_EFFECT);
        register_class("InputStateInfo", InputStateInfo_funcs);
        register_class("ThemeMenu", ThemeMenu_funcs);
@@ -1741,8 +1778,8 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he
 
        // TODO: Can we do better, e.g. by running setup_chain() and seeing what it references?
        // Actually, setup_chain does maybe hold all the references we need now anyway?
-       chain.input_frames.reserve(num_cards * FRAME_HISTORY_LENGTH);
-       for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
+       chain.input_frames.reserve(MAX_VIDEO_CARDS * FRAME_HISTORY_LENGTH);
+       for (unsigned card_index = 0; card_index < MAX_VIDEO_CARDS; ++card_index) {
                for (unsigned frame_num = 0; frame_num < FRAME_HISTORY_LENGTH; ++frame_num) {
                        chain.input_frames.push_back(input_state.buffered_frames[card_index][frame_num].frame);
                }
@@ -1952,24 +1989,25 @@ int Theme::map_signal_to_card(int signal_num)
        }
 
        int card_index;
-       if (global_flags.output_card != -1 && num_cards > 1) {
+       if (global_flags.output_card != -1) {
                // Try to exclude the output card from the default card_index.
-               card_index = signal_num % (num_cards - 1);
+               card_index = signal_num % (global_flags.max_num_cards - 1);
                if (card_index >= global_flags.output_card) {
                         ++card_index;
                }
-               if (signal_num >= int(num_cards - 1)) {
+               if (signal_num >= int(global_flags.max_num_cards - 1)) {
                        print_warning(L, "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);
+                               signal_num, global_flags.max_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)) {
-                       print_warning(L, "Theme asked for input %d, but we only have %u card(s).\n", signal_num, num_cards);
+               card_index = signal_num % global_flags.max_num_cards;
+               if (signal_num >= int(global_flags.max_num_cards)) {
+                       print_warning(L, "Theme asked for input %d, but we only have %u card(s).\n", signal_num, global_flags.max_num_cards);
                        fprintf(stderr, "Mapping to card %d instead.\n", card_index);
                }
        }
+       global_mixer->force_card_active(card_index);
        signal_to_card_mapping[signal_num] = card_index;
        return card_index;
 }
@@ -1977,7 +2015,7 @@ int Theme::map_signal_to_card(int signal_num)
 void Theme::set_signal_mapping(int signal_num, int card_idx)
 {
        lock_guard<mutex> lock(map_m);
-       assert(card_idx < int(num_cards));
+       assert(card_idx < MAX_VIDEO_CARDS);
        signal_to_card_mapping[signal_num] = card_idx;
 }
 
@@ -2120,3 +2158,15 @@ string Theme::format_status_line(const string &disk_space_left_text, double file
        assert(lua_gettop(L) == 0);
        return text;
 }
+
+void Theme::remove_card(unsigned card_index)
+{
+       lock_guard<mutex> lock(map_m);
+       for (auto it = signal_to_card_mapping.begin(); it != signal_to_card_mapping.end(); ) {
+               if (it->second == int(card_index)) {
+                       it = signal_to_card_mapping.erase(it);
+               } else {
+                       ++it;
+               }
+       }
+}