X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=theme.cpp;h=0fa4d1d5ea3702936ef3aa44cdbc60fe50b01689;hb=4a0187ffb4075b4d217b8d9e9c96cac548b199d8;hp=5fc5a7538cee288ae7e3fc335c1550bfdfe1dd2e;hpb=4ed8afda0ec060a66ca6af76d15afe62af543849;p=nageru diff --git a/theme.cpp b/theme.cpp index 5fc5a75..0fa4d1d 100644 --- a/theme.cpp +++ b/theme.cpp @@ -297,7 +297,7 @@ int EffectChain_add_video_input(lua_State* L) if (ret == 1) { Theme *theme = get_theme_updata(L); LiveInputWrapper **live_input = (LiveInputWrapper **)lua_touserdata(L, -1); - theme->register_video_signal_connection(*live_input, *capture); + theme->register_video_signal_connection(chain, *live_input, *capture); } return ret; } @@ -320,7 +320,7 @@ int EffectChain_add_html_input(lua_State* L) if (ret == 1) { Theme *theme = get_theme_updata(L); LiveInputWrapper **live_input = (LiveInputWrapper **)lua_touserdata(L, -1); - theme->register_html_signal_connection(*live_input, *capture); + theme->register_html_signal_connection(chain, *live_input, *capture); } return ret; } @@ -463,6 +463,14 @@ int VideoInput_rewind(lua_State* L) return 0; } +int VideoInput_disconnect(lua_State* L) +{ + assert(lua_gettop(L) == 1); + FFmpegCapture **video_input = (FFmpegCapture **)luaL_checkudata(L, 1, "VideoInput"); + (*video_input)->disconnect(); + return 0; +} + int VideoInput_change_rate(lua_State* L) { assert(lua_gettop(L) == 2); @@ -759,6 +767,7 @@ const luaL_Reg ImageInput_funcs[] = { const luaL_Reg VideoInput_funcs[] = { { "new", VideoInput_new }, { "rewind", VideoInput_rewind }, + { "disconnect", VideoInput_disconnect }, { "change_rate", VideoInput_change_rate }, { "get_signal_num", VideoInput_get_signal_num }, { NULL, NULL } @@ -1090,24 +1099,7 @@ Theme::Theme(const string &filename, const vector &search_dirs, Resource L = luaL_newstate(); luaL_openlibs(L); - register_constants(); - register_class("EffectChain", EffectChain_funcs); - register_class("LiveInputWrapper", LiveInputWrapper_funcs); - register_class("ImageInput", ImageInput_funcs); - register_class("VideoInput", VideoInput_funcs); - register_class("HTMLInput", HTMLInput_funcs); - register_class("WhiteBalanceEffect", WhiteBalanceEffect_funcs); - register_class("ResampleEffect", ResampleEffect_funcs); - register_class("PaddingEffect", PaddingEffect_funcs); - register_class("IntegralPaddingEffect", IntegralPaddingEffect_funcs); - register_class("OverlayEffect", OverlayEffect_funcs); - register_class("ResizeEffect", ResizeEffect_funcs); - register_class("MultiplyEffect", MultiplyEffect_funcs); - register_class("MixEffect", MixEffect_funcs); - register_class("InputStateInfo", InputStateInfo_funcs); - register_class("ThemeMenu", ThemeMenu_funcs); - - // Run script. Search through all directories until we find a file that will load + // Search through all directories until we find a file that will load // (as in, does not return LUA_ERRFILE); then run it. We store load errors // from all the attempts, and show them once we know we can't find any of them. lua_settop(L, 0); @@ -1121,8 +1113,9 @@ Theme::Theme(const string &filename, const vector &search_dirs, Resource real_search_dirs = search_dirs; } + string path; + int theme_code_ref; for (const string &dir : real_search_dirs) { - string path; if (dir.empty()) { path = filename; } else { @@ -1130,11 +1123,13 @@ Theme::Theme(const string &filename, const vector &search_dirs, Resource } int err = luaL_loadfile(L, path.c_str()); if (err == 0) { - // Success; actually call the code. - if (lua_pcall(L, 0, LUA_MULTRET, 0)) { - fprintf(stderr, "Error when running %s: %s\n", path.c_str(), lua_tostring(L, -1)); - exit(1); - } + // Save the theme for when we're actually going to run it + // (we need to set up the right environment below first, + // and we couldn't do that before, because we didn't know the + // path to put in Nageru.THEME_PATH). + theme_code_ref = luaL_ref(L, LUA_REGISTRYINDEX); + assert(lua_gettop(L) == 0); + success = true; break; } @@ -1154,6 +1149,46 @@ Theme::Theme(const string &filename, const vector &search_dirs, Resource } assert(lua_gettop(L) == 0); + // Make sure the path exposed to the theme (as Nageru.THEME_PATH; + // can be useful for locating files when talking to CEF) is absolute. + // In a sense, it would be nice if realpath() had a mode not to + // resolve symlinks, but it doesn't, so we only call it if we don't + // already have an absolute path (which may leave ../ elements etc.). + if (path[0] == '/') { + theme_path = path; + } else { + char *absolute_theme_path = realpath(path.c_str(), nullptr); + theme_path = absolute_theme_path; + free(absolute_theme_path); + } + + // Set up the API we provide. + register_constants(); + register_class("EffectChain", EffectChain_funcs); + register_class("LiveInputWrapper", LiveInputWrapper_funcs); + register_class("ImageInput", ImageInput_funcs); + register_class("VideoInput", VideoInput_funcs); + register_class("HTMLInput", HTMLInput_funcs); + register_class("WhiteBalanceEffect", WhiteBalanceEffect_funcs); + register_class("ResampleEffect", ResampleEffect_funcs); + register_class("PaddingEffect", PaddingEffect_funcs); + register_class("IntegralPaddingEffect", IntegralPaddingEffect_funcs); + register_class("OverlayEffect", OverlayEffect_funcs); + register_class("ResizeEffect", ResizeEffect_funcs); + register_class("MultiplyEffect", MultiplyEffect_funcs); + register_class("MixEffect", MixEffect_funcs); + register_class("InputStateInfo", InputStateInfo_funcs); + register_class("ThemeMenu", ThemeMenu_funcs); + + // Now actually run the theme to get everything set up. + lua_rawgeti(L, LUA_REGISTRYINDEX, theme_code_ref); + luaL_unref(L, LUA_REGISTRYINDEX, theme_code_ref); + if (lua_pcall(L, 0, 0, 0)) { + fprintf(stderr, "Error when running %s: %s\n", path.c_str(), lua_tostring(L, -1)); + exit(1); + } + assert(lua_gettop(L) == 0); + // Ask it for the number of channels. num_channels = call_num_channels(L); } @@ -1166,18 +1201,26 @@ Theme::~Theme() void Theme::register_constants() { // Set Nageru.VIDEO_FORMAT_BGRA = bmusb::PixelFormat_8BitBGRA, etc. - const vector> constants = { + const vector> num_constants = { { "VIDEO_FORMAT_BGRA", bmusb::PixelFormat_8BitBGRA }, { "VIDEO_FORMAT_YCBCR", bmusb::PixelFormat_8BitYCbCrPlanar }, }; + const vector> str_constants = { + { "THEME_PATH", theme_path }, + }; lua_newtable(L); // t = {} - for (const pair &constant : constants) { + for (const pair &constant : num_constants) { lua_pushstring(L, constant.first.c_str()); lua_pushinteger(L, constant.second); lua_settable(L, 1); // t[key] = value } + for (const pair &constant : str_constants) { + lua_pushstring(L, constant.first.c_str()); + lua_pushstring(L, constant.second.c_str()); + lua_settable(L, 1); // t[key] = value + } lua_setglobal(L, "Nageru"); // Nageru = t assert(lua_gettop(L) == 0); @@ -1213,12 +1256,13 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he exit(1); } - chain.chain = (EffectChain *)luaL_testudata(L, -2, "EffectChain"); - if (chain.chain == nullptr) { + EffectChain *effect_chain = (EffectChain *)luaL_testudata(L, -2, "EffectChain"); + if (effect_chain == nullptr) { fprintf(stderr, "get_chain() for chain number %d did not return an EffectChain\n", num); exit(1); } + chain.chain = effect_chain; if (!lua_isfunction(L, -1)) { fprintf(stderr, "Argument #-1 should be a function\n"); exit(1); @@ -1228,7 +1272,7 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he lua_pop(L, 2); assert(lua_gettop(L) == 0); - chain.setup_chain = [this, funcref, input_state]{ + chain.setup_chain = [this, funcref, input_state, effect_chain]{ unique_lock lock(m); assert(this->input_state == nullptr); @@ -1239,9 +1283,24 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he if (lua_pcall(L, 0, 0, 0) != 0) { fprintf(stderr, "error running chain setup callback: %s\n", lua_tostring(L, -1)); exit(1); - } + } assert(lua_gettop(L) == 0); + // The theme can't (or at least shouldn't!) call connect_signal() on + // each FFmpeg or CEF input, so we'll do it here. + if (video_signal_connections.count(effect_chain)) { + for (const VideoSignalConnection &conn : video_signal_connections[effect_chain]) { + conn.wrapper->connect_signal_raw(conn.source->get_card_index(), input_state); + } + } +#ifdef HAVE_CEF + if (html_signal_connections.count(effect_chain)) { + for (const CEFSignalConnection &conn : html_signal_connections[effect_chain]) { + conn.wrapper->connect_signal_raw(conn.source->get_card_index(), input_state); + } + } +#endif + this->input_state = nullptr; };