From 65cd12e5ece94aa53a2c4b7deb7ab174b15cce9d Mon Sep 17 00:00:00 2001 From: Eva Date: Sat, 13 May 2023 08:07:32 +0200 Subject: [PATCH] Add from_memory option --- thumbfast.lua | 136 ++++++++++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 59 deletions(-) diff --git a/thumbfast.lua b/thumbfast.lua index f71aa0c..24f9070 100644 --- a/thumbfast.lua +++ b/thumbfast.lua @@ -37,6 +37,9 @@ local options = { -- Windows only: use native Windows API to write to pipe (requires LuaJIT) direct_io = false, + -- Display thumbnail data from memory (requires LuaJIT) + from_memory = false, + -- Custom path to the mpv executable mpv_path = "mpv" } @@ -67,55 +70,19 @@ function subprocess(args, async, callback) end end -local winapi = {} -if options.direct_io then - local ffi_loaded, ffi = pcall(require, "ffi") - if ffi_loaded then - winapi = { - ffi = ffi, - C = ffi.C, - bit = require("bit"), - socket_wc = "", - - -- WinAPI constants - CP_UTF8 = 65001, - GENERIC_WRITE = 0x40000000, - OPEN_EXISTING = 3, - FILE_FLAG_WRITE_THROUGH = 0x80000000, - FILE_FLAG_NO_BUFFERING = 0x20000000, - PIPE_NOWAIT = ffi.new("unsigned long[1]", 0x00000001), - - INVALID_HANDLE_VALUE = ffi.cast("void*", -1), - - -- don't care about how many bytes WriteFile wrote, so allocate something to store the result once - _lpNumberOfBytesWritten = ffi.new("unsigned long[1]"), - } - -- cache flags used in run() to avoid bor() call - winapi._createfile_pipe_flags = winapi.bit.bor(winapi.FILE_FLAG_WRITE_THROUGH, winapi.FILE_FLAG_NO_BUFFERING) - - ffi.cdef[[ - void* __stdcall CreateFileW(const wchar_t *lpFileName, unsigned long dwDesiredAccess, unsigned long dwShareMode, void *lpSecurityAttributes, unsigned long dwCreationDisposition, unsigned long dwFlagsAndAttributes, void *hTemplateFile); - bool __stdcall WriteFile(void *hFile, const void *lpBuffer, unsigned long nNumberOfBytesToWrite, unsigned long *lpNumberOfBytesWritten, void *lpOverlapped); - bool __stdcall CloseHandle(void *hObject); - bool __stdcall SetNamedPipeHandleState(void *hNamedPipe, unsigned long *lpMode, unsigned long *lpMaxCollectionCount, unsigned long *lpCollectDataTimeout); - int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); - ]] - - winapi.MultiByteToWideChar = function(MultiByteStr) - if MultiByteStr then - local utf16_len = winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, MultiByteStr, -1, nil, 0) - if utf16_len > 0 then - local utf16_str = winapi.ffi.new("wchar_t[?]", utf16_len) - if winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, MultiByteStr, -1, utf16_str, utf16_len) > 0 then - return utf16_str - end - end - end - return "" - end +local ffi_loaded, ffi - else +local function extract_address(s) + local addr = tostring(ffi.cast("char*",s)) + local _, loc = string.find(addr, ": 0x") + return tonumber(string.sub(addr,loc+1,-1),16) +end + +if options.direct_io or options.from_memory then + ffi_loaded, ffi = pcall(require, "ffi") + if not ffi_loaded then options.direct_io = false + options.from_memory = false end end @@ -248,16 +215,7 @@ local unique = mp.utils.getpid() options.socket = options.socket .. unique options.thumbnail = options.thumbnail .. unique -if options.direct_io then - if os_name == "windows" then - winapi.socket_wc = winapi.MultiByteToWideChar("\\\\.\\pipe\\" .. options.socket) - end - - if winapi.socket_wc == "" then - options.direct_io = false - end -end - +local thumbnail_bgra = options.thumbnail..".bgra" local mpv_path = options.mpv_path local libmpv = false @@ -280,6 +238,60 @@ if mpv_path == "mpv" and os_name == "darwin" and unique then end end +local winapi = {} +if options.direct_io then + winapi = { + ffi = ffi, + C = ffi.C, + bit = require("bit"), + socket_wc = "", + + -- WinAPI constants + CP_UTF8 = 65001, + GENERIC_WRITE = 0x40000000, + OPEN_EXISTING = 3, + FILE_FLAG_WRITE_THROUGH = 0x80000000, + FILE_FLAG_NO_BUFFERING = 0x20000000, + PIPE_NOWAIT = ffi.new("unsigned long[1]", 0x00000001), + + INVALID_HANDLE_VALUE = ffi.cast("void*", -1), + + -- don't care about how many bytes WriteFile wrote, so allocate something to store the result once + _lpNumberOfBytesWritten = ffi.new("unsigned long[1]"), + } + -- cache flags used in run() to avoid bor() call + winapi._createfile_pipe_flags = winapi.bit.bor(winapi.FILE_FLAG_WRITE_THROUGH, winapi.FILE_FLAG_NO_BUFFERING) + + ffi.cdef[[ + void* __stdcall CreateFileW(const wchar_t *lpFileName, unsigned long dwDesiredAccess, unsigned long dwShareMode, void *lpSecurityAttributes, unsigned long dwCreationDisposition, unsigned long dwFlagsAndAttributes, void *hTemplateFile); + bool __stdcall WriteFile(void *hFile, const void *lpBuffer, unsigned long nNumberOfBytesToWrite, unsigned long *lpNumberOfBytesWritten, void *lpOverlapped); + bool __stdcall CloseHandle(void *hObject); + bool __stdcall SetNamedPipeHandleState(void *hNamedPipe, unsigned long *lpMode, unsigned long *lpMaxCollectionCount, unsigned long *lpCollectDataTimeout); + int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); + ]] + + winapi.MultiByteToWideChar = function(MultiByteStr) + if MultiByteStr then + local utf16_len = winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, MultiByteStr, -1, nil, 0) + if utf16_len > 0 then + local utf16_str = winapi.ffi.new("wchar_t[?]", utf16_len) + if winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, MultiByteStr, -1, utf16_str, utf16_len) > 0 then + return utf16_str + end + end + end + return "" + end + + if os_name == "windows" then + winapi.socket_wc = winapi.MultiByteToWideChar("\\\\.\\pipe\\" .. options.socket) + end + + if winapi.socket_wc == "" then + options.direct_io = false + end +end + local function vf_string(filters, full) local vf = "" local vf_table = properties["vf"] @@ -528,9 +540,9 @@ local function draw(w, h, script) if not w or not show_thumbnail then return end if x ~= nil then if pre_0_30_0 then - mp.command_native({"overlay-add", options.overlay_id, x, y, options.thumbnail..".bgra", 0, "bgra", w, h, (4*w)}) + mp.command_native({"overlay-add", options.overlay_id, x, y, thumbnail_bgra, 0, "bgra", w, h, (4*w)}) else - mp.command_native_async({"overlay-add", options.overlay_id, x, y, options.thumbnail..".bgra", 0, "bgra", w, h, (4*w)}, function() end) + mp.command_native_async({"overlay-add", options.overlay_id, x, y, thumbnail_bgra, 0, "bgra", w, h, (4*w)}, function() end) end elseif script then local json, err = mp.utils.format_json({width=w, height=h, x=x, y=y, socket=options.socket, thumbnail=options.thumbnail, overlay_id=options.overlay_id}) @@ -621,6 +633,12 @@ local function check_new_thumb() local w, h = real_res(effective_w, effective_h, finfo.size) if w then -- only accept valid thumbnails move_file(tmp, options.thumbnail..".bgra") + if options.from_memory and not script_name then + local thumbnail_file = io.open(options.thumbnail..".bgra", "rb") + local thumbnail_data = thumbnail_file:read("*all") + thumbnail_bgra = string.format("&%.f", extract_address(thumbnail_data)) + thumbnail_file:close() + end real_w, real_h = w, h if real_w and (real_w ~= last_real_w or real_h ~= last_real_h) then