Tuesday, February 14, 2012

command line mp3 player using gstreamer

Gstreamer is an opensource multimedia framework which is widely using in various multimedia application.
It comes with bunch of codes, mux , demux etc.,
Below diagram shows how to build the pipeline using variuos plugins(in our case pipeline built for mp3 audio playing)

 
Compilation steps :

gcc player.c -o player $(pkg-config --cflags --libs gstreamer-0.10)

Run command:

./player <folder containing mp3 files>

 source code:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <gst/gst.h>
#include <glib.h>
#include <pthread.h>

int flag=TRUE;

void play(char *song);
static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data);

static gboolean
cb_print_position (GstElement *pipeline);

int check_mp3(char *name)
{
    char buf[4];
    int i;

    while(*name != '\0')
        name++;
    name = name - 3;
    for(i=0;i<3;i++){
        buf[i] = *name;
        name++;
    }
    buf[i]='\0';
    return strcmp(buf,"mp3");
}

int main(int argc,char *argv[])
{
    DIR *dir;
    struct dirent *dent;
    char buf[PATH_MAX];

    if(argc != 2)
    {
        printf("Usage: ./player <mp3_songs_folder>\n");
        exit(EXIT_FAILURE);
    }
   
    if(!(dir = opendir(argv[1])))
    {
        perror("opendir()");
        exit(EXIT_FAILURE);
    }

    while((dent = readdir(dir)))
    {
        if(!check_mp3(dent->d_name)){
            snprintf(buf,PATH_MAX,"%s/%s",argv[1],dent->d_name);
            g_print("Playing :- %s\n",dent->d_name);
            play(buf);
           
        }
    }
    return 0;
}

static gboolean
cb_print_position (GstElement *pipeline)
{
    GstFormat fmt = GST_FORMAT_TIME;
    gint64 pos, len;

    if (gst_element_query_position (pipeline, &fmt, &pos)
        && gst_element_query_duration (pipeline, &fmt, &len)) {
        g_print ("Time: %lld,%lld\r",
             (long long int) pos,(long long int)len);
    }

    if(flag == TRUE)
        return TRUE;
    else
    {
        flag = TRUE;
        return FALSE;
    }
}


void play(char *song)
{
    GMainLoop *loop;
    GstElement *pipeline,*filesrc,*mad,*audioconvert,*autoaudiosink;
    GstBus *bus;
   
    gst_init(NULL,NULL);
    loop = g_main_loop_new(NULL,FALSE);
   
    pipeline = gst_pipeline_new("mp3_player");
   
    filesrc = gst_element_factory_make("filesrc","filesrc");
    mad = gst_element_factory_make("mad","mad");
    audioconvert  = gst_element_factory_make("audioconvert","audioconvert");
    autoaudiosink = gst_element_factory_make("autoaudiosink","autoaudiosink");

    g_object_set(G_OBJECT(filesrc),"location",song,NULL);
   
    bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
    gst_bus_add_watch (bus, bus_call, loop);
    gst_object_unref (bus);

    gst_bin_add_many(GST_BIN(pipeline),filesrc,mad,audioconvert,autoaudiosink,NULL);
    gst_element_link_many(filesrc,mad,audioconvert,autoaudiosink,NULL);
   
    gst_element_set_state(pipeline,GST_STATE_PLAYING);
   
    g_timeout_add (200, (GSourceFunc) cb_print_position, pipeline);
    g_main_loop_run(loop);
    gst_element_set_state(pipeline,GST_STATE_NULL);
    gst_object_unref(pipeline);
}

static gboolean bus_call(GstBus *bus,GstMessage *msg,gpointer data)
{
    GMainLoop *loop = (GMainLoop *) data;

    switch (GST_MESSAGE_TYPE (msg)) {

    case GST_MESSAGE_EOS:
        g_print ("\nEnd of stream\n");
        g_main_loop_quit (loop);
        flag=FALSE;
        break;

    case GST_MESSAGE_ERROR: {
        gchar  *debug;
        GError *error;

        gst_message_parse_error (msg, &error, &debug);
        g_free (debug);

        g_printerr ("Error: %s\n", error->message);
        g_error_free (error);

        g_main_loop_quit (loop);
        break;
    }
    default:
        break;
    }

    return TRUE;
}