renatofilho@20: /**
renatofilho@20:  * GMyth Library
renatofilho@20:  *
renatofilho@20:  * @file gmyth/mmyth_tvplayer.c
renatofilho@20:  * 
renatofilho@20:  * @brief <p> This component provides playback of the remote A/V using
renatofilho@20:  * GStreamer.
renatofilho@20:  * 
renatofilho@20:  * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
renatofilho@20:  * @author Hallyson Luiz de Morais Melo <hallyson.melo@indt.org.br>
renatofilho@20:  *
renatofilho@20:  *//*
renatofilho@20:  * 
renatofilho@20:  * This program is free software; you can redistribute it and/or modify
renatofilho@20:  * it under the terms of the GNU Lesser General Public License as published by
renatofilho@20:  * the Free Software Foundation; either version 2 of the License, or
renatofilho@20:  * (at your option) any later version.
renatofilho@20:  *
renatofilho@20:  * This program is distributed in the hope that it will be useful,
renatofilho@20:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
renatofilho@20:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
renatofilho@20:  * GNU General Public License for more details.
renatofilho@20:  *
renatofilho@20:  * You should have received a copy of the GNU Lesser General Public License
renatofilho@20:  * along with this program; if not, write to the Free Software
renatofilho@20:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
renatofilho@20:  */
renatofilho@20: 
renatofilho@20: #include "mmyth_tvplayer.h"
renatofilho@20:  
renatofilho@20: #include <gdk/gdkx.h>
renatofilho@20: 
rosfran@208: #include <gmyth/gmyth_remote_util.h>
rosfran@208: 
rosfran@208: #define MYTHTV_VERSION_DEFAULT	30
renatofilho@20: 
renatofilho@20: typedef struct _GstPlayerWindowStateChange
renatofilho@20: {
renatofilho@20:     GstElement *play;
renatofilho@20:     GstState old_state, new_state;
renatofilho@20:     MMythTVPlayer *tvplayer;
renatofilho@20: } GstPlayerWindowStateChange;
renatofilho@20: 
renatofilho@20: typedef struct _GstPlayerWindowTagFound
renatofilho@20: {
renatofilho@20:     GstElement *play;
renatofilho@20:     GstTagList *taglist;
renatofilho@20:     MMythTVPlayer *tvplayer;
renatofilho@20: } GstPlayerWindowTagFound;
renatofilho@20: 
renatofilho@20: /*
renatofilho@20: static gboolean idle_state (gpointer data);
renatofilho@20: */
renatofilho@20: static gboolean bus_call (GstBus * bus, GstMessage * msg, gpointer data);
renatofilho@20: 
renatofilho@20: static void mmyth_tvplayer_class_init          (MMythTVPlayerClass *klass);
renatofilho@20: static void mmyth_tvplayer_init                (MMythTVPlayer *object);
renatofilho@20: 
renatofilho@20: static void mmyth_tvplayer_dispose  (GObject *object);
renatofilho@20: static void mmyth_tvplayer_finalize (GObject *object);
renatofilho@20: 
renatofilho@20: G_DEFINE_TYPE(MMythTVPlayer, mmyth_tvplayer, G_TYPE_OBJECT)
renatofilho@20: 
renatofilho@20: static gboolean mmyth_tvplayer_create_pipeline (MMythTVPlayer* tvplayer);
renatofilho@20: static void     new_pad_cb (GstElement *element, 
renatofilho@20:                             GstPad *pad, gpointer data);
renatofilho@20: 
renatofilho@20: static gboolean expose_cb (GtkWidget * widget, 
renatofilho@20:                            GdkEventExpose * event, 
renatofilho@20:                            gpointer user_data);
renatofilho@20: 
renatofilho@20: static void
renatofilho@20: mmyth_tvplayer_class_init (MMythTVPlayerClass *klass)
renatofilho@20: {
renatofilho@20: 	GObjectClass *gobject_class;
renatofilho@20: 
rosfran@208: 	gobject_class = (GObjectClass *) klass;
rosfran@208: 
rosfran@208: 	gobject_class->dispose  = mmyth_tvplayer_dispose;
rosfran@208: 	gobject_class->finalize = mmyth_tvplayer_finalize;	
renatofilho@20: }
renatofilho@20: 
renatofilho@20: static void
renatofilho@20: new_pad_cb (GstElement *element, GstPad *pad, gpointer data)
renatofilho@20: {
renatofilho@20: 	MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (data);
renatofilho@20: 	GstPadLinkReturn ret;
renatofilho@20: 	char *s;
renatofilho@20: 	
renatofilho@20: 	s = gst_caps_to_string (pad->caps);
renatofilho@20: 
renatofilho@20: 	if ( s[0] == 'a') {
rosfran@64: 		ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->audioqueue1, "sink"));
renatofilho@20: 	} else {
rosfran@64: 		ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->videoqueue1, "sink")); 
renatofilho@20: 	}
renatofilho@20: 	
renatofilho@20: 	g_free(s);
renatofilho@20: }
renatofilho@20: 
renatofilho@20: static gboolean
renatofilho@20: expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
renatofilho@20: {
rosfran@64: 	MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (user_data);
renatofilho@20: 
renatofilho@20: 	if (tvplayer && tvplayer->videow) {
rosfran@64: 		gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (tvplayer->gst_videosink),
rosfran@64: 				GDK_WINDOW_XWINDOW (widget->window));
renatofilho@20: 		return TRUE;
renatofilho@20: 	}
rosfran@64: 
renatofilho@20: 	g_warning ("MMythTVPlayer expose called before setting video window\n");
rosfran@64: 
rosfran@64: 	return FALSE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: static void
renatofilho@20: mmyth_tvplayer_init (MMythTVPlayer *tvplayer)
renatofilho@20: {
rosfran@64: 	tvplayer->gst_pipeline = NULL;
rosfran@64: 	tvplayer->gst_source = NULL;
rosfran@64: 	tvplayer->gst_videodec = NULL;
rosfran@64: 	tvplayer->gst_videosink = NULL;
rosfran@64: 	tvplayer->gst_videocolortrs = NULL;
rosfran@64: 	tvplayer->videoqueue1 = NULL;
rosfran@64: 	tvplayer->videoqueue2 = NULL;
rosfran@64: 	tvplayer->audioqueue1 = NULL;
rosfran@64: 	tvplayer->audioqueue2 = NULL;   
rosfran@64: 
rosfran@64: 	/* GTKWidget for rendering the video */
rosfran@64: 	tvplayer->videow = NULL;
renatofilho@20: 	tvplayer->expose_handler = 0;
rosfran@64: 
renatofilho@20: 	tvplayer->backend_hostname = NULL;
renatofilho@20: 	tvplayer->backend_port = 0;
renatofilho@20: 	tvplayer->local_hostname = NULL;
renatofilho@20: 
rosfran@64: 	tvplayer->recorder = NULL;
renatofilho@20: 	tvplayer->tvchain = NULL;
renatofilho@20: 	tvplayer->proginfo = NULL;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: static void
renatofilho@20: mmyth_tvplayer_dispose (GObject *object)
renatofilho@20: {
renatofilho@20: 
renatofilho@20: 	G_OBJECT_CLASS (mmyth_tvplayer_parent_class)->dispose (object);
renatofilho@20: }
renatofilho@20: 
renatofilho@20: static void
renatofilho@20: mmyth_tvplayer_finalize (GObject *object)
renatofilho@20: {
renatofilho@20: 	g_signal_handlers_destroy (object);
renatofilho@20: 
renatofilho@20: 	MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (object);
renatofilho@20: 
renatofilho@20: 	g_debug ("[%s] Finalizing tvplayer", __FUNCTION__);
renatofilho@20: 	
renatofilho@20: 	if (tvplayer->videow != NULL) {
renatofilho@20: 		if (g_signal_handler_is_connected (tvplayer->videow, 
renatofilho@20: 						tvplayer->expose_handler)) {
renatofilho@20: 			g_signal_handler_disconnect (tvplayer->videow,
renatofilho@20: 				tvplayer->expose_handler);
renatofilho@20: 		}
renatofilho@20: 		g_object_unref (tvplayer->videow);
renatofilho@20: 	}
renatofilho@20: 	
rosfran@64: 	if ( tvplayer->recorder != NULL )
rosfran@64: 		g_object_unref (tvplayer->recorder);
renatofilho@20: 	if ( tvplayer->tvchain != NULL )
renatofilho@20: 		g_object_unref (tvplayer->tvchain);
renatofilho@20: 	if ( tvplayer->proginfo != NULL )
renatofilho@20: 		g_object_unref (tvplayer->proginfo);	
renatofilho@20: 
renatofilho@20: 	// Release Gstreamer elements
renatofilho@20: 	if ( tvplayer->gst_pipeline != NULL )
renatofilho@20: 		g_object_unref (tvplayer->gst_pipeline);	
renatofilho@20: 	if ( tvplayer->gst_source != NULL )
renatofilho@20: 		g_object_unref (tvplayer->gst_source);	
renatofilho@20: 	if ( tvplayer->gst_videodec != NULL )
renatofilho@20: 		g_object_unref (tvplayer->gst_videodec);	
rosfran@64: 	if ( tvplayer->gst_videocolortrs != NULL )
rosfran@64: 		g_object_unref (tvplayer->gst_videocolortrs);
renatofilho@20: 	if ( tvplayer->gst_videosink != NULL )
renatofilho@20: 		g_object_unref (tvplayer->gst_videosink);	
rosfran@64: 	if ( tvplayer->videoqueue1 != NULL )
rosfran@64: 		g_object_unref (tvplayer->videoqueue1);
rosfran@64: 	if ( tvplayer->videoqueue2 != NULL )
rosfran@64: 		g_object_unref (tvplayer->videoqueue2);
rosfran@64: 	if ( tvplayer->audioqueue1 != NULL )
rosfran@64: 		g_object_unref (tvplayer->audioqueue1);	
rosfran@64: 	if ( tvplayer->audioqueue2 != NULL )
rosfran@64: 		g_object_unref (tvplayer->audioqueue2);	
renatofilho@20: 
renatofilho@20: 	G_OBJECT_CLASS (mmyth_tvplayer_parent_class)->finalize (object);
renatofilho@20: }
renatofilho@20: 
renatofilho@20: /** Creates a new instance of MMythTVPlayer. 
renatofilho@20:  * 
renatofilho@20:  * @return a new instance of MMythTVPlayer.
renatofilho@20:  */
renatofilho@20: MMythTVPlayer *
renatofilho@20: mmyth_tvplayer_new ()
renatofilho@20: {
renatofilho@20:     MMythTVPlayer *tvplayer = 
renatofilho@20:         MMYTH_TVPLAYER (g_object_new(MMYTH_TVPLAYER_TYPE, NULL));
renatofilho@20:     
renatofilho@20:     return tvplayer;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: /** Initializes the tv player.
renatofilho@20:  *
renatofilho@20:  * @param tvplayer the object instance.
renatofilho@20:  * @return gboolean TRUE if the pipeline was created 
renatofilho@20:  * successfully, FALSE otherwise.
renatofilho@20:  */
renatofilho@20: gboolean
rosfran@208: mmyth_tvplayer_initialize (MMythTVPlayer *tvplayer, GMythBackendInfo *backend_info)
renatofilho@20: {
rosfran@208: 	tvplayer->backend_info = backend_info;
rosfran@208: 
rosfran@208: 	if (!mmyth_tvplayer_create_pipeline (tvplayer)) {
rosfran@208: 		g_warning ("[%s] Error while creating pipeline. TV Player not initialized", __FUNCTION__);
renatofilho@20: 		return FALSE;
renatofilho@20: 	} else {
renatofilho@20: 		g_debug ("[%s] GStreamer pipeline created", __FUNCTION__);	
rosfran@208: 	}
renatofilho@20: 
renatofilho@20: 	return TRUE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: /** Creates the GStreamer pipeline used by the player.
renatofilho@20:  *
renatofilho@20:  * @param tvplayer the object instance.
renatofilho@20:  * @return gboolean TRUE if the pipeline was created 
renatofilho@20:  * successfully, FALSE otherwise.
renatofilho@20:  */
renatofilho@20: static gboolean
renatofilho@20: mmyth_tvplayer_create_pipeline (MMythTVPlayer* tvplayer)
renatofilho@20: {
renatofilho@20:     GstElement *pipeline;
renatofilho@20:     GstElement *source, *parser;
renatofilho@20:     GstElement *videodec, *videosink;
rosfran@64:     GstElement *videocolortrs;
renatofilho@20: #ifndef MAEMO_PLATFORM    
renatofilho@20:     GstElement *audiodec, *audioconv;
renatofilho@20: #endif
renatofilho@20:     GstElement *audiosink;
rosfran@64:     GstElement *videoqueue1, *videoqueue2, *audioqueue1, *audioqueue2;
renatofilho@20: 
renatofilho@20:     g_debug ("MMythTVPlayer: Setting the Gstreamer pipeline\n");
renatofilho@20: 	
renatofilho@20:     pipeline = gst_pipeline_new ("video-player");
renatofilho@20:     source = gst_element_factory_make ("mythtvsrc", "myth-source");
rosfran@64:     parser = gst_element_factory_make ("nuvdemux", "nuv-demux");
renatofilho@20: 
renatofilho@20:     /* Gstreamer Video elements */
rosfran@64:     videoqueue1 = gst_element_factory_make ("queue", "video-queue1");
leo_sobral@99:     videodec = gst_element_factory_make ("ffdec_mpeg4", "video-decoder");
rosfran@64:     videoqueue2 = gst_element_factory_make ("queue", "video-queue2");
rosfran@64:     videocolortrs = gst_element_factory_make ("ffmpegcolorspace", "image-color-transforms");
rosfran@64: 
renatofilho@20: #ifdef MAEMO_PLATFORM
renatofilho@20:     videosink = gst_element_factory_make ("sdlvideosink", "image-output");
renatofilho@20: #else
renatofilho@20:     videosink = gst_element_factory_make ("xvimagesink", "image-output");
renatofilho@20: #endif
renatofilho@20:     
renatofilho@20:     /* Gstreamer Audio elements */
rosfran@64:     audioqueue1 = gst_element_factory_make ("queue", "audio-queue1");    
rosfran@64:     audioqueue2 = gst_element_factory_make ("queue", "audio-queue2");
renatofilho@20: #ifdef MAEMO_PLATFORM    
renatofilho@20:     audiosink = gst_element_factory_make ("dspmp3sink", "audio-output");
renatofilho@20: #else    
rosfran@64:     audiodec = gst_element_factory_make ("mad", "audio-decoder");
renatofilho@20:     audioconv = gst_element_factory_make ("audioconvert", "audio-converter");
renatofilho@20:     audiosink = gst_element_factory_make ("alsasink", "audio-output");
renatofilho@20: #endif    
renatofilho@20:     
renatofilho@20:     if (!(pipeline && source && parser && videodec && videosink) ||
rosfran@64:     	!(videoqueue1 && videoqueue2 && audioqueue1 && audioqueue2 && audiosink)) {
renatofilho@20:         /* FIXME: hanlde the error correctly */
renatofilho@20:         /* video_alignment is not being created (below) 
renatofilho@20:            and is causing problems to the ui */
renatofilho@20: 
renatofilho@20: 	    tvplayer->gst_pipeline = NULL;
renatofilho@20: 	    tvplayer->gst_videodec = NULL;
renatofilho@20: 	    tvplayer->gst_videosink = NULL;
rosfran@64: 	    tvplayer->gst_videocolortrs = NULL;
renatofilho@20:            
renatofilho@20:         g_warning ("GstElement creation error!\n");
renatofilho@20:         return FALSE;
renatofilho@20:     }
renatofilho@20: 
renatofilho@20: #ifndef MAEMO_PLATFORM    
renatofilho@20:     if (!(audiodec && audioconv)) {
renatofilho@20:         g_warning ("GstElement for audio stream creation error!");
renatofilho@20:         return FALSE;
renatofilho@20:     }
renatofilho@20: #endif    
renatofilho@20:     
renatofilho@20:     tvplayer->gst_pipeline = pipeline;
renatofilho@20:     tvplayer->gst_source = source;
renatofilho@20:     tvplayer->gst_videodec = videodec;
renatofilho@20:     tvplayer->gst_videosink = videosink;
rosfran@64:     tvplayer->gst_videocolortrs = videocolortrs;
renatofilho@20:     g_object_ref (tvplayer->gst_pipeline);
renatofilho@20:     g_object_ref (tvplayer->gst_source);
renatofilho@20:     g_object_ref (tvplayer->gst_videodec);
renatofilho@20:     g_object_ref (tvplayer->gst_videosink);
rosfran@64:     g_object_ref (tvplayer->gst_videocolortrs);
renatofilho@20: 
rosfran@64:     tvplayer->videoqueue1 = videoqueue1;
rosfran@64:     tvplayer->videoqueue2 = videoqueue2;
rosfran@64:     tvplayer->audioqueue1 = audioqueue1;
rosfran@64:     tvplayer->audioqueue2 = audioqueue2;
rosfran@64:     g_object_ref (tvplayer->videoqueue1);
rosfran@64:     g_object_ref (tvplayer->videoqueue2);
rosfran@64:     g_object_ref (tvplayer->audioqueue1);
rosfran@64:     g_object_ref (tvplayer->audioqueue2);
rosfran@64:   	
rosfran@208:     //g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
renatofilho@20:     g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
renatofilho@20: 
renatofilho@20:     gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (tvplayer->gst_pipeline)),
renatofilho@20:                        bus_call, tvplayer);
renatofilho@20: 
rosfran@64:     gst_bin_add_many (GST_BIN (pipeline), source, parser, videoqueue1,
rosfran@64:     			videodec, videoqueue2, videocolortrs, videosink, audioqueue1, 
rosfran@64: 			audiodec, audioconv, audioqueue2, audiosink, NULL);
renatofilho@20: 
renatofilho@20:     {
renatofilho@20: //        GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp", NULL);
renatofilho@20: //        gst_element_link_filtered(source, parser, rtpcaps);
renatofilho@20:     }
renatofilho@20:     
renatofilho@20:     gst_element_link (source, parser);
rosfran@64:     gst_element_link_many (videoqueue1, videodec, videoqueue2, videocolortrs, videosink, NULL);
rosfran@64:     gst_element_link_many (audioqueue1, audiodec, audioconv, audioqueue2, audiosink, NULL);
renatofilho@20:     
renatofilho@20:     g_signal_connect (parser, "pad-added", G_CALLBACK (new_pad_cb), tvplayer);
renatofilho@20:     
renatofilho@20:     return TRUE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: /** Configures the backend and the tv player 
renatofilho@20:  * for playing the recorded content A/V.
renatofilho@20:  *
renatofilho@20:  * FIXME: Change filename to program info or other structure about the recorded
renatofilho@20:  *
renatofilho@20:  * @param tvplayer the object instance.
renatofilho@20:  * @param filename the file uri of the recorded content to be played.
renatofilho@20:  * @return TRUE if successfull, FALSE if any error happens.
renatofilho@20:  */
renatofilho@20: gboolean
rosfran@244: mmyth_tvplayer_record_setup (MMythTVPlayer *tvplayer, const gchar *filename)
renatofilho@20: {
renatofilho@20: 	// FIXME: we should receive the uri instead of filename
rosfran@244: 	const gchar *hostname = gmyth_backend_info_get_hostname (tvplayer->backend_info);
rosfran@244: 	const gint port = gmyth_backend_info_get_port(tvplayer->backend_info);
renatofilho@20: 	
renatofilho@20: 	GString *fullpath = g_string_new ("myth://");
rosfran@208: 	g_string_append_printf (fullpath, "%s:%d/%s", hostname, port, filename);
renatofilho@20: 	
renatofilho@20: 	tvplayer->is_livetv = FALSE;
renatofilho@20: 
renatofilho@20: 	g_debug ("[%s] Setting record uri to gstreamer pipeline to %s", __FUNCTION__, fullpath->str);
renatofilho@20: 		
renatofilho@20:     g_object_set (G_OBJECT (tvplayer->gst_source), "location",
renatofilho@20:           fullpath->str, NULL);
renatofilho@20:           
renatofilho@20:     return TRUE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: /** Configures the backend and the tv player 
renatofilho@20:  * for playing the live tv.
renatofilho@20:  *
renatofilho@20:  * @param tvplayer the object instance.
renatofilho@20:  * @return TRUE if successfull, FALSE if any error happens.
renatofilho@20:  */
renatofilho@20: gboolean
renatofilho@20: mmyth_tvplayer_livetv_setup (MMythTVPlayer *tvplayer)
renatofilho@20: {
renatofilho@20: 	gboolean res = TRUE;
renatofilho@20: 
rosfran@208: 	tvplayer->livetv = gmyth_livetv_new ();
rosfran@208: 
rosfran@208: 	if ( !gmyth_livetv_setup( tvplayer->livetv, tvplayer->backend_info ) )
renatofilho@20: 		goto error;
rosfran@208: 	
renatofilho@20: 	return res;
renatofilho@20: 
renatofilho@20: error:
rosfran@208: 	res = FALSE;
rosfran@208: 	if ( tvplayer->livetv != NULL ) {
rosfran@208: 		g_object_unref( tvplayer->livetv );
renatofilho@20: 	}
renatofilho@20: 
renatofilho@20: 	if ( tvplayer->local_hostname != NULL ) {
renatofilho@20: 		g_string_free( tvplayer->local_hostname, TRUE );
renatofilho@20: 	}
renatofilho@20: 
rosfran@64: 	if ( tvplayer->recorder != NULL ) {
rosfran@64: 		g_object_unref (tvplayer->recorder);
rosfran@64: 		tvplayer->recorder = NULL;
renatofilho@20: 	}
renatofilho@20: 
renatofilho@20: 	if ( tvplayer->tvchain != NULL ) {
renatofilho@20: 		g_object_unref (tvplayer->tvchain);
renatofilho@20: 		tvplayer->tvchain = NULL;
renatofilho@20: 	}
renatofilho@20: 
renatofilho@20: 	if ( tvplayer->proginfo != NULL ) {
renatofilho@20: 		g_object_unref (tvplayer->proginfo);
renatofilho@20: 		tvplayer->proginfo = NULL;
renatofilho@20: 	}
renatofilho@20: 
renatofilho@20: 	return res;
renatofilho@20: 
renatofilho@20: }
renatofilho@20: 
renatofilho@20: /** Sets the GTK video widget for the tv player. 
renatofilho@20:  *
renatofilho@20:  * @param tvplayer the object instance.
renatofilho@20:  * @param videow the GTK video window.
renatofilho@20:  * @return TRUE if successfull, FALSE if any error happens.
renatofilho@20:  */
renatofilho@20: gboolean
renatofilho@20: mmyth_tvplayer_set_widget (MMythTVPlayer *tvplayer, GtkWidget *videow)
renatofilho@20: {
renatofilho@20: 	tvplayer->videow = videow;
renatofilho@20: 	g_object_ref (videow);
renatofilho@20: 	
renatofilho@20: 	g_debug ("[%s] Setting widget for tv player render", __FUNCTION__);
renatofilho@20: 	
renatofilho@20:     tvplayer->expose_handler = g_signal_connect (tvplayer->videow, "expose-event", 
renatofilho@20:                                                  G_CALLBACK (expose_cb), tvplayer);
renatofilho@20: 
renatofilho@20:     //g_signal_connect(miptv_ui->videow, "size_request", G_CALLBACK(cb_preferred_video_size), miptv_ui);
renatofilho@20: 
renatofilho@20:     return TRUE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: static gboolean
renatofilho@20: bus_call (GstBus * bus, GstMessage * msg, gpointer data)
renatofilho@20: {
renatofilho@20:     //MMythTVPlayer *tvplayer = MMYTH_TVPLAYER ( data );
renatofilho@20:     //GMainLoop *loop = tvplayer->loop;
renatofilho@20: 
renatofilho@20:     switch (GST_MESSAGE_TYPE (msg)) {
renatofilho@20:         case GST_MESSAGE_EOS:
renatofilho@20: 			printf ("End of stream\n");
renatofilho@20:             //g_idle_add ((GSourceFunc) idle_eos, data);
renatofilho@20:             gst_element_set_state ( GST_ELEMENT (GST_MESSAGE_SRC (msg)), GST_STATE_NULL );
rosfran@25: 	    gst_element_set_locked_state ( GST_ELEMENT (GST_MESSAGE_SRC (msg)), TRUE );
renatofilho@20:             break;
renatofilho@20:         case GST_MESSAGE_ERROR:
renatofilho@20:         {
renatofilho@20:                 gchar *debug;
renatofilho@20:                 GError *err;
renatofilho@20: 
renatofilho@20:                 gst_message_parse_error (msg, &err, &debug);
renatofilho@20:                 g_free (debug);
renatofilho@20: 
renatofilho@20:                 printf ("Error: %s\n", err->message);
renatofilho@20:                 g_error_free (err);
renatofilho@20: 
renatofilho@20:                 //g_main_loop_quit (loop);
renatofilho@20:         }
renatofilho@20:             break;
renatofilho@20:         default:
renatofilho@20:             printf (gst_message_type_get_name (GST_MESSAGE_TYPE (msg)));
renatofilho@20:             printf ("\n");
renatofilho@20:             break;
renatofilho@20:     }
renatofilho@20: 
renatofilho@20:     return TRUE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: 
renatofilho@20: #if 0
renatofilho@20: static gboolean
renatofilho@20: idle_state (gpointer data)
renatofilho@20: {
renatofilho@20:     GstPlayerWindowStateChange *st = data;
renatofilho@20: 
renatofilho@20:     if (st->old_state == GST_STATE_PLAYING) {
renatofilho@20:         if (st->miptv_ui->idle_id != 0) {
renatofilho@20:             g_source_remove (st->miptv_ui->idle_id);
renatofilho@20:             st->miptv_ui->idle_id = 0;
renatofilho@20:         }
renatofilho@20:     }
renatofilho@20:     else if (st->new_state == GST_STATE_PLAYING) {
renatofilho@20:         if (st->miptv_ui->idle_id != 0)
renatofilho@20:             g_source_remove (st->miptv_ui->idle_id);
renatofilho@20: 
renatofilho@20:         st->miptv_ui->idle_id = g_idle_add (cb_iterate, st->miptv_ui);
renatofilho@20:     }
renatofilho@20: 
renatofilho@20:     /* new movie loaded? */
renatofilho@20:     if (st->old_state == GST_STATE_READY && st->new_state > GST_STATE_READY) {
renatofilho@20: 
renatofilho@20:         /* gboolean have_video = FALSE; */
renatofilho@20: 
renatofilho@20:         gtk_widget_show (st->miptv_ui->videow);
renatofilho@20: 
renatofilho@20:         gtk_window_resize (GTK_WINDOW (st->miptv_ui->main_window), 1, 1);
renatofilho@20: 
renatofilho@20:     }
renatofilho@20: 
renatofilho@20:     /* discarded movie? */
renatofilho@20:     if (st->old_state > GST_STATE_READY && st->new_state == GST_STATE_READY) {
renatofilho@20: 
renatofilho@20:         if (st->miptv_ui->tagcache) {
renatofilho@20:             gst_tag_list_free (st->miptv_ui->tagcache);
renatofilho@20:             st->miptv_ui->tagcache = NULL;
renatofilho@20:         }
renatofilho@20:     }
renatofilho@20: 
renatofilho@20:     gst_object_unref (GST_OBJECT (st->play));
renatofilho@20:     //g_object_unref (G_OBJECT (st->win));
renatofilho@20:     g_free (st);
renatofilho@20: 
renatofilho@20:     /* once */
renatofilho@20:     return FALSE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: #endif
renatofilho@20: 
renatofilho@20: /** Stops playing the current A/V.
renatofilho@20:  *
renatofilho@20:  * FIXME: How to proceed differently between livetv 
renatofilho@20:  * and recorded content?
renatofilho@20:  *
renatofilho@20:  * @param tvplayer the object instance.
renatofilho@20:  * @return void 
renatofilho@20:  */
renatofilho@20: void
renatofilho@20: mmyth_tvplayer_stop_playing (MMythTVPlayer *tvplayer) 
renatofilho@20: {
renatofilho@20:     g_debug ("[%s] Setting gstreamer pipeline state to NULL", __FUNCTION__);
renatofilho@20: 
renatofilho@20:     gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_NULL);
renatofilho@20:     
renatofilho@20:     if (tvplayer->is_livetv) {
rosfran@64: 	    if (!gmyth_recorder_stop_livetv (tvplayer->recorder)) {
renatofilho@20: 	    	g_warning ("[%s] Error while stoping remote encoder", __FUNCTION__);	
renatofilho@20: 	    }
renatofilho@20:     }
renatofilho@20: }
renatofilho@20: 
renatofilho@20: /** Queries if the tvplayer is active playing A/V content.
renatofilho@20:  *
renatofilho@20:  * @param tvplayer the object instance.
renatofilho@20:  * @return TRUE if the tvplayer is active, FALSE otherwise.
renatofilho@20:  */
renatofilho@20: gboolean
renatofilho@20: mmyth_tvplayer_is_playing (MMythTVPlayer *tvplayer)
renatofilho@20: {
renatofilho@20: 	return (GST_STATE (tvplayer->gst_pipeline) == GST_STATE_PLAYING);
renatofilho@20: }
renatofilho@20: 
renatofilho@20: /** Static function that sets the tvplayer state to PLAYING.
renatofilho@20:  *
renatofilho@20:  * @param tvplayer the object instance.
renatofilho@20:  * @return TRUE if the tvplayer is active, FALSE otherwise.
renatofilho@20:  */
renatofilho@20: static gboolean
renatofilho@20: idle_play (gpointer data)
renatofilho@20: {
renatofilho@20:     MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (data);
renatofilho@20: 
renatofilho@20: 	g_debug ("MMythTVPlayer: Setting pipeline state to PLAYING\n");
renatofilho@20: 
renatofilho@20:     gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_PLAYING);
renatofilho@20: 
renatofilho@20:     return FALSE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: /** Start playing A/V with the tvplayer attributes.
renatofilho@20:  *
renatofilho@20:  * @param tvplayer the object instance.
renatofilho@20:  */
renatofilho@20: void
renatofilho@20: mmyth_tvplayer_start_playing (MMythTVPlayer *tvplayer)
renatofilho@20: {
renatofilho@20: 
renatofilho@20: 	// FIXME: Move this to livetv_setup??
renatofilho@20: 	if (tvplayer->is_livetv) {
renatofilho@20: 
renatofilho@20: 	#if 0
renatofilho@20: 		if (!tvplayer || !(tvplayer->proginfo) || !(tvplayer->local_hostname)
renatofilho@20: 				|| !(tvplayer->gst_source)) {
renatofilho@20: 			g_warning ("GMythtvPlayer not ready to start playing\n");		
renatofilho@20: 		}
renatofilho@20: 
renatofilho@20: 		if (!(tvplayer->proginfo->pathname)) {
renatofilho@20: 			g_warning ("[%s] Playback url is null, could not play the myth content", __FUNCTION__);
renatofilho@20: 			return;
renatofilho@20: 		}
renatofilho@20: 
renatofilho@20: 		g_debug ("MMythTVPlayer: Start playing %s", tvplayer->proginfo->pathname->str);
renatofilho@20: #endif
renatofilho@20: 		g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live",
renatofilho@20: 				TRUE, NULL);
renatofilho@20: #if 0
renatofilho@20: 		if ( tvplayer->tvchain != NULL ) {
renatofilho@20: 			GString *str_chainid = gmyth_tvchain_get_id(tvplayer->tvchain);
renatofilho@20: 			g_print( "[%s]\tCHAIN ID: %s\n", __FUNCTION__, str_chainid->str );
renatofilho@20: 
renatofilho@20: 			g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-chainid", 
renatofilho@20: 					g_strdup( str_chainid->str ), NULL);      
renatofilho@20: 			if ( str_chainid!=NULL)
renatofilho@20: 				g_string_free( str_chainid, FALSE );
renatofilho@20: 		}
renatofilho@20: 
rosfran@64: 		if ( tvplayer->recorder != NULL )	
renatofilho@20: 			g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-id",
rosfran@64: 					tvplayer->recorder->recorder_num, NULL );
renatofilho@20: 		g_debug ("[%s] Setting location to %s", __FUNCTION__, 
renatofilho@20: 				tvplayer->proginfo->pathname->str);
renatofilho@20: 
renatofilho@20: 		/* Sets the gstreamer properties acording to the service access address */
renatofilho@20: 		g_object_set (G_OBJECT (tvplayer->gst_source), "location",
renatofilho@20: 				tvplayer->proginfo->pathname->str, NULL);              
renatofilho@20: #endif
renatofilho@20: 	}
renatofilho@20: 
renatofilho@20: 	g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-version",
renatofilho@20:               MYTHTV_VERSION_DEFAULT, NULL);
renatofilho@20: 
renatofilho@20:     g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-debug",
renatofilho@20:               TRUE, NULL);
renatofilho@20: 
renatofilho@20:     g_idle_add (idle_play, tvplayer);
renatofilho@20: 
renatofilho@20: }
renatofilho@20: