/tinyletter

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, &micro, &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.

GObject Introspection is

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