diff --git a/OverLua/docs/sample1.lua b/OverLua/docs/sample1.lua new file mode 100644 index 000000000..2714897d6 --- /dev/null +++ b/OverLua/docs/sample1.lua @@ -0,0 +1,134 @@ +--[[ + +Sample script for OverLua + - demonstrate basic reading in an ASS subtitle file and rendering its lines on the video + +Given into the public domain. +(You can do anything you want with this file, with no restrictions whatsoever. + You don't get any warranties of any kind either, though.) + +Originally authored by Niels Martin Hansen. + +]] + +-- overlua_datastring is the string given to data= argument in Avisynth filter invocation +timing_input_file = overlua_datastring +-- You may want to get these from somewhere else +-- Or just stick to hardcoding all styling information +font_name = "Arial" +font_size = 24 + +-- A little check that an input file was actually given +assert(timing_input_file, "Missing input file") + + +-- An easier way to convert a string to a number and be guaranteed to get something useful +function parsenum(str) + return tonumber(str) or 0 +end +-- Convert an ASS timestamp into a number of seconds +function parse_ass_time(ass) + local h, m, s, cs = ass:match("(%d+):(%d+):(%d+)%.(%d+)") + return parsenum(cs)/100 + parsenum(s) + parsenum(m)*60 + parsenum(h)*3600 +end + +-- Not used here, but do some basic \k timing parsing +function parse_k_timing(text) + local syls = {} + local i = 1 + for timing, syltext in text:gmatch("{\\k(%d+)}([^{]*)") do + local syl = {dur = parsenum(timing)/100, text = syltext, i = i} + table.insert(syls, syl) + i = i + 1 + end + return syls +end + +-- Really stupid ASS parser +function read_input_file(name) + for line in io.lines(name) do + -- You can catch Style lines in the same way if you want + local start_time, end_time, style, fx, text = line:match("Dialogue: 0,(.-),(.-),(.-),.-,0000,0000,0000,(.-),(.*)") + if text then + local ls = {} + ls.start_time = parse_ass_time(start_time) + ls.end_time = parse_ass_time(end_time) + ls.style = style + ls.fx = fx + ls.rawtext = text + ls.kara = parse_k_timing(text) + -- Clear out override blocks + ls.cleantext = text:gsub("{.-}", "") + table.insert(lines, ls) + end + end +end + +-- Initialisation function, intended to be run on the first frame +-- I think it's better to delay initialisation until first frame is requested +-- rather than doing it immediately at load time. +-- I believe much encoding software might be more graceful about that. +function init() + if inited then return end + inited = true + + lines = {} + read_input_file(timing_input_file) +end + + +-- Actual work function, this is what's called by OverLua for each frame +-- f is a video frame object, what we'll be drawing to +-- t is the timestamp of the frame, given in seconds (floating point) +function render_frame(f, t) + -- Just call init() every time, init itself makes sure it doesn't init more than once + init() + + -- Find lines to be drawn + -- NOTE: This structure is very simplistic. + -- Advanced karaoke effects will probably need to build an object/effect list + -- as initialisation and then instead go over the list of objects/effects per frame, + -- instead of going over lines. + -- (Ie. preprocessing in the style of ASS karaoke generation.) + for i, line in pairs(lines) do + if line.start_time <= t and line.end_time > t then + -- Initial position of line + local x = 0 + local y = f.height - 25 + + -- Initialise drawing surface and context + local surf = cairo.image_surface_create(f.width, f.height, "argb32") + local c = surf.create_context() + + -- Select our font + c.select_font_face(font_name) + c.set_font_size(font_size) + + -- Get sizing information for font and line text + if not line.te then line.te = c.text_extents(line.cleantext); line.fe = c.font_extents() end + -- Calculate centered position + x = (f.width - line.te.width) / 2 - line.te.x_bearing + + -- Produce text path + c.move_to(x, y) + c.text_path(line.cleantext) + + -- Draw a black border + -- It will be centered on the text outline + c.set_line_width(4) + c.set_line_join("round") -- default is "miter" + c.set_source_rgba(0, 0, 0, 1) + -- "preserve" to keep the text path in the context + c.stroke_preserve() + -- Apply a little box blur to the border, effectively \be1 + raster.box_blur(surf, 3) + + -- Draw a white fill - this will draw over the inner part of the border + c.set_source_rgba(1, 1, 1, 1) + c.fill() + + -- Overlay on video + f.overlay_cairo_surface(surf, 0, 0) + end + end +end diff --git a/OverLua/video_frame.h b/OverLua/video_frame.h index 01bb26ff7..b03026a5b 100644 --- a/OverLua/video_frame.h +++ b/OverLua/video_frame.h @@ -298,7 +298,7 @@ badtable: { // Get inputs MyType **ud = (MyType**)lua_touserdata(L, lua_upvalueindex(1)); - LuaCairoSurface *surfwrap = LuaCairoSurface::CheckPointer(*(void**)lua_touserdata(L, 1)); + LuaCairoSurface *surfwrap = LuaCairoSurface::GetObjPointer(L, 1); if (!surfwrap) { lua_pushliteral(L, "Argument to frame.overlay_cairo_surface is not a Cairo surface"); lua_error(L);