]> git.sesse.net Git - nageru/blob - theme.cpp
Better error messages when channel_name/channel_color return nil.
[nageru] / theme.cpp
1 #include "theme.h"
2
3 #include <assert.h>
4 #include <lauxlib.h>
5 #include <lua.hpp>
6 #include <movit/effect.h>
7 #include <movit/effect_chain.h>
8 #include <movit/image_format.h>
9 #include <movit/mix_effect.h>
10 #include <movit/overlay_effect.h>
11 #include <movit/padding_effect.h>
12 #include <movit/resample_effect.h>
13 #include <movit/resize_effect.h>
14 #include <movit/multiply_effect.h>
15 #include <movit/util.h>
16 #include <movit/white_balance_effect.h>
17 #include <movit/ycbcr.h>
18 #include <movit/ycbcr_input.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <cstddef>
22 #include <new>
23 #include <utility>
24 #include <memory>
25
26 #include "defs.h"
27 #include "flags.h"
28 #include "image_input.h"
29 #include "mixer.h"
30
31 namespace movit {
32 class ResourcePool;
33 }  // namespace movit
34
35 using namespace std;
36 using namespace movit;
37
38 extern Mixer *global_mixer;
39
40 namespace {
41
42 // Contains basically the same data as InputState, but does not hold on to
43 // a reference to the frames. This is important so that we can release them
44 // without having to wait for Lua's GC.
45 struct InputStateInfo {
46         InputStateInfo(const InputState& input_state);
47
48         unsigned last_width[MAX_CARDS], last_height[MAX_CARDS];
49         bool last_interlaced[MAX_CARDS], last_has_signal[MAX_CARDS];
50         unsigned last_frame_rate_nom[MAX_CARDS], last_frame_rate_den[MAX_CARDS];
51 };
52
53 InputStateInfo::InputStateInfo(const InputState &input_state)
54 {
55         for (unsigned signal_num = 0; signal_num < MAX_CARDS; ++signal_num) {
56                 BufferedFrame frame = input_state.buffered_frames[signal_num][0];
57                 if (frame.frame == nullptr) {
58                         last_width[signal_num] = last_height[signal_num] = 0;
59                         last_interlaced[signal_num] = false;
60                         last_has_signal[signal_num] = false;
61                         continue;
62                 }
63                 const PBOFrameAllocator::Userdata *userdata = (const PBOFrameAllocator::Userdata *)frame.frame->userdata;
64                 last_width[signal_num] = userdata->last_width[frame.field_number];
65                 last_height[signal_num] = userdata->last_height[frame.field_number];
66                 last_interlaced[signal_num] = userdata->last_interlaced;
67                 last_has_signal[signal_num] = userdata->last_has_signal;
68                 last_frame_rate_nom[signal_num] = userdata->last_frame_rate_nom;
69                 last_frame_rate_den[signal_num] = userdata->last_frame_rate_den;
70         }
71 }
72
73 class LuaRefWithDeleter {
74 public:
75         LuaRefWithDeleter(mutex *m, lua_State *L, int ref) : m(m), L(L), ref(ref) {}
76         ~LuaRefWithDeleter() {
77                 unique_lock<mutex> lock(*m);
78                 luaL_unref(L, LUA_REGISTRYINDEX, ref);
79         }
80         int get() const { return ref; }
81
82 private:
83         LuaRefWithDeleter(const LuaRefWithDeleter &) = delete;
84
85         mutex *m;
86         lua_State *L;
87         int ref;
88 };
89
90 template<class T, class... Args>
91 int wrap_lua_object(lua_State* L, const char *class_name, Args&&... args)
92 {
93         // Construct the C++ object and put it on the stack.
94         void *mem = lua_newuserdata(L, sizeof(T));
95         new(mem) T(forward<Args>(args)...);
96
97         // Look up the metatable named <class_name>, and set it on the new object.
98         luaL_getmetatable(L, class_name);
99         lua_setmetatable(L, -2);
100
101         return 1;
102 }
103
104 // Like wrap_lua_object, but the object is not owned by Lua; ie. it's not freed
105 // by Lua GC. This is typically the case for Effects, which are owned by EffectChain
106 // and expected to be destructed by it. The object will be of type T** instead of T*
107 // when exposed to Lua.
108 //
109 // Note that we currently leak if you allocate an Effect in this way and never call
110 // add_effect. We should see if there's a way to e.g. set __gc on it at construction time
111 // and then release that once add_effect() takes ownership.
112 template<class T, class... Args>
113 int wrap_lua_object_nonowned(lua_State* L, const char *class_name, Args&&... args)
114 {
115         // Construct the pointer ot the C++ object and put it on the stack.
116         T **obj = (T **)lua_newuserdata(L, sizeof(T *));
117         *obj = new T(forward<Args>(args)...);
118
119         // Look up the metatable named <class_name>, and set it on the new object.
120         luaL_getmetatable(L, class_name);
121         lua_setmetatable(L, -2);
122
123         return 1;
124 }
125
126 Theme *get_theme_updata(lua_State* L)
127 {       
128         luaL_checktype(L, lua_upvalueindex(1), LUA_TLIGHTUSERDATA);
129         return (Theme *)lua_touserdata(L, lua_upvalueindex(1));
130 }
131
132 Effect *get_effect(lua_State *L, int idx)
133 {
134         if (luaL_testudata(L, idx, "WhiteBalanceEffect") ||
135             luaL_testudata(L, idx, "ResampleEffect") ||
136             luaL_testudata(L, idx, "PaddingEffect") ||
137             luaL_testudata(L, idx, "IntegralPaddingEffect") ||
138             luaL_testudata(L, idx, "OverlayEffect") ||
139             luaL_testudata(L, idx, "ResizeEffect") ||
140             luaL_testudata(L, idx, "MultiplyEffect") ||
141             luaL_testudata(L, idx, "MixEffect") ||
142             luaL_testudata(L, idx, "ImageInput")) {
143                 return *(Effect **)lua_touserdata(L, idx);
144         }
145         luaL_error(L, "Error: Index #%d was not an Effect type\n", idx);
146         return nullptr;
147 }
148
149 InputStateInfo *get_input_state_info(lua_State *L, int idx)
150 {
151         if (luaL_testudata(L, idx, "InputStateInfo")) {
152                 return (InputStateInfo *)lua_touserdata(L, idx);
153         }
154         luaL_error(L, "Error: Index #%d was not InputStateInfo\n", idx);
155         return nullptr;
156 }
157
158 bool checkbool(lua_State* L, int idx)
159 {
160         luaL_checktype(L, idx, LUA_TBOOLEAN);
161         return lua_toboolean(L, idx);
162 }
163
164 string checkstdstring(lua_State *L, int index)
165 {
166         size_t len;
167         const char* cstr = lua_tolstring(L, index, &len);
168         return string(cstr, len);
169 }
170
171 int EffectChain_new(lua_State* L)
172 {
173         assert(lua_gettop(L) == 2);
174         Theme *theme = get_theme_updata(L);
175         int aspect_w = luaL_checknumber(L, 1);
176         int aspect_h = luaL_checknumber(L, 2);
177
178         return wrap_lua_object<EffectChain>(L, "EffectChain", aspect_w, aspect_h, theme->get_resource_pool());
179 }
180
181 int EffectChain_gc(lua_State* L)
182 {
183         assert(lua_gettop(L) == 1);
184         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
185         chain->~EffectChain();
186         return 0;
187 }
188
189 int EffectChain_add_live_input(lua_State* L)
190 {
191         assert(lua_gettop(L) == 3);
192         Theme *theme = get_theme_updata(L);
193         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
194         bool override_bounce = checkbool(L, 2);
195         bool deinterlace = checkbool(L, 3);
196         return wrap_lua_object<LiveInputWrapper>(L, "LiveInputWrapper", theme, chain, override_bounce, deinterlace);
197 }
198
199 int EffectChain_add_effect(lua_State* L)
200 {
201         assert(lua_gettop(L) >= 2);
202         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
203
204         // TODO: Better error reporting.
205         Effect *effect = get_effect(L, 2);
206         if (lua_gettop(L) == 2) {
207                 if (effect->num_inputs() == 0) {
208                         chain->add_input((Input *)effect);
209                 } else {
210                         chain->add_effect(effect);
211                 }
212         } else {
213                 vector<Effect *> inputs;
214                 for (int idx = 3; idx <= lua_gettop(L); ++idx) {
215                         if (luaL_testudata(L, idx, "LiveInputWrapper")) {
216                                 LiveInputWrapper *input = (LiveInputWrapper *)lua_touserdata(L, idx);
217                                 inputs.push_back(input->get_effect());
218                         } else {
219                                 inputs.push_back(get_effect(L, idx));
220                         }
221                 }
222                 chain->add_effect(effect, inputs);
223         }
224
225         lua_settop(L, 2);  // Return the effect itself.
226
227         // Make sure Lua doesn't garbage-collect it away.
228         lua_pushvalue(L, -1);
229         luaL_ref(L, LUA_REGISTRYINDEX);  // TODO: leak?
230
231         return 1;
232 }
233
234 int EffectChain_finalize(lua_State* L)
235 {
236         assert(lua_gettop(L) == 2);
237         EffectChain *chain = (EffectChain *)luaL_checkudata(L, 1, "EffectChain");
238         bool is_main_chain = checkbool(L, 2);
239
240         // Add outputs as needed.
241         // NOTE: If you change any details about the output format, you will need to
242         // also update what's given to the muxer (HTTPD::Mux constructor) and
243         // what's put in the H.264 stream (sps_rbsp()).
244         ImageFormat inout_format;
245         inout_format.color_space = COLORSPACE_REC_709;
246
247         // Output gamma is tricky. We should output Rec. 709 for TV, except that
248         // we expect to run with web players and others that don't really care and
249         // just output with no conversion. So that means we'll need to output sRGB,
250         // even though H.264 has no setting for that (we use “unspecified”).
251         inout_format.gamma_curve = GAMMA_sRGB;
252
253         if (is_main_chain) {
254                 YCbCrFormat output_ycbcr_format;
255                 // We actually output 4:2:0 in the end, but chroma subsampling
256                 // happens in a pass not run by Movit (see Mixer::subsample_chroma()).
257                 output_ycbcr_format.chroma_subsampling_x = 1;
258                 output_ycbcr_format.chroma_subsampling_y = 1;
259
260                 // Rec. 709 would be the sane thing to do, but it seems many players
261                 // (e.g. MPlayer and VLC) just default to BT.601 coefficients no matter
262                 // what (see discussions in e.g. https://trac.ffmpeg.org/ticket/4978).
263                 // We _do_ set the right flags, though, so that a player that works
264                 // properly doesn't have to guess.
265                 output_ycbcr_format.luma_coefficients = YCBCR_REC_601;
266                 output_ycbcr_format.full_range = false;
267                 output_ycbcr_format.num_levels = 256;
268
269                 chain->add_ycbcr_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED, output_ycbcr_format, YCBCR_OUTPUT_SPLIT_Y_AND_CBCR);
270                 chain->set_dither_bits(8);
271                 chain->set_output_origin(OUTPUT_ORIGIN_TOP_LEFT);
272         }
273         chain->add_output(inout_format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
274
275         chain->finalize();
276         return 0;
277 }
278
279 int LiveInputWrapper_connect_signal(lua_State* L)
280 {
281         assert(lua_gettop(L) == 2);
282         LiveInputWrapper *input = (LiveInputWrapper *)luaL_checkudata(L, 1, "LiveInputWrapper");
283         int signal_num = luaL_checknumber(L, 2);
284         input->connect_signal(signal_num);
285         return 0;
286 }
287
288 int ImageInput_new(lua_State* L)
289 {
290         assert(lua_gettop(L) == 1);
291         string filename = checkstdstring(L, 1);
292         return wrap_lua_object_nonowned<ImageInput>(L, "ImageInput", filename);
293 }
294
295 int WhiteBalanceEffect_new(lua_State* L)
296 {
297         assert(lua_gettop(L) == 0);
298         return wrap_lua_object_nonowned<WhiteBalanceEffect>(L, "WhiteBalanceEffect");
299 }
300
301 int ResampleEffect_new(lua_State* L)
302 {
303         assert(lua_gettop(L) == 0);
304         return wrap_lua_object_nonowned<ResampleEffect>(L, "ResampleEffect");
305 }
306
307 int PaddingEffect_new(lua_State* L)
308 {
309         assert(lua_gettop(L) == 0);
310         return wrap_lua_object_nonowned<PaddingEffect>(L, "PaddingEffect");
311 }
312
313 int IntegralPaddingEffect_new(lua_State* L)
314 {
315         assert(lua_gettop(L) == 0);
316         return wrap_lua_object_nonowned<IntegralPaddingEffect>(L, "IntegralPaddingEffect");
317 }
318
319 int OverlayEffect_new(lua_State* L)
320 {
321         assert(lua_gettop(L) == 0);
322         return wrap_lua_object_nonowned<OverlayEffect>(L, "OverlayEffect");
323 }
324
325 int ResizeEffect_new(lua_State* L)
326 {
327         assert(lua_gettop(L) == 0);
328         return wrap_lua_object_nonowned<ResizeEffect>(L, "ResizeEffect");
329 }
330
331 int MultiplyEffect_new(lua_State* L)
332 {
333         assert(lua_gettop(L) == 0);
334         return wrap_lua_object_nonowned<MultiplyEffect>(L, "MultiplyEffect");
335 }
336
337 int MixEffect_new(lua_State* L)
338 {
339         assert(lua_gettop(L) == 0);
340         return wrap_lua_object_nonowned<MixEffect>(L, "MixEffect");
341 }
342
343 int InputStateInfo_get_width(lua_State* L)
344 {
345         assert(lua_gettop(L) == 2);
346         InputStateInfo *input_state_info = get_input_state_info(L, 1);
347         Theme *theme = get_theme_updata(L);
348         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
349         lua_pushnumber(L, input_state_info->last_width[signal_num]);
350         return 1;
351 }
352
353 int InputStateInfo_get_height(lua_State* L)
354 {
355         assert(lua_gettop(L) == 2);
356         InputStateInfo *input_state_info = get_input_state_info(L, 1);
357         Theme *theme = get_theme_updata(L);
358         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
359         lua_pushnumber(L, input_state_info->last_height[signal_num]);
360         return 1;
361 }
362
363 int InputStateInfo_get_interlaced(lua_State* L)
364 {
365         assert(lua_gettop(L) == 2);
366         InputStateInfo *input_state_info = get_input_state_info(L, 1);
367         Theme *theme = get_theme_updata(L);
368         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
369         lua_pushboolean(L, input_state_info->last_interlaced[signal_num]);
370         return 1;
371 }
372
373 int InputStateInfo_get_has_signal(lua_State* L)
374 {
375         assert(lua_gettop(L) == 2);
376         InputStateInfo *input_state_info = get_input_state_info(L, 1);
377         Theme *theme = get_theme_updata(L);
378         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
379         lua_pushboolean(L, input_state_info->last_has_signal[signal_num]);
380         return 1;
381 }
382
383 int InputStateInfo_get_frame_rate_nom(lua_State* L)
384 {
385         assert(lua_gettop(L) == 2);
386         InputStateInfo *input_state_info = get_input_state_info(L, 1);
387         Theme *theme = get_theme_updata(L);
388         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
389         lua_pushnumber(L, input_state_info->last_frame_rate_nom[signal_num]);
390         return 1;
391 }
392
393 int InputStateInfo_get_frame_rate_den(lua_State* L)
394 {
395         assert(lua_gettop(L) == 2);
396         InputStateInfo *input_state_info = get_input_state_info(L, 1);
397         Theme *theme = get_theme_updata(L);
398         int signal_num = theme->map_signal(luaL_checknumber(L, 2));
399         lua_pushnumber(L, input_state_info->last_frame_rate_den[signal_num]);
400         return 1;
401 }
402
403 int Effect_set_float(lua_State *L)
404 {
405         assert(lua_gettop(L) == 3);
406         Effect *effect = (Effect *)get_effect(L, 1);
407         string key = checkstdstring(L, 2);
408         float value = luaL_checknumber(L, 3);
409         if (!effect->set_float(key, value)) {
410                 luaL_error(L, "Effect refused set_float(\"%s\", %d) (invalid key?)", key.c_str(), int(value));
411         }
412         return 0;
413 }
414
415 int Effect_set_int(lua_State *L)
416 {
417         assert(lua_gettop(L) == 3);
418         Effect *effect = (Effect *)get_effect(L, 1);
419         string key = checkstdstring(L, 2);
420         float value = luaL_checknumber(L, 3);
421         if (!effect->set_int(key, value)) {
422                 luaL_error(L, "Effect refused set_int(\"%s\", %d) (invalid key?)", key.c_str(), int(value));
423         }
424         return 0;
425 }
426
427 int Effect_set_vec3(lua_State *L)
428 {
429         assert(lua_gettop(L) == 5);
430         Effect *effect = (Effect *)get_effect(L, 1);
431         string key = checkstdstring(L, 2);
432         float v[3];
433         v[0] = luaL_checknumber(L, 3);
434         v[1] = luaL_checknumber(L, 4);
435         v[2] = luaL_checknumber(L, 5);
436         if (!effect->set_vec3(key, v)) {
437                 luaL_error(L, "Effect refused set_vec3(\"%s\", %f, %f, %f) (invalid key?)", key.c_str(),
438                         v[0], v[1], v[2]);
439         }
440         return 0;
441 }
442
443 int Effect_set_vec4(lua_State *L)
444 {
445         assert(lua_gettop(L) == 6);
446         Effect *effect = (Effect *)get_effect(L, 1);
447         string key = checkstdstring(L, 2);
448         float v[4];
449         v[0] = luaL_checknumber(L, 3);
450         v[1] = luaL_checknumber(L, 4);
451         v[2] = luaL_checknumber(L, 5);
452         v[3] = luaL_checknumber(L, 6);
453         if (!effect->set_vec4(key, v)) {
454                 luaL_error(L, "Effect refused set_vec4(\"%s\", %f, %f, %f, %f) (invalid key?)", key.c_str(),
455                         v[0], v[1], v[2], v[3]);
456         }
457         return 0;
458 }
459
460 const luaL_Reg EffectChain_funcs[] = {
461         { "new", EffectChain_new },
462         { "__gc", EffectChain_gc },
463         { "add_live_input", EffectChain_add_live_input },
464         { "add_effect", EffectChain_add_effect },
465         { "finalize", EffectChain_finalize },
466         { NULL, NULL }
467 };
468
469 const luaL_Reg LiveInputWrapper_funcs[] = {
470         { "connect_signal", LiveInputWrapper_connect_signal },
471         { NULL, NULL }
472 };
473
474 const luaL_Reg ImageInput_funcs[] = {
475         { "new", ImageInput_new },
476         { "set_float", Effect_set_float },
477         { "set_int", Effect_set_int },
478         { "set_vec3", Effect_set_vec3 },
479         { "set_vec4", Effect_set_vec4 },
480         { NULL, NULL }
481 };
482
483 const luaL_Reg WhiteBalanceEffect_funcs[] = {
484         { "new", WhiteBalanceEffect_new },
485         { "set_float", Effect_set_float },
486         { "set_int", Effect_set_int },
487         { "set_vec3", Effect_set_vec3 },
488         { "set_vec4", Effect_set_vec4 },
489         { NULL, NULL }
490 };
491
492 const luaL_Reg ResampleEffect_funcs[] = {
493         { "new", ResampleEffect_new },
494         { "set_float", Effect_set_float },
495         { "set_int", Effect_set_int },
496         { "set_vec3", Effect_set_vec3 },
497         { "set_vec4", Effect_set_vec4 },
498         { NULL, NULL }
499 };
500
501 const luaL_Reg PaddingEffect_funcs[] = {
502         { "new", PaddingEffect_new },
503         { "set_float", Effect_set_float },
504         { "set_int", Effect_set_int },
505         { "set_vec3", Effect_set_vec3 },
506         { "set_vec4", Effect_set_vec4 },
507         { NULL, NULL }
508 };
509
510 const luaL_Reg IntegralPaddingEffect_funcs[] = {
511         { "new", IntegralPaddingEffect_new },
512         { "set_float", Effect_set_float },
513         { "set_int", Effect_set_int },
514         { "set_vec3", Effect_set_vec3 },
515         { "set_vec4", Effect_set_vec4 },
516         { NULL, NULL }
517 };
518
519 const luaL_Reg OverlayEffect_funcs[] = {
520         { "new", OverlayEffect_new },
521         { "set_float", Effect_set_float },
522         { "set_int", Effect_set_int },
523         { "set_vec3", Effect_set_vec3 },
524         { "set_vec4", Effect_set_vec4 },
525         { NULL, NULL }
526 };
527
528 const luaL_Reg ResizeEffect_funcs[] = {
529         { "new", ResizeEffect_new },
530         { "set_float", Effect_set_float },
531         { "set_int", Effect_set_int },
532         { "set_vec3", Effect_set_vec3 },
533         { "set_vec4", Effect_set_vec4 },
534         { NULL, NULL }
535 };
536
537 const luaL_Reg MultiplyEffect_funcs[] = {
538         { "new", MultiplyEffect_new },
539         { "set_float", Effect_set_float },
540         { "set_int", Effect_set_int },
541         { "set_vec3", Effect_set_vec3 },
542         { "set_vec4", Effect_set_vec4 },
543         { NULL, NULL }
544 };
545
546 const luaL_Reg MixEffect_funcs[] = {
547         { "new", MixEffect_new },
548         { "set_float", Effect_set_float },
549         { "set_int", Effect_set_int },
550         { "set_vec3", Effect_set_vec3 },
551         { "set_vec4", Effect_set_vec4 },
552         { NULL, NULL }
553 };
554
555 const luaL_Reg InputStateInfo_funcs[] = {
556         { "get_width", InputStateInfo_get_width },
557         { "get_height", InputStateInfo_get_height },
558         { "get_interlaced", InputStateInfo_get_interlaced },
559         { "get_has_signal", InputStateInfo_get_has_signal },
560         { "get_frame_rate_nom", InputStateInfo_get_frame_rate_nom },
561         { "get_frame_rate_den", InputStateInfo_get_frame_rate_den },
562         { NULL, NULL }
563 };
564
565 }  // namespace
566
567 LiveInputWrapper::LiveInputWrapper(Theme *theme, EffectChain *chain, bool override_bounce, bool deinterlace)
568         : theme(theme),
569           deinterlace(deinterlace)
570 {
571         ImageFormat inout_format;
572         inout_format.color_space = COLORSPACE_sRGB;
573
574         // Gamma curve depends on the input signal, and we don't really get any
575         // indications. A camera would be expected to do Rec. 709, but
576         // I haven't checked if any do in practice. However, computers _do_ output
577         // in sRGB gamma (ie., they don't convert from sRGB to Rec. 709), and
578         // I wouldn't really be surprised if most non-professional cameras do, too.
579         // So we pick sRGB as the least evil here.
580         inout_format.gamma_curve = GAMMA_sRGB;
581
582         // The Blackmagic driver docs claim that the device outputs Y'CbCr
583         // according to Rec. 601, but practical testing indicates it definitely
584         // is Rec. 709 (at least up to errors attributable to rounding errors).
585         // Perhaps 601 was only to indicate the subsampling positions, not the
586         // colorspace itself? Tested with a Lenovo X1 gen 3 as input.
587         YCbCrFormat input_ycbcr_format;
588         input_ycbcr_format.chroma_subsampling_x = 2;
589         input_ycbcr_format.chroma_subsampling_y = 1;
590         input_ycbcr_format.cb_x_position = 0.0;
591         input_ycbcr_format.cr_x_position = 0.0;
592         input_ycbcr_format.cb_y_position = 0.5;
593         input_ycbcr_format.cr_y_position = 0.5;
594         input_ycbcr_format.luma_coefficients = YCBCR_REC_709;
595         input_ycbcr_format.full_range = false;
596
597         unsigned num_inputs;
598         if (deinterlace) {
599                 deinterlace_effect = new movit::DeinterlaceEffect();
600
601                 // As per the comments in deinterlace_effect.h, we turn this off.
602                 // The most likely interlaced input for us is either a camera
603                 // (where it's fine to turn it off) or a laptop (where it _should_
604                 // be turned off).
605                 CHECK(deinterlace_effect->set_int("enable_spatial_interlacing_check", 0));
606
607                 num_inputs = deinterlace_effect->num_inputs();
608                 assert(num_inputs == FRAME_HISTORY_LENGTH);
609         } else {
610                 num_inputs = 1;
611         }
612         for (unsigned i = 0; i < num_inputs; ++i) {
613                 if (override_bounce) {
614                         inputs.push_back(new NonBouncingYCbCrInput(inout_format, input_ycbcr_format, WIDTH, HEIGHT, YCBCR_INPUT_SPLIT_Y_AND_CBCR));
615                 } else {
616                         inputs.push_back(new YCbCrInput(inout_format, input_ycbcr_format, WIDTH, HEIGHT, YCBCR_INPUT_SPLIT_Y_AND_CBCR));
617                 }
618                 chain->add_input(inputs.back());
619         }
620
621         if (deinterlace) {
622                 vector<Effect *> reverse_inputs(inputs.rbegin(), inputs.rend());
623                 chain->add_effect(deinterlace_effect, reverse_inputs);
624         }
625 }
626
627 void LiveInputWrapper::connect_signal(int signal_num)
628 {
629         if (global_mixer == nullptr) {
630                 // No data yet.
631                 return;
632         }
633
634         signal_num = theme->map_signal(signal_num);
635
636         BufferedFrame first_frame = theme->input_state->buffered_frames[signal_num][0];
637         if (first_frame.frame == nullptr) {
638                 // No data yet.
639                 return;
640         }
641         unsigned width, height;
642         {
643                 const PBOFrameAllocator::Userdata *userdata = (const PBOFrameAllocator::Userdata *)first_frame.frame->userdata;
644                 width = userdata->last_width[first_frame.field_number];
645                 height = userdata->last_height[first_frame.field_number];
646         }
647
648         BufferedFrame last_good_frame = first_frame;
649         for (unsigned i = 0; i < inputs.size(); ++i) {
650                 BufferedFrame frame = theme->input_state->buffered_frames[signal_num][i];
651                 if (frame.frame == nullptr) {
652                         // Not enough data; reuse last frame (well, field).
653                         // This is suboptimal, but we have nothing better.
654                         frame = last_good_frame;
655                 }
656                 const PBOFrameAllocator::Userdata *userdata = (const PBOFrameAllocator::Userdata *)frame.frame->userdata;
657
658                 if (userdata->last_width[frame.field_number] != width ||
659                     userdata->last_height[frame.field_number] != height) {
660                         // Resolution changed; reuse last frame/field.
661                         frame = last_good_frame;
662                         userdata = (const PBOFrameAllocator::Userdata *)frame.frame->userdata;
663                 }
664
665                 inputs[i]->set_texture_num(0, userdata->tex_y[frame.field_number]);
666                 inputs[i]->set_texture_num(1, userdata->tex_cbcr[frame.field_number]);
667                 inputs[i]->set_width(userdata->last_width[frame.field_number]);
668                 inputs[i]->set_height(userdata->last_height[frame.field_number]);
669
670                 last_good_frame = frame;
671         }
672
673         if (deinterlace) {
674                 BufferedFrame frame = theme->input_state->buffered_frames[signal_num][0];
675                 CHECK(deinterlace_effect->set_int("current_field_position", frame.field_number));
676         }
677 }
678
679 namespace {
680
681 int call_num_channels(lua_State *L)
682 {
683         lua_getglobal(L, "num_channels");
684
685         if (lua_pcall(L, 0, 1, 0) != 0) {
686                 fprintf(stderr, "error running function `num_channels': %s\n", lua_tostring(L, -1));
687                 exit(1);
688         }
689
690         int num_channels = luaL_checknumber(L, 1);
691         lua_pop(L, 1);
692         assert(lua_gettop(L) == 0);
693         return num_channels;
694 }
695
696 }  // namespace
697
698 Theme::Theme(const char *filename, ResourcePool *resource_pool, unsigned num_cards)
699         : resource_pool(resource_pool), num_cards(num_cards), signal_to_card_mapping(global_flags.default_stream_mapping)
700 {
701         L = luaL_newstate();
702         luaL_openlibs(L);
703
704         register_class("EffectChain", EffectChain_funcs); 
705         register_class("LiveInputWrapper", LiveInputWrapper_funcs); 
706         register_class("ImageInput", ImageInput_funcs);
707         register_class("WhiteBalanceEffect", WhiteBalanceEffect_funcs);
708         register_class("ResampleEffect", ResampleEffect_funcs);
709         register_class("PaddingEffect", PaddingEffect_funcs);
710         register_class("IntegralPaddingEffect", IntegralPaddingEffect_funcs);
711         register_class("OverlayEffect", OverlayEffect_funcs);
712         register_class("ResizeEffect", ResizeEffect_funcs);
713         register_class("MultiplyEffect", MultiplyEffect_funcs);
714         register_class("MixEffect", MixEffect_funcs);
715         register_class("InputStateInfo", InputStateInfo_funcs);
716
717         // Run script.
718         lua_settop(L, 0);
719         if (luaL_dofile(L, filename)) {
720                 fprintf(stderr, "error: %s\n", lua_tostring(L, -1));
721                 lua_pop(L, 1);
722                 exit(1);
723         }
724         assert(lua_gettop(L) == 0);
725
726         // Ask it for the number of channels.
727         num_channels = call_num_channels(L);
728 }
729
730 Theme::~Theme()
731 {
732         lua_close(L);
733 }
734
735 void Theme::register_class(const char *class_name, const luaL_Reg *funcs)
736 {
737         assert(lua_gettop(L) == 0);
738         luaL_newmetatable(L, class_name);  // mt = {}
739         lua_pushlightuserdata(L, this);
740         luaL_setfuncs(L, funcs, 1);        // for (name,f in funcs) { mt[name] = f, with upvalue {theme} }
741         lua_pushvalue(L, -1);
742         lua_setfield(L, -2, "__index");    // mt.__index = mt
743         lua_setglobal(L, class_name);      // ClassName = mt
744         assert(lua_gettop(L) == 0);
745 }
746
747 Theme::Chain Theme::get_chain(unsigned num, float t, unsigned width, unsigned height, InputState input_state) 
748 {
749         Chain chain;
750
751         unique_lock<mutex> lock(m);
752         assert(lua_gettop(L) == 0);
753         lua_getglobal(L, "get_chain");  /* function to be called */
754         lua_pushnumber(L, num);
755         lua_pushnumber(L, t);
756         lua_pushnumber(L, width);
757         lua_pushnumber(L, height);
758         wrap_lua_object<InputStateInfo>(L, "InputStateInfo", input_state);
759
760         if (lua_pcall(L, 5, 2, 0) != 0) {
761                 fprintf(stderr, "error running function `get_chain': %s\n", lua_tostring(L, -1));
762                 exit(1);
763         }
764
765         chain.chain = (EffectChain *)luaL_testudata(L, -2, "EffectChain");
766         if (chain.chain == nullptr) {
767                 fprintf(stderr, "get_chain() for chain number %d did not return an EffectChain\n",
768                         num);
769                 exit(1);
770         }
771         if (!lua_isfunction(L, -1)) {
772                 fprintf(stderr, "Argument #-1 should be a function\n");
773                 exit(1);
774         }
775         lua_pushvalue(L, -1);
776         shared_ptr<LuaRefWithDeleter> funcref(new LuaRefWithDeleter(&m, L, luaL_ref(L, LUA_REGISTRYINDEX)));
777         lua_pop(L, 2);
778         assert(lua_gettop(L) == 0);
779
780         chain.setup_chain = [this, funcref, input_state]{
781                 unique_lock<mutex> lock(m);
782
783                 this->input_state = &input_state;
784
785                 // Set up state, including connecting signals.
786                 lua_rawgeti(L, LUA_REGISTRYINDEX, funcref->get());
787                 if (lua_pcall(L, 0, 0, 0) != 0) {
788                         fprintf(stderr, "error running chain setup callback: %s\n", lua_tostring(L, -1));
789                         exit(1);
790                 }
791                 assert(lua_gettop(L) == 0);
792         };
793
794         // TODO: Can we do better, e.g. by running setup_chain() and seeing what it references?
795         // Actually, setup_chain does maybe hold all the references we need now anyway?
796         for (unsigned card_index = 0; card_index < num_cards; ++card_index) {
797                 for (unsigned frame_num = 0; frame_num < FRAME_HISTORY_LENGTH; ++frame_num) {
798                         chain.input_frames.push_back(input_state.buffered_frames[card_index][frame_num].frame);
799                 }
800         }
801
802         return chain;
803 }
804
805 string Theme::get_channel_name(unsigned channel)
806 {
807         unique_lock<mutex> lock(m);
808         lua_getglobal(L, "channel_name");
809         lua_pushnumber(L, channel);
810         if (lua_pcall(L, 1, 1, 0) != 0) {
811                 fprintf(stderr, "error running function `channel_name': %s\n", lua_tostring(L, -1));
812                 exit(1);
813         }
814         const char *ret = lua_tostring(L, -1);
815         if (ret == nullptr) {
816                 fprintf(stderr, "function `channel_name' returned nil for channel %d\n", channel);
817                 exit(1);
818         }
819
820         string retstr = ret;
821         lua_pop(L, 1);
822         assert(lua_gettop(L) == 0);
823         return retstr;
824 }
825
826 int Theme::get_channel_signal(unsigned channel)
827 {
828         unique_lock<mutex> lock(m);
829         lua_getglobal(L, "channel_signal");
830         lua_pushnumber(L, channel);
831         if (lua_pcall(L, 1, 1, 0) != 0) {
832                 fprintf(stderr, "error running function `channel_signal': %s\n", lua_tostring(L, -1));
833                 exit(1);
834         }
835
836         int ret = luaL_checknumber(L, 1);
837         lua_pop(L, 1);
838         assert(lua_gettop(L) == 0);
839         return ret;
840 }
841
842 std::string Theme::get_channel_color(unsigned channel)
843 {
844         unique_lock<mutex> lock(m);
845         lua_getglobal(L, "channel_color");
846         lua_pushnumber(L, channel);
847         if (lua_pcall(L, 1, 1, 0) != 0) {
848                 fprintf(stderr, "error running function `channel_color': %s\n", lua_tostring(L, -1));
849                 exit(1);
850         }
851
852         const char *ret = lua_tostring(L, -1);
853         if (ret == nullptr) {
854                 fprintf(stderr, "function `channel_color' returned nil for channel %d\n", channel);
855                 exit(1);
856         }
857
858         string retstr = ret;
859         lua_pop(L, 1);
860         assert(lua_gettop(L) == 0);
861         return retstr;
862 }
863
864 bool Theme::get_supports_set_wb(unsigned channel)
865 {
866         unique_lock<mutex> lock(m);
867         lua_getglobal(L, "supports_set_wb");
868         lua_pushnumber(L, channel);
869         if (lua_pcall(L, 1, 1, 0) != 0) {
870                 fprintf(stderr, "error running function `supports_set_wb': %s\n", lua_tostring(L, -1));
871                 exit(1);
872         }
873
874         bool ret = checkbool(L, -1);
875         lua_pop(L, 1);
876         assert(lua_gettop(L) == 0);
877         return ret;
878 }
879
880 void Theme::set_wb(unsigned channel, double r, double g, double b)
881 {
882         unique_lock<mutex> lock(m);
883         lua_getglobal(L, "set_wb");
884         lua_pushnumber(L, channel);
885         lua_pushnumber(L, r);
886         lua_pushnumber(L, g);
887         lua_pushnumber(L, b);
888         if (lua_pcall(L, 4, 0, 0) != 0) {
889                 fprintf(stderr, "error running function `set_wb': %s\n", lua_tostring(L, -1));
890                 exit(1);
891         }
892
893         assert(lua_gettop(L) == 0);
894 }
895
896 vector<string> Theme::get_transition_names(float t)
897 {
898         unique_lock<mutex> lock(m);
899         lua_getglobal(L, "get_transitions");
900         lua_pushnumber(L, t);
901         if (lua_pcall(L, 1, 1, 0) != 0) {
902                 fprintf(stderr, "error running function `get_transitions': %s\n", lua_tostring(L, -1));
903                 exit(1);
904         }
905
906         vector<string> ret;
907         lua_pushnil(L);
908         while (lua_next(L, -2) != 0) {
909                 ret.push_back(lua_tostring(L, -1));
910                 lua_pop(L, 1);
911         }
912         lua_pop(L, 1);
913         assert(lua_gettop(L) == 0);
914         return ret;
915 }       
916
917 int Theme::map_signal(int signal_num)
918 {
919         unique_lock<mutex> lock(map_m);
920         if (signal_to_card_mapping.count(signal_num)) {
921                 return signal_to_card_mapping[signal_num];
922         }
923         if (signal_num >= int(num_cards)) {
924                 fprintf(stderr, "WARNING: Theme asked for input %d, but we only have %u card(s).\n", signal_num, num_cards);
925                 fprintf(stderr, "Mapping to card %d instead.\n", signal_num % num_cards);
926         }
927         signal_to_card_mapping[signal_num] = signal_num % num_cards;
928         return signal_num % num_cards;
929 }
930
931 void Theme::set_signal_mapping(int signal_num, int card_num)
932 {
933         unique_lock<mutex> lock(map_m);
934         assert(card_num < int(num_cards));
935         signal_to_card_mapping[signal_num] = card_num;
936 }
937
938 void Theme::transition_clicked(int transition_num, float t)
939 {
940         unique_lock<mutex> lock(m);
941         lua_getglobal(L, "transition_clicked");
942         lua_pushnumber(L, transition_num);
943         lua_pushnumber(L, t);
944
945         if (lua_pcall(L, 2, 0, 0) != 0) {
946                 fprintf(stderr, "error running function `transition_clicked': %s\n", lua_tostring(L, -1));
947                 exit(1);
948         }
949         assert(lua_gettop(L) == 0);
950 }
951
952 void Theme::channel_clicked(int preview_num)
953 {
954         unique_lock<mutex> lock(m);
955         lua_getglobal(L, "channel_clicked");
956         lua_pushnumber(L, preview_num);
957
958         if (lua_pcall(L, 1, 0, 0) != 0) {
959                 fprintf(stderr, "error running function `channel_clicked': %s\n", lua_tostring(L, -1));
960                 exit(1);
961         }
962         assert(lua_gettop(L) == 0);
963 }