GStreamer is the core framework that powers the multimedia capabilities of Overscan. GStreamer is also a C framework, which means that a big part of Overscan’s codebase is dedicated to the interop between Racket and C. Racket provides a phenomenal Foreign Interface, but to create foreign functions for all the relevant portions of GStreamer would be cumbersome, at best.
Luckily, GStreamer is written with GLib and contains GObject Introspection metadata. GObject Introspection (aka GIR) is an interface description layer that allows for a language to read this metadata and dynamically create bindings for the C library.
The Overscan package provides a module designed to accompany Racket’s FFI collection. This module brings additional functionality and C Types for working with introspected C libraries. This module powers the GStreamer module, but can be used outside of Overscan for working with other GLib libraries.
|(require ffi/unsafe/introspection)||package: overscan|
Using GIR will typically go as follows: Introspect a namespace that you have a typelib for with introspection, call that namespace as a procedure to look up a binding, work with that binding either as a procedure or some other value (typically a gobject).
In this case of a typical "Hello, world" style example with GStreamer, that would look like this:
(define gst (introspection 'Gst)) (define gst-version (gst 'version_string)) (printf "This program is linked against ~a" (gst-version))
This will result in the string "This program is linked against GStreamer 1.10.4" being printed, or whatever version of GStreamer is available.
In the second line of this program, the 'version_string symbol is looked up against the GStreamer typelib and a gi-function? is returned. That can then be called as a procedure, which in this case takes no arguments.
GIR’s GIRepository API manages the namespaces provided by the GIR system and type libraries. Each namespace contains metadata entries that map to C functionality. In the case of GStreamer, the 'Gst namespace contains all of the introspection information used to power that interface.
An example for loading the GStreamer namespace:
> (define gst (introspection 'Gst)) #<procedure:gi-repository>
This is the only provided mechanism to construct a gi-repository.
When called as in the first form, without an argument, the proc will return a hash of all of the known members of the namespace.
When called as the second form, this is the equivalent to gi-repository-find-name with the first argument already set. e.g.
> (gst 'version) #<procedure:gi-function>
The GIBaseInfo C Struct is the base struct for all GIR metadata entries. Whenever you do some lookup within GIR, what’s returned is an instance of a descendant from this struct. The gi-base struct is the Racket equivalent, and introspection will return entities that inherit from this base struct.
The typical subtypes are:
An introspected C function. Call this as you would any other Racket procedure. C functions have a tendency to mutate call-by-reference pointers, and when that is the case calling a gi-function returns multiple values. The first return value is always the return value of the function.
(gi-constant) → any/cCalling a gi-constant as a procedure returns its value.
The first argument to a gi-struct is the name of a method, with subsequent arguments passed in to that method call. This procedure form is mainly used for calling factory style methods, and more useful for the similar gi-object. Usually, you’ll be working with instances of this type, gstructs.
Like gi-struct, calling a gi-object as a procedure will accept a method name and subsequent arguments. This is the preferred form for calling constructors that will return gobjects.
gi-enum : gi-enum?
See GObjects for more information about using GObjects from within Racket.
A gobject instance, like the introspected metadata entries provided by GIR, is a transparent pointer with additional utilities to be called as an object within Racket. GObjects behave like Racket objects, with the exception that they aren’t backed by classes in the racket/class sense, but instead are derived from the introspected metadata.
(connect obj signal-name handler [ #:data data #:cast _user-data]) → exact-integer? obj : gobject? signal-name : symbol? handler : procedure? data : any/c = #f _user-data : (or/c ctype? gi-object?) = #f
(gobject-get obj propname ctype) → any?
obj : gobject? propname : string? ctype : (or/c ctype? gi-registered-type? (listof symbol?))
A convenient mechanism for creating a getter and a setter for a GObject property.
The prop:gobject property allows a GObject instance to be transparently wrapped by a structure that may have additional values or properties.
(make-gobject-delegate method-decl ...)
method-decl = id | (id internal-method)
internal-method : symbol?
(make-gobject-delegate get-name get-factory [static-pad 'get_static_pad])
(mixin (gobject<%>) (gobject<%>) (super-new) (inherit-field pointer) (define/public (get-name . args) (apply gobject-send pointer 'get_name args)) (define/public (get-factory . args) (apply gobject-send pointer 'get_factory args)) (define/public (static-pad . args) (apply gobject-send pointer 'get_static_pad args)))