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