lgi-devs / lgi

Dynamic Lua binding to GObject libraries using GObject-Introspection
MIT License
440 stars 70 forks source link

range restriction on Gst.Bus.timed_pop_filtered doesnt work with Gst.CLOCK_TIME_NONE #246

Open mxh69420 opened 4 years ago

mxh69420 commented 4 years ago

hello

ive tried porting the hello world example from gstreamer into lua. Gst.Bus.timed_pop_filtered is supposed to take a timeout value, or Gst.CLOCK_TIME_NONE if you dont want it to time out.

my lua version: luajit 2.1.0-beta3

local bit = require "bit"

local lgi = require "lgi"
local Gst = lgi.Gst

local pipeline = Gst.parse_launch("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm")
pipeline:set_state('PLAYING')

local bus = pipeline:get_bus()

local msg = bus:timed_pop_filtered(Gst.CLOCK_TIME_NONE, bit.bor(Gst.MessageType.EOS, Gst.MessageType.ERROR))
--bad argument #2 to 'timed_pop_filtered' (-1 is out of <0, 1.844674407371e+19>)

pipeline:set_state('NULL')

changing Gst.CLOCK_TIME_NONE to Gst.SECOND * 10000 works just fine, but this of course wont work for videos longer than 10000 seconds.

mxh69420 commented 4 years ago

using 0xFFFFFFFF seems to work as a workaround (0xFFFFFFFFFFFFFFFF oddly doesnt)

psychon commented 4 years ago

I downloaded the debian package and extracted it to /tmp without installing:

$ GI_TYPELIB_PATH=/tmp/data/usr/lib/x86_64-linux-gnu/girepository-1.0 lua -e 'print(require("lgi").Gst.CLOCK_TIME_NONE)'
1.844674407371e+19

So... apparently the contained value is correct. I guess this is some overflow somewhere. A double has less than 64 bits for the mantissa, so it cannot represent the value exactly. Since (in older Lua versions) all numbers are doubles, I guess this cannot always work correctly. LuaJIT is one of those Luas where all numbers are doubles, I think.

For future-me:

The argument in question has type GstClockTime, which is a typedef of guint64: https://github.com/GStreamer/gstreamer/blob/9831c9bbdbd89ad7adac3cdb837d3730a3f6e39e/gst/gstclock.h#L41-L46 GST_CLOCK_TIME_NONE is defined here as ((GstClockTime) -1): https://github.com/GStreamer/gstreamer/blob/9831c9bbdbd89ad7adac3cdb837d3730a3f6e39e/gst/gstclock.h#L68-L73

psychon commented 4 years ago

Huh, I forgot an important step: Trying to reproduce the problem. Actually, I cannot reproduce. Your program above runs without any errors for me, for all the Lua versions that I have available.

for lua in lua5.1 lua5.2 lua5.3 luajit ; do echo ; echo $lua ; GI_TYPELIB_PATH=/tmp/data/usr/lib/x86_64-linux-gnu/girepository-1.0 $lua -e 'Gst = require("lgi").Gst; local pipeline = Gst.parse_launch("playbin uri=https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.webm"); pipeline:set_state("PLAYING"); local bus = pipeline:get_bus(); local msg = bus:timed_pop_filtered(Gst.CLOCK_TIME_NONE, (Gst.MessageType.EOS + Gst.MessageType.ERROR))' ; done

LuaJIT is 2.1.0-beta3, same as yours. I am on debian testing.

psychon commented 4 years ago

I set a breakpoint on gst_bus_timed_pop_filtered in gdb. Sadly, I do not have debugging symbols installed, but:

(gdb) info registers 
rax            0x0                 0
rbx            0x400581d0          1074102736
rcx            0x20                32
rdx            0x3                 3
rsi            0x0                 0
rdi            0x555555889250      93824995594832
rbp            0x7fffffffe2d0      0x7fffffffe2d0
rsp            0x7fffffffe2c8      0x7fffffffe2c8
r8             0x400003b8          1073742776
r9             0x0                 0
r10            0x0                 0
r11            0x7ffff75c9e40      140737343430208
r12            0x0                 0
r13            0x7fffffffe380      140737488348032
r14            0x40058268          1074102888
r15            0x7fffffffe37c      140737488348028
rip            0x7ffff75c9e40      0x7ffff75c9e40 <gst_bus_timed_pop_filtered>
eflags         0x246               [ PF ZF IF ]
cs             0x33                51
ss             0x2b                43
ds             0x0                 0
es             0x0                 0
fs             0x0                 0
gs             0x0                 0

If I got the calling convention right, the second argument should be rsi, so is 0x0. That could explain why that function returns here immediately with nil. :-/

psychon commented 4 years ago

@samiam308 Could you run the following and tell me its output? For me, this produces 0 (which matches the output that gdb gives me).

gobject = require("lgi").GObject
value = gobject.Value()
value:init(11 * 4) -- This is G_TYPE_UINT64
value:set_uint64(require("lgi").Gst.CLOCK_TIME_NONE)
print(value:get_uint64())
mxh69420 commented 4 years ago

sorry it took me a while. for me, it doesnt even reach the print.

luajit: script.lua:4: bad argument #2 to 'set_uint64' (-1 is out of <0, 1.844674407371e+19>)
stack traceback:
    [C]: in function 'set_uint64'
    script.lua:4: in main chunk
    [C]: at 0x559e47c0e200
psychon commented 4 years ago

Weird. No idea where that difference could come from. Sorry.

v1993 commented 3 years ago

I'm not sure how this should behave, but for me (git lgi)

v@v-home:~$ lua
Lua 5.3.3  Copyright (C) 1994-2016 Lua.org, PUC-Rio
> gobject = require("lgi").GObject
> value = gobject.Value()
> value:init(11 * 4) -- This is G_TYPE_UINT64
lgi.rec 0x558f17534ce8:GObject.Value
> value:set_uint64(require("lgi").Gst.CLOCK_TIME_NONE)
stdin:1: bad argument #2 to 'set_uint64' (-1 is out of <0, 9223372036854775807>)
stack traceback:
    [C]: in method 'set_uint64'
    stdin:1: in main chunk
    [C]: in ?

> require("lgi").Gst.CLOCK_TIME_NONE
-1

It seems that Lua exports negative unsigned values without wrapping them from their max value? Or something like this.

Another possibility: Lua can't store max value of unsigned 64-bit integer correctly (well, it can't). It would do so imprecisely in double (5.1/5.2) and just fail to in 64-bit signed integer in 5.3+.