The Programs of the Week of the Oscars
This Week’s Program: Feb 27 - Mar 3
This week, I did something that I thought was pretty cool. I wrote some Racket code that called into a C framework. I did it through two different mechanisms.
baf315f2112bc5f7612086d2ae9e6f378af7542b
In my first bit of true Racket code I’ve committed, I use
Racket’s Foreign Interface to
load libgstreamer
and run it
through a bit of a Hello, World example.
In GStreamer’s documentation, the first example they show is one to print out the library version information, just to show that you’ve successfully linked the library. Here’s their C example:
#include <stdio.h>
#include <gst/gst.h>
int
main (int argc,
char *argv[])
{
const gchar *nano_str;
guint major, minor, micro, nano;
gst_init (&argc, &argv);
gst_version (&major, &minor, µ, &nano);
if (nano == 1)
nano_str = "(CVS)";
else if (nano == 2)
nano_str = "(Prerelease)";
else
nano_str = "";
printf ("This program is linked against GStreamer %d.%d.%d %s\n",
major, minor, micro, nano_str);
return 0;
}
In Racket, using ffi/unsafe
, that becomes:
(displayln
(format "This program is linked against ~a" (gst_version_string)))
I run this and I see: “This program is linked against GStreamer 1.10.3”. Eureka!
d4866be5c35e413d41a50891986dc47a4ce6a3b3
In this commit, the outcome is the same, but this time I’m using a Racket GObject Introspection library.
a middleware layer between C libraries (using GObject) and language bindings. The C library can be scanned at compile time and generate a metadata file, in addition to the actual native C library. Then at runtime, language bindings can read this metadata and automatically provide bindings to call into the C library.
So GObject Introspection provides a set of annotations for GObject-infused C code that allows another language to easily create bindings to that library. Those bindings are created by looking into a GObject Introspection Repository, or GIR for short. GStreamer, thankfully, is written with this convention. With a Racket GIR library in hand, I don’t have to write foreign function interfaces for every function in GStreamer, and my Hello, World can lose a lot of boilerplate.
573cd52b4636976b0cd606a140860229226c6d86
With the new power of GIR, I initialize GStreamer by creating a
function, initialize
that returns #t
or #f
(Racket’s true or
false) depending on if initialization was successful.
I’m super stoked that this works and really glad to get my hands into
both Racket and C simultaneously, but I did hit a snag. The
Racket gir library hasn’t been
updated in nearly a year, and it seems to do some incorrect things
around methods that return C pointers and factory functions. That’s
not going to work. My first spike into overscan
is to simply get a
video to play through a GStreamer binding. In order to do that, I
either have to do tedious FFI bindings and ignore GIR entirely, or I
can write my own Racket bindings for GObject Introspection.
I think I’m going to have to do things the hard way.
Yours in λ,
Mark