GtkMediaPlayer: Widget Gtk de reproducción de películas e son

De Wiki do Ciclo ASIR do IES de Rodeira
Saltar á navegación Saltar á procura

Introducción

GtkMediaPlayer é un widget GTK+ que permite reproducir vídeo empotrado nas aplicacións GTK utilizando mplayer como reproductor. Polo tanto, con este widget se poderá reproducir calquera fonte que sexa capaz de reproducir mplayer.

Descrición do Proxecto

O propósito principal deste proxecto é a ilustración da construcción dun widget GTK+ e a súa integración en glade. Tamén é un bo exemplo do control e comunicación de procesos.

O Widget GtkMediaPlayer aprovéitase da facilidade ofrecida polo reproductor mplayer de amosar a súa saída na ventá elexida polo usuario mediante o parámetro -wid e do Widget GTK+ GtkSocket para ofrecer unha API de programación que permita empotrar vídeo/audio nas nosas aplicacións GTK+ e o desenvolvemento visual mediante glade e libglade.

A execución das instancias de mplayer faise nun proceso independente en segundo plano que se pode controlar dende o proceso principal (a aplicación), e se ofrecen 3 modalidades de reproducción:

  • Modalidade Normal: O medio indicado reprodúcese directamente co mplayer. É o medio axeitado para reproducir medios locais e cos streams de audio e vídeo (mms://, rtsp:// ...).
  • Modalidade wget: O medio se descarga con wget e se entuba (pipe) a súa saída directamente o mplayer (non se descarga localmente o medio). É util para medios aloxados remotamente ós que se accede mediante protocolos coma http:// ou ftp://.
  • Modalidade youtube: O chamo así porque é o único co que se poden ver vídeos de youtube (flash), e consiste en descarga-lo medio con wget a un directorio local (o widget o descargará en /tmp) e reproducilo con mplayer a un mismo tempo. É util para os protocolos http:// ou ftp:// e preferible o método wget sempre que queiramos descargar o medio para ter unha copia local.
  • Modalidade resolve-youtube: Esta modalidade é exclusiva para os vídeos de youtube, e consiste en que antes de reproducir o medio, se averigua a súa URL real (en youtube esta url cambia cada pouco tempo). A reproducción é idéntica á modalidade youtube).

Para elaborar este proxecto fíxose uso intensivo da documentación gtk+ 2.0, libglade-2.0, GLib,GObject e do manual de glade-3.

O resto de ferramentas empregadas foron un PC con Debian lenny GNU/Linux, gcc 4.1.3 e [gedit].

O widget GtkMediaPlayer precisa intercepta-lo sinal SIGCHLD, de modo que si a aplicación principal precisa ter o control deste sinal non poderá interceptala con signal, senon que terá que enlazar a chamada á función de control da sinal coa función do API GtkMediaPlayer void gtk_media_player_chain_sigchld(void (*handler)(int pid));.

Requerimentos de Hardware

  • Calquera máquina capaz de executa-lo mplayer.

A potencia requerida dependerá da tarxeta gráfica e dos codecs de vídeo que se empreguen.

Requerimentos de Software

  • GNU/Linux co entorno XWindow.
  • GTK+ 2.0.
  • mplayer.
  • wget.
  • glade-3 e libglade-2.

Lista de Cambios

  • Versión 1.3-2:
    • Arranxado problema que impedia engadir novos elementos ó menu e a barra de control.
    • Solucionados algúns fallos na compilación de GNetVideoPlayer
  • Versión 1.3-1:
    • Modificada a aplicación de exemplo GNetVideoPlayer para correxir o accesó ós vídeos de Stage6
  • Versión 1.3:
    • Modificada a resolución da url de youtube (youtube cambiou a páxina).
    • Separadas as funcións de acceso a youtube a ficheiros independentes para facilitar a súa modificación.
    • Eliminada a creación das librerías estáticas con comentarios no Makefile.
  • Versión 1.2: Resoltos pequenos fallos e engadido soporte para glade-3
  • Versión 1.1: Versión Inicial

Por Facer

  • Internacionalización e construcción mediante autoconf
  • Engadir API para tamano das miniaturas
  • Entrada no menú para visualizar en escala 1:1
  • Barra de progreso ocultable para resolver youtube e par indicar o inicio de reproducción
  • Posibilidade de eliminar o menú popup

Erros Coñecidos

  • (CORREXIDO NA v1.3-2) Debido a unha definición errónea nun ficheiro de cabeceira non funciona a descarga de contido en GNetVideoPlayer
  • (CORREXIDO NA v1.3-1) Debido a un cambio nas páxinas de Stage6, non funciona ben gnetvideoplayer
  • (CORREXIDO NA v1.3) Debido a un cambio nas páxinas de youtube non funciona o resolve_youtube
  • (CORREXIDO NA v1.3) IMPORTANTE: Na versión 1.2 faltan as iconas para o glade-3.
  • Algúns videos en modo youtube non se reproducen por rematar prematuramente.
  • A barra de progreso amosa as veces información errónea, necesita unha revisión grande.

Descargas

Lista de Correo

Instalación

  • Unha vez descargado o paquete tar.gz, se debe descomprimir con tar -xvzf arquivo.tar.gz.
  • Situámonos no directorio xerado e escribimos: make&make install, e make example para compila-lo exemplo
  • Dentro das carpetas das aplicacións as compilamos con make

Estas accións ademáis de compilar e permitir executar os exemplos, instalarán a librería compartida en /usr/lib, os ficheiros de apoio para o glade en /usr/lib/glade3/modules e /usr/share/glade3/catalogs/, o ficheiro de cabeceira para o desenvolvemento gtkmediaplayer. en /usr/include e as iconas para o glade3 en /usr/share/glade3/pixmaps/16x16 e /usr/share/glade3/pixmaps/22x22.

Exemplos

Os seguintes exemplos ilustran as posibilidades deste Widget, e son un bó exemplo de como realizar diversas accións comúns como cambiar os elementos do menú/barra de control, descargar medios ... etc.

Example

Este programa amosará catro vídeos. Os tres primeiros están empotrados e o cuarto se reproduce nunha ventá autónoma, coma si fora un reproductor.

Os reproductores empotrados reproducen de tres xeitos distintos: Entubando dende wget, descargando con wget e reproducindo (modo youtube) e resolvendo a url de youtube á url real, descargando con wget e reproducindo (modo resolve youtube).

Un dos reproductores empotrados ten modificada a súa barra de botons.

O vídeo independente reproduce directamente co mplayer, sen utilizar wget.

Pantallas de Mostra

Ficheiro:Example.png
Example - Vista Normal
Ficheiro:Example1.png
Example - Vídeos Soltos do GUI
Ficheiro:Example2.png
Example - Soltos cun GtkHandle

GYoutubePlayer

Este programa de exemplo, amosará o vídeo indicando a súa URL do estilo http://www.youtube.com/watch?v=axcmXOwNjuE, permitindo ademáis descargalo ó disco local, ou salvalo si xa se descargara enteiro durante a reproducción. E un bo exemplo de como se pode utilizar glade-3 con este widget, xa que os outros exemplos realizáronse cando o soporte para glade-3 aínda non existía.

Pantallas de Mostra

GNetVideoPlayer

Este programa permite facer procuras de vídeos en youtube e stage6. Utiliza o método "youtube" (descarga con wget e reproducción) e permite garda-lo vídeo unha vez descargado na súa totalidade ou descargalo sen reproducilo.

Os vídeos de youtube reproducen no modo "resolve youtube", que antes de facer a descarga co wget averigua a url real do vídeo.

Ofrécese un modo de paxinación doble: No combobox pode cambiarse de páxina, e nas flechas se elixe a 'subpáxina' dentro da páxina.

Podes ver un vídeo demostración.

Pantallas de Mostra

Ficheiro:GNetVideoPlayer.png
GNetVideoPlayer - Vista Normal
Ficheiro:GNetVideoPlayer1.png
GNetVideoPlayer - Vídeos Soltos do GUI
Ficheiro:GNetVideoPlayer2.png
GNetVideoPlayer - Soltos cun GtkHandle
Ficheiro:GNetVideoPlayer3.png
GNetVideoPlayer - Paneis de Búsqueda Soltos
Ficheiro:GNetVideoPlayer4.png
GNetVideoPlayer - Ocultando Stage3
Ficheiro:GNetVideoPlayer5.png
GNetVideoPlayer - Descargando Vídeos

Documentación Técnica de Desenvolvemento

Sinais de GtkMediaPlayer

  • "media_load"
Esta sinal se produce cando se remata de cargar un novo medio (se verificou a súa existencia e se fixo o snapshot).
void load_handler_callback(GtkMediaPlayer *player,gpointer data);
  • "media_stop"
Sinal producida cando remata a reproducción dun medio
void stop_handler_callback(GtkMediaPlayer *player,gpointer data);
  • "media_play"
Sinal producida cando comenza a reproducción dun medio
void play_handler_callback(GtkMediaPlayer *player,gpointer data);
  • "media_pause"
Sinal producida cando se fai unha pausa na reproducción dun medio
void pause_handler_callback(GtkMediaPlayer *player,gpointer data);
  • "media_continue"
Sinal producida cando se continúa reproducción dun medio que estaba en pausa.
void continue_handler_callback(GtkMediaPlayer *player,gpointer data);
  • "player_attach"
Sinal producida cando empotramos de novo o reproductor na súa ventá.
void attach_handler_callback(GtkMediaPlayer *player,gpointer data);
  • "player_detach"
Sinal producida cando soltamos o reproductor da súa ventá e se amosa nunha nova independente.
void detach_handler_callback(GtkMediaPlayer *player,gpointer data);
  • "media_download"
Esta sinal se produce cando se está a reproducir un medio en "modo youtube" (descarga con wget e reproducción simultánea) e a descarga chega ó seu final. A función de tratamento desta sinal recibe o GtkMediaPlayer que rematou a descarga, o url do arquivo descargado e os datos especificados polo usuario:
void download_handler_callback(GtkMediaPlayer *player,gchar *url, gpointer data);
Nos exemplos GNetVideoPlayer e GYoutubePlayer pode verse como se aproveita esta sinal para proporcionarlle a oportunidade o usuario de facer unha copia do medio reproducido.
  • "media_underflow"
Esta sinal prodúcese cando a reproducción está moi cerca do final do arquivo que se está a descargar. Para evitar o remate prematuro da reproducción, farase unha pausa automática na reproducción do medio e se emite esta sinal.
void underflow_handler_callback(GtkMediaPlayer *player,gpointer data);
  • "media_overflow"
Indica que se recuperou un underflow e a reproducción continuará.
void overflow_handler_callback(GtkMediaPlayer *player,gpointer data);

Modificando o menú por defecto e a barra de botóns

Este anaco de código amosa como se pode engadir un novo elemento á barra de botóns e ó menú por defecto do player de xeito que todos os novos reproductores creados o incorporen. Pode verse tamén como se inclúe o nome da función encargada de xestionar o botón / Entrada do menú (download_file):

#define GTK_MEDIA_PLAYER_BAR_DOWNLOAD (GTK_MEDIA_PLAYER_BAR_USER+1)

/* Rexistra un elemento (icona e mensaxe) no stock da aplicación
*/
void rexistra_stock_entry(char *file_icon_name,char *id,GtkStockItem *si,int nelems)
{
	GtkIconFactory *ifac;
	GtkIconSet *iset;
	GdkPixbuf *pb;
	GtkWidget *im;

	im=gtk_image_new_from_file(file_icon_name);
	pb=gtk_image_get_pixbuf(GTK_IMAGE(im));
	ifac=gtk_icon_factory_new();
	iset=gtk_icon_set_new_from_pixbuf(pb);
	gtk_icon_factory_add(ifac,id,iset);
	gtk_icon_factory_add_default(ifac);

	if (si!=NULL) gtk_stock_add(si,nelems);
}

int main(int argc,char *argv[])
{
   [...]
   GtkStockItem si[1]={{.stock_id="gtkmp_download",
	                .label="Descargar",
	                .modifier=0,
			.keyval=0,
			.translation_domain="gl_ES"}};
   MenuItem nm={.icon="gtkmp_download", 
		.mask=GTK_MEDIA_PLAYER_BAR_DOWNLOAD,
		.handler=download_file, 
		.sinal="activate" };
   [...]

   rexistra_stock_entry("icon_download.png","gtkmp_download",si,1);
   // Engadimos a nova entrada ó menu popup e a barra de botons
   gtk_media_player_new_entry(GTK_MEDIA_COMMAND_MENU,&nm);
   nm.sinal="button_press_event";
   gtk_media_player_new_entry(GTK_MEDIA_COMMAND_BAR,&nm);

   // Engadimos ó menú popup por defecto un separador e a nova entrada  
   gtk_media_player_add_to_default(GTK_MEDIA_COMMAND_MENU,GTK_MEDIA_PLAYER_BAR_SEPARATOR);
   gtk_media_player_add_to_default(GTK_MEDIA_COMMAND_MENU,GTK_MEDIA_PLAYER_BAR_DOWNLOAD);

   // Engadimos á barra de botons a nova entrada
   gtk_media_player_add_to_default(GTK_MEDIA_COMMAND_BAR,GTK_MEDIA_PLAYER_BAR_DOWNLOAD);

   [...]
}
NOTA
A función rexistra_stock_entry non é necesario escribila, xa que forma parte da libraría

Tamén e posible modificar so a barra de botons e/ou o menú dun so dos reproductores creados. Para facer eso bastará en lugar de engadir o botón/elemento do menú ós elementos por defecto, incluír un menú/barra persoalizado:

gint barExample[]={GTK_MEDIA_PLAYER_BAR_PLAY,GTK_MEDIA_PLAYER_BAR_STOP,
		   GTK_MEDIA_PLAYER_BAR_PROGRESS,GTK_MEDIA_PLAYER_BAR_DOWNLOAD,
		   GTK_MEDIA_PLAYER_BAR_NONE};

[...]

gtk_media_player_set_bar(GTK_MEDIA_PLAYER(player),barExample);

[...]
NOTA
O último elemento TEN que ser GTK_MEDIA_PLAYER_BAR_NONE.

API de GtkMediaPlayer

Introducción

Coas novas facilidades do glade-3 é posible incluir widgets dun xeito simple, e polo tanto agora é posible o deseño visual utilizando GtkMediaPlayer. O control deste reproductor realizaráse a través das funcións do API que se describirán a continuación.

Aquí podes ver un exemplo de desenvolvemento co glade-3 e gtkmediaplayer, ou se queres descargalo con maior calidade.

Descrición do API

Elementos da Barra de Botóns e do Menú

#define GTK_MEDIA_COMMAND_MENU	0
#define GTK_MEDIA_COMMAND_BAR	1

#define GTK_MEDIA_PLAYER_BAR_DEFAULT  0x00000000
#define GTK_MEDIA_PLAYER_BAR_PLAY     0x00000001
#define GTK_MEDIA_PLAYER_BAR_PAUSE    0x00000002
#define GTK_MEDIA_PLAYER_BAR_STOP     0x00000004
#define GTK_MEDIA_PLAYER_BAR_REWIND   0x00000008
#define GTK_MEDIA_PLAYER_BAR_FORWARD  0x00000010
#define GTK_MEDIA_PLAYER_BAR_PREVIOUS 0x00000020
#define GTK_MEDIA_PLAYER_BAR_NEXT     0x00000040

#define GTK_MEDIA_PLAYER_BAR_PROGRESS 0x00000080
#define GTK_MEDIA_PLAYER_BAR_LANG     0x00000100

#define GTK_MEDIA_PLAYER_BAR_VOLUME      0x00000200
#define GTK_MEDIA_PLAYER_BAR_FULLSCREEN	 0x00000400
#define GTK_MEDIA_PLAYER_BAR_ATTACH      0x00000800

#define GTK_MEDIA_PLAYER_BAR_PREFERENCES 0x00001000
#define GTK_MEDIA_PLAYER_BAR_PROPERTIES	 0x00002000
#define GTK_MEDIA_PLAYER_BAR_INFO        0x00004000

#define GTK_MEDIA_PLAYER_BAR_FILE        0x00008000
#define GTK_MEDIA_PLAYER_BAR_SEPARATOR   0x00010000
#define GTK_MEDIA_PLAYER_BAR_HIDE        0x00020000
#define GTK_MEDIA_PLAYER_BAR_QUIT        0x00040000

#define GTK_MEDIA_PLAYER_BAR_NONE        0x00080000
#define GTK_MEDIA_PLAYER_BAR_USER        0x01000000

Creación de Reproductores

GtkWidget *gtk_media_player_new               (void);
GtkWidget *gtk_media_player_new_with_bar (gint bar[]);
GtkWidget *gtk_media_player_new_with_menu (gint menu[]);
GtkWidget *gtk_media_player_new_with_menu_and_bar(gint menu[],gint bar[]);
GtkWidget *gtk_media_player_new_with_media (gchar *media);

void gtk_media_player_show(GtkMediaPlayer *player);

Configuración do mplayer

void gtk_media_player_get_info(GtkMediaPlayer *player,GtkMediaPlayerInfo *info);
GtkImage *gtk_media_player_get_media_snapshot(GtkMediaPlayer *player);

void gtk_media_player_set_title(GtkMediaPlayer *player,char *title);
gboolean gtk_media_player_set_player(GtkMediaPlayer *player,gchar *command);
void gtk_media_player_play_cmd (GtkMediaPlayer *player,gchar *cmd);
void gtk_media_player_set_lang(GtkMediaPlayer *player,int idaudio);
void gtk_media_player_set_snapshot(GtkMediaPlayer *player,char *snap);

void gtk_media_player_youtube_cache(GtkMediaPlayer *player,gboolean opt);
void gtk_media_player_resolve_youtube_url(GtkMediaPlayer *player,gboolean resolv);
void gtk_media_player_youtube(GtkMediaPlayer *player,gboolean isytb);
void gtk_media_player_wget(GtkMediaPlayer *player,gboolean iswg);
 
void gtk_media_player_set_quit_command(GtkMediaPlayer *player,gboolean (*fnc)(gpointer fnc));

Funcións de Configuración de Barra de Botons e Menú

int gtk_media_player_new_entry(gint which,MenuItem *mi);
int gtk_media_player_add_to_default(gint which,int mask);

void gtk_media_player_set_bar(GtkMediaPlayer *player,gint bar[]);
void gtk_media_player_set_menu(GtkMediaPlayer *player,gint menu[]);
void gtk_media_player_bar_hide(GtkMediaPlayer *player);
void gtk_media_player_bar_show(GtkMediaPlayer *player);
void gtk_media_player_destroy_button(GtkMediaPlayer *player,gint mask);
void gtk_media_player_destroy_menu_entry(GtkMediaPlayer *player,gint mask);
void gtk_media_player_disable_controls(GtkMediaPlayer *player,gboolean disable);

void gtk_media_player_bar_hide_on_attach(GtkMediaPlayer *player,gboolean hide);
void gtk_media_player_bar_show_on_detach(GtkMediaPlayer *player,gboolean show);

Control da Reproducción

void gtk_media_player_load_media(GtkMediaPlayer *player,gchar *media);

#define gtk_media_player_play(player) 	gtk_media_player_play_cmd((GTK_MEDIA_PLAYER(player)),NULL)
void gtk_media_player_stop(GtkMediaPlayer *player);
void gtk_media_player_pause(GtkMediaPlayer *player);

#define gtk_media_player_next(player) gtk_media_player_command(player,"pt_step +1\n")
#define gtk_media_player_prev(player) gtk_media_player_command(player,"pt_step -1\n")
#define gtk_media_player_rewind(player) gtk_media_player_command(player,"seek -10\n")
#define gtk_media_player_forward(player) gtk_media_player_command(player,"seek +10\n")
void gtk_media_player_command(GtkMediaPlayer *player,char *command);

Empotrar e Soltar

void gtk_media_player_detach(GtkMediaPlayer *player);
void gtk_media_player_attach(GtkContainer *container,GtkMediaPlayer *player);
void gtk_media_player_plugger_switch(GtkMediaPlayer *player);

Manexo de SIGCHLD

void gtk_media_player_chain_sigchld(void (*handler)(int pid));