maemo-ui/src/mmyth_videoplayer.c
author rosfran
Fri Oct 27 00:11:21 2006 +0100 (2006-10-27)
branchtrunk
changeset 57 c83c59b22fe1
permissions -rw-r--r--
[svn r58] Fixed delay on audio frames's timestamps, and refactoring the autotools usage.
     1 
     2 #include <gst/gst.h>
     3 #include <gtk/gtk.h>
     4 #include <gdk/gdkx.h>
     5 #include <gst/interfaces/xoverlay.h>
     6 #include <unistd.h>
     7 
     8 #include "mmyth_ui.h"
     9 #include "mmyth_videoplayer.h"
    10 #include "mmyth_sdpreader.h"
    11 
    12 #include "esg_database.h"
    13 
    14 #include "ipd_demux.h"
    15 #include "ipd_network.h"
    16 
    17 #ifdef INDT_IP_DECAPSULATOR
    18 #include <sys/types.h>
    19 #include <signal.h>
    20 #endif
    21 
    22 /* Global flag/semaphore to control IP decapsulator threads */
    23 gboolean state_keep_running = 0;
    24 
    25 
    26 typedef struct _GstPlayerWindowStateChange
    27 {
    28     GstElement *play;
    29     GstState old_state, new_state;
    30     MMythUi *mmyth_ui;
    31 } GstPlayerWindowStateChange;
    32 
    33 typedef struct _GstPlayerWindowTagFound
    34 {
    35     GstElement *play;
    36     GstTagList *taglist;
    37     MMythUi *mmyth_ui;
    38 } GstPlayerWindowTagFound;
    39 
    40 
    41 GstElement *gst_pipeline, *gst_decoder, *gst_videosink;
    42 
    43 static gboolean idle_state (gpointer data);
    44 
    45 static gboolean
    46 bus_call (GstBus * bus, GstMessage * msg, gpointer data)
    47 {
    48     MMythUi *mmyth_ui = (MMythUi *) data;
    49     GMainLoop *loop = mmyth_ui->loop;
    50 
    51     switch (GST_MESSAGE_TYPE (msg)) {
    52         case GST_MESSAGE_EOS:
    53 
    54             if (mmyth_ui->idle_id != 0) {
    55                 g_source_remove (mmyth_ui->idle_id);
    56                 mmyth_ui->idle_id = 0;
    57             }
    58 
    59             //g_idle_add ((GSourceFunc) idle_eos, data);
    60             gst_element_set_state (GST_ELEMENT (GST_MESSAGE_SRC (msg)),
    61                                    GST_STATE_READY);
    62             break;
    63         case GST_MESSAGE_ERROR:{
    64                 gchar *debug;
    65                 GError *err;
    66 
    67                 gst_message_parse_error (msg, &err, &debug);
    68                 g_free (debug);
    69 
    70                 printf ("Error: %s\n", err->message);
    71                 g_error_free (err);
    72 
    73                 g_main_loop_quit (loop);
    74             }
    75             break;
    76         case GST_MESSAGE_STATE_CHANGED:{
    77                 GstState oldstate;
    78                 GstState newstate;
    79                 GstState pending;
    80                 GstPlayerWindowStateChange *st =
    81                     g_new (GstPlayerWindowStateChange, 1);
    82 
    83                 gst_message_parse_state_changed (msg,
    84                                                  &oldstate,
    85                                                  &newstate, &pending);
    86 
    87                 st->play = mmyth_ui->play;
    88                 gst_object_ref (GST_OBJECT (mmyth_ui->play));
    89                 st->old_state = oldstate;
    90                 st->new_state = newstate;
    91 
    92                 st->mmyth_ui = mmyth_ui;
    93 
    94                 /* State debug messages */
    95                 printf ("oldstate = %s, newstate = %s, pendingstate = %s\n",
    96                         gst_element_state_get_name (oldstate),
    97                         gst_element_state_get_name (newstate),
    98                         gst_element_state_get_name (pending));
    99 
   100                 g_idle_add ((GSourceFunc) idle_state, st);
   101 
   102             }
   103             break;
   104         default:
   105             printf (gst_message_type_get_name (GST_MESSAGE_TYPE (msg)));
   106             printf ("\n");
   107             break;
   108     }
   109 
   110     return TRUE;
   111 }
   112 
   113 
   114 static gboolean
   115 cb_iterate (gpointer data)
   116 {
   117     MMythUi *mmyth_ui = (MMythUi *) data;
   118     //gboolean res;
   119 
   120     g_main_loop_run (mmyth_ui->loop);
   121 /*
   122 	if (!GST_FLAG_IS_SET (mmyth_ui->play, GST_BIN_SELF_SCHEDULABLE)) {
   123     	res = gst_bin_iterate (GST_BIN (mmyth_ui->play));
   124 	} else {
   125     	g_usleep (100);
   126 		res = (gst_element_get_state (mmyth_ui->play) == GST_STATE_PLAYING);
   127 	}
   128 
   129 	if (!res)
   130     	mmyth_ui->idle_id = 0;
   131     	
   132     return res;
   133 */
   134     return FALSE;
   135 
   136 }
   137 
   138 static gboolean
   139 idle_state (gpointer data)
   140 {
   141     GstPlayerWindowStateChange *st = data;
   142 
   143     if (st->old_state == GST_STATE_PLAYING) {
   144         if (st->mmyth_ui->idle_id != 0) {
   145             g_source_remove (st->mmyth_ui->idle_id);
   146             st->mmyth_ui->idle_id = 0;
   147         }
   148     }
   149     else if (st->new_state == GST_STATE_PLAYING) {
   150         if (st->mmyth_ui->idle_id != 0)
   151             g_source_remove (st->mmyth_ui->idle_id);
   152 
   153         st->mmyth_ui->idle_id = g_idle_add (cb_iterate, st->mmyth_ui);
   154     }
   155 
   156     /* new movie loaded? */
   157     if (st->old_state == GST_STATE_READY && st->new_state > GST_STATE_READY) {
   158 
   159         /* gboolean have_video = FALSE; */
   160 
   161         gtk_widget_show (st->mmyth_ui->videow);
   162 
   163         gtk_window_resize (GTK_WINDOW (st->mmyth_ui->main_window), 1, 1);
   164 
   165     }
   166 
   167     /* discarded movie? */
   168     if (st->old_state > GST_STATE_READY && st->new_state == GST_STATE_READY) {
   169 
   170         if (st->mmyth_ui->tagcache) {
   171             gst_tag_list_free (st->mmyth_ui->tagcache);
   172             st->mmyth_ui->tagcache = NULL;
   173         }
   174     }
   175 
   176     gst_object_unref (GST_OBJECT (st->play));
   177     //g_object_unref (G_OBJECT (st->win));
   178     g_free (st);
   179 
   180     /* once */
   181     return FALSE;
   182 }
   183 
   184 
   185 
   186 static gboolean
   187 expose (GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
   188 {
   189     MMythUi *mmyth_ui = (MMythUi *) user_data;
   190 
   191     gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (mmyth_ui->videosink),
   192                                   GDK_WINDOW_XWINDOW (mmyth_ui->videow->
   193                                                       window));
   194     return TRUE;
   195 }
   196 
   197 
   198 void
   199 mmyth_player_init (MMythUi * mmyth_ui)
   200 {
   201     GstElement *play;
   202     GstElement *source, *parser, *decoder, *videosink;
   203 
   204     play = gst_pipeline_new ("video-player");
   205     source = gst_element_factory_make ("udpsrc", "file-source");
   206     parser = gst_element_factory_make ("rtph263pdepay", "rtp-demux");
   207     decoder = gst_element_factory_make ("ffdec_h263", "mpeg-decoder");
   208     videosink = gst_element_factory_make ("xvimagesink", "image-output");
   209     gst_pipeline = play;
   210     gst_decoder = decoder;
   211     gst_videosink = videosink;
   212 
   213     if (!(gst_pipeline && source && parser && decoder && videosink)) {
   214         /* FIXME: hanlde the error correctly */
   215         /* video_alignment is not being created (below) 
   216            and is causing problems to the ui */
   217         g_print ("GstElement creation error!\n");
   218         return;
   219     }
   220 
   221     g_object_set (G_OBJECT (videosink), "sync", FALSE, NULL);
   222 
   223     gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (gst_pipeline)),
   224                        bus_call, mmyth_ui);
   225 
   226     gst_bin_add_many (GST_BIN (gst_pipeline), source, parser, decoder,
   227                       videosink, NULL);
   228 
   229     {
   230         GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp", NULL);
   231         gst_element_link_filtered(source, parser, rtpcaps);
   232     }
   233     
   234     gst_element_link_many (/*source,*/ parser, decoder, videosink, NULL);
   235 
   236     /* actual window */
   237     mmyth_ui->play = play;
   238     mmyth_ui->videosink = videosink;
   239     mmyth_ui->udpsource = source;
   240 
   241     g_object_ref (mmyth_ui->play);
   242     g_object_ref (mmyth_ui->videosink);
   243 
   244     /* video widget */
   245     //mmyth_ui->videow = gst_player_video_new (videosink, play);
   246     mmyth_ui->videow = gtk_drawing_area_new ();
   247     gtk_widget_set_size_request (mmyth_ui->videow, 300, 240);
   248 
   249     mmyth_ui->logo = gdk_pixbuf_new_from_file ("logo.png", NULL);
   250 
   251 
   252     mmyth_ui->video_alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
   253     gtk_widget_hide (mmyth_ui->video_alignment);
   254 
   255     gtk_container_add (GTK_CONTAINER (mmyth_ui->video_alignment),
   256                        mmyth_ui->videow);
   257 
   258     g_signal_connect (mmyth_ui->videow, "expose-event", G_CALLBACK (expose),
   259                       mmyth_ui);
   260     //g_signal_connect(mmyth_ui->videow, "size_request", G_CALLBACK(cb_preferred_video_size), mmyth_ui);
   261 
   262 
   263     g_object_ref (mmyth_ui->videow);
   264     g_object_ref (mmyth_ui->video_alignment);
   265 
   266     //gnome_app_set_contents (app, videow);
   267     //gtk_widget_show (mmyth_ui->videow);
   268 
   269 //fail:
   270 //  gst_object_unref (GST_OBJECT (play));
   271 //  return NULL;  
   272 
   273 }
   274 
   275 void
   276 mmyth_player_stop (MMythUi * mmyth_ui)
   277 {
   278     gst_element_set_state (mmyth_ui->play, GST_STATE_NULL);
   279 
   280     if(mmyth_ui->videow != NULL)
   281         gtk_widget_hide (mmyth_ui->videow);
   282 
   283     /* Disable IP Decapsulator playing threads */
   284     state_keep_running = FALSE;	
   285 
   286 }
   287 
   288 static gboolean
   289 idle_play (gpointer data)
   290 {
   291     MMythUi *mmyth_ui = (MMythUi *) data;
   292 
   293     sleep (2);
   294 
   295     gst_element_set_state (mmyth_ui->play, GST_STATE_PLAYING);
   296 
   297     return FALSE;
   298 }
   299 
   300 
   301 /* Run IP decapsulator play function in a new thread. The thread is finished setting the
   302  * semaphore "state_keep_running" to FALSE*/
   303 gpointer
   304 run_ipd(gpointer data)
   305 {
   306     GString *ip_addr = (GString*) data;
   307 
   308 	state_keep_running = TRUE;
   309 
   310 	printf("Inside thread\n");
   311 
   312 	ipd_mpe_play_section (ip_addr->str, &state_keep_running);
   313 
   314 	return 0;
   315 }
   316 
   317 void
   318 mmyth_play_channel (MMythUi * mmyth_ui, gint service_number)
   319 {
   320 	ESGDatabase *esg_db;
   321     DVBHService *service;
   322 	SDPData sdp_data;
   323 	GString *service_ip_addr;
   324 	
   325 	/* First verifies if there is a tuned network */
   326 	if ( !ipd_network_is_tuned() ) {
   327 		/* FIXME: show alert and handle this error */
   328         g_warning ("Play not possible, network not tuned");
   329 		return;
   330 	}
   331 
   332     esg_db = esg_database_get_instance();
   333     /* Gets the service structure */
   334     service = (DVBHService *) esg_database_get_service_from_number
   335                                  (esg_db, service_number);
   336 
   337 	/* Verifies if sdp fragment exists to this service */
   338 	if ( service->sdp_file == NULL ) {
   339 		/* FIXME: Implement error handling */
   340         g_warning ("SDP fragment not available to access service");
   341 		return;
   342     }
   343 	
   344 	/* Parses the sdp to get ipv6 address and port */
   345 	mmyth_sdp_parse_file (service->sdp_file->str, &sdp_data);
   346 
   347     /* Sets the gstreamer properties acording to the service access address */
   348 	/* FIXME: Develop sdp_bin in gstreamer to give sdp file as pipeline config */
   349     g_object_set (G_OBJECT (mmyth_ui->udpsource), "multicast_group",
   350                   sdp_data.ip_addr->str, NULL);
   351     g_object_set (G_OBJECT (mmyth_ui->udpsource), "port", sdp_data.video_port, NULL);
   352 
   353     /* Shows the video widget on screen */
   354     mmyth_ui_set_widget (mmyth_ui, mmyth_ui->video_uicommon);
   355 
   356     gtk_widget_show (mmyth_ui->videow);
   357     gtk_widget_queue_draw (mmyth_ui->videow);
   358 
   359 #ifdef INDT_IP_DECAPSULATOR
   360     /* Will be dealocated in run_ipd */	
   361 	service_ip_addr = g_string_new (sdp_data.ip_addr->str);
   362 	
   363 	/* Requests the IP decapsulator to play the channel stream*/
   364 	g_thread_create (run_ipd, (gpointer) service_ip_addr, FALSE, NULL);
   365 #endif
   366 		
   367     //gst_element_set_state (mmyth_ui->play, GST_STATE_PLAYING);
   368     g_idle_add (idle_play, mmyth_ui);
   369 }