SDL
SDL enables fflive to use input devices such as
keyboard,
mouse, and
joysticks.
A global constructor SDL() is built-in to the quickjs engine.
This is a simple wrapper around SDL functionality.
This page is mostly based on SDL documentation itself.
NOTE: Currently, you need to explicitly poll for the events.
I plan on moving this to using
async functions
in the future.
NOTE2: SDL support only works with fflive (and not ffgac or ffedit).
SDL Constructor
The new SDL() constructor is used to create a new SDL object.
Syntax
new SDL()
Return value
The new SDL object.
Examples
const sdl = new SDL();
if ( sdl )
print("SDL initialized");
SDL.prototype.numJoysticks()
This is a wrapper around SDL_NumJoysticks().
Syntax
numJoysticks()
Return value
Returns the number of attached joysticks on success or a negative error code on failure.
Examples
const sdl = new SDL();
const numJoysticks = sdl.numJoysticks();
print(`numJoysticks: ${numJoysticks}`);
SDL.prototype.joystickOpen()
This is a wrapper around SDL_JoystickOpen().
NOTE: The resulting object is kept internally in the SDL object.
Syntax
joystickOpen(device_index)
Parameters
device_index is the index of the joystick to query.
Return value
Nothing useful.
Examples
const sdl = new SDL();
sdl.joystickOpen(0);
SDL.prototype.joystickClose()
This is a wrapper around SDL_JoystickClose().
NOTE: The input parameter is obtained internally from the SDL object
(joystickOpen() must have already been called).
Syntax
joystickClose()
Return value
Nothing useful.
Examples
const sdl = new SDL();
sdl.joystickOpen(0);
sdl.joystickClose();
SDL.prototype.gameControllerOpen()
This is a wrapper around SDL_GameControllerOpen().
NOTE: The resulting object is kept internally in the SDL object.
Syntax
gameControllerOpen(joystick_index)
Parameters
joystick_index is the device_index of a device, up to SDL_NumJoysticks().
Return value
Nothing useful.
Examples
const sdl = new SDL();
sdl.gameControllerOpen(0);
SDL.prototype.gameControllerClose()
This is a wrapper around SDL_GameControllerClose().
NOTE: The input parameter is obtained internally fromt the SDL object
(gameControllerOpen() must have already been called).
Syntax
gameControllerClose()
Return value
Nothing useful.
Examples
const sdl = new SDL();
sdl.gameControllerOpen(0);
sdl.gameControllerClose();
SDL.prototype.getEvent()
This is a poll-based abstraction around SDL_PeepEvents().
You should call this function repeatedly and process the resulting SDL_Event until the function returns null.
Syntax
getEvent()
Return value
An SDL_Event (defined below) if available, null otherwise.
Examples
const sdl = new SDL();
sdl.joystickOpen(0);
while ( true )
{
const e = sdl.getEvent();
if ( e === null )
break;
print(JSON.stringify(e));
}
sdl.joystickClose();
SDL_Event
The SDL_Events returned by getEvent() are a representation of the
SDL_Event structure from SDL.
The structure is different depending on the type of event.
SDL_KeyboardEvent
TODO: number:
SDL.SDL_KEYDOWN or SDL.SDL_KEYUP.
TODO: number:
Event timestamp, in milliseconds.
TODO: number:
SDL.SDL_PRESSED or SDL.SDL_RELEASED.
TODO: number:
Non-zero if this is a key repeat.
TODO: number:
SDL physical key code - see SDL_Scancode for details.
- The key codes are available in the global
SDLobject, i.e.:SDL.SDL_SCANCODE_UNKNOWN.
TODO: number:
SDL virtual key code - see SDL_Keycode for details.
- The key codes are available in the global
SDLobject, i.e.:SDL.SDLK_UNKNOWN.
TODO: number:
Current key modifiers.
SDL_JoyAxisEvent
TODO: number:
SDL.SDL_JOYAXISMOTION.
TODO: number:
Event timestamp, in milliseconds.
TODO: number:
The joystick instance id.
TODO: number:
The joystick axis index.
TODO: number:
The axis value (range: -32768 to 32767).
SDL_JoyBallEvent
TODO: number:
SDL.SDL_JOYBALLMOTION.
TODO: number:
Event timestamp, in milliseconds.
TODO: number:
The joystick instance id.
TODO: number:
The joystick trackball index.
TODO: number:
The relative motion in the X direction.
TODO: number:
The relative motion in the Y direction.
SDL_JoyHatEvent
TODO: number:
SDL.SDL_JOYHATMOTION.
TODO: number:
Event timestamp, in milliseconds.
TODO: number:
The joystick instance id.
TODO: number:
The joystick trackball index.
TODO: number:
The hat position value.
SDL_JoyButtonEvent
TODO: number:
SDL.SDL_JOYBUTTONDOWN or SDL.SDL_JOYBUTTONUP.
TODO: number:
Event timestamp, in milliseconds.
TODO: number:
The joystick instance id.
: number:
The joystick button index.
TODO: number:
SDL.SDL_PRESSED or SDL.SDL_RELEASED.
SDL_ControllerAxisEvent
TODO: number:
SDL.SDL_CONTROLLERAXISMOTION.
TODO: number:
Event timestamp, in milliseconds.
TODO: number:
The joystick instance id.
TODO: number:
The controller axis (SDL_GameControllerAxis).
TODO: number:
The axis value (range: -32768 to 32767).
SDL_ControllerButtonEvent
TODO: number:
SDL.SDL_CONTROLLERBUTTONDOWN or SDL.SDL_CONTROLLERBUTTONUP.
TODO: number:
Event timestamp, in milliseconds.
TODO: number:
The joystick instance id.
: number:
The controller button (SDL_GameControllerButton).
TODO: number:
SDL.SDL_PRESSED or SDL.SDL_RELEASED.
Full Example
This example will open the first joystick found (I use a cheap SNES USB controller),
and use the arrow keys to add motion to the entire frame.
let sdl;
let cur_pan_mv = new MV(0,0);
let step = 0;
export function setup(args)
{
// select motion vectors
args.features = [ "mv" ];
// parse params from command line (a number is expected)
if ( !("params" in args) )
throw new Error("A parameter is expected for the step in the command line (use -sp <step>).");
step = args.params;
// initialize SDL with first joystick
sdl = new SDL();
const numJoysticks = sdl.numJoysticks();
console.log(`numJoysticks: ${numJoysticks}`);
if ( numJoysticks > 0 )
sdl.joystickOpen(0);
}
export function glitch_frame(frame)
{
const fwd_mvs = frame.mv?.forward;
if ( !fwd_mvs )
return;
// set motion vector overflow behaviour in ffglitch to "truncate"
frame.mv.overflow = "truncate";
// parse all SDL events
while ( true )
{
const event = sdl.getEvent();
if ( event === null )
break;
// Uncomment the following line to debug the event structure.
// console.log(JSON.stringify(event));
if ( event.type === SDL.SDL_JOYAXISMOTION )
{
// Update current MV on arrow keys
switch ( event.value )
{
case -32768: cur_pan_mv[event.axis] += step; break;
case 32767: cur_pan_mv[event.axis] -= step; break;
}
}
}
// pan entire frame with current MV
fwd_mvs.add(cur_pan_mv);
}
Run it with:
$ fflive -i input.avi -s script.js -sp 3