March 2008 Archives

Last night I was thinking about simple concepts we use everyday to communicate. I'm very unpleased to not have a fitting example, but I think I'll be able to let you understand.

Sometimes happens to tell someone: <<Have you watched Star Trek?>> and our mate will answer: <<Do you mean the movie or the show?>> This is a very silly example but sometimes things need to be qualified to be exact.

OK, let's go back to Tagsistant and your full episode collection of star trek tv shows and movies and video games and whatever. It would be very nice to have category tagging in Tagsistant to tell that the first are "tvshow:startrek", the second are "movie:startrek" and the third are "videogames:startrek".

So we'll be able to find everything about Star Trek with an usual

$ ls tags/startrek/

query, but we'll also find all Star Trek tv shows by

$ ls tags/tvshow:startrek/

and also all our tv shows by searching for

$ ls tags/tvshow:/

(note the colon at the end).

One of the coolest feature of POSIX systems is dynamic loading of libraries and plugins. Everything is managed by dlopen() and its companions. Loading at runtime means just:

  1. locating the library file
  2. use dlopen() to get a pointer to the library
  3. use dlsym() to get a pointer for each function inside the library you need
  4. use dlclose() to keep you code clean and help make the world a better place to live in ;-)

MacOS X and GNU/Linux both provide the same interface and code is straight portable. So, why I'm writing about that? Because you may have inserted in your code some check to locate the plugins of your application, dropping other files present in the same directory.

For example, Tagsistant uses /usr/local/lib/ as default path to store its plugins, which are named libtagsistant_<mimetype>.so under GNU/Linux. And here enters the matter: under MacOS X the extension is ".dylib" instead of ".so"!

The code which locates the plugins is the following:

#define TAGSISTANT_PLUGIN_PREFIX "libtagsistant_"
char *needle = strstr(de->d_name, TAGSISTANT_PLUGIN_PREFIX);
if ((needle == NULL) || (needle != de->d_name))
        continue;

needle = strstr(de->d_name, ".so");
if ((needle == NULL) || (needle != de->d_name + strlen(de->d_name) - 3))
        continue;

This fragment is inserted into a cycle which traverse the whole plugins list, that's why uses continue in reaction to failure. Number 3 in last if statement is the length of ".so" string. This code compiles cleanly under MacOS X but fails. After discovering the extension difference, I've changed this code as:

#define TAGSISTANT_PLUGIN_PREFIX "libtagsistant_"
char *needle = strstr(de->d_name, TAGSISTANT_PLUGIN_PREFIX);
if ((needle == NULL) || (needle != de->d_name))
        continue;

#ifdef MACOSX
#       define PLUGIN_EXT ".dylib"
#else
#       define PLUGIN_EXT ".so"
#endif

needle = strstr(de->d_name, PLUGIN_EXT);
if ((needle == NULL) || (needle != de->d_name + strlen(de->d_name) - strlen(PLUGIN_EXT)))
        continue;


And now, finally, Tagsistant locates and loads its plugins!

Recently I've got a MacBook at work. Of course, the temptation of using it for other purposes than official ones was too high to resist. So I've started porting Tagsistant to MacOS X.

Compiling GNU/Linux software on MacOS X needs some fine tuning but not as much as I thought. After reading some docs on the net, I've learned about FUSE port called MacFUSE. Installing MacFUSE is a piece of cake. Using it no. Autoconf script needs some tweaking to guess the architecture type. But it's quite easy to add it. Insert a AC_CANONICAL_TARGET macro in configure.ac or configure.in file to let it figure out the four-field values for $host variable, like in i686-pc-linux-gnu example. MacOS X 10.5.1 returns i686-apple-darwin9.1.0 on a Core 2 Duo host.

Using $host value the script will be able to make some adjustments to compile and link options. Just add some bash scripting like the following:

echo configure detected host $host
case $host in
  *-*-linux*)
    echo "Live long and prosper, GNU/Linux"
    ;;
  *-*-darwin*)
    AC_SUBST([CFLAGS],["${CFLAGS} -D__FreeBSD__=10 -DMACOSX -DFUSE_USE_VERSION=25"])
    AC_SUBST([LDFLAGS],["${LDFLAGS} -flat_namespace -force_flat_namespace"])
    ;;
esac


As you see, we add -D__FreeBSD__=10 -DMACOSX -DFUSE_USE_VERSION=25 to CFLAGS and -flat_namespace -force_flat_namespace to LDFLAGS. __FreeBSD__ macro appears in some headers, like in MacFUSE's, to declare some structures dedicated to BSD hosts. MACOSX is a macro I've declared to include some conditional compiling inside tagsistant. May be it's not the best name since it can easily conflict with symbols having the same name but elsewhere declared. But it's working so we'll keep it. Also, BSD requires FUSE API to be at least version 2.5. After running configure you can check inside Makefiles if proper CFLAGS and LDFLAGS appeared.

After adding this code, I've run a compilation test which ended good, if we ignore the small, insignificant side effect due to link failure: strndup() and getline() were missing! Damn GNU extensions! So comfortable to use, that you'll forget about portability issues! Ok, don't worry, we can rewrite it.

I know that rewriting libc functions does not seem to be the right thing, but just in this case it is, as I can assure after reading on-line the bunch of documentation talking about that. Especially a paper on Grid Computing on MacOS X confirmed me that getline() is usually replaced with POSIX fgets() and that strndup() is rewritten, probably, using memcpy() as i did. This is the code:

#ifdef MACOSX
ssize_t getline(char **lineptr, size_t *n, FILE *stream)
{
  if (*lineptr == NULL)
    *lineptr = calloc(sizeof(char), *n + 1);

  if (*lineptr == NULL)
    return 0;

  if (fgets(*lineptr, *n, stream) == NULL)
    *n = 0;
  else
    *n = strlen(*lineptr);

  return *n;
}

char *strndup(const char *s, size_t n)
{
  char *result = calloc(sizeof(char), n+1);
  if (result == NULL)
    return NULL;

  memcpy(result, s, n);
  result[n] = '\0';
  return result;
}
#endif


After adding this code to my project, compilation went good and now I have a working tagsistant installation on a MacBook. It seemed a complete success, but something happened to ruin everything. Something I've not yet solved. mknod() is not working! Why the hell I'm not able to create a file inside a tagsistant filesystem while everything else works and the same code works perfectly under GNU/Linux? Files are stored inside the ~/.tagsistant/archive/ directory which is created with user's permissions and ownership. Why it's failing? It's a MacFUSE security restriction? I don't know so far, so if someone has some clue I would really appreciate it.

Welcome back to "How to build a movie player". In this third howto, we'll see how GStreamer should be integrated inside our application.

GStreamer is to multimedia like Gtk is to graphic interfaces. Everything is a module that should be chained with other modules to be useful. Our application will use a small bunch of all the available modules of GStreamer. In particular, our working horse will be the playbin module which is a full featured demuxer, decoder, subtitle displayer and much more, all prepackaged for us.

Firs of all, we include a lot of Gtk, Gstreamer and X11 headers to import library functions and also declare some global symbols in main.c which will be visible to all other application files. So, outside everything else, we write:

#include <X11/Xlib.h>
#include <gst/gst.h>
#include <gst/interfaces/xoverlay.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>

GMainLoop *loop;
GstElement *playbin, *vsink;

The *loop element is a GLib provided event loop. *playbin is our everything doing engine and *vsink is our video output, which will be connected to GtkImage "video_preview" widget to display video output. Then inside the function we declare those elements.

loop = g_main_loop_new (NULL, FALSE);

The loop will handle all the events and will be started in the decoding function.

playbin = gst_element_factory_make("playbin", "playbin");
vsink = gst_element_factory_make("ximagesink", "vsink");
g_object_set(G_OBJECT(playbin), "video-sink", vsink, NULL);

The playbin is extracted from the factory with the same name, while the video sink vsink is a "ximagesink" module. The third line connects the playbin output to video sink using an usual GObject statement on playbin "video-sink" property.

Then we need some code to start audio/video decoding and playing. This is the start_decode() function depicted here:


void
start_decode()
{
  /* if paused just resume */
  if (paused) {
    paused = 0;
    gst_element_set_state (playbin, GST_STATE_PLAYING);
    return;
  }

  if (stream_uri == NULL) return;

  /* tell playbin which URI has to play */
  g_object_set(G_OBJECT(playbin), "uri", stream_uri, NULL);

  /*
   * getting the drawing area for video preview
   * and setting video sink overlay
   */
  GtkWidget *da = lookup_widget(minitheater, "video_preview");
  gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(vsink),GDK_WINDOW_XID(da->window));

  /* play */
  g_timeout_add (500, (GSourceFunc) cb_print_position, playbin);
  gst_element_set_state (playbin, GST_STATE_PLAYING);
  g_main_loop_run (loop);
}


Not too complex but even not banal. Let's start. First of all, it checks if the player is paused and should only be continued. paused is a boolean integer which is defined outside start_decode() function and is changed by Gtk callbacks.

stream_uri is the URI of the resource to be played. A URI? Why not a plain filename? Because playbin is so cool that it's able even to play directly from the net! So, to play a local resource like file /home/myself/movie.avi we need to convert the path into file:///home/myself/movie.avi. This function expects the URI to be already formatted into stream_uri variable. URI formatting is done inside the callback which Gtk calls when a file is chosen from the file chooser dialog, as we'll see in a future post. To set the URI inside playbin we need just a GObject call as in g_object_set(G_OBJECT(playbin), "uri", stream_uri, NULL);

Then we need to connect the video sink to Gtk widget devoted to video output. So we first gather the widget using Gtk lookup_widget() function and then use a function from the X11 overlay interface of GStreamer. The lines are:

GtkWidget *da = lookup_widget(minitheater, "video_preview");
gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(vsink),GDK_WINDOW_XID(da->window));

GDK_WINDOW_XID() is a GDK macro to extract the X11 window id of a Gtk widget. GStreamer will later use this id to target video output to the right area.

Then we connect a timeout function which every 500 milliseconds will update the interface, using g_timeout_add() facility provided by GLib. The function cb_print_position() will be shown in a later post. And finally we start playing, with both GStreamer gst_element_set_state() function, which put playbin pipeline in GST_STATE_PLAYING state, and g_main_loop_run() which starts GLib provided event loop.

That's all the setup we need. In next issue we'll see how this code gets activated by Gtk callbacks in response to user action on the interface. Stay tuned.

Welcome back to "How to build a movie player". This is second lesson (lesson?). This time we'll aproach GStreamer to begin understanding how it works and what need to be done to build the multimedia subsystem of our player. First of all, some URL. GStreamer site is located at http://gstreamer.freedesktop.org/. On that site you'll find a lot of documentation to better focus arguments exposed here.

GStreamer is a framework, composed by several different reusable components called plugins. Plugins can be of more than one kind: sources, demuxers, decoders, video and audio players. We mentioned demuxes and decoders only because we are building a player application, but GStreamer, as the name suggest, is also able to produce contents, so it's also equipped with muxers, encoders and network stremers.

Plugins are interconnected by pads. Pads are like directional slots that produce or consume data. Some plaugins have just producing pads, like file readers or stream downloaders, some have consuming pads only, like audio or video players, some have both, like filtering plugins, demuxes, decoders and so on. Producing pads are called sources, consuming pads are called syncs.

Joining plugins by connecting pads creates a pipeline, which is a complete chain of media management able to acquire, process and output audio and video contents. If you need total control of what's happening inside your application, you can build your own pipeline by yourself. Otherwise you can follow GStreamer developer suggestion and use the prebuild playbin pipeline. Playbin is a plugin providing a complete pipeline which needs very little customization to work. Playing media content requires just setting the uri property of playbin to point to your file or stream and playbin will handle all the dirt work for you.

GStreamer comes with two useful command line tools: gst-launch and gst-inspect. The first one can be used to test pipelines before writing even one single line of code. The second one can be used to inspect plugin properties and found the plugin that best matches your needs. For example, the man page of gst-launch report some examples of pipelines, like the following:

gst-launch filesrc location=music.mp3 ! mad ! audioconvert ! audioresample ! osssink

Reading for left to right, this pipeline does:

  1. read file music.mp3 with filesrc plugin
  2. process it with mad plugin to decode the MP3 stream
  3. convert it to a playable audio format with audioconvert plugin
  4. resample to a useful rate with audioresample plugin
  5. play it to /dev/dsp using the osssink plugin, which is based on OSS Linux audio system

location is a property of filesrc plugin which is set on command line to point to source audio file. osssink is a consumer only plugin, being at the end of the pipeline, while filesrc is a producer only plugin. Similarly here is a ogg/vorbis player:


gst-launch filesrc location=music.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! osssink

The main difference is that ogg-vorbis has a container (the Ogg format) around audio content (the Vorbis stream), so the pipeline needs to unwrap Vorbis data before decoding it; that's done by the couple oggdemux ! vorbisdec, an Ogg demuxer unwrapping content later fed to a Vorbis decoder.

That's both simple and complex at the same time. How I'm supposed to know which plugin connect to which other in forming a pipeline? The answer is very easy. GStreamer plugins provide self inspection. With command line tool gst-inspect you can learn how a plugin interfaces to outside world and what can be connected to it, and also which formats the plugin can receive and produce and a lot more. Calling gst-inspect without parameters will return a full list of all the available plugins. Providing the name of a plugin will return more informations on that plugin only. Let see what can we learn about the first plugin, filesrc:

Pad Templates:
  SRC template: 'src'
    Availability: Always
    Capabilities:
      ANY


That section informs us that any kind of output can be produced by this plugin (Capabilities: ANY). That makes sense, since a file sourcing plugin can read any kind of data from inside the file.

Pads:
  SRC: 'src'
    Implementation:
      Has getrangefunc(): gst_base_src_pad_get_range
      Has custom eventfunc(): gst_base_src_event_handler
      Has custom queryfunc(): gst_base_src_query
    Pad Template: 'src'


The plugin provides a pad called src which refers to previously seen 'src' template. So we now know that using this plugin will provides us a src pad which is a producer pad outputting any kind of data in the known and unknown universe. The output is actually much more longer but we don't manage to analyze it all here. That was just to give you a taste of GStreamer plugins. But, as we mentioned before, building a pipeline is quite complex. Another thing to consider is that pads can be static or dynamic. Some file contains an arbitrary number of streams of the same kind (think to multilanguage audio tracks inside an AVI or Ogg file). So certain plugins will create pads dynamically. If you really need all that complexity you can get your hands dirt, but otherwise there is another solution: the playbin pipeline we already mentioned before.

Playbin is a full, dynamic pipeline implemented in a single plugin. To use it you have just to set one or more properties and all the black magic will be done behind the scenes by GStreamer. The most important one is the uri property which points to media to be played, using  a compliant URI syntax, like file:///home/myself/Video/concert.ogg or http://www.on.line.source.net/song.mp3. Doing it on the command line is just a matter of:

gst-launch playbin uri="file:///usr/share/example-content/Experience ubuntu.ogg"

Just issue this command and you'll see and hear your media played for you. We'll use playbin for our movie player in later posts.

I hope the load of information has not been too high. GStreamer is quite easy to be used as a multimedia framework, but quite easy should be intended in relation to the intrinsics complexity of multimedia frameworks. You need to study for some days the good documentation the project provides and you'll be able to start coding more faster than you imagine.

So far, that's all. In the next issue we'll use GStreamer playbin inside our application to provide playing capability. See you next time.

Recently I've started to play with GStreamer, a powerful and complex multimedia framework based on glib object model. In less than two weeks I've been able to build a (basic) player which can handle audio and video. In this post I'm starting a report on how to build such a basic player as an introduction to GStreamer.

We'll use Glade-2 to build a Gtk+2.0 interface for our player and we'll build the interface code using C as target language. We'll also use autotools from GNU project, since Glade kindly provides all the setup files for use. We'll need just to tweak a little bit with Makefile.am to add GStreamer compile flags.

Ok, starting! Run Glade and start a new project. Call it as you prefer. In out tutorial we'll call our application blogtheater. Then start placing widgets on the ground. The very first widget you should pick is of course a window. After clicking on window item in glade palette, something similar should appear:

mt001.jpeg

Now it's time to fill the interface with familiarly looking widgets: a menu bar, a working area and a status bar which informs the user about what's going on. We place a vertical box of four slot, we add the menu bar in the first and the status bar in the last. In the second one we'll place the main contents while in the third one we'll place the controls. The result should look like in following picture:

mt002.jpeg

The buttons need some makeup: using stock buttons will do the job. First button will be Open, then Play, Pause and (we miss a slot, should add one!) Stop. In the left most slot we'll put a two lines vertical box with timestamp up and a range down, to visualize the media playing position. The result, again, look like the picture:

mt003.jpegMore promising, isn't it? OK. Let me explain some tricks I've used with glade. Nothing is marked as "fill" and "expand" except the vertical box holding the range and the timestamp. The timestamp if formed by three distinct labels: the first and the third (for elapsed and total time) and another one which is just "/". That will simplify the callback, as we'll see while coding file callbacks.c. Now, let's add the screen and the playlist, the first on left, the second on right, as follows:

mt004.jpegInside the vertical pane object (the one divided in two vertical region by a draggable separator, are placed two frame widgets with "No file playing" and "Playlist:" as labels. The GtkAdjustment of left frame has been set to resizeable while the rightest one has not. That's due to gravity behaviour when the window is resized. Left frame hosts a GtkImage widget which will be used by GStreamer to show video contents. The right one contains a GtkTreeView widget which allows displaying of a structured list of arbitrary data.

The interface is almost complete (OK, no "About" dialog, but who cares? You are skilled enough to add it yourself) and we miss just a file selector dialog, so we click on the FileChooser widget inside Glade palette. Than we save the project and we build the code which will look like any other ordinary GNU package, with configure and everything in place.

So far, that's all. If you wish, you can download blogtheater glade project. In the next issue we'll see how GStreamer performs data pipelining and how use it inside a multimedia application. Stay tuned. :-)




Just after having published the web interface plugin for BitFlu, I've tested it on newest version of bitflu development branch. The good news is that it's still working. The bad news (if it's so) is that something has changed and installation is a bit different, but even better (so definitely it isn't a bad news).


First of all, the plugin should be renamed as 10_AdminWeb.pm. But you no longer need to add Bitflu::AdminWeb to plugin list to have the plugin loaded, 'cause plugins list is built by reading plugin directory contents.

An AJAX interface for Bitflu

| | Comments (0) | TrackBacks (0)

Bitflu is a bittorrent client written in Perl by Adrian Ulrich. It's very lightweight and is well suited for installation on small machines like your linux mini firewall that you have built with that old mother board and that 400MHz CPU you found in a closet. Its memory usage is impressively low: 15/20M with many active torrents; nothing to share with other clients occupation (150M + ).


Bitflu comes in two releases: a stable and a development one. We need the second one which is a new rebirth for bitflu, being a completely rewriting from scratch of everything with a deeper modular design in mind (even core functions of bitflu has been implemented as plugins). Stable version included a web interface, while the development one has just a textual telnet interface.


bitflu_screenshot_s.jpg

And here enters my plugin. AdminWeb.pm. It's basically a Perl plugin which provides a nice web interface to most of Bitflu functions. You can upload a .torrent by specifying the URL on the web or the path on server (Adrian told me that URL fetching will be included in bitflu and so will disappear from my plugin). You can monitor downloads by expanding download section, you can commit a download when finished and see its progress in percentage. You can query bitflu about installed plugins and other informations. By installing Filesys::DfPortable Perl module you can also have a report about available disk space.

To install: download the plugin and simply extract the archive in your bitflu_dir/plugins/Bitflu/ directory and edit bitflu.conf by adding Bitflu::AdminWeb to entry plugins. If the entry (or the whole file) does not exists and you feel yourself hacker enough, you can also edit bitflu.pl itself by adding plugin name to internal list (search for "$self->{conf}->{plugins}" and edit the value pointed by this key).


Recent development in Distributed Hash Tables has opened a huge landscape of possibilities. DHT has been used for storage and retrieval of an enormous range of information kinds. One of this kind of informations is network names. A lot of alternatives to DNS has been proposed and sometimes even deployed, providing registration flexibility and ease of use. But most of that solutions deviated from DNS original standard, settling into to vertical application niches which lead to dead routes.


DNA tries to depart from this tradition learning from errors and wants to develop e new compatible standard able to smoothly interoperate with existing DNS server network. Basically, using DHT to route informations through participant nodes, DNA is able to resolve unofficially registered TLDs (Top Level Domains) as well as official ones. Zones are managed in a delegated way as already done for usual domains, but TLD registration will be bureaucracy free and will be anonymous.


If a DNA TLD will clash with an official one, DNA network will simply drop registering request and will serve query requests as normal DNS ones. For the end user, using DNA means just selecting a DNA node as resolver. Disabling DNA is as easy as substituting DNA resolver with a traditional one, probably provided by user ISP.


Actual DNA implementation is called RNA (Rhizomatic Name Archiver) and is entirely written in Perl, released as free software under GNU GPL v.2. For further informations please refer to http://www.dna-project.net/

Several weeks ago something happened with my paypal account. They was claiming irregular use of my account and decided to block it until I send city released papers about me.

I've tried to get more informations from paypal about the very nature of irregular use, but they have not revealed anything simply sticking to repeat that something went wrong and, of course, being them so concerned about my very own security, they blocked near everything. After sending a city issued paper, everything come back to order. But still no info.

I've two answers, which one is the right one, I still don't know.

First answer: they where just trying to be sure that I was the one I was claiming to be. So they used a little trick to force me sending some papers.

Second answer: I was using tor to navigate anonymously. May be paypal did not consider tor as a an accepted tool of modern Internet life because of money being involved. Tor is basically a tool to navigate without being traced by the other peer and anyone being finger tapping the network in between. But, as you already may know, privacy is no value while money are involved.

I don't which one is true. But what's worse, I even don't know which one is better.

Tagsistant is a filesystem for Linux/BSD kernels based on libfuse. As you already know, every day you manage lots of files. Searching takes some time very long time and finding is not always guaranteed. Tagsistant is a simple tagging layer between you and your files. Mount it on a dedicated directory and create tags with tools you already are used to by making new directories inside it and copy your files in tag-directories. To perform a search just walk inside tagsistant space to write a query, like in path tagsistant/holidays/AND/summer/AND/sea/OR/holidays/AND/Rome/. Finding your stuff has never been simpler.

Tagsistant e' un filesystem per kernel Linux e BSD basato su libfuse. Ti sarai gia' reso conto che ogni giorni maneggi molti file. Cercarli a volte richiede molto tempo e trovarli non e' sempre garantito. Tagsistant e' un semplice layer di etichettatura fra te e i tuoi file. Montalo in una directory dedicata e crea le tag usando strumenti a cui sei gia' abituato semplicemente creando nuove directory dentro cui copiare i tuoi file. Per eseguire una ricerca muoviti nello spazio gestito da tagsistant per scrivere una query, come con il percorso

tagsistant/vacanze/AND/estate/AND/mare/OR/vacanze/AND/Roma/.

Trovare le tue cose non e' mai stato cosi' semplice.

Magma is a network filesystem for Linux/BSD kernels. Its main goal is to provide a reliable filesystem built on distributed hash tables, fault tolerant to network and hardware failure and redundant on managed data.

Magma e' un network filesystem per kernel Linux e BSD. Il suo scopo principale e' fornire un filesystem affidabile basato su distributed hash table, resistente agli inconvenienti della rete e dell'hardware e capace di ridondare i dati contenuti.

Strumenti resistenti is a place to discuss about software that place resistance as main goal. Resistence as quality in conception and programming it, but also as an attitude on raising pressure exercised on digital rights done by who would want a community of  obedient and malleable users.

Strumenti resistenti e' un contenitore per discutere di software che pongano la resistenza come obiettivo centrale. Resistenza intesa sia come qualita' nella programmazione e nella concezione, sia come attitudine alla crescente pressione esercitata sui diritti digitali da chi vorrebbe una comunita' di utenti docili e malleabili.

About this Archive

This page is an archive of entries from March 2008 listed from newest to oldest.

Find recent content on the main index or look in the archives to find all content.

Categories

Pages