renatofilho@20: 
renatofilho@20: #include <gst/gst.h>
renatofilho@20: #include <gtk/gtk.h>
renatofilho@20: #include <gdk/gdkx.h>
renatofilho@20: #include <gst/interfaces/xoverlay.h>
renatofilho@20: #include <unistd.h>
renatofilho@20: 
renatofilho@20: #include "mmyth_ui.h"
renatofilho@20: #include "mmyth_videoplayer.h"
renatofilho@20: #include "mmyth_sdpreader.h"
renatofilho@20: 
renatofilho@20: #include "esg_database.h"
renatofilho@20: 
renatofilho@20: #include "ipd_demux.h"
renatofilho@20: #include "ipd_network.h"
renatofilho@20: 
renatofilho@20: #ifdef INDT_IP_DECAPSULATOR
renatofilho@20: #include <sys/types.h>
renatofilho@20: #include <signal.h>
renatofilho@20: #endif
renatofilho@20: 
renatofilho@20: /* Global flag/semaphore to control IP decapsulator threads */
renatofilho@20: gboolean state_keep_running = 0;
renatofilho@20: 
renatofilho@20: 
renatofilho@20: typedef struct _GstPlayerWindowStateChange
renatofilho@20: {
renatofilho@20:     GstElement *play;
renatofilho@20:     GstState old_state, new_state;
renatofilho@20:     MMythUi *mmyth_ui;
renatofilho@20: } GstPlayerWindowStateChange;
renatofilho@20: 
renatofilho@20: typedef struct _GstPlayerWindowTagFound
renatofilho@20: {
renatofilho@20:     GstElement *play;
renatofilho@20:     GstTagList *taglist;
renatofilho@20:     MMythUi *mmyth_ui;
renatofilho@20: } GstPlayerWindowTagFound;
renatofilho@20: 
renatofilho@20: 
renatofilho@20: GstElement *gst_pipeline, *gst_decoder, *gst_videosink;
renatofilho@20: 
renatofilho@20: static gboolean idle_state (gpointer data);
renatofilho@20: 
renatofilho@20: static gboolean
renatofilho@20: bus_call (GstBus * bus, GstMessage * msg, gpointer data)
renatofilho@20: {
renatofilho@20:     MMythUi *mmyth_ui = (MMythUi *) data;
renatofilho@20:     GMainLoop *loop = mmyth_ui->loop;
renatofilho@20: 
renatofilho@20:     switch (GST_MESSAGE_TYPE (msg)) {
renatofilho@20:         case GST_MESSAGE_EOS:
renatofilho@20: 
renatofilho@20:             if (mmyth_ui->idle_id != 0) {
renatofilho@20:                 g_source_remove (mmyth_ui->idle_id);
renatofilho@20:                 mmyth_ui->idle_id = 0;
renatofilho@20:             }
renatofilho@20: 
renatofilho@20:             //g_idle_add ((GSourceFunc) idle_eos, data);
renatofilho@20:             gst_element_set_state (GST_ELEMENT (GST_MESSAGE_SRC (msg)),
renatofilho@20:                                    GST_STATE_READY);
renatofilho@20:             break;
renatofilho@20:         case GST_MESSAGE_ERROR:{
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:         case GST_MESSAGE_STATE_CHANGED:{
renatofilho@20:                 GstState oldstate;
renatofilho@20:                 GstState newstate;
renatofilho@20:                 GstState pending;
renatofilho@20:                 GstPlayerWindowStateChange *st =
renatofilho@20:                     g_new (GstPlayerWindowStateChange, 1);
renatofilho@20: 
renatofilho@20:                 gst_message_parse_state_changed (msg,
renatofilho@20:                                                  &oldstate,
renatofilho@20:                                                  &newstate, &pending);
renatofilho@20: 
renatofilho@20:                 st->play = mmyth_ui->play;
renatofilho@20:                 gst_object_ref (GST_OBJECT (mmyth_ui->play));
renatofilho@20:                 st->old_state = oldstate;
renatofilho@20:                 st->new_state = newstate;
renatofilho@20: 
renatofilho@20:                 st->mmyth_ui = mmyth_ui;
renatofilho@20: 
renatofilho@20:                 /* State debug messages */
renatofilho@20:                 printf ("oldstate = %s, newstate = %s, pendingstate = %s\n",
renatofilho@20:                         gst_element_state_get_name (oldstate),
renatofilho@20:                         gst_element_state_get_name (newstate),
renatofilho@20:                         gst_element_state_get_name (pending));
renatofilho@20: 
renatofilho@20:                 g_idle_add ((GSourceFunc) idle_state, st);
renatofilho@20: 
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: static gboolean
renatofilho@20: cb_iterate (gpointer data)
renatofilho@20: {
renatofilho@20:     MMythUi *mmyth_ui = (MMythUi *) data;
renatofilho@20:     //gboolean res;
renatofilho@20: 
renatofilho@20:     g_main_loop_run (mmyth_ui->loop);
renatofilho@20: /*
renatofilho@20: 	if (!GST_FLAG_IS_SET (mmyth_ui->play, GST_BIN_SELF_SCHEDULABLE)) {
renatofilho@20:     	res = gst_bin_iterate (GST_BIN (mmyth_ui->play));
renatofilho@20: 	} else {
renatofilho@20:     	g_usleep (100);
renatofilho@20: 		res = (gst_element_get_state (mmyth_ui->play) == GST_STATE_PLAYING);
renatofilho@20: 	}
renatofilho@20: 
renatofilho@20: 	if (!res)
renatofilho@20:     	mmyth_ui->idle_id = 0;
renatofilho@20:     	
renatofilho@20:     return res;
renatofilho@20: */
renatofilho@20:     return FALSE;
renatofilho@20: 
renatofilho@20: }
renatofilho@20: 
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->mmyth_ui->idle_id != 0) {
renatofilho@20:             g_source_remove (st->mmyth_ui->idle_id);
renatofilho@20:             st->mmyth_ui->idle_id = 0;
renatofilho@20:         }
renatofilho@20:     }
renatofilho@20:     else if (st->new_state == GST_STATE_PLAYING) {
renatofilho@20:         if (st->mmyth_ui->idle_id != 0)
renatofilho@20:             g_source_remove (st->mmyth_ui->idle_id);
renatofilho@20: 
renatofilho@20:         st->mmyth_ui->idle_id = g_idle_add (cb_iterate, st->mmyth_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->mmyth_ui->videow);
renatofilho@20: 
renatofilho@20:         gtk_window_resize (GTK_WINDOW (st->mmyth_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->mmyth_ui->tagcache) {
renatofilho@20:             gst_tag_list_free (st->mmyth_ui->tagcache);
renatofilho@20:             st->mmyth_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: 
renatofilho@20: 
renatofilho@20: static gboolean
renatofilho@20: expose (GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
renatofilho@20: {
renatofilho@20:     MMythUi *mmyth_ui = (MMythUi *) user_data;
renatofilho@20: 
renatofilho@20:     gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (mmyth_ui->videosink),
renatofilho@20:                                   GDK_WINDOW_XWINDOW (mmyth_ui->videow->
renatofilho@20:                                                       window));
renatofilho@20:     return TRUE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: 
renatofilho@20: void
renatofilho@20: mmyth_player_init (MMythUi * mmyth_ui)
renatofilho@20: {
renatofilho@20:     GstElement *play;
renatofilho@20:     GstElement *source, *parser, *decoder, *videosink;
renatofilho@20: 
renatofilho@20:     play = gst_pipeline_new ("video-player");
renatofilho@20:     source = gst_element_factory_make ("udpsrc", "file-source");
renatofilho@20:     parser = gst_element_factory_make ("rtph263pdepay", "rtp-demux");
renatofilho@20:     decoder = gst_element_factory_make ("ffdec_h263", "mpeg-decoder");
renatofilho@20:     videosink = gst_element_factory_make ("xvimagesink", "image-output");
renatofilho@20:     gst_pipeline = play;
renatofilho@20:     gst_decoder = decoder;
renatofilho@20:     gst_videosink = videosink;
renatofilho@20: 
renatofilho@20:     if (!(gst_pipeline && source && parser && decoder && videosink)) {
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:         g_print ("GstElement creation error!\n");
renatofilho@20:         return;
renatofilho@20:     }
renatofilho@20: 
renatofilho@20:     g_object_set (G_OBJECT (videosink), "sync", FALSE, NULL);
renatofilho@20: 
renatofilho@20:     gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (gst_pipeline)),
renatofilho@20:                        bus_call, mmyth_ui);
renatofilho@20: 
renatofilho@20:     gst_bin_add_many (GST_BIN (gst_pipeline), source, parser, decoder,
renatofilho@20:                       videosink, 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_many (/*source,*/ parser, decoder, videosink, NULL);
renatofilho@20: 
renatofilho@20:     /* actual window */
renatofilho@20:     mmyth_ui->play = play;
renatofilho@20:     mmyth_ui->videosink = videosink;
renatofilho@20:     mmyth_ui->udpsource = source;
renatofilho@20: 
renatofilho@20:     g_object_ref (mmyth_ui->play);
renatofilho@20:     g_object_ref (mmyth_ui->videosink);
renatofilho@20: 
renatofilho@20:     /* video widget */
renatofilho@20:     //mmyth_ui->videow = gst_player_video_new (videosink, play);
renatofilho@20:     mmyth_ui->videow = gtk_drawing_area_new ();
renatofilho@20:     gtk_widget_set_size_request (mmyth_ui->videow, 300, 240);
renatofilho@20: 
renatofilho@20:     mmyth_ui->logo = gdk_pixbuf_new_from_file ("logo.png", NULL);
renatofilho@20: 
renatofilho@20: 
renatofilho@20:     mmyth_ui->video_alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
renatofilho@20:     gtk_widget_hide (mmyth_ui->video_alignment);
renatofilho@20: 
renatofilho@20:     gtk_container_add (GTK_CONTAINER (mmyth_ui->video_alignment),
renatofilho@20:                        mmyth_ui->videow);
renatofilho@20: 
renatofilho@20:     g_signal_connect (mmyth_ui->videow, "expose-event", G_CALLBACK (expose),
renatofilho@20:                       mmyth_ui);
renatofilho@20:     //g_signal_connect(mmyth_ui->videow, "size_request", G_CALLBACK(cb_preferred_video_size), mmyth_ui);
renatofilho@20: 
renatofilho@20: 
renatofilho@20:     g_object_ref (mmyth_ui->videow);
renatofilho@20:     g_object_ref (mmyth_ui->video_alignment);
renatofilho@20: 
renatofilho@20:     //gnome_app_set_contents (app, videow);
renatofilho@20:     //gtk_widget_show (mmyth_ui->videow);
renatofilho@20: 
renatofilho@20: //fail:
renatofilho@20: //  gst_object_unref (GST_OBJECT (play));
renatofilho@20: //  return NULL;  
renatofilho@20: 
renatofilho@20: }
renatofilho@20: 
renatofilho@20: void
renatofilho@20: mmyth_player_stop (MMythUi * mmyth_ui)
renatofilho@20: {
renatofilho@20:     gst_element_set_state (mmyth_ui->play, GST_STATE_NULL);
renatofilho@20: 
renatofilho@20:     if(mmyth_ui->videow != NULL)
renatofilho@20:         gtk_widget_hide (mmyth_ui->videow);
renatofilho@20: 
renatofilho@20:     /* Disable IP Decapsulator playing threads */
renatofilho@20:     state_keep_running = FALSE;	
renatofilho@20: 
renatofilho@20: }
renatofilho@20: 
renatofilho@20: static gboolean
renatofilho@20: idle_play (gpointer data)
renatofilho@20: {
renatofilho@20:     MMythUi *mmyth_ui = (MMythUi *) data;
renatofilho@20: 
renatofilho@20:     sleep (2);
renatofilho@20: 
renatofilho@20:     gst_element_set_state (mmyth_ui->play, GST_STATE_PLAYING);
renatofilho@20: 
renatofilho@20:     return FALSE;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: 
renatofilho@20: /* Run IP decapsulator play function in a new thread. The thread is finished setting the
renatofilho@20:  * semaphore "state_keep_running" to FALSE*/
renatofilho@20: gpointer
renatofilho@20: run_ipd(gpointer data)
renatofilho@20: {
renatofilho@20:     GString *ip_addr = (GString*) data;
renatofilho@20: 
renatofilho@20: 	state_keep_running = TRUE;
renatofilho@20: 
renatofilho@20: 	printf("Inside thread\n");
renatofilho@20: 
renatofilho@20: 	ipd_mpe_play_section (ip_addr->str, &state_keep_running);
renatofilho@20: 
renatofilho@20: 	return 0;
renatofilho@20: }
renatofilho@20: 
renatofilho@20: void
renatofilho@20: mmyth_play_channel (MMythUi * mmyth_ui, gint service_number)
renatofilho@20: {
renatofilho@20: 	ESGDatabase *esg_db;
renatofilho@20:     DVBHService *service;
renatofilho@20: 	SDPData sdp_data;
renatofilho@20: 	GString *service_ip_addr;
renatofilho@20: 	
renatofilho@20: 	/* First verifies if there is a tuned network */
renatofilho@20: 	if ( !ipd_network_is_tuned() ) {
renatofilho@20: 		/* FIXME: show alert and handle this error */
renatofilho@20:         g_warning ("Play not possible, network not tuned");
renatofilho@20: 		return;
renatofilho@20: 	}
renatofilho@20: 
renatofilho@20:     esg_db = esg_database_get_instance();
renatofilho@20:     /* Gets the service structure */
renatofilho@20:     service = (DVBHService *) esg_database_get_service_from_number
renatofilho@20:                                  (esg_db, service_number);
renatofilho@20: 
renatofilho@20: 	/* Verifies if sdp fragment exists to this service */
renatofilho@20: 	if ( service->sdp_file == NULL ) {
renatofilho@20: 		/* FIXME: Implement error handling */
renatofilho@20:         g_warning ("SDP fragment not available to access service");
renatofilho@20: 		return;
renatofilho@20:     }
renatofilho@20: 	
renatofilho@20: 	/* Parses the sdp to get ipv6 address and port */
renatofilho@20: 	mmyth_sdp_parse_file (service->sdp_file->str, &sdp_data);
renatofilho@20: 
renatofilho@20:     /* Sets the gstreamer properties acording to the service access address */
renatofilho@20: 	/* FIXME: Develop sdp_bin in gstreamer to give sdp file as pipeline config */
renatofilho@20:     g_object_set (G_OBJECT (mmyth_ui->udpsource), "multicast_group",
renatofilho@20:                   sdp_data.ip_addr->str, NULL);
renatofilho@20:     g_object_set (G_OBJECT (mmyth_ui->udpsource), "port", sdp_data.video_port, NULL);
renatofilho@20: 
renatofilho@20:     /* Shows the video widget on screen */
renatofilho@20:     mmyth_ui_set_widget (mmyth_ui, mmyth_ui->video_uicommon);
renatofilho@20: 
renatofilho@20:     gtk_widget_show (mmyth_ui->videow);
renatofilho@20:     gtk_widget_queue_draw (mmyth_ui->videow);
renatofilho@20: 
renatofilho@20: #ifdef INDT_IP_DECAPSULATOR
renatofilho@20:     /* Will be dealocated in run_ipd */	
renatofilho@20: 	service_ip_addr = g_string_new (sdp_data.ip_addr->str);
renatofilho@20: 	
renatofilho@20: 	/* Requests the IP decapsulator to play the channel stream*/
renatofilho@20: 	g_thread_create (run_ipd, (gpointer) service_ip_addr, FALSE, NULL);
renatofilho@20: #endif
renatofilho@20: 		
renatofilho@20:     //gst_element_set_state (mmyth_ui->play, GST_STATE_PLAYING);
renatofilho@20:     g_idle_add (idle_play, mmyth_ui);
renatofilho@20: }