renatofilho@20: renatofilho@20: #include renatofilho@20: #include renatofilho@20: #include renatofilho@20: #include renatofilho@20: #include 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 renatofilho@20: #include 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: }