1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/maemo-ui/src/mmyth_videoplayer.c Mon Oct 23 16:02:15 2006 +0100
1.3 @@ -0,0 +1,369 @@
1.4 +
1.5 +#include <gst/gst.h>
1.6 +#include <gtk/gtk.h>
1.7 +#include <gdk/gdkx.h>
1.8 +#include <gst/interfaces/xoverlay.h>
1.9 +#include <unistd.h>
1.10 +
1.11 +#include "mmyth_ui.h"
1.12 +#include "mmyth_videoplayer.h"
1.13 +#include "mmyth_sdpreader.h"
1.14 +
1.15 +#include "esg_database.h"
1.16 +
1.17 +#include "ipd_demux.h"
1.18 +#include "ipd_network.h"
1.19 +
1.20 +#ifdef INDT_IP_DECAPSULATOR
1.21 +#include <sys/types.h>
1.22 +#include <signal.h>
1.23 +#endif
1.24 +
1.25 +/* Global flag/semaphore to control IP decapsulator threads */
1.26 +gboolean state_keep_running = 0;
1.27 +
1.28 +
1.29 +typedef struct _GstPlayerWindowStateChange
1.30 +{
1.31 + GstElement *play;
1.32 + GstState old_state, new_state;
1.33 + MMythUi *mmyth_ui;
1.34 +} GstPlayerWindowStateChange;
1.35 +
1.36 +typedef struct _GstPlayerWindowTagFound
1.37 +{
1.38 + GstElement *play;
1.39 + GstTagList *taglist;
1.40 + MMythUi *mmyth_ui;
1.41 +} GstPlayerWindowTagFound;
1.42 +
1.43 +
1.44 +GstElement *gst_pipeline, *gst_decoder, *gst_videosink;
1.45 +
1.46 +static gboolean idle_state (gpointer data);
1.47 +
1.48 +static gboolean
1.49 +bus_call (GstBus * bus, GstMessage * msg, gpointer data)
1.50 +{
1.51 + MMythUi *mmyth_ui = (MMythUi *) data;
1.52 + GMainLoop *loop = mmyth_ui->loop;
1.53 +
1.54 + switch (GST_MESSAGE_TYPE (msg)) {
1.55 + case GST_MESSAGE_EOS:
1.56 +
1.57 + if (mmyth_ui->idle_id != 0) {
1.58 + g_source_remove (mmyth_ui->idle_id);
1.59 + mmyth_ui->idle_id = 0;
1.60 + }
1.61 +
1.62 + //g_idle_add ((GSourceFunc) idle_eos, data);
1.63 + gst_element_set_state (GST_ELEMENT (GST_MESSAGE_SRC (msg)),
1.64 + GST_STATE_READY);
1.65 + break;
1.66 + case GST_MESSAGE_ERROR:{
1.67 + gchar *debug;
1.68 + GError *err;
1.69 +
1.70 + gst_message_parse_error (msg, &err, &debug);
1.71 + g_free (debug);
1.72 +
1.73 + printf ("Error: %s\n", err->message);
1.74 + g_error_free (err);
1.75 +
1.76 + g_main_loop_quit (loop);
1.77 + }
1.78 + break;
1.79 + case GST_MESSAGE_STATE_CHANGED:{
1.80 + GstState oldstate;
1.81 + GstState newstate;
1.82 + GstState pending;
1.83 + GstPlayerWindowStateChange *st =
1.84 + g_new (GstPlayerWindowStateChange, 1);
1.85 +
1.86 + gst_message_parse_state_changed (msg,
1.87 + &oldstate,
1.88 + &newstate, &pending);
1.89 +
1.90 + st->play = mmyth_ui->play;
1.91 + gst_object_ref (GST_OBJECT (mmyth_ui->play));
1.92 + st->old_state = oldstate;
1.93 + st->new_state = newstate;
1.94 +
1.95 + st->mmyth_ui = mmyth_ui;
1.96 +
1.97 + /* State debug messages */
1.98 + printf ("oldstate = %s, newstate = %s, pendingstate = %s\n",
1.99 + gst_element_state_get_name (oldstate),
1.100 + gst_element_state_get_name (newstate),
1.101 + gst_element_state_get_name (pending));
1.102 +
1.103 + g_idle_add ((GSourceFunc) idle_state, st);
1.104 +
1.105 + }
1.106 + break;
1.107 + default:
1.108 + printf (gst_message_type_get_name (GST_MESSAGE_TYPE (msg)));
1.109 + printf ("\n");
1.110 + break;
1.111 + }
1.112 +
1.113 + return TRUE;
1.114 +}
1.115 +
1.116 +
1.117 +static gboolean
1.118 +cb_iterate (gpointer data)
1.119 +{
1.120 + MMythUi *mmyth_ui = (MMythUi *) data;
1.121 + //gboolean res;
1.122 +
1.123 + g_main_loop_run (mmyth_ui->loop);
1.124 +/*
1.125 + if (!GST_FLAG_IS_SET (mmyth_ui->play, GST_BIN_SELF_SCHEDULABLE)) {
1.126 + res = gst_bin_iterate (GST_BIN (mmyth_ui->play));
1.127 + } else {
1.128 + g_usleep (100);
1.129 + res = (gst_element_get_state (mmyth_ui->play) == GST_STATE_PLAYING);
1.130 + }
1.131 +
1.132 + if (!res)
1.133 + mmyth_ui->idle_id = 0;
1.134 +
1.135 + return res;
1.136 +*/
1.137 + return FALSE;
1.138 +
1.139 +}
1.140 +
1.141 +static gboolean
1.142 +idle_state (gpointer data)
1.143 +{
1.144 + GstPlayerWindowStateChange *st = data;
1.145 +
1.146 + if (st->old_state == GST_STATE_PLAYING) {
1.147 + if (st->mmyth_ui->idle_id != 0) {
1.148 + g_source_remove (st->mmyth_ui->idle_id);
1.149 + st->mmyth_ui->idle_id = 0;
1.150 + }
1.151 + }
1.152 + else if (st->new_state == GST_STATE_PLAYING) {
1.153 + if (st->mmyth_ui->idle_id != 0)
1.154 + g_source_remove (st->mmyth_ui->idle_id);
1.155 +
1.156 + st->mmyth_ui->idle_id = g_idle_add (cb_iterate, st->mmyth_ui);
1.157 + }
1.158 +
1.159 + /* new movie loaded? */
1.160 + if (st->old_state == GST_STATE_READY && st->new_state > GST_STATE_READY) {
1.161 +
1.162 + /* gboolean have_video = FALSE; */
1.163 +
1.164 + gtk_widget_show (st->mmyth_ui->videow);
1.165 +
1.166 + gtk_window_resize (GTK_WINDOW (st->mmyth_ui->main_window), 1, 1);
1.167 +
1.168 + }
1.169 +
1.170 + /* discarded movie? */
1.171 + if (st->old_state > GST_STATE_READY && st->new_state == GST_STATE_READY) {
1.172 +
1.173 + if (st->mmyth_ui->tagcache) {
1.174 + gst_tag_list_free (st->mmyth_ui->tagcache);
1.175 + st->mmyth_ui->tagcache = NULL;
1.176 + }
1.177 + }
1.178 +
1.179 + gst_object_unref (GST_OBJECT (st->play));
1.180 + //g_object_unref (G_OBJECT (st->win));
1.181 + g_free (st);
1.182 +
1.183 + /* once */
1.184 + return FALSE;
1.185 +}
1.186 +
1.187 +
1.188 +
1.189 +static gboolean
1.190 +expose (GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
1.191 +{
1.192 + MMythUi *mmyth_ui = (MMythUi *) user_data;
1.193 +
1.194 + gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (mmyth_ui->videosink),
1.195 + GDK_WINDOW_XWINDOW (mmyth_ui->videow->
1.196 + window));
1.197 + return TRUE;
1.198 +}
1.199 +
1.200 +
1.201 +void
1.202 +mmyth_player_init (MMythUi * mmyth_ui)
1.203 +{
1.204 + GstElement *play;
1.205 + GstElement *source, *parser, *decoder, *videosink;
1.206 +
1.207 + play = gst_pipeline_new ("video-player");
1.208 + source = gst_element_factory_make ("udpsrc", "file-source");
1.209 + parser = gst_element_factory_make ("rtph263pdepay", "rtp-demux");
1.210 + decoder = gst_element_factory_make ("ffdec_h263", "mpeg-decoder");
1.211 + videosink = gst_element_factory_make ("xvimagesink", "image-output");
1.212 + gst_pipeline = play;
1.213 + gst_decoder = decoder;
1.214 + gst_videosink = videosink;
1.215 +
1.216 + if (!(gst_pipeline && source && parser && decoder && videosink)) {
1.217 + /* FIXME: hanlde the error correctly */
1.218 + /* video_alignment is not being created (below)
1.219 + and is causing problems to the ui */
1.220 + g_print ("GstElement creation error!\n");
1.221 + return;
1.222 + }
1.223 +
1.224 + g_object_set (G_OBJECT (videosink), "sync", FALSE, NULL);
1.225 +
1.226 + gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (gst_pipeline)),
1.227 + bus_call, mmyth_ui);
1.228 +
1.229 + gst_bin_add_many (GST_BIN (gst_pipeline), source, parser, decoder,
1.230 + videosink, NULL);
1.231 +
1.232 + {
1.233 + GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp", NULL);
1.234 + gst_element_link_filtered(source, parser, rtpcaps);
1.235 + }
1.236 +
1.237 + gst_element_link_many (/*source,*/ parser, decoder, videosink, NULL);
1.238 +
1.239 + /* actual window */
1.240 + mmyth_ui->play = play;
1.241 + mmyth_ui->videosink = videosink;
1.242 + mmyth_ui->udpsource = source;
1.243 +
1.244 + g_object_ref (mmyth_ui->play);
1.245 + g_object_ref (mmyth_ui->videosink);
1.246 +
1.247 + /* video widget */
1.248 + //mmyth_ui->videow = gst_player_video_new (videosink, play);
1.249 + mmyth_ui->videow = gtk_drawing_area_new ();
1.250 + gtk_widget_set_size_request (mmyth_ui->videow, 300, 240);
1.251 +
1.252 + mmyth_ui->logo = gdk_pixbuf_new_from_file ("logo.png", NULL);
1.253 +
1.254 +
1.255 + mmyth_ui->video_alignment = gtk_alignment_new (0.5, 0.5, 0, 0);
1.256 + gtk_widget_hide (mmyth_ui->video_alignment);
1.257 +
1.258 + gtk_container_add (GTK_CONTAINER (mmyth_ui->video_alignment),
1.259 + mmyth_ui->videow);
1.260 +
1.261 + g_signal_connect (mmyth_ui->videow, "expose-event", G_CALLBACK (expose),
1.262 + mmyth_ui);
1.263 + //g_signal_connect(mmyth_ui->videow, "size_request", G_CALLBACK(cb_preferred_video_size), mmyth_ui);
1.264 +
1.265 +
1.266 + g_object_ref (mmyth_ui->videow);
1.267 + g_object_ref (mmyth_ui->video_alignment);
1.268 +
1.269 + //gnome_app_set_contents (app, videow);
1.270 + //gtk_widget_show (mmyth_ui->videow);
1.271 +
1.272 +//fail:
1.273 +// gst_object_unref (GST_OBJECT (play));
1.274 +// return NULL;
1.275 +
1.276 +}
1.277 +
1.278 +void
1.279 +mmyth_player_stop (MMythUi * mmyth_ui)
1.280 +{
1.281 + gst_element_set_state (mmyth_ui->play, GST_STATE_NULL);
1.282 +
1.283 + if(mmyth_ui->videow != NULL)
1.284 + gtk_widget_hide (mmyth_ui->videow);
1.285 +
1.286 + /* Disable IP Decapsulator playing threads */
1.287 + state_keep_running = FALSE;
1.288 +
1.289 +}
1.290 +
1.291 +static gboolean
1.292 +idle_play (gpointer data)
1.293 +{
1.294 + MMythUi *mmyth_ui = (MMythUi *) data;
1.295 +
1.296 + sleep (2);
1.297 +
1.298 + gst_element_set_state (mmyth_ui->play, GST_STATE_PLAYING);
1.299 +
1.300 + return FALSE;
1.301 +}
1.302 +
1.303 +
1.304 +/* Run IP decapsulator play function in a new thread. The thread is finished setting the
1.305 + * semaphore "state_keep_running" to FALSE*/
1.306 +gpointer
1.307 +run_ipd(gpointer data)
1.308 +{
1.309 + GString *ip_addr = (GString*) data;
1.310 +
1.311 + state_keep_running = TRUE;
1.312 +
1.313 + printf("Inside thread\n");
1.314 +
1.315 + ipd_mpe_play_section (ip_addr->str, &state_keep_running);
1.316 +
1.317 + return 0;
1.318 +}
1.319 +
1.320 +void
1.321 +mmyth_play_channel (MMythUi * mmyth_ui, gint service_number)
1.322 +{
1.323 + ESGDatabase *esg_db;
1.324 + DVBHService *service;
1.325 + SDPData sdp_data;
1.326 + GString *service_ip_addr;
1.327 +
1.328 + /* First verifies if there is a tuned network */
1.329 + if ( !ipd_network_is_tuned() ) {
1.330 + /* FIXME: show alert and handle this error */
1.331 + g_warning ("Play not possible, network not tuned");
1.332 + return;
1.333 + }
1.334 +
1.335 + esg_db = esg_database_get_instance();
1.336 + /* Gets the service structure */
1.337 + service = (DVBHService *) esg_database_get_service_from_number
1.338 + (esg_db, service_number);
1.339 +
1.340 + /* Verifies if sdp fragment exists to this service */
1.341 + if ( service->sdp_file == NULL ) {
1.342 + /* FIXME: Implement error handling */
1.343 + g_warning ("SDP fragment not available to access service");
1.344 + return;
1.345 + }
1.346 +
1.347 + /* Parses the sdp to get ipv6 address and port */
1.348 + mmyth_sdp_parse_file (service->sdp_file->str, &sdp_data);
1.349 +
1.350 + /* Sets the gstreamer properties acording to the service access address */
1.351 + /* FIXME: Develop sdp_bin in gstreamer to give sdp file as pipeline config */
1.352 + g_object_set (G_OBJECT (mmyth_ui->udpsource), "multicast_group",
1.353 + sdp_data.ip_addr->str, NULL);
1.354 + g_object_set (G_OBJECT (mmyth_ui->udpsource), "port", sdp_data.video_port, NULL);
1.355 +
1.356 + /* Shows the video widget on screen */
1.357 + mmyth_ui_set_widget (mmyth_ui, mmyth_ui->video_uicommon);
1.358 +
1.359 + gtk_widget_show (mmyth_ui->videow);
1.360 + gtk_widget_queue_draw (mmyth_ui->videow);
1.361 +
1.362 +#ifdef INDT_IP_DECAPSULATOR
1.363 + /* Will be dealocated in run_ipd */
1.364 + service_ip_addr = g_string_new (sdp_data.ip_addr->str);
1.365 +
1.366 + /* Requests the IP decapsulator to play the channel stream*/
1.367 + g_thread_create (run_ipd, (gpointer) service_ip_addr, FALSE, NULL);
1.368 +#endif
1.369 +
1.370 + //gst_element_set_state (mmyth_ui->play, GST_STATE_PLAYING);
1.371 + g_idle_add (idle_play, mmyth_ui);
1.372 +}