Indice

Utilizzare mplayer come backend

Autore: Fabio Di Matteo
Ultima revisione: 3/12/2010

In questo articolo vedremo come integrare Mplayer nei nostri programmi (dotati di gui e non). Prima di cominciare ad integrare mplayer nelle nostre interfaccie grafiche è bene parlare di come si possano inviare comandi ad mplayer da un programma esterno.

Mplayer , il famoso lettore multimediale da riga di comando puo' essere usato come backend nei nostri programmi attraverso l'utilizzo di pipe (in pratica proprio come avviene per il programma Gnome-mplayer). Ovvero si puo' controllare tramite l'invio di comandi sul stdin.
E' sufficente,infatti, lanciare il lettore con l'opzione -slave per metterlo in “ascolto” sullo stdin per captare eventuali comandi. Per l'elenco dei comandi digitare da console mplayer -input cmdlist .
Di seguito un semplice sorgente C che mostra come controllare mplayer attraverso un nostro programma che fa uso di pipe.

 
 /* avviando mplayer con l'opzione -slave  rimarra in "ascolto" sullo stdin 
  * per captare eventuali comandi (per un elenco dei comandi e' sufficiente lanciare
  * 'mplayer -input cmdlist' )*/
 
 #define MPLAYER "/usr/bin/mplayer -slave -quiet -idle prova.3gp"
 #include <stdio.h>
 #include <stdlib.h>
 
 int main(int argc, char **argv) 
 {
  		FILE *mplayer;
 
	  	/*Apriamo una normale pipe in scrittura*/
		if ( ( mplayer = popen ( MPLAYER , "w") ) ) 
		{
			/*Stampo il codec video usato dal filmato*/
			fputs("get_video_codec\n", mplayer);
			fflush(mplayer);
 
			/*Aspetto 3 secondi*/
			sleep(3);
 
			/*Pausa del filmato*/
			fputs("pause\n", mplayer);
			fflush(mplayer);
 
			/*Aspetto 3 secondi*/
			sleep(3);
 
			/*Play del filmato*/
			fputs("pause\n", mplayer);
			fflush(mplayer);
 
			sleep(3);
 
			/*Stop del filmato*/
			fputs("stop\n", mplayer);
			fflush(mplayer);
 
 
			/*Chiudo la pipe*/
			fputs("quit\n", mplayer);
			fflush(mplayer);
			pclose(mplayer);
	  	}
 
  exit( 0 );
}

Compiliamo con:

gcc mplayer-backend.c -o mplayer-backend

La documentazione sull'uso dell' opzione slave e' consultabile qui: slave.txt

Integrare mplayer nelle nostre finestre gtk+2

Andremo questa volta ad integrare il nostro lettore multimediale all'interno di un nostro widget (GtkDrawingArea) chiedendo ad mplayer di utilizzare il nostro widget tramite il parametro -wid . Ovvero quello che faremo è ricavare il window id della nostra GtkDrawingArea e fornirlo ad mplayer (il tutto nella funzione on_btCarica_clicked() ). Per quanto riguarda il controllo del lettore useremo la tecnica della pipe esposta all'inizio di questo articolo.

Il sorgente

main.c
per la creazione dello scheletro dell'applicazione abbiamo usato il nostro script autogtkbuilder (Creazione automatica dello scheletro per applicazioni gtkbuilder).

#include <gtk/gtk.h>                                                //includo le librerie gtk e glade.
#include <gdk/gdkx.h>
 
 
GtkBuilder *xml;                                                 //questo è il puntatore al file xml che contiene l'interfaccia  
GtkWidget  *widget;                                              //questa variabile serve per recuperare di volta in volta il  
                                                                //  widget (ovvero l'oggetto ) che vogliamo usare
/*Pipe per comandare mplayer*/
FILE* mplayer;
 
 
void on_brStop_clicked(GtkWidget *widget, gpointer user_data)
{
	fputs("stop\n",mplayer);
	fflush(mplayer);
} 
 
void on_btPlayPause_clicked(GtkWidget *widget, gpointer user_data) 
{
	fputs("pause\n",mplayer);
	fflush(mplayer);
}
 
void on_btCarica_clicked(GtkWidget *widget, gpointer user_data) 
{
 
	/*Apro un dialogo per la scelta del file*/
 
	GtkWidget *dialog, *MainWindow;
	GtkFileFilter* filter;
	gchar *filename;
 
	MainWindow= GTK_WIDGET (gtk_builder_get_object(xml, "MainWindow"));
 
	dialog = gtk_file_chooser_dialog_new ("Seleziona un file",
						  GTK_WINDOW(MainWindow),
						  GTK_FILE_CHOOSER_ACTION_OPEN,
						  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
						  GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
						  NULL);
 
 
	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
	{
		 /*Prendo il path del file da aprire*/
		 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
 
		 /*Include il mediaplayer dentro un widget gtk (drawing area) */
		 widget= GTK_WIDGET (gtk_builder_get_object(xml, "drvMplayer"));
		 int  xwin = GDK_WINDOW_XWINDOW (GTK_WIDGET (widget)->window);
 
		 /*Se mplayer e' gia' stato avviato lo stoppo*/
		 if (mplayer!=NULL)
		 {
			fputs("stop\n",mplayer);
			fflush(mplayer);
		 }
 
		 /*Apro una pipe con mplayer e lancio il comando per caricare il file
		  * per un elenco dei comandi accettabili via pipe da mplayer visitare:
		  * http://www.mplayerhq.hu/DOCS/tech/slave.txt */
		 char cmdMplayer[50];
		 sprintf(cmdMplayer,"mplayer -wid %d -slave -quiet -idle",xwin);
 
		 if ( ( mplayer = popen ( cmdMplayer , "w") ) ) 
		 {
			filename = g_strconcat("loadfile '", filename,"'\n",NULL);
			fputs(filename,mplayer);
			fflush(mplayer);
		 }
 
	}
	/*Distruggo alcune variabili ormai inutili*/
	gtk_widget_destroy (dialog);
	g_free (filename);	
 
}
 
 
 
void on_MainWindow_delete_event(GtkWidget *widget, gpointer user_data)        //altra callback associata alla chiusura della 
{                                                                         // finestra 
    fputs("quit\n",mplayer);
    fflush(mplayer);
    pclose(mplayer);
    gtk_main_quit();
}
 
 
 
int
main (int argc, char *argv[])
{
  	gtk_init (&argc, &argv);
	gchar* base;
	gchar* glade_file;
 
	if (g_find_program_in_path ("mplayer-embedded")==NULL){
		/*Ricava il percorso dell'eseguibile, senza il nome del file*/ 
		base = g_path_get_dirname(argv[0]);
 
		/*Concatena il percorso base al nome file gui.glade */
		glade_file = g_build_filename (base,"../share/mplayer-embedded", "gui.glade", NULL);
	}else{
		base = g_path_get_dirname(g_find_program_in_path ("mplayer-embedded"));
		glade_file = g_build_filename (base,"../share/mplayer-embedded", "gui.glade", NULL);
	}	
 
    /*Infine carica come disolito il file dell'interfaccia */
    GError* error = NULL;
	xml = gtk_builder_new ();
	if (!gtk_builder_add_from_file (xml, glade_file, &error))
	  {
		g_warning ("Couldn't load builder file: %s", error->message);
		g_error_free (error);
	  }
 
 
	 /* connette tutti gli eventi dei widget alle rispettive funzioni */
   	 gtk_builder_connect_signals (xml, NULL);
 
 
      	/* Avvia il ciclo principale delle gtAvvia il ciclo principale delle gtk*/ 
	gtk_main ();
 
  return 0;
 
}

Il file della Gui creato con Glade

Questo è il file xml con la gui dello screenshot.

gui.glade

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="2.16"/>
  <!-- interface-naming-policy project-wide -->
  <object class="GtkWindow" id="MainWindow">
    <property name="visible">True</property>
    <signal name="delete_event" handler="on_MainWindow_delete_event"/>
    <child>
      <object class="GtkVBox" id="vbox1">
        <property name="visible">True</property>
        <property name="spacing">9</property>
        <child>
          <object class="GtkLabel" id="label1">
            <property name="visible">True</property>
            <property name="label" translatable="yes">&lt;b&gt;Integrare mplayer dentro finestra gtk&lt;/b&gt;</property>
            <property name="use_markup">True</property>
          </object>
          <packing>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkDrawingArea" id="drvMplayer">
            <property name="width_request">640</property>
            <property name="height_request">480</property>
            <property name="visible">True</property>
          </object>
          <packing>
            <property name="position">1</property>
          </packing>
        </child>
        <child>
          <object class="GtkHBox" id="hbox1">
            <property name="visible">True</property>
            <property name="spacing">23</property>
            <child>
              <object class="GtkButton" id="btCarica">
                <property name="label" translatable="yes">Carica</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_btCarica_clicked"/>
              </object>
              <packing>
                <property name="position">0</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="btPlayPause">
                <property name="label" translatable="yes">Play/Pause</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_btPlayPause_clicked"/>
              </object>
              <packing>
                <property name="position">1</property>
              </packing>
            </child>
            <child>
              <object class="GtkButton" id="brStop">
                <property name="label" translatable="yes">Stop</property>
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="receives_default">True</property>
                <signal name="clicked" handler="on_brStop_clicked"/>
              </object>
              <packing>
                <property name="position">2</property>
              </packing>
            </child>
          </object>
          <packing>
            <property name="position">2</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

Il nostro CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
PROJECT(mplayer-embedded)
SET (AUTHOR "Fabio Di Matteo" INTERNAL "Author")
SET (VERSION "0.1.0")
INCLUDE (FindPkgConfig)
IF (NOT PKG_CONFIG_FOUND)
	MESSAGE (FATAL_ERROR "pkg-config not found...") 
ENDIF (NOT PKG_CONFIG_FOUND)
pkg_check_modules (GTK REQUIRED gtk+-2.0>=2.6)
IF (NOT GTK_FOUND)
	MESSAGE(FATAL_ERROR "You don't seem to have gtk >= 2.6 development libraries installed...")
ENDIF (NOT GTK_FOUND)
ADD_DEFINITIONS()
INCLUDE_DIRECTORIES (. ${GTK_INCLUDE_DIRS})
LINK_DIRECTORIES (${GTK_LIBRARY_DIRS} )
LINK_LIBRARIES (${GTK_LIBRARIES} )
#Indichiamo dove sara' messo l'eseguibile
ADD_EXECUTABLE( bin/mplayer-embedded src/main.c)
#Se se si ha bisogno di eventuali dipendenze fornite da noi stessi
#ADD_DEPENDENCIES (mplayer-embedded src/main.c)
#Variabili per le directory di installazione
#ADD_DEFINITIONS (-DVERSION=\"${VERSION}\")
#ADD_DEFINITIONS (-DDATADIR=\"${CMAKE_INSTALL_PREFIX}/share\")
#Copia file per l'installazione
#ADD_SUBDIRECTORY (src)
INSTALL (TARGETS bin/mplayer-embedded DESTINATION bin)
INSTALL (DIRECTORY share/mplayer-embedded DESTINATION share)