====== Crosscompilare progetto gtk - libvlc per windows su Linux ======
Autore: **//Fabio Di Matteo//** \\ Ultima revisione: **//08/11/2011//** \\ \\
Partendo dall'articolo "[[programmazione:libvlc:creare_un_lettore_multimediale]]" vedremo come realizzare un semplice lettore multimediale basato sulla libreria [[http://wiki.videolan.org/Libvlc|Libvlc]] anche per i sistemi windows. Facendo in modo tale, che una volta lanciato su windows il nostro eseguibile, non richieda l'installazione di altre dipendenze. Distribuiremo infatti le librerie assieme alla nostra applicazione, portandoci dietro tutto quello che serve (senza compilare staticamente) .
{{programmazione:libvlc:gtk-vlc.png|}}
===== Preparare il nostro ambiente di lavoro =====
- Scarichiamo i binari di Vlc per windows con la cartella SDK (contenente i file di sviluppo di libvlc );
- Scarichiamo il pacchetto [[http://www.gtk.org/download/win32.php|All-in-one bundles]] contenente il necessario per sviluppare con le GTK+ su windows;
- a questo punto dobbiamo individuare i file **libvlc.dll** e **libvlcore.dll** e la cartella **plugins/** dello Sdk di Vlc e copiarli dentro la cartella **bin/** del bundle gtk appena scaricato;
- copiamo **include/vlc** in **include/** del nostro bundle Gtk;
- posizioniamo i nostri sorgenti in una cartella di nome **src/** nella root del progetto;
- uniamom la cartella **lib** dell'sdk vlc con quella del bundle gtk.
Avremo come risultato una cartella con una struttura simile alla seguente:
drwx------ 2 fabio fabio 4096 2011-10-21 12:22 bin (qui dentro ci sara' l'eseguibile della nostra applicazione)
drwx------ 5 fabio fabio 4096 2011-10-21 11:23 etc
drwx------ 13 fabio fabio 4096 2011-10-21 11:23 include
drwx------ 6 fabio fabio 4096 2011-10-21 11:23 lib
drwx------ 3 fabio fabio 4096 2011-10-21 11:23 man
drwx------ 2 fabio fabio 4096 2011-10-21 11:23 manifest
drwx------ 10 fabio fabio 4096 2011-10-21 11:23 share (qui dentro una cartella con dentro il file .glade della nostra interfaccia)
drwx------ 3 fabio fabio 4096 2011-10-21 11:23 src (qui dentro i sorgenti della nostra applicazione e il makefile)
Non è strettamente necessario, ma io per realizzare lo scheletro dell'applicazione che fa uso di gtk e del suo nativo supporto alle interfacce realizzate con glade ho utilizzato il nostro script che automatizza il processo ( [[programmazione:gtk:creazione_scheletro_per_applicazioni_gtkbuilder]] ) e ho unito le cartelle con quelle appena ottenute. \\ \\
Per la compilazione nativa per Linux invece le dipendenze (debian/ubuntu) sono: libvlccore-dev, libvlc-dev, libgtk2.0-dev, gcc .
===== Il sorgente =====
**mytest.c**
#include // includo le librerie gtk e glade.
#include // includo le librerie vlc
#ifdef _WIN32
#include
#define WINOPT G_MODULE_EXPORT void // necessario per attivare la callbacks automatiche
#endif // acnhe su win32. Ogni callback deve restituire il
#ifdef __linux // tipo G_MODULE_EXPORT void su win32 .
#include
#define WINOPT void
#endif
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
/*Instanza di libvlc (core)*/
libvlc_instance_t * inst;
/*Instanza di libvlc media player*/
libvlc_media_player_t *mp;
/*Media (file o url da leggere)*/
libvlc_media_t *m;
WINOPT on_MainWindow_delete_event(GtkWidget *widget, gpointer user_data) //altra callback associata alla chiusura della
{ // finestra
gtk_main_quit();
}
WINOPT on_btStop_clicked(GtkWidget *widget, gpointer user_data)
{
/* Stop playing */
libvlc_media_player_stop(mp);
}
WINOPT on_btPause_clicked(GtkWidget *widget, gpointer user_data)
{
/*Se il lettore sta leggendo qualcosa lo mette in pausa,
* altrimenti lo mette in play*/
if (libvlc_media_player_is_playing(mp)==1)
{
libvlc_media_player_set_pause(mp,1);
}else{
libvlc_media_player_play (mp);
}
}
WINOPT on_btLoad_clicked (GtkWidget *widget, gpointer user_data)
{
/*Dialog gtk per caricare il 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)
{
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
/*Path for plugin (bin/plugins)*/
const char * const vlc_args[] = { "--plugin-path=.\\plugins" };
/* Load the VLC engine */
inst = libvlc_new (1, vlc_args);
/* Create a new item */
m = libvlc_media_new_path (inst, (char* )filename);
/* Create a media player playing environement */
mp = libvlc_media_player_new_from_media (m);
/* No need to keep the media now */
libvlc_media_release (m);
/*Include il mediaplayer dentro un widget gtk (drawing area) */
#ifdef __linux
widget= GTK_WIDGET (gtk_builder_get_object(xml, "MediaPlayer"));
uint32_t xwin = GDK_WINDOW_XWINDOW (GTK_WIDGET (widget)->window);
libvlc_media_player_set_xwindow(mp,xwin);
#endif
#ifdef _WIN32
widget= GTK_WIDGET (gtk_builder_get_object(xml, "MediaPlayer"));
HWND win = GDK_WINDOW_HWND(GTK_WIDGET (widget)->window); //buono ma copre tutta la finestra
libvlc_media_player_set_hwnd(mp, (void*) win);
#endif
/* play the media_player */
libvlc_media_player_play (mp);
}
gtk_widget_destroy (dialog);
g_free (filename);
}
int
main (int argc, char *argv[])
{
gtk_init (&argc, &argv);
gchar* base;
gchar* glade_file;
if (g_find_program_in_path ("gtk-vlc")==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/gtk-vlc", "gui.glade", NULL);
}else{
base = g_path_get_dirname(g_find_program_in_path ("gtk-vlc"));
glade_file = g_build_filename (base,"../share/gtk-vlc", "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 Gtk */
gtk_main ();
return 0;
}
===== Il makefile =====
Il makefile generera' 2 eseguibili, **mytest** e **mytest.exe** rispettivamente per Linux e windows. \\ \\
**makefile**
CPPWIN32 = i586-mingw32msvc-gcc
OPTSWIN32 = -mwindows -I../include -L../lib -I../include/vlc -mms-bitfields -I../include/gtk-2.0/gdk -I../include/gtk-2.0 -I../lib/gtk-2.0/include -I../include/atk-1.0 -I../include/cairo -I../include/gdk-pixbuf-2.0 -I../include/pango-1.0 -I../include/glib-2.0 -I../lib/glib-2.0/include -I../include -I../include/freetype2 -I../include/libpng14 -L../lib -lgtk-win32-2.0 -lgdk-win32-2.0 -latk-1.0 -lgio-2.0 -lpangowin32-1.0 -lgdi32 -lpangocairo-1.0 -lgdk_pixbuf-2.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -lgthread-2.0 -lglib-2.0 -lintl -lvlc
CPP= gcc
OPTS= `pkg-config --cflags --libs gtk+-2.0 libvlc gdk-x11-2.0` -export-dynamic
all:
$(CPPWIN32) mytest.c -o ../bin/mytest.exe $(OPTSWIN32)
$(CPP) mytest.c -o ../bin/mytest $(OPTS)
clean:
rm mytest.exe
rm mytest
===== Problemi della versione windows =====
Attualmente ho riscontrato dei problemi nella versione windows. Ovvero quando viene eseguito un video , questo sostituisce per intero il contenuto della finestra oscurando tutti gli altri widget. Cosa che non accade nella versione nativa per Linux. Se qualcuno ha una soluzione a questo inconveniente puo' postarla nei commenti.