X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=nageru%2Ftheme.cpp;h=7226e82d55e50b6a7cd4dde12ed1a71ed84a5321;hb=84eaa9862694f12f95d378abd6dd6b07a64c7b1d;hp=d28f5b2501030b0911b342a4124b95b1538e98c2;hpb=aa6cef228bda3977763472d6bbc03b5a0302c866;p=nageru diff --git a/nageru/theme.cpp b/nageru/theme.cpp index d28f5b2..7226e82 100644 --- a/nageru/theme.cpp +++ b/nageru/theme.cpp @@ -72,6 +72,8 @@ struct InputStateInfo { unsigned last_width[MAX_VIDEO_CARDS], last_height[MAX_VIDEO_CARDS]; bool last_interlaced[MAX_VIDEO_CARDS], last_has_signal[MAX_VIDEO_CARDS], last_is_connected[MAX_VIDEO_CARDS]; unsigned last_frame_rate_nom[MAX_VIDEO_CARDS], last_frame_rate_den[MAX_VIDEO_CARDS]; + bool has_last_subtitle[MAX_VIDEO_CARDS]; + std::string last_subtitle[MAX_VIDEO_CARDS]; }; InputStateInfo::InputStateInfo(const InputState &input_state) @@ -93,6 +95,8 @@ InputStateInfo::InputStateInfo(const InputState &input_state) last_is_connected[signal_num] = userdata->last_is_connected; last_frame_rate_nom[signal_num] = userdata->last_frame_rate_nom; last_frame_rate_den[signal_num] = userdata->last_frame_rate_den; + has_last_subtitle[signal_num] = userdata->has_last_subtitle; + last_subtitle[signal_num] = userdata->last_subtitle; } } @@ -100,7 +104,7 @@ class LuaRefWithDeleter { public: LuaRefWithDeleter(mutex *m, lua_State *L, int ref) : m(m), L(L), ref(ref) {} ~LuaRefWithDeleter() { - unique_lock lock(*m); + lock_guard lock(*m); luaL_unref(L, LUA_REGISTRYINDEX, ref); } int get() const { return ref; } @@ -189,6 +193,57 @@ string checkstdstring(lua_State *L, int index) return string(cstr, len); } +void add_outputs_and_finalize(EffectChain *chain, bool is_main_chain) +{ + // Add outputs as needed. + // NOTE: If you change any details about the output format, you will need to + // also update what's given to the muxer (HTTPD::Mux constructor) and + // what's put in the H.264 stream (sps_rbsp()). + ImageFormat inout_format; + inout_format.color_space = COLORSPACE_REC_709; + + // Output gamma is tricky. We should output Rec. 709 for TV, except that + // we expect to run with web players and others that don't really care and + // just output with no conversion. So that means we'll need to output sRGB, + // even though H.264 has no setting for that (we use “unspecified”). + inout_format.gamma_curve = GAMMA_sRGB; + + if (is_main_chain) { + YCbCrFormat output_ycbcr_format; + // 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; + + // 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 = 1 << global_flags.x264_bit_depth; + + GLenum type = global_flags.x264_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); + + // If we're using zerocopy video encoding (so the destination + // Y texture is owned by VA-API and will be unavailable for + // display), add a copy, where we'll only be using the Y component. + 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_output_origin(OUTPUT_ORIGIN_TOP_LEFT); + } else { + chain->add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); + } + + chain->finalize(); +} + int EffectChain_new(lua_State* L) { assert(lua_gettop(L) == 2); @@ -307,54 +362,7 @@ int EffectChain_finalize(lua_State* L) assert(lua_gettop(L) == 2); EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain"); bool is_main_chain = checkbool(L, 2); - - // Add outputs as needed. - // NOTE: If you change any details about the output format, you will need to - // also update what's given to the muxer (HTTPD::Mux constructor) and - // what's put in the H.264 stream (sps_rbsp()). - ImageFormat inout_format; - inout_format.color_space = COLORSPACE_REC_709; - - // Output gamma is tricky. We should output Rec. 709 for TV, except that - // we expect to run with web players and others that don't really care and - // just output with no conversion. So that means we'll need to output sRGB, - // even though H.264 has no setting for that (we use “unspecified”). - inout_format.gamma_curve = GAMMA_sRGB; - - if (is_main_chain) { - YCbCrFormat output_ycbcr_format; - // 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; - - // 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 = 1 << global_flags.x264_bit_depth; - - GLenum type = global_flags.x264_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); - - // If we're using zerocopy video encoding (so the destination - // Y texture is owned by VA-API and will be unavailable for - // display), add a copy, where we'll only be using the Y component. - 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_output_origin(OUTPUT_ORIGIN_TOP_LEFT); - } else { - chain->add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); - } - - chain->finalize(); + add_outputs_and_finalize(chain, is_main_chain); return 0; } @@ -451,7 +459,7 @@ int HTMLInput_new(lua_State* L) #else fprintf(stderr, "This version of Nageru has been compiled without CEF support.\n"); fprintf(stderr, "HTMLInput is not available.\n"); - exit(1); + abort(); #endif } @@ -634,6 +642,20 @@ int InputStateInfo_get_frame_rate_den(lua_State* L) return 1; } +int InputStateInfo_get_last_subtitle(lua_State* L) +{ + assert(lua_gettop(L) == 2); + InputStateInfo *input_state_info = get_input_state_info(L, 1); + Theme *theme = get_theme_updata(L); + int signal_num = theme->map_signal(luaL_checknumber(L, 2)); + if (!input_state_info->has_last_subtitle[signal_num]) { + lua_pushnil(L); + } else { + lua_pushstring(L, input_state_info->last_subtitle[signal_num].c_str()); + } + return 1; +} + int Effect_set_float(lua_State *L) { assert(lua_gettop(L) == 3); @@ -829,6 +851,7 @@ const luaL_Reg InputStateInfo_funcs[] = { { "get_is_connected", InputStateInfo_get_is_connected }, { "get_frame_rate_nom", InputStateInfo_get_frame_rate_nom }, { "get_frame_rate_den", InputStateInfo_get_frame_rate_den }, + { "get_last_subtitle", InputStateInfo_get_last_subtitle }, { NULL, NULL } }; @@ -1060,7 +1083,7 @@ int call_num_channels(lua_State *L) if (lua_pcall(L, 0, 1, 0) != 0) { fprintf(stderr, "error running function `num_channels': %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } int num_channels = luaL_checknumber(L, 1); @@ -1123,7 +1146,7 @@ Theme::Theme(const string &filename, const vector &search_dirs, Resource for (const string &error : errors) { fprintf(stderr, "%s\n", error.c_str()); } - exit(1); + abort(); } assert(lua_gettop(L) == 0); @@ -1164,7 +1187,7 @@ Theme::Theme(const string &filename, const vector &search_dirs, Resource 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); + abort(); } assert(lua_gettop(L) == 0); @@ -1221,7 +1244,7 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he { Chain chain; - unique_lock lock(m); + lock_guard lock(m); assert(lua_gettop(L) == 0); lua_getglobal(L, "get_chain"); /* function to be called */ lua_pushnumber(L, num); @@ -1232,19 +1255,19 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he if (lua_pcall(L, 5, 2, 0) != 0) { fprintf(stderr, "error running function `get_chain': %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } 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); + abort(); } chain.chain = effect_chain; if (!lua_isfunction(L, -1)) { fprintf(stderr, "Argument #-1 should be a function\n"); - exit(1); + abort(); } lua_pushvalue(L, -1); shared_ptr funcref(new LuaRefWithDeleter(&m, L, luaL_ref(L, LUA_REGISTRYINDEX))); @@ -1252,7 +1275,7 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he assert(lua_gettop(L) == 0); chain.setup_chain = [this, funcref, input_state, effect_chain]{ - unique_lock lock(m); + lock_guard lock(m); assert(this->input_state == nullptr); this->input_state = &input_state; @@ -1261,8 +1284,8 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he lua_rawgeti(L, LUA_REGISTRYINDEX, funcref->get()); if (lua_pcall(L, 0, 0, 0) != 0) { fprintf(stderr, "error running chain setup callback: %s\n", lua_tostring(L, -1)); - exit(1); - } + abort(); + } assert(lua_gettop(L) == 0); // The theme can't (or at least shouldn't!) call connect_signal() on @@ -1297,17 +1320,17 @@ Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned he string Theme::get_channel_name(unsigned channel) { - unique_lock lock(m); + lock_guard lock(m); lua_getglobal(L, "channel_name"); 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)); - exit(1); + abort(); } const char *ret = lua_tostring(L, -1); if (ret == nullptr) { fprintf(stderr, "function `channel_name' returned nil for channel %d\n", channel); - exit(1); + abort(); } string retstr = ret; @@ -1318,12 +1341,12 @@ string Theme::get_channel_name(unsigned channel) int Theme::get_channel_signal(unsigned channel) { - unique_lock lock(m); + lock_guard lock(m); lua_getglobal(L, "channel_signal"); lua_pushnumber(L, channel); if (lua_pcall(L, 1, 1, 0) != 0) { fprintf(stderr, "error running function `channel_signal': %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } int ret = luaL_checknumber(L, 1); @@ -1334,18 +1357,18 @@ int Theme::get_channel_signal(unsigned channel) std::string Theme::get_channel_color(unsigned channel) { - unique_lock lock(m); + lock_guard lock(m); lua_getglobal(L, "channel_color"); lua_pushnumber(L, channel); if (lua_pcall(L, 1, 1, 0) != 0) { fprintf(stderr, "error running function `channel_color': %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } const char *ret = lua_tostring(L, -1); if (ret == nullptr) { fprintf(stderr, "function `channel_color' returned nil for channel %d\n", channel); - exit(1); + abort(); } string retstr = ret; @@ -1356,12 +1379,12 @@ std::string Theme::get_channel_color(unsigned channel) bool Theme::get_supports_set_wb(unsigned channel) { - unique_lock lock(m); + lock_guard lock(m); lua_getglobal(L, "supports_set_wb"); lua_pushnumber(L, channel); if (lua_pcall(L, 1, 1, 0) != 0) { fprintf(stderr, "error running function `supports_set_wb': %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } bool ret = checkbool(L, -1); @@ -1372,7 +1395,7 @@ bool Theme::get_supports_set_wb(unsigned channel) void Theme::set_wb(unsigned channel, double r, double g, double b) { - unique_lock lock(m); + lock_guard lock(m); lua_getglobal(L, "set_wb"); lua_pushnumber(L, channel); lua_pushnumber(L, r); @@ -1380,7 +1403,7 @@ void Theme::set_wb(unsigned channel, double r, double g, double b) lua_pushnumber(L, b); if (lua_pcall(L, 4, 0, 0) != 0) { fprintf(stderr, "error running function `set_wb': %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } assert(lua_gettop(L) == 0); @@ -1388,12 +1411,12 @@ void Theme::set_wb(unsigned channel, double r, double g, double b) vector Theme::get_transition_names(float t) { - unique_lock lock(m); + lock_guard lock(m); lua_getglobal(L, "get_transitions"); lua_pushnumber(L, t); if (lua_pcall(L, 1, 1, 0) != 0) { fprintf(stderr, "error running function `get_transitions': %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } vector ret; @@ -1405,7 +1428,7 @@ vector Theme::get_transition_names(float t) lua_pop(L, 1); assert(lua_gettop(L) == 0); return ret; -} +} int Theme::map_signal(int signal_num) { @@ -1414,7 +1437,7 @@ int Theme::map_signal(int signal_num) return -1 - signal_num; } - unique_lock lock(map_m); + lock_guard lock(map_m); if (signal_to_card_mapping.count(signal_num)) { return signal_to_card_mapping[signal_num]; } @@ -1444,34 +1467,34 @@ int Theme::map_signal(int signal_num) void Theme::set_signal_mapping(int signal_num, int card_num) { - unique_lock lock(map_m); + lock_guard lock(map_m); assert(card_num < int(num_cards)); signal_to_card_mapping[signal_num] = card_num; } void Theme::transition_clicked(int transition_num, float t) { - unique_lock lock(m); + lock_guard lock(m); lua_getglobal(L, "transition_clicked"); lua_pushnumber(L, transition_num); lua_pushnumber(L, t); if (lua_pcall(L, 2, 0, 0) != 0) { fprintf(stderr, "error running function `transition_clicked': %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } assert(lua_gettop(L) == 0); } void Theme::channel_clicked(int preview_num) { - unique_lock lock(m); + lock_guard lock(m); lua_getglobal(L, "channel_clicked"); lua_pushnumber(L, preview_num); if (lua_pcall(L, 1, 0, 0) != 0) { fprintf(stderr, "error running function `channel_clicked': %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } assert(lua_gettop(L) == 0); } @@ -1507,10 +1530,10 @@ int Theme::set_theme_menu(lua_State *L) void Theme::theme_menu_entry_clicked(int lua_ref) { - unique_lock lock(m); + lock_guard lock(m); lua_rawgeti(L, LUA_REGISTRYINDEX, lua_ref); if (lua_pcall(L, 0, 0, 0) != 0) { fprintf(stderr, "error running menu callback: %s\n", lua_tostring(L, -1)); - exit(1); + abort(); } }