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