Skip to content

Commit

Permalink
Add from_memory option
Browse files Browse the repository at this point in the history
  • Loading branch information
po5 committed May 13, 2023
1 parent 07ba568 commit 65cd12e
Showing 1 changed file with 77 additions and 59 deletions.
136 changes: 77 additions & 59 deletions thumbfast.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand All @@ -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"]
Expand Down Expand Up @@ -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})
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 65cd12e

Please sign in to comment.