#include "defs.h"
#include "deinterlace_effect.h"
+#include "ffmpeg_capture.h"
#include "flags.h"
#include "image_input.h"
#include "input.h"
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;
- return wrap_lua_object<LiveInputWrapper>(L, "LiveInputWrapper", theme, chain, pixel_format, override_bounce, deinterlace);
+
+ // 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);
+}
+
+int EffectChain_add_video_input(lua_State* L)
+{
+ assert(lua_gettop(L) == 3);
+ Theme *theme = get_theme_updata(L);
+ EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
+ FFmpegCapture **capture = (FFmpegCapture **)luaL_checkudata(L, 2, "VideoInput");
+ bool deinterlace = checkbool(L, 3);
+
+ // These need to be nonowned, so that the LiveInputWrapper still exists
+ // and can feed frames to the right EffectChain even if the Lua code
+ // 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,
+ /*override_bounce=*/false, deinterlace);
+ if (ret == 1) {
+ Theme *theme = get_theme_updata(L);
+ LiveInputWrapper **live_input = (LiveInputWrapper **)lua_touserdata(L, -1);
+ theme->register_signal_connection(*live_input, *capture);
+ }
+ return ret;
}
int EffectChain_add_effect(lua_State* L)
vector<Effect *> inputs;
for (int idx = 3; idx <= lua_gettop(L); ++idx) {
if (luaL_testudata(L, idx, "LiveInputWrapper")) {
- LiveInputWrapper *input = (LiveInputWrapper *)lua_touserdata(L, idx);
- inputs.push_back(input->get_effect());
+ LiveInputWrapper **input = (LiveInputWrapper **)lua_touserdata(L, idx);
+ inputs.push_back((*input)->get_effect());
} else {
inputs.push_back(get_effect(L, idx));
}
int LiveInputWrapper_connect_signal(lua_State* L)
{
assert(lua_gettop(L) == 2);
- LiveInputWrapper *input = (LiveInputWrapper *)luaL_checkudata(L, 1, "LiveInputWrapper");
+ LiveInputWrapper **input = (LiveInputWrapper **)luaL_checkudata(L, 1, "LiveInputWrapper");
int signal_num = luaL_checknumber(L, 2);
- input->connect_signal(signal_num);
+ (*input)->connect_signal(signal_num);
return 0;
}
return wrap_lua_object_nonowned<ImageInput>(L, "ImageInput", filename);
}
+int VideoInput_new(lua_State* L)
+{
+ assert(lua_gettop(L) == 1);
+ string filename = checkstdstring(L, 1);
+ int ret = wrap_lua_object_nonowned<FFmpegCapture>(L, "VideoInput", filename, global_flags.width, global_flags.height);
+ if (ret == 1) {
+ Theme *theme = get_theme_updata(L);
+ FFmpegCapture **capture = (FFmpegCapture **)lua_touserdata(L, -1);
+ theme->register_video_input(*capture);
+ }
+ return ret;
+}
+
+int VideoInput_rewind(lua_State* L)
+{
+ assert(lua_gettop(L) == 1);
+ FFmpegCapture **video_input = (FFmpegCapture **)luaL_checkudata(L, 1, "VideoInput");
+ (*video_input)->rewind();
+ 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 WhiteBalanceEffect_new(lua_State* L)
{
assert(lua_gettop(L) == 0);
{ "new", EffectChain_new },
{ "__gc", EffectChain_gc },
{ "add_live_input", EffectChain_add_live_input },
+ { "add_video_input", EffectChain_add_video_input },
{ "add_effect", EffectChain_add_effect },
{ "finalize", EffectChain_finalize },
{ NULL, NULL }
{ NULL, NULL }
};
+const luaL_Reg VideoInput_funcs[] = {
+ { "new", VideoInput_new },
+ { "rewind", VideoInput_rewind },
+ { "change_rate", VideoInput_change_rate },
+ { NULL, NULL }
+};
+
const luaL_Reg WhiteBalanceEffect_funcs[] = {
{ "new", WhiteBalanceEffect_new },
{ "set_float", Effect_set_float },
if (pixel_format == bmusb::PixelFormat_8BitRGBA) {
for (unsigned i = 0; i < num_inputs; ++i) {
- rgba_inputs.push_back(new FlatInput(inout_format, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, GL_UNSIGNED_BYTE, global_flags.width, global_flags.height));
+ 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 {
+ rgba_inputs.push_back(new NonsRGBCapableFlatInput(inout_format, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, GL_UNSIGNED_BYTE, global_flags.width, global_flags.height));
+ }
chain->add_input(rgba_inputs.back());
}
}
signal_num = theme->map_signal(signal_num);
+ connect_signal_raw(signal_num);
+}
+void LiveInputWrapper::connect_signal_raw(int signal_num)
+{
BufferedFrame first_frame = theme->input_state->buffered_frames[signal_num][0];
if (first_frame.frame == nullptr) {
// No data yet.
register_class("EffectChain", EffectChain_funcs);
register_class("LiveInputWrapper", LiveInputWrapper_funcs);
register_class("ImageInput", ImageInput_funcs);
+ register_class("VideoInput", VideoInput_funcs);
register_class("WhiteBalanceEffect", WhiteBalanceEffect_funcs);
register_class("ResampleEffect", ResampleEffect_funcs);
register_class("PaddingEffect", PaddingEffect_funcs);