GtkMediaPlayer: Widget Gtk de reproducción de películas e son
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
- Versión 1.3-2 (29/09/2007)
- Versión 1.3-1 (18/09/2007)
- Versión 1.3 (01/09/2007)
- Versión 1.2 (13/08/2007)
- Versión 1.1 (08/08/2007)
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
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
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));