return 2
end
--- API ENTRY POINT
--- Returns the name for each additional channel (starting from 2).
--- Called at the start of the program, and then each frame for live
--- channels in case they change resolution.
-function channel_name(channel)
- if channel == 2 then
- return "First input"
- elseif channel == 3 then
- return "Second input"
- end
-end
+-- Set some global state.
+Nageru.set_channel_name(2, "First input")
+Nageru.set_channel_name(3, "Second input")
-- API ENTRY POINT
-- Returns, given a channel number, which signal it corresponds to (starting from 0).
} // namespace
+int Nageru_set_channel_name(lua_State *L)
+{
+ // NOTE: m is already locked.
+ Theme *theme = get_theme_updata(L);
+ unsigned channel = luaL_checknumber(L, 1);
+ const string text = checkstdstring(L, 2);
+ theme->channel_names[channel] = text;
+ lua_pop(L, 2);
+ 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)
{
}
// Set up the API we provide.
- register_constants();
+ register_globals();
register_class("Scene", Scene_funcs);
register_class("Block", Block_funcs);
register_class("EffectBlueprint", EffectBlueprint_funcs);
lua_close(L);
}
-void Theme::register_constants()
+void Theme::register_globals()
{
// Set Nageru.VIDEO_FORMAT_BGRA = bmusb::PixelFormat_8BitBGRA, etc.
const vector<pair<string, int>> num_constants = {
lua_settable(L, 1); // t[key] = value
}
+ const luaL_Reg Nageru_funcs[] = {
+ { "set_channel_name", Nageru_set_channel_name },
+ { NULL, NULL }
+ };
+ lua_pushlightuserdata(L, this);
+ luaL_setfuncs(L, Nageru_funcs, 1); // for (name,f in funcs) { mt[name] = f, with upvalue {theme} }
+
lua_setglobal(L, "Nageru"); // Nageru = t
assert(lua_gettop(L) == 0);
}
string Theme::get_channel_name(unsigned channel)
{
lock_guard<mutex> lock(m);
+
lua_getglobal(L, "channel_name");
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1);
+ if (channel_names.count(channel)) {
+ return channel_names[channel];
+ } else {
+ return "(no title)";
+ }
+ }
+
lua_pushnumber(L, channel);
if (lua_pcall(L, 1, 1, 0) != 0) {
fprintf(stderr, "error running function `channel_name': %s\n", lua_tostring(L, -1));
}
private:
- void register_constants();
+ void register_globals();
void register_class(const char *class_name, const luaL_Reg *funcs, EffectType effect_type = NO_EFFECT_TYPE);
int set_theme_menu(lua_State *L);
Chain get_chain_from_effect_chain(movit::EffectChain *effect_chain, unsigned num, const InputState &input_state);
std::unique_ptr<MenuEntry> theme_menu;
std::function<void()> theme_menu_callback;
+ std::map<unsigned, std::string> channel_names; // Set using Nageru.set_theme(). Protected by <m>.
+
friend class LiveInputWrapper;
friend class Scene;
friend int ThemeMenu_set(lua_State *L);
+ friend int Nageru_set_channel_name(lua_State *L);
};
// LiveInputWrapper is a facade on top of an YCbCrInput, exposed to
local ZOOM_TRANSITION = 1 -- Also for slides.
local FADE_TRANSITION = 2
--- Last width/height/frame rate for each channel, if we have it.
--- Note that unlike the values we get from Nageru, the resolution is per
--- frame and not per field, since we deinterlace.
-local last_resolution = {}
-
function make_sbs_input(scene)
return {
input = scene:add_input(),
static_scene:add_input(static_image) -- Note: Locks this input to images only.
static_scene:finalize()
+-- Set some global state.
+Nageru.set_channel_name(SBS_SIGNAL_NUM + 2, "Side-by-side")
+Nageru.set_channel_name(STATIC_SIGNAL_NUM + 2, "Static picture")
+
-- API ENTRY POINT
-- Returns the number of outputs in addition to the live (0) and preview (1).
-- Called only once, at the start of the program.
return num == INPUT0_SIGNAL_NUM or num == INPUT1_SIGNAL_NUM
end
--- API ENTRY POINT
--- Returns the name for each additional channel (starting from 2).
--- Called at the start of the program, and then each frame for live
--- channels in case they change resolution.
-function channel_name(channel)
- local signal_num = channel - 2
- if is_plain_signal(signal_num) then
- if last_resolution[signal_num] then
- return "Input " .. (signal_num + 1) .. " (" .. last_resolution[signal_num].human_readable_resolution .. ")"
- else
- return "Input " .. (signal_num + 1)
- end
- elseif signal_num == SBS_SIGNAL_NUM then
- return "Side-by-side"
- elseif signal_num == STATIC_SIGNAL_NUM then
- return "Static picture"
- end
-end
-
-- API ENTRY POINT
-- Returns, given a channel number, which signal it corresponds to (starting from 0).
-- Should return -1 if the channel does not correspond to a simple signal
is_connected = signals:get_is_connected(signal_num),
has_signal = signals:get_has_signal(signal_num),
frame_rate_nom = signals:get_frame_rate_nom(signal_num),
- frame_rate_den = signals:get_frame_rate_den(signal_num),
- human_readable_resolution = signals:get_human_readable_resolution(signal_num)
+ frame_rate_den = signals:get_frame_rate_den(signal_num)
}
if res.interlaced then
end
input_resolution[signal_num] = res
+
+ local text_res = signals:get_human_readable_resolution(signal_num)
+ Nageru.set_channel_name(signal_num + 2, "Input " .. (signal_num + 1) .. " (" .. text_res .. ")")
end
- last_resolution = input_resolution
if num == 0 then -- Live.
finish_transitions(t)