]> git.sesse.net Git - nageru/blob - theme.cpp
Make compiling with CEF optional.
[nageru] / theme.cpp
1 #include "theme.h"
2
3 #include <assert.h>
4 #include <bmusb/bmusb.h>
5 #include <epoxy/gl.h>
6 #include <lauxlib.h>
7 #include <lua.hpp>
8 #include <movit/deinterlace_effect.h>
9 #include <movit/effect.h>
10 #include <movit/effect_chain.h>
11 #include <movit/image_format.h>
12 #include <movit/input.h>
13 #include <movit/mix_effect.h>
14 #include <movit/multiply_effect.h>
15 #include <movit/overlay_effect.h>
16 #include <movit/padding_effect.h>
17 #include <movit/resample_effect.h>
18 #include <movit/resize_effect.h>
19 #include <movit/util.h>
20 #include <movit/white_balance_effect.h>
21 #include <movit/ycbcr.h>
22 #include <movit/ycbcr_input.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <cstddef>
26 #include <memory>
27 #include <new>
28 #include <utility>
29
30 #include "defs.h"
31 #ifdef HAVE_CEF
32 #include "cef_capture.h"
33 #endif
34 #include "ffmpeg_capture.h"
35 #include "flags.h"
36 #include "image_input.h"
37 #include "input_state.h"
38 #include "pbo_frame_allocator.h"
39
40 class Mixer;
41
42 namespace movit {
43 class ResourcePool;
44 }  // namespace movit
45
46 using namespace std;
47 using namespace movit;
48
49 extern Mixer *global_mixer;
50
51 namespace {
52
53 // Contains basically the same data as InputState, but does not hold on to
54 // a reference to the frames. This is important so that we can release them
55 // without having to wait for Lua's GC.
56 struct InputStateInfo {
57         InputStateInfo(const InputState& input_state);
58
59         unsigned last_width[MAX_VIDEO_CARDS], last_height[MAX_VIDEO_CARDS];
60         bool last_interlaced[MAX_VIDEO_CARDS], last_has_signal[MAX_VIDEO_CARDS], last_is_connected[MAX_VIDEO_CARDS];
61         unsigned last_frame_rate_nom[MAX_VIDEO_CARDS], last_frame_rate_den[MAX_VIDEO_CARDS];
62 };
63
64 InputStateInfo::InputStateInfo(const InputState &input_state)
65 {
66         for (unsigned signal_num = 0; signal_num < MAX_VIDEO_CARDS; ++signal_num) {
67                 BufferedFrame frame = input_state.buffered_frames[signal_num][0];
68                 if (frame.frame == nullptr) {
69                         last_width[signal_num] = last_height[signal_num] = 0;
70                         last_interlaced[signal_num] = false;
71                         last_has_signal[signal_num] = false;
72                         last_is_connected[signal_num] = false;
73                         continue;
74                 }
75                 const PBOFrameAllocator::Userdata *userdata = (const PBOFrameAllocator::Userdata *)frame.frame->userdata;
76                 last_width[signal_num] = userdata->last_width[frame.field_number];
77                 last_height[signal_num] = userdata->last_height[frame.field_number];
78                 last_interlaced[signal_num] = userdata->last_interlaced;
79                 last_has_signal[signal_num] = userdata->last_has_signal;
80                 last_is_connected[signal_num] = userdata->last_is_connected;
81                 last_frame_rate_nom[signal_num] = userdata->last_frame_rate_nom;
82                 last_frame_rate_den[signal_num] = userdata->last_frame_rate_den;
83         }
84 }
85
86 class LuaRefWithDeleter {
87 public:
88         LuaRefWithDeleter(mutex *m, lua_State *L, int ref) : m(m), L(L), ref(ref) {}
89         ~LuaRefWithDeleter() {
90                 unique_lock<mutex> lock(*m);
91                 luaL_unref(L, LUA_REGISTRYINDEX, ref);
92         }
93         int get() const { return ref; }
94
95 private:
96         LuaRefWithDeleter(const LuaRefWithDeleter &) = delete;
97
98         mutex *m;
99         lua_State *L;
100         int ref;
101 };
102
103 template<class T, class... Args>
104 int wrap_lua_object(lua_State* L, const char *class_name, Args&&... args)
105 {
106         // Construct the C++ object and put it on the stack.
107         void *mem = lua_newuserdata(L, sizeof(T));
108         new(mem) T(forward<Args>(args)...);
109
110         // Look up the metatable named <class_name>, and set it on the new object.
111         luaL_getmetatable(L, class_name);
112         lua_setmetatable(L, -2);
113
114         return 1;
115 }
116
117 // Like wrap_lua_object, but the object is not owned by Lua; ie. it's not freed
118 // by Lua GC. This is typically the case for Effects, which are owned by EffectChain
119 // and expected to be destructed by it. The object will be of type T** instead of T*
120 // when exposed to Lua.
121 //
122 // Note that we currently leak if you allocate an Effect in this way and never call
123 // add_effect. We should see if there's a way to e.g. set __gc on it at construction time
124 // and then release that once add_effect() takes ownership.
125 template<class T, class... Args>
126 int wrap_lua_object_nonowned(lua_State* L, const char *class_name, Args&&... args)
127 {
128         // Construct the pointer ot the C++ object and put it on the stack.
129         T **obj = (T **)lua_newuserdata(L, sizeof(T *));
130         *obj = new T(forward<Args>(args)...);
131
132         // Look up the metatable named <class_name>, and set it on the new object.
133         luaL_getmetatable(L, class_name);
134         lua_setmetatable(L, -2);
135
136         return 1;
137 }
138
139 Theme *get_theme_updata(lua_State* L)
140 {       
141         luaL_checktype(L, lua_upvalueindex(1), LUA_TLIGHTUSERDATA);
142         return (Theme *)lua_touserdata(L, lua_upvalueindex(1));
143 }
144
145 Effect *get_effect(lua_State *L, int idx)
146 {
147         if (luaL_testudata(L, idx, "WhiteBalanceEffect") ||
148             luaL_testudata(L, idx, "ResampleEffect") ||
149             luaL_testudata(L, idx, "PaddingEffect") ||
150             luaL_testudata(L, idx, "IntegralPaddingEffect") ||
151             luaL_testudata(L, idx, "OverlayEffect") ||
152             luaL_testudata(L, idx, "ResizeEffect") ||
153             luaL_testudata(L, idx, "MultiplyEffect") ||
154             luaL_testudata(L, idx, "MixEffect") ||
155             luaL_testudata(L, idx, "ImageInput")) {
156                 return *(Effect **)lua_touserdata(L, idx);
157         }
158         luaL_error(L, "Error: Index #%d was not an Effect type\n", idx);
159         return nullptr;
160 }
161
162 InputStateInfo *get_input_state_info(lua_State *L, int idx)
163 {
164         if (luaL_testudata(L, idx, "InputStateInfo")) {
165                 return (InputStateInfo *)lua_touserdata(L, idx);
166         }
167         luaL_error(L, "Error: Index #%d was not InputStateInfo\n", idx);
168         return nullptr;
169 }
170
171 bool checkbool(lua_State* L, int idx)
172 {
173         luaL_checktype(L, idx, LUA_TBOOLEAN);
174         return lua_toboolean(L, idx);
175 }
176
177 string checkstdstring(lua_State *L, int index)
178 {
179         size_t len;
180         const char* cstr = lua_tolstring(L, index, &len);
181         return string(cstr, len);
182 }
183
184 int EffectChain_new(lua_State* L)
185 {
186         assert(lua_gettop(L) == 2);
187         Theme *theme = get_theme_updata(L);
188         int aspect_w = luaL_checknumber(L, 1);
189         int aspect_h = luaL_checknumber(L, 2);
190
191         return wrap_lua_object<EffectChain>(L, "EffectChain", aspect_w, aspect_h, theme->get_resource_pool());
192 }
193
194 int EffectChain_gc(lua_State* L)
195 {
196         assert(lua_gettop(L) == 1);
197         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
198         chain->~EffectChain();
199         return 0;
200 }
201
202 int EffectChain_add_live_input(lua_State* L)
203 {
204         assert(lua_gettop(L) == 3);
205         Theme *theme = get_theme_updata(L);
206         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
207         bool override_bounce = checkbool(L, 2);
208         bool deinterlace = checkbool(L, 3);
209         bmusb::PixelFormat pixel_format = global_flags.ten_bit_input ? bmusb::PixelFormat_10BitYCbCr : bmusb::PixelFormat_8BitYCbCr;
210
211         // Needs to be nonowned to match add_video_input (see below).
212         return wrap_lua_object_nonowned<LiveInputWrapper>(L, "LiveInputWrapper", theme, chain, pixel_format, override_bounce, deinterlace);
213 }
214
215 int EffectChain_add_video_input(lua_State* L)
216 {
217         assert(lua_gettop(L) == 3);
218         Theme *theme = get_theme_updata(L);
219         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
220         FFmpegCapture **capture = (FFmpegCapture **)luaL_checkudata(L, 2, "VideoInput");
221         bool deinterlace = checkbool(L, 3);
222
223         // These need to be nonowned, so that the LiveInputWrapper still exists
224         // and can feed frames to the right EffectChain even if the Lua code
225         // doesn't care about the object anymore. (If we change this, we'd need
226         // to also unregister the signal connection on __gc.)
227         int ret = wrap_lua_object_nonowned<LiveInputWrapper>(
228                 L, "LiveInputWrapper", theme, chain, (*capture)->get_current_pixel_format(),
229                 /*override_bounce=*/false, deinterlace);
230         if (ret == 1) {
231                 Theme *theme = get_theme_updata(L);
232                 LiveInputWrapper **live_input = (LiveInputWrapper **)lua_touserdata(L, -1);
233                 theme->register_video_signal_connection(*live_input, *capture);
234         }
235         return ret;
236 }
237
238 #ifdef HAVE_CEF
239 int EffectChain_add_html_input(lua_State* L)
240 {
241         assert(lua_gettop(L) == 2);
242         Theme *theme = get_theme_updata(L);
243         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
244         CEFCapture **capture = (CEFCapture **)luaL_checkudata(L, 2, "HTMLInput");
245
246         // These need to be nonowned, so that the LiveInputWrapper still exists
247         // and can feed frames to the right EffectChain even if the Lua code
248         // doesn't care about the object anymore. (If we change this, we'd need
249         // to also unregister the signal connection on __gc.)
250         int ret = wrap_lua_object_nonowned<LiveInputWrapper>(
251                 L, "LiveInputWrapper", theme, chain, (*capture)->get_current_pixel_format(),
252                 /*override_bounce=*/false, /*deinterlace=*/false);
253         if (ret == 1) {
254                 Theme *theme = get_theme_updata(L);
255                 LiveInputWrapper **live_input = (LiveInputWrapper **)lua_touserdata(L, -1);
256                 theme->register_html_signal_connection(*live_input, *capture);
257         }
258         return ret;
259 }
260 #endif
261
262 int EffectChain_add_effect(lua_State* L)
263 {
264         assert(lua_gettop(L) >= 2);
265         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
266
267         // TODO: Better error reporting.
268         Effect *effect = get_effect(L, 2);
269         if (lua_gettop(L) == 2) {
270                 if (effect->num_inputs() == 0) {
271                         chain->add_input((Input *)effect);
272                 } else {
273                         chain->add_effect(effect);
274                 }
275         } else {
276                 vector<Effect *> inputs;
277                 for (int idx = 3; idx <= lua_gettop(L); ++idx) {
278                         if (luaL_testudata(L, idx, "LiveInputWrapper")) {
279                                 LiveInputWrapper **input = (LiveInputWrapper **)lua_touserdata(L, idx);
280                                 inputs.push_back((*input)->get_effect());
281                         } else {
282                                 inputs.push_back(get_effect(L, idx));
283                         }
284                 }
285                 chain->add_effect(effect, inputs);
286         }
287
288         lua_settop(L, 2);  // Return the effect itself.
289
290         // Make sure Lua doesn't garbage-collect it away.
291         lua_pushvalue(L, -1);
292         luaL_ref(L, LUA_REGISTRYINDEX);  // TODO: leak?
293
294         return 1;
295 }
296
297 int EffectChain_finalize(lua_State* L)
298 {
299         assert(lua_gettop(L) == 2);
300         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
301         bool is_main_chain = checkbool(L, 2);
302
303         // Add outputs as needed.
304         // NOTE: If you change any details about the output format, you will need to
305         // also update what's given to the muxer (HTTPD::Mux constructor) and
306         // what's put in the H.264 stream (sps_rbsp()).
307         ImageFormat inout_format;
308         inout_format.color_space = COLORSPACE_REC_709;
309
310         // Output gamma is tricky. We should output Rec. 709 for TV, except that
311         // we expect to run with web players and others that don't really care and
312         // just output with no conversion. So that means we'll need to output sRGB,
313         // even though H.264 has no setting for that (we use “unspecified”).
314         inout_format.gamma_curve = GAMMA_sRGB;
315
316         if (is_main_chain) {
317                 YCbCrFormat output_ycbcr_format;
318                 // We actually output 4:2:0 and/or 4:2:2 in the end, but chroma subsampling
319                 // happens in a pass not run by Movit (see ChromaSubsampler::subsample_chroma()).
320                 output_ycbcr_format.chroma_subsampling_x = 1;
321                 output_ycbcr_format.chroma_subsampling_y = 1;
322
323                 // This will be overridden if HDMI/SDI output is in force.
324                 if (global_flags.ycbcr_rec709_coefficients) {
325                         output_ycbcr_format.luma_coefficients = YCBCR_REC_709;
326                 } else {
327                         output_ycbcr_format.luma_coefficients = YCBCR_REC_601;
328                 }
329
330                 output_ycbcr_format.full_range = false;
331                 output_ycbcr_format.num_levels = 1 << global_flags.x264_bit_depth;
332
333                 GLenum type = global_flags.x264_bit_depth > 8 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE;
334
335                 chain->add_ycbcr_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, output_ycbcr_format, YCBCR_OUTPUT_SPLIT_Y_AND_CBCR, type);
336
337                 // If we're using zerocopy video encoding (so the destination
338                 // Y texture is owned by VA-API and will be unavailable for
339                 // display), add a copy, where we'll only be using the Y component.
340                 if (global_flags.use_zerocopy) {
341                         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.
342                 }
343                 chain->set_dither_bits(global_flags.x264_bit_depth > 8 ? 16 : 8);
344                 chain->set_output_origin(OUTPUT_ORIGIN_TOP_LEFT);
345         } else {
346                 chain->add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
347         }
348
349         chain->finalize();
350         return 0;
351 }
352
353 int LiveInputWrapper_connect_signal(lua_State* L)
354 {
355         assert(lua_gettop(L) == 2);
356         LiveInputWrapper **input = (LiveInputWrapper **)luaL_checkudata(L, 1, "LiveInputWrapper");
357         int signal_num = luaL_checknumber(L, 2);
358         (*input)->connect_signal(signal_num);
359         return 0;
360 }
361
362 int ImageInput_new(lua_State* L)
363 {
364         assert(lua_gettop(L) == 1);
365         string filename = checkstdstring(L, 1);
366         return wrap_lua_object_nonowned<ImageInput>(L, "ImageInput", filename);
367 }
368
369 int VideoInput_new(lua_State* L)
370 {
371         assert(lua_gettop(L) == 2);
372         string filename = checkstdstring(L, 1);
373         int pixel_format = luaL_checknumber(L, 2);
374         if (pixel_format != bmusb::PixelFormat_8BitYCbCrPlanar &&
375             pixel_format != bmusb::PixelFormat_8BitBGRA) {
376                 fprintf(stderr, "WARNING: Invalid enum %d used for video format, choosing Y'CbCr.\n",
377                         pixel_format);
378                 pixel_format = bmusb::PixelFormat_8BitYCbCrPlanar;
379         }
380         int ret = wrap_lua_object_nonowned<FFmpegCapture>(L, "VideoInput", filename, global_flags.width, global_flags.height);
381         if (ret == 1) {
382                 FFmpegCapture **capture = (FFmpegCapture **)lua_touserdata(L, -1);
383                 (*capture)->set_pixel_format(bmusb::PixelFormat(pixel_format));
384
385                 Theme *theme = get_theme_updata(L);
386                 theme->register_video_input(*capture);
387         }
388         return ret;
389 }
390
391 int VideoInput_rewind(lua_State* L)
392 {
393         assert(lua_gettop(L) == 1);
394         FFmpegCapture **video_input = (FFmpegCapture **)luaL_checkudata(L, 1, "VideoInput");
395         (*video_input)->rewind();
396         return 0;
397 }
398
399 int VideoInput_change_rate(lua_State* L)
400 {
401         assert(lua_gettop(L) == 2);
402         FFmpegCapture **video_input = (FFmpegCapture **)luaL_checkudata(L, 1, "VideoInput");
403         double new_rate = luaL_checknumber(L, 2);
404         (*video_input)->change_rate(new_rate);
405         return 0;
406 }
407
408 int VideoInput_get_signal_num(lua_State* L)
409 {
410         assert(lua_gettop(L) == 1);
411         FFmpegCapture **video_input = (FFmpegCapture **)luaL_checkudata(L, 1, "VideoInput");
412         lua_pushnumber(L, -1 - (*video_input)->get_card_index());
413         return 1;
414 }
415
416 int HTMLInput_new(lua_State* L)
417 {
418 #ifdef HAVE_CEF
419         assert(lua_gettop(L) == 1);
420         string url = checkstdstring(L, 1);
421         int ret = wrap_lua_object_nonowned<CEFCapture>(L, "HTMLInput", url, global_flags.width, global_flags.height);
422         if (ret == 1) {
423                 CEFCapture **capture = (CEFCapture **)lua_touserdata(L, -1);
424                 Theme *theme = get_theme_updata(L);
425                 theme->register_html_input(*capture);
426         }
427         return ret;
428 #else
429         fprintf(stderr, "This version of Nageru has been compiled without CEF support.\n");
430         fprintf(stderr, "HTMLInput is not available.\n");
431         exit(1);
432 #endif
433 }
434
435 #ifdef HAVE_CEF
436 int HTMLInput_set_url(lua_State* L)
437 {
438         assert(lua_gettop(L) == 2);
439         CEFCapture **video_input = (CEFCapture **)luaL_checkudata(L, 1, "HTMLInput");
440         string new_url = checkstdstring(L, 2);
441         (*video_input)->set_url(new_url);
442         return 0;
443 }
444
445 int HTMLInput_reload(lua_State* L)
446 {
447         assert(lua_gettop(L) == 1);
448         CEFCapture **video_input = (CEFCapture **)luaL_checkudata(L, 1, "HTMLInput");
449         (*video_input)->reload();
450         return 0;
451 }
452
453 int HTMLInput_set_max_fps(lua_State* L)
454 {
455         assert(lua_gettop(L) == 2);
456         CEFCapture **video_input = (CEFCapture **)luaL_checkudata(L, 1, "HTMLInput");
457         int max_fps = lrint(luaL_checknumber(L, 2));
458         (*video_input)->set_max_fps(max_fps);
459         return 0;
460 }
461
462 int HTMLInput_execute_javascript_async(lua_State* L)
463 {
464         assert(lua_gettop(L) == 2);
465         CEFCapture **video_input = (CEFCapture **)luaL_checkudata(L, 1, "HTMLInput");
466         string js = checkstdstring(L, 2);
467         (*video_input)->execute_javascript_async(js);
468         return 0;
469 }
470
471 int HTMLInput_get_signal_num(lua_State* L)
472 {
473         assert(lua_gettop(L) == 1);
474         CEFCapture **video_input = (CEFCapture **)luaL_checkudata(L, 1, "HTMLInput");
475         lua_pushnumber(L, -1 - (*video_input)->get_card_index());
476         return 1;
477 }
478 #endif
479
480 int WhiteBalanceEffect_new(lua_State* L)
481 {
482         assert(lua_gettop(L) == 0);
483         return wrap_lua_object_nonowned<WhiteBalanceEffect>(L, "WhiteBalanceEffect");
484 }
485
486 int ResampleEffect_new(lua_State* L)
487 {
488         assert(lua_gettop(L) == 0);
489         return wrap_lua_object_nonowned<ResampleEffect>(L, "ResampleEffect");
490 }
491
492 int PaddingEffect_new(lua_State* L)
493 {
494         assert(lua_gettop(L) == 0);
495         return wrap_lua_object_nonowned<PaddingEffect>(L, "PaddingEffect");
496 }
497
498 int IntegralPaddingEffect_new(lua_State* L)
499 {
500         assert(lua_gettop(L) == 0);
501         return wrap_lua_object_nonowned<IntegralPaddingEffect>(L, "IntegralPaddingEffect");
502 }
503
504 int OverlayEffect_new(lua_State* L)
505 {
506         assert(lua_gettop(L) == 0);
507         return wrap_lua_object_nonowned<OverlayEffect>(L, "OverlayEffect");
508 }
509
510 int ResizeEffect_new(lua_State* L)
511 {
512         assert(lua_gettop(L) == 0);
513         return wrap_lua_object_nonowned<ResizeEffect>(L, "ResizeEffect");
514 }
515
516 int MultiplyEffect_new(lua_State* L)
517 {
518         assert(lua_gettop(L) == 0);
519         return wrap_lua_object_nonowned<MultiplyEffect>(L, "MultiplyEffect");
520 }
521
522 int MixEffect_new(lua_State* L)
523 {
524         assert(lua_gettop(L) == 0);
525         return wrap_lua_object_nonowned<MixEffect>(L, "MixEffect");
526 }
527
528 int InputStateInfo_get_width(lua_State* L)
529 {
530         assert(lua_gettop(L) == 2);
531         InputStateInfo *input_state_info = get_input_state_info(L, 1);
532         Theme *theme = get_theme_updata(L);
533         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
534         lua_pushnumber(L, input_state_info->last_width[signal_num]);
535         return 1;
536 }
537
538 int InputStateInfo_get_height(lua_State* L)
539 {
540         assert(lua_gettop(L) == 2);
541         InputStateInfo *input_state_info = get_input_state_info(L, 1);
542         Theme *theme = get_theme_updata(L);
543         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
544         lua_pushnumber(L, input_state_info->last_height[signal_num]);
545         return 1;
546 }
547
548 int InputStateInfo_get_interlaced(lua_State* L)
549 {
550         assert(lua_gettop(L) == 2);
551         InputStateInfo *input_state_info = get_input_state_info(L, 1);
552         Theme *theme = get_theme_updata(L);
553         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
554         lua_pushboolean(L, input_state_info->last_interlaced[signal_num]);
555         return 1;
556 }
557
558 int InputStateInfo_get_has_signal(lua_State* L)
559 {
560         assert(lua_gettop(L) == 2);
561         InputStateInfo *input_state_info = get_input_state_info(L, 1);
562         Theme *theme = get_theme_updata(L);
563         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
564         lua_pushboolean(L, input_state_info->last_has_signal[signal_num]);
565         return 1;
566 }
567
568 int InputStateInfo_get_is_connected(lua_State* L)
569 {
570         assert(lua_gettop(L) == 2);
571         InputStateInfo *input_state_info = get_input_state_info(L, 1);
572         Theme *theme = get_theme_updata(L);
573         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
574         lua_pushboolean(L, input_state_info->last_is_connected[signal_num]);
575         return 1;
576 }
577
578 int InputStateInfo_get_frame_rate_nom(lua_State* L)
579 {
580         assert(lua_gettop(L) == 2);
581         InputStateInfo *input_state_info = get_input_state_info(L, 1);
582         Theme *theme = get_theme_updata(L);
583         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
584         lua_pushnumber(L, input_state_info->last_frame_rate_nom[signal_num]);
585         return 1;
586 }
587
588 int InputStateInfo_get_frame_rate_den(lua_State* L)
589 {
590         assert(lua_gettop(L) == 2);
591         InputStateInfo *input_state_info = get_input_state_info(L, 1);
592         Theme *theme = get_theme_updata(L);
593         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
594         lua_pushnumber(L, input_state_info->last_frame_rate_den[signal_num]);
595         return 1;
596 }
597
598 int Effect_set_float(lua_State *L)
599 {
600         assert(lua_gettop(L) == 3);
601         Effect *effect = (Effect *)get_effect(L, 1);
602         string key = checkstdstring(L, 2);
603         float value = luaL_checknumber(L, 3);
604         if (!effect->set_float(key, value)) {
605                 luaL_error(L, "Effect refused set_float(\"%s\", %d) (invalid key?)", key.c_str(), int(value));
606         }
607         return 0;
608 }
609
610 int Effect_set_int(lua_State *L)
611 {
612         assert(lua_gettop(L) == 3);
613         Effect *effect = (Effect *)get_effect(L, 1);
614         string key = checkstdstring(L, 2);
615         float value = luaL_checknumber(L, 3);
616         if (!effect->set_int(key, value)) {
617                 luaL_error(L, "Effect refused set_int(\"%s\", %d) (invalid key?)", key.c_str(), int(value));
618         }
619         return 0;
620 }
621
622 int Effect_set_vec3(lua_State *L)
623 {
624         assert(lua_gettop(L) == 5);
625         Effect *effect = (Effect *)get_effect(L, 1);
626         string key = checkstdstring(L, 2);
627         float v[3];
628         v[0] = luaL_checknumber(L, 3);
629         v[1] = luaL_checknumber(L, 4);
630         v[2] = luaL_checknumber(L, 5);
631         if (!effect->set_vec3(key, v)) {
632                 luaL_error(L, "Effect refused set_vec3(\"%s\", %f, %f, %f) (invalid key?)", key.c_str(),
633                         v[0], v[1], v[2]);
634         }
635         return 0;
636 }
637
638 int Effect_set_vec4(lua_State *L)
639 {
640         assert(lua_gettop(L) == 6);
641         Effect *effect = (Effect *)get_effect(L, 1);
642         string key = checkstdstring(L, 2);
643         float v[4];
644         v[0] = luaL_checknumber(L, 3);
645         v[1] = luaL_checknumber(L, 4);
646         v[2] = luaL_checknumber(L, 5);
647         v[3] = luaL_checknumber(L, 6);
648         if (!effect->set_vec4(key, v)) {
649                 luaL_error(L, "Effect refused set_vec4(\"%s\", %f, %f, %f, %f) (invalid key?)", key.c_str(),
650                         v[0], v[1], v[2], v[3]);
651         }
652         return 0;
653 }
654
655 const luaL_Reg EffectChain_funcs[] = {
656         { "new", EffectChain_new },
657         { "__gc", EffectChain_gc },
658         { "add_live_input", EffectChain_add_live_input },
659         { "add_video_input", EffectChain_add_video_input },
660 #ifdef HAVE_CEF
661         { "add_html_input", EffectChain_add_html_input },
662 #endif
663         { "add_effect", EffectChain_add_effect },
664         { "finalize", EffectChain_finalize },
665         { NULL, NULL }
666 };
667
668 const luaL_Reg LiveInputWrapper_funcs[] = {
669         { "connect_signal", LiveInputWrapper_connect_signal },
670         { NULL, NULL }
671 };
672
673 const luaL_Reg ImageInput_funcs[] = {
674         { "new", ImageInput_new },
675         { "set_float", Effect_set_float },
676         { "set_int", Effect_set_int },
677         { "set_vec3", Effect_set_vec3 },
678         { "set_vec4", Effect_set_vec4 },
679         { NULL, NULL }
680 };
681
682 const luaL_Reg VideoInput_funcs[] = {
683         { "new", VideoInput_new },
684         { "rewind", VideoInput_rewind },
685         { "change_rate", VideoInput_change_rate },
686         { "get_signal_num", VideoInput_get_signal_num },
687         { NULL, NULL }
688 };
689
690 const luaL_Reg HTMLInput_funcs[] = {
691         { "new", HTMLInput_new },
692 #ifdef HAVE_CEF
693         { "set_url", HTMLInput_set_url },
694         { "reload", HTMLInput_reload },
695         { "set_max_fps", HTMLInput_set_max_fps },
696         { "execute_javascript_async", HTMLInput_execute_javascript_async },
697         { "get_signal_num", HTMLInput_get_signal_num },
698 #endif
699         { NULL, NULL }
700 };
701
702 const luaL_Reg WhiteBalanceEffect_funcs[] = {
703         { "new", WhiteBalanceEffect_new },
704         { "set_float", Effect_set_float },
705         { "set_int", Effect_set_int },
706         { "set_vec3", Effect_set_vec3 },
707         { "set_vec4", Effect_set_vec4 },
708         { NULL, NULL }
709 };
710
711 const luaL_Reg ResampleEffect_funcs[] = {
712         { "new", ResampleEffect_new },
713         { "set_float", Effect_set_float },
714         { "set_int", Effect_set_int },
715         { "set_vec3", Effect_set_vec3 },
716         { "set_vec4", Effect_set_vec4 },
717         { NULL, NULL }
718 };
719
720 const luaL_Reg PaddingEffect_funcs[] = {
721         { "new", PaddingEffect_new },
722         { "set_float", Effect_set_float },
723         { "set_int", Effect_set_int },
724         { "set_vec3", Effect_set_vec3 },
725         { "set_vec4", Effect_set_vec4 },
726         { NULL, NULL }
727 };
728
729 const luaL_Reg IntegralPaddingEffect_funcs[] = {
730         { "new", IntegralPaddingEffect_new },
731         { "set_float", Effect_set_float },
732         { "set_int", Effect_set_int },
733         { "set_vec3", Effect_set_vec3 },
734         { "set_vec4", Effect_set_vec4 },
735         { NULL, NULL }
736 };
737
738 const luaL_Reg OverlayEffect_funcs[] = {
739         { "new", OverlayEffect_new },
740         { "set_float", Effect_set_float },
741         { "set_int", Effect_set_int },
742         { "set_vec3", Effect_set_vec3 },
743         { "set_vec4", Effect_set_vec4 },
744         { NULL, NULL }
745 };
746
747 const luaL_Reg ResizeEffect_funcs[] = {
748         { "new", ResizeEffect_new },
749         { "set_float", Effect_set_float },
750         { "set_int", Effect_set_int },
751         { "set_vec3", Effect_set_vec3 },
752         { "set_vec4", Effect_set_vec4 },
753         { NULL, NULL }
754 };
755
756 const luaL_Reg MultiplyEffect_funcs[] = {
757         { "new", MultiplyEffect_new },
758         { "set_float", Effect_set_float },
759         { "set_int", Effect_set_int },
760         { "set_vec3", Effect_set_vec3 },
761         { "set_vec4", Effect_set_vec4 },
762         { NULL, NULL }
763 };
764
765 const luaL_Reg MixEffect_funcs[] = {
766         { "new", MixEffect_new },
767         { "set_float", Effect_set_float },
768         { "set_int", Effect_set_int },
769         { "set_vec3", Effect_set_vec3 },
770         { "set_vec4", Effect_set_vec4 },
771         { NULL, NULL }
772 };
773
774 const luaL_Reg InputStateInfo_funcs[] = {
775         { "get_width", InputStateInfo_get_width },
776         { "get_height", InputStateInfo_get_height },
777         { "get_interlaced", InputStateInfo_get_interlaced },
778         { "get_has_signal", InputStateInfo_get_has_signal },
779         { "get_is_connected", InputStateInfo_get_is_connected },
780         { "get_frame_rate_nom", InputStateInfo_get_frame_rate_nom },
781         { "get_frame_rate_den", InputStateInfo_get_frame_rate_den },
782         { NULL, NULL }
783 };
784
785 }  // namespace
786
787 LiveInputWrapper::LiveInputWrapper(Theme *theme, EffectChain *chain, bmusb::PixelFormat pixel_format, bool override_bounce, bool deinterlace)
788         : theme(theme),
789           pixel_format(pixel_format),
790           deinterlace(deinterlace)
791 {
792         ImageFormat inout_format;
793         inout_format.color_space = COLORSPACE_sRGB;
794
795         // Gamma curve depends on the input signal, and we don't really get any
796         // indications. A camera would be expected to do Rec. 709, but
797         // I haven't checked if any do in practice. However, computers _do_ output
798         // in sRGB gamma (ie., they don't convert from sRGB to Rec. 709), and
799         // I wouldn't really be surprised if most non-professional cameras do, too.
800         // So we pick sRGB as the least evil here.
801         inout_format.gamma_curve = GAMMA_sRGB;
802
803         unsigned num_inputs;
804         if (deinterlace) {
805                 deinterlace_effect = new movit::DeinterlaceEffect();
806
807                 // As per the comments in deinterlace_effect.h, we turn this off.
808                 // The most likely interlaced input for us is either a camera
809                 // (where it's fine to turn it off) or a laptop (where it _should_
810                 // be turned off).
811                 CHECK(deinterlace_effect->set_int("enable_spatial_interlacing_check", 0));
812
813                 num_inputs = deinterlace_effect->num_inputs();
814                 assert(num_inputs == FRAME_HISTORY_LENGTH);
815         } else {
816                 num_inputs = 1;
817         }
818
819         if (pixel_format == bmusb::PixelFormat_8BitBGRA) {
820                 for (unsigned i = 0; i < num_inputs; ++i) {
821                         // We upload our textures ourselves, and Movit swaps
822                         // R and B in the shader if we specify BGRA, so lie and say RGBA.
823                         if (global_flags.can_disable_srgb_decoder) {
824                                 rgba_inputs.push_back(new sRGBSwitchingFlatInput(inout_format, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, GL_UNSIGNED_BYTE, global_flags.width, global_flags.height));
825                         } else {
826                                 rgba_inputs.push_back(new NonsRGBCapableFlatInput(inout_format, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, GL_UNSIGNED_BYTE, global_flags.width, global_flags.height));
827                         }
828                         chain->add_input(rgba_inputs.back());
829                 }
830
831                 if (deinterlace) {
832                         vector<Effect *> reverse_inputs(rgba_inputs.rbegin(), rgba_inputs.rend());
833                         chain->add_effect(deinterlace_effect, reverse_inputs);
834                 }
835         } else {
836                 assert(pixel_format == bmusb::PixelFormat_8BitYCbCr ||
837                        pixel_format == bmusb::PixelFormat_10BitYCbCr ||
838                        pixel_format == bmusb::PixelFormat_8BitYCbCrPlanar);
839
840                 // Most of these settings will be overridden later if using PixelFormat_8BitYCbCrPlanar.
841                 input_ycbcr_format.chroma_subsampling_x = (pixel_format == bmusb::PixelFormat_10BitYCbCr) ? 1 : 2;
842                 input_ycbcr_format.chroma_subsampling_y = 1;
843                 input_ycbcr_format.num_levels = (pixel_format == bmusb::PixelFormat_10BitYCbCr) ? 1024 : 256;
844                 input_ycbcr_format.cb_x_position = 0.0;
845                 input_ycbcr_format.cr_x_position = 0.0;
846                 input_ycbcr_format.cb_y_position = 0.5;
847                 input_ycbcr_format.cr_y_position = 0.5;
848                 input_ycbcr_format.luma_coefficients = YCBCR_REC_709;  // Will be overridden later even if not planar.
849                 input_ycbcr_format.full_range = false;  // Will be overridden later even if not planar.
850
851                 for (unsigned i = 0; i < num_inputs; ++i) {
852                         // When using 10-bit input, we're converting to interleaved through v210Converter.
853                         YCbCrInputSplitting splitting;
854                         if (pixel_format == bmusb::PixelFormat_10BitYCbCr) {
855                                 splitting = YCBCR_INPUT_INTERLEAVED;
856                         } else if (pixel_format == bmusb::PixelFormat_8BitYCbCr) {
857                                 splitting = YCBCR_INPUT_SPLIT_Y_AND_CBCR;
858                         } else {
859                                 splitting = YCBCR_INPUT_PLANAR;
860                         }
861                         if (override_bounce) {
862                                 ycbcr_inputs.push_back(new NonBouncingYCbCrInput(inout_format, input_ycbcr_format, global_flags.width, global_flags.height, splitting));
863                         } else {
864                                 ycbcr_inputs.push_back(new YCbCrInput(inout_format, input_ycbcr_format, global_flags.width, global_flags.height, splitting));
865                         }
866                         chain->add_input(ycbcr_inputs.back());
867                 }
868
869                 if (deinterlace) {
870                         vector<Effect *> reverse_inputs(ycbcr_inputs.rbegin(), ycbcr_inputs.rend());
871                         chain->add_effect(deinterlace_effect, reverse_inputs);
872                 }
873         }
874 }
875
876 void LiveInputWrapper::connect_signal(int signal_num)
877 {
878         if (global_mixer == nullptr) {
879                 // No data yet.
880                 return;
881         }
882
883         signal_num = theme->map_signal(signal_num);
884         connect_signal_raw(signal_num, *theme->input_state);
885 }
886
887 void LiveInputWrapper::connect_signal_raw(int signal_num, const InputState &input_state)
888 {
889         BufferedFrame first_frame = input_state.buffered_frames[signal_num][0];
890         if (first_frame.frame == nullptr) {
891                 // No data yet.
892                 return;
893         }
894         unsigned width, height;
895         {
896                 const PBOFrameAllocator::Userdata *userdata = (const PBOFrameAllocator::Userdata *)first_frame.frame->userdata;
897                 width = userdata->last_width[first_frame.field_number];
898                 height = userdata->last_height[first_frame.field_number];
899         }
900
901         movit::YCbCrLumaCoefficients ycbcr_coefficients = input_state.ycbcr_coefficients[signal_num];
902         bool full_range = input_state.full_range[signal_num];
903
904         if (input_state.ycbcr_coefficients_auto[signal_num]) {
905                 full_range = false;
906
907                 // The Blackmagic driver docs claim that the device outputs Y'CbCr
908                 // according to Rec. 601, but this seems to indicate the subsampling
909                 // positions only, as they publish Y'CbCr → RGB formulas that are
910                 // different for HD and SD (corresponding to Rec. 709 and 601, respectively),
911                 // and a Lenovo X1 gen 3 I used to test definitely outputs Rec. 709
912                 // (at least up to rounding error). Other devices seem to use Rec. 601
913                 // even on HD resolutions. Nevertheless, Rec. 709 _is_ the right choice
914                 // for HD, so we default to that if the user hasn't set anything.
915                 if (height >= 720) {
916                         ycbcr_coefficients = YCBCR_REC_709;
917                 } else {
918                         ycbcr_coefficients = YCBCR_REC_601;
919                 }
920         }
921
922         // This is a global, but it doesn't really matter.
923         input_ycbcr_format.luma_coefficients = ycbcr_coefficients;
924         input_ycbcr_format.full_range = full_range;
925
926         BufferedFrame last_good_frame = first_frame;
927         for (unsigned i = 0; i < max(ycbcr_inputs.size(), rgba_inputs.size()); ++i) {
928                 BufferedFrame frame = input_state.buffered_frames[signal_num][i];
929                 if (frame.frame == nullptr) {
930                         // Not enough data; reuse last frame (well, field).
931                         // This is suboptimal, but we have nothing better.
932                         frame = last_good_frame;
933                 }
934                 const PBOFrameAllocator::Userdata *userdata = (const PBOFrameAllocator::Userdata *)frame.frame->userdata;
935
936                 unsigned this_width = userdata->last_width[frame.field_number];
937                 unsigned this_height = userdata->last_height[frame.field_number];
938                 if (this_width != width || this_height != height) {
939                         // Resolution changed; reuse last frame/field.
940                         frame = last_good_frame;
941                         userdata = (const PBOFrameAllocator::Userdata *)frame.frame->userdata;
942                 }
943
944                 assert(userdata->pixel_format == pixel_format);
945                 switch (pixel_format) {
946                 case bmusb::PixelFormat_8BitYCbCr:
947                         ycbcr_inputs[i]->set_texture_num(0, userdata->tex_y[frame.field_number]);
948                         ycbcr_inputs[i]->set_texture_num(1, userdata->tex_cbcr[frame.field_number]);
949                         ycbcr_inputs[i]->change_ycbcr_format(input_ycbcr_format);
950                         ycbcr_inputs[i]->set_width(width);
951                         ycbcr_inputs[i]->set_height(height);
952                         break;
953                 case bmusb::PixelFormat_8BitYCbCrPlanar:
954                         ycbcr_inputs[i]->set_texture_num(0, userdata->tex_y[frame.field_number]);
955                         ycbcr_inputs[i]->set_texture_num(1, userdata->tex_cb[frame.field_number]);
956                         ycbcr_inputs[i]->set_texture_num(2, userdata->tex_cr[frame.field_number]);
957                         ycbcr_inputs[i]->change_ycbcr_format(userdata->ycbcr_format);
958                         ycbcr_inputs[i]->set_width(width);
959                         ycbcr_inputs[i]->set_height(height);
960                         break;
961                 case bmusb::PixelFormat_10BitYCbCr:
962                         ycbcr_inputs[i]->set_texture_num(0, userdata->tex_444[frame.field_number]);
963                         ycbcr_inputs[i]->change_ycbcr_format(input_ycbcr_format);
964                         ycbcr_inputs[i]->set_width(width);
965                         ycbcr_inputs[i]->set_height(height);
966                         break;
967                 case bmusb::PixelFormat_8BitBGRA:
968                         rgba_inputs[i]->set_texture_num(userdata->tex_rgba[frame.field_number]);
969                         rgba_inputs[i]->set_width(width);
970                         rgba_inputs[i]->set_height(height);
971                         break;
972                 default:
973                         assert(false);
974                 }
975
976                 last_good_frame = frame;
977         }
978
979         if (deinterlace) {
980                 BufferedFrame frame = input_state.buffered_frames[signal_num][0];
981                 CHECK(deinterlace_effect->set_int("current_field_position", frame.field_number));
982         }
983 }
984
985 namespace {
986
987 int call_num_channels(lua_State *L)
988 {
989         lua_getglobal(L, "num_channels");
990
991         if (lua_pcall(L, 0, 1, 0) != 0) {
992                 fprintf(stderr, "error running function `num_channels': %s\n", lua_tostring(L, -1));
993                 exit(1);
994         }
995
996         int num_channels = luaL_checknumber(L, 1);
997         lua_pop(L, 1);
998         assert(lua_gettop(L) == 0);
999         return num_channels;
1000 }
1001
1002 }  // namespace
1003
1004 Theme::Theme(const string &filename, const vector<string> &search_dirs, ResourcePool *resource_pool, unsigned num_cards)
1005         : resource_pool(resource_pool), num_cards(num_cards), signal_to_card_mapping(global_flags.default_stream_mapping)
1006 {
1007         L = luaL_newstate();
1008         luaL_openlibs(L);
1009
1010         register_constants();
1011         register_class("EffectChain", EffectChain_funcs); 
1012         register_class("LiveInputWrapper", LiveInputWrapper_funcs); 
1013         register_class("ImageInput", ImageInput_funcs);
1014         register_class("VideoInput", VideoInput_funcs);
1015         register_class("HTMLInput", HTMLInput_funcs);
1016         register_class("WhiteBalanceEffect", WhiteBalanceEffect_funcs);
1017         register_class("ResampleEffect", ResampleEffect_funcs);
1018         register_class("PaddingEffect", PaddingEffect_funcs);
1019         register_class("IntegralPaddingEffect", IntegralPaddingEffect_funcs);
1020         register_class("OverlayEffect", OverlayEffect_funcs);
1021         register_class("ResizeEffect", ResizeEffect_funcs);
1022         register_class("MultiplyEffect", MultiplyEffect_funcs);
1023         register_class("MixEffect", MixEffect_funcs);
1024         register_class("InputStateInfo", InputStateInfo_funcs);
1025
1026         // Run script. Search through all directories until we find a file that will load
1027         // (as in, does not return LUA_ERRFILE); then run it. We store load errors
1028         // from all the attempts, and show them once we know we can't find any of them.
1029         lua_settop(L, 0);
1030         vector<string> errors;
1031         bool success = false;
1032         for (size_t i = 0; i < search_dirs.size(); ++i) {
1033                 string path = search_dirs[i] + "/" + filename;
1034                 int err = luaL_loadfile(L, path.c_str());
1035                 if (err == 0) {
1036                         // Success; actually call the code.
1037                         if (lua_pcall(L, 0, LUA_MULTRET, 0)) {
1038                                 fprintf(stderr, "Error when running %s: %s\n", path.c_str(), lua_tostring(L, -1));
1039                                 exit(1);
1040                         }
1041                         success = true;
1042                         break;
1043                 }
1044                 errors.push_back(lua_tostring(L, -1));
1045                 lua_pop(L, 1);
1046                 if (err != LUA_ERRFILE) {
1047                         // The file actually loaded, but failed to parse somehow. Abort; don't try the next one.
1048                         break;
1049                 }
1050         }
1051
1052         if (!success) {
1053                 for (const string &error : errors) {
1054                         fprintf(stderr, "%s\n", error.c_str());
1055                 }
1056                 exit(1);
1057         }
1058         assert(lua_gettop(L) == 0);
1059
1060         // Ask it for the number of channels.
1061         num_channels = call_num_channels(L);
1062 }
1063
1064 Theme::~Theme()
1065 {
1066         lua_close(L);
1067 }
1068
1069 void Theme::register_constants()
1070 {
1071         // Set Nageru.VIDEO_FORMAT_BGRA = bmusb::PixelFormat_8BitBGRA, etc.
1072         const vector<pair<string, int>> constants = {
1073                 { "VIDEO_FORMAT_BGRA", bmusb::PixelFormat_8BitBGRA },
1074                 { "VIDEO_FORMAT_YCBCR", bmusb::PixelFormat_8BitYCbCrPlanar },
1075         };
1076
1077         lua_newtable(L);  // t = {}
1078
1079         for (const pair<string, int> &constant : constants) {
1080                 lua_pushstring(L, constant.first.c_str());
1081                 lua_pushinteger(L, constant.second);
1082                 lua_settable(L, 1);  // t[key] = value
1083         }
1084
1085         lua_setglobal(L, "Nageru");  // Nageru = t
1086         assert(lua_gettop(L) == 0);
1087 }
1088
1089 void Theme::register_class(const char *class_name, const luaL_Reg *funcs)
1090 {
1091         assert(lua_gettop(L) == 0);
1092         luaL_newmetatable(L, class_name);  // mt = {}
1093         lua_pushlightuserdata(L, this);
1094         luaL_setfuncs(L, funcs, 1);        // for (name,f in funcs) { mt[name] = f, with upvalue {theme} }
1095         lua_pushvalue(L, -1);
1096         lua_setfield(L, -2, "__index");    // mt.__index = mt
1097         lua_setglobal(L, class_name);      // ClassName = mt
1098         assert(lua_gettop(L) == 0);
1099 }
1100
1101 Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned height, InputState input_state) 
1102 {
1103         Chain chain;
1104
1105         unique_lock<mutex> lock(m);
1106         assert(lua_gettop(L) == 0);
1107         lua_getglobal(L, "get_chain");  /* function to be called */
1108         lua_pushnumber(L, num);
1109         lua_pushnumber(L, t);
1110         lua_pushnumber(L, width);
1111         lua_pushnumber(L, height);
1112         wrap_lua_object<InputStateInfo>(L, "InputStateInfo", input_state);
1113
1114         if (lua_pcall(L, 5, 2, 0) != 0) {
1115                 fprintf(stderr, "error running function `get_chain': %s\n", lua_tostring(L, -1));
1116                 exit(1);
1117         }
1118
1119         chain.chain = (EffectChain *)luaL_testudata(L, -2, "EffectChain");
1120         if (chain.chain == nullptr) {
1121                 fprintf(stderr, "get_chain() for chain number %d did not return an EffectChain\n",
1122                         num);
1123                 exit(1);
1124         }
1125         if (!lua_isfunction(L, -1)) {
1126                 fprintf(stderr, "Argument #-1 should be a function\n");
1127                 exit(1);
1128         }
1129         lua_pushvalue(L, -1);
1130         shared_ptr<LuaRefWithDeleter> funcref(new LuaRefWithDeleter(&m, L, luaL_ref(L, LUA_REGISTRYINDEX)));
1131         lua_pop(L, 2);
1132         assert(lua_gettop(L) == 0);
1133
1134         chain.setup_chain = [this, funcref, input_state]{
1135                 unique_lock<mutex> lock(m);
1136
1137                 assert(this->input_state == nullptr);
1138                 this->input_state = &input_state;
1139
1140                 // Set up state, including connecting signals.
1141                 lua_rawgeti(L, LUA_REGISTRYINDEX, funcref->get());
1142                 if (lua_pcall(L, 0, 0, 0) != 0) {
1143                         fprintf(stderr, "error running chain setup callback: %s\n", lua_tostring(L, -1));
1144                         exit(1);
1145                 }
1146                 assert(lua_gettop(L) == 0);
1147
1148                 this->input_state = nullptr;
1149         };
1150
1151         // TODO: Can we do better, e.g. by running setup_chain() and seeing what it references?
1152         // Actually, setup_chain does maybe hold all the references we need now anyway?
1153         chain.input_frames.reserve(num_cards * FRAME_HISTORY_LENGTH);
1154         for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
1155                 for (unsigned frame_num = 0; frame_num < FRAME_HISTORY_LENGTH; ++frame_num) {
1156                         chain.input_frames.push_back(input_state.buffered_frames[card_index][frame_num].frame);
1157                 }
1158         }
1159
1160         return chain;
1161 }
1162
1163 string Theme::get_channel_name(unsigned channel)
1164 {
1165         unique_lock<mutex> lock(m);
1166         lua_getglobal(L, "channel_name");
1167         lua_pushnumber(L, channel);
1168         if (lua_pcall(L, 1, 1, 0) != 0) {
1169                 fprintf(stderr, "error running function `channel_name': %s\n", lua_tostring(L, -1));
1170                 exit(1);
1171         }
1172         const char *ret = lua_tostring(L, -1);
1173         if (ret == nullptr) {
1174                 fprintf(stderr, "function `channel_name' returned nil for channel %d\n", channel);
1175                 exit(1);
1176         }
1177
1178         string retstr = ret;
1179         lua_pop(L, 1);
1180         assert(lua_gettop(L) == 0);
1181         return retstr;
1182 }
1183
1184 int Theme::get_channel_signal(unsigned channel)
1185 {
1186         unique_lock<mutex> lock(m);
1187         lua_getglobal(L, "channel_signal");
1188         lua_pushnumber(L, channel);
1189         if (lua_pcall(L, 1, 1, 0) != 0) {
1190                 fprintf(stderr, "error running function `channel_signal': %s\n", lua_tostring(L, -1));
1191                 exit(1);
1192         }
1193
1194         int ret = luaL_checknumber(L, 1);
1195         lua_pop(L, 1);
1196         assert(lua_gettop(L) == 0);
1197         return ret;
1198 }
1199
1200 std::string Theme::get_channel_color(unsigned channel)
1201 {
1202         unique_lock<mutex> lock(m);
1203         lua_getglobal(L, "channel_color");
1204         lua_pushnumber(L, channel);
1205         if (lua_pcall(L, 1, 1, 0) != 0) {
1206                 fprintf(stderr, "error running function `channel_color': %s\n", lua_tostring(L, -1));
1207                 exit(1);
1208         }
1209
1210         const char *ret = lua_tostring(L, -1);
1211         if (ret == nullptr) {
1212                 fprintf(stderr, "function `channel_color' returned nil for channel %d\n", channel);
1213                 exit(1);
1214         }
1215
1216         string retstr = ret;
1217         lua_pop(L, 1);
1218         assert(lua_gettop(L) == 0);
1219         return retstr;
1220 }
1221
1222 bool Theme::get_supports_set_wb(unsigned channel)
1223 {
1224         unique_lock<mutex> lock(m);
1225         lua_getglobal(L, "supports_set_wb");
1226         lua_pushnumber(L, channel);
1227         if (lua_pcall(L, 1, 1, 0) != 0) {
1228                 fprintf(stderr, "error running function `supports_set_wb': %s\n", lua_tostring(L, -1));
1229                 exit(1);
1230         }
1231
1232         bool ret = checkbool(L, -1);
1233         lua_pop(L, 1);
1234         assert(lua_gettop(L) == 0);
1235         return ret;
1236 }
1237
1238 void Theme::set_wb(unsigned channel, double r, double g, double b)
1239 {
1240         unique_lock<mutex> lock(m);
1241         lua_getglobal(L, "set_wb");
1242         lua_pushnumber(L, channel);
1243         lua_pushnumber(L, r);
1244         lua_pushnumber(L, g);
1245         lua_pushnumber(L, b);
1246         if (lua_pcall(L, 4, 0, 0) != 0) {
1247                 fprintf(stderr, "error running function `set_wb': %s\n", lua_tostring(L, -1));
1248                 exit(1);
1249         }
1250
1251         assert(lua_gettop(L) == 0);
1252 }
1253
1254 vector<string> Theme::get_transition_names(float t)
1255 {
1256         unique_lock<mutex> lock(m);
1257         lua_getglobal(L, "get_transitions");
1258         lua_pushnumber(L, t);
1259         if (lua_pcall(L, 1, 1, 0) != 0) {
1260                 fprintf(stderr, "error running function `get_transitions': %s\n", lua_tostring(L, -1));
1261                 exit(1);
1262         }
1263
1264         vector<string> ret;
1265         lua_pushnil(L);
1266         while (lua_next(L, -2) != 0) {
1267                 ret.push_back(lua_tostring(L, -1));
1268                 lua_pop(L, 1);
1269         }
1270         lua_pop(L, 1);
1271         assert(lua_gettop(L) == 0);
1272         return ret;
1273 }       
1274
1275 int Theme::map_signal(int signal_num)
1276 {
1277         // Negative numbers map to raw signals.
1278         if (signal_num < 0) {
1279                 return -1 - signal_num;
1280         }
1281
1282         unique_lock<mutex> lock(map_m);
1283         if (signal_to_card_mapping.count(signal_num)) {
1284                 return signal_to_card_mapping[signal_num];
1285         }
1286
1287         int card_index;
1288         if (global_flags.output_card != -1 && num_cards > 1) {
1289                 // Try to exclude the output card from the default card_index.
1290                 card_index = signal_num % (num_cards - 1);
1291                 if (card_index >= global_flags.output_card) {
1292                          ++card_index;
1293                 }
1294                 if (signal_num >= int(num_cards - 1)) {
1295                         fprintf(stderr, "WARNING: Theme asked for input %d, but we only have %u input card(s) (card %d is busy with output).\n",
1296                                 signal_num, num_cards - 1, global_flags.output_card);
1297                         fprintf(stderr, "Mapping to card %d instead.\n", card_index);
1298                 }
1299         } else {
1300                 card_index = signal_num % num_cards;
1301                 if (signal_num >= int(num_cards)) {
1302                         fprintf(stderr, "WARNING: Theme asked for input %d, but we only have %u card(s).\n", signal_num, num_cards);
1303                         fprintf(stderr, "Mapping to card %d instead.\n", card_index);
1304                 }
1305         }
1306         signal_to_card_mapping[signal_num] = card_index;
1307         return card_index;
1308 }
1309
1310 void Theme::set_signal_mapping(int signal_num, int card_num)
1311 {
1312         unique_lock<mutex> lock(map_m);
1313         assert(card_num < int(num_cards));
1314         signal_to_card_mapping[signal_num] = card_num;
1315 }
1316
1317 void Theme::transition_clicked(int transition_num, float t)
1318 {
1319         unique_lock<mutex> lock(m);
1320         lua_getglobal(L, "transition_clicked");
1321         lua_pushnumber(L, transition_num);
1322         lua_pushnumber(L, t);
1323
1324         if (lua_pcall(L, 2, 0, 0) != 0) {
1325                 fprintf(stderr, "error running function `transition_clicked': %s\n", lua_tostring(L, -1));
1326                 exit(1);
1327         }
1328         assert(lua_gettop(L) == 0);
1329 }
1330
1331 void Theme::channel_clicked(int preview_num)
1332 {
1333         unique_lock<mutex> lock(m);
1334         lua_getglobal(L, "channel_clicked");
1335         lua_pushnumber(L, preview_num);
1336
1337         if (lua_pcall(L, 1, 0, 0) != 0) {
1338                 fprintf(stderr, "error running function `channel_clicked': %s\n", lua_tostring(L, -1));
1339                 exit(1);
1340         }
1341         assert(lua_gettop(L) == 0);
1342 }