maemo-ui/src/mmyth_tvplayer.c
author renatofilho
Thu Nov 09 19:45:27 2006 +0000 (2006-11-09)
branchtrunk
changeset 75 761a8bbe4278
parent 25 2ee2974c72c1
child 99 404189e73f8e
permissions -rw-r--r--
[svn r76] typefind copyed from gstreamer cvs
renatofilho@20
     1
/**
renatofilho@20
     2
 * GMyth Library
renatofilho@20
     3
 *
renatofilho@20
     4
 * @file gmyth/mmyth_tvplayer.c
renatofilho@20
     5
 * 
renatofilho@20
     6
 * @brief <p> This component provides playback of the remote A/V using
renatofilho@20
     7
 * GStreamer.
renatofilho@20
     8
 * 
renatofilho@20
     9
 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
renatofilho@20
    10
 * @author Hallyson Luiz de Morais Melo <hallyson.melo@indt.org.br>
renatofilho@20
    11
 *
renatofilho@20
    12
 *//*
renatofilho@20
    13
 * 
renatofilho@20
    14
 * This program is free software; you can redistribute it and/or modify
renatofilho@20
    15
 * it under the terms of the GNU Lesser General Public License as published by
renatofilho@20
    16
 * the Free Software Foundation; either version 2 of the License, or
renatofilho@20
    17
 * (at your option) any later version.
renatofilho@20
    18
 *
renatofilho@20
    19
 * This program is distributed in the hope that it will be useful,
renatofilho@20
    20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
renatofilho@20
    21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
renatofilho@20
    22
 * GNU General Public License for more details.
renatofilho@20
    23
 *
renatofilho@20
    24
 * You should have received a copy of the GNU Lesser General Public License
renatofilho@20
    25
 * along with this program; if not, write to the Free Software
renatofilho@20
    26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
renatofilho@20
    27
 */
renatofilho@20
    28
renatofilho@20
    29
#include "mmyth_tvplayer.h"
renatofilho@20
    30
 
renatofilho@20
    31
#include <gdk/gdkx.h>
renatofilho@20
    32
renatofilho@20
    33
#include "gmyth_context.h"
renatofilho@20
    34
#include "gmyth_remote_util.h"
renatofilho@20
    35
renatofilho@20
    36
typedef struct _GstPlayerWindowStateChange
renatofilho@20
    37
{
renatofilho@20
    38
    GstElement *play;
renatofilho@20
    39
    GstState old_state, new_state;
renatofilho@20
    40
    MMythTVPlayer *tvplayer;
renatofilho@20
    41
} GstPlayerWindowStateChange;
renatofilho@20
    42
renatofilho@20
    43
typedef struct _GstPlayerWindowTagFound
renatofilho@20
    44
{
renatofilho@20
    45
    GstElement *play;
renatofilho@20
    46
    GstTagList *taglist;
renatofilho@20
    47
    MMythTVPlayer *tvplayer;
renatofilho@20
    48
} GstPlayerWindowTagFound;
renatofilho@20
    49
renatofilho@20
    50
/*
renatofilho@20
    51
static gboolean idle_state (gpointer data);
renatofilho@20
    52
*/
renatofilho@20
    53
static gboolean bus_call (GstBus * bus, GstMessage * msg, gpointer data);
renatofilho@20
    54
renatofilho@20
    55
static void mmyth_tvplayer_class_init          (MMythTVPlayerClass *klass);
renatofilho@20
    56
static void mmyth_tvplayer_init                (MMythTVPlayer *object);
renatofilho@20
    57
renatofilho@20
    58
static void mmyth_tvplayer_dispose  (GObject *object);
renatofilho@20
    59
static void mmyth_tvplayer_finalize (GObject *object);
renatofilho@20
    60
renatofilho@20
    61
G_DEFINE_TYPE(MMythTVPlayer, mmyth_tvplayer, G_TYPE_OBJECT)
renatofilho@20
    62
renatofilho@20
    63
static gboolean mmyth_tvplayer_create_pipeline (MMythTVPlayer* tvplayer);
renatofilho@20
    64
static void     new_pad_cb (GstElement *element, 
renatofilho@20
    65
                            GstPad *pad, gpointer data);
renatofilho@20
    66
renatofilho@20
    67
static gboolean expose_cb (GtkWidget * widget, 
renatofilho@20
    68
                           GdkEventExpose * event, 
renatofilho@20
    69
                           gpointer user_data);
renatofilho@20
    70
renatofilho@20
    71
static void
renatofilho@20
    72
mmyth_tvplayer_class_init (MMythTVPlayerClass *klass)
renatofilho@20
    73
{
renatofilho@20
    74
	GObjectClass *gobject_class;
renatofilho@20
    75
renatofilho@20
    76
    gobject_class = (GObjectClass *) klass;
renatofilho@20
    77
	
renatofilho@20
    78
    gobject_class->dispose  = mmyth_tvplayer_dispose;
renatofilho@20
    79
    gobject_class->finalize = mmyth_tvplayer_finalize;	
renatofilho@20
    80
}
renatofilho@20
    81
renatofilho@20
    82
static void
renatofilho@20
    83
new_pad_cb (GstElement *element, GstPad *pad, gpointer data)
renatofilho@20
    84
{
renatofilho@20
    85
	MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (data);
renatofilho@20
    86
	GstPadLinkReturn ret;
renatofilho@20
    87
	char *s;
renatofilho@20
    88
	
renatofilho@20
    89
	s = gst_caps_to_string (pad->caps);
renatofilho@20
    90
renatofilho@20
    91
	if ( s[0] == 'a') {
rosfran@64
    92
		ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->audioqueue1, "sink"));
renatofilho@20
    93
	} else {
rosfran@64
    94
		ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->videoqueue1, "sink")); 
renatofilho@20
    95
	}
renatofilho@20
    96
	
renatofilho@20
    97
	g_free(s);
renatofilho@20
    98
}
renatofilho@20
    99
renatofilho@20
   100
static gboolean
renatofilho@20
   101
expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
renatofilho@20
   102
{
rosfran@64
   103
	MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (user_data);
renatofilho@20
   104
renatofilho@20
   105
	if (tvplayer && tvplayer->videow) {
rosfran@64
   106
		gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (tvplayer->gst_videosink),
rosfran@64
   107
				GDK_WINDOW_XWINDOW (widget->window));
renatofilho@20
   108
		return TRUE;
renatofilho@20
   109
	}
rosfran@64
   110
renatofilho@20
   111
	g_warning ("MMythTVPlayer expose called before setting video window\n");
rosfran@64
   112
rosfran@64
   113
	return FALSE;
renatofilho@20
   114
}
renatofilho@20
   115
renatofilho@20
   116
static void
renatofilho@20
   117
mmyth_tvplayer_init (MMythTVPlayer *tvplayer)
renatofilho@20
   118
{
rosfran@64
   119
	tvplayer->gst_pipeline = NULL;
rosfran@64
   120
	tvplayer->gst_source = NULL;
rosfran@64
   121
	tvplayer->gst_videodec = NULL;
rosfran@64
   122
	tvplayer->gst_videosink = NULL;
rosfran@64
   123
	tvplayer->gst_videocolortrs = NULL;
rosfran@64
   124
	tvplayer->videoqueue1 = NULL;
rosfran@64
   125
	tvplayer->videoqueue2 = NULL;
rosfran@64
   126
	tvplayer->audioqueue1 = NULL;
rosfran@64
   127
	tvplayer->audioqueue2 = NULL;   
rosfran@64
   128
rosfran@64
   129
	/* GTKWidget for rendering the video */
rosfran@64
   130
	tvplayer->videow = NULL;
renatofilho@20
   131
	tvplayer->expose_handler = 0;
rosfran@64
   132
renatofilho@20
   133
	tvplayer->backend_hostname = NULL;
renatofilho@20
   134
	tvplayer->backend_port = 0;
renatofilho@20
   135
	tvplayer->local_hostname = NULL;
renatofilho@20
   136
rosfran@64
   137
	tvplayer->recorder = NULL;
renatofilho@20
   138
	tvplayer->tvchain = NULL;
renatofilho@20
   139
	tvplayer->proginfo = NULL;
renatofilho@20
   140
}
renatofilho@20
   141
renatofilho@20
   142
static void
renatofilho@20
   143
mmyth_tvplayer_dispose (GObject *object)
renatofilho@20
   144
{
renatofilho@20
   145
renatofilho@20
   146
	G_OBJECT_CLASS (mmyth_tvplayer_parent_class)->dispose (object);
renatofilho@20
   147
}
renatofilho@20
   148
renatofilho@20
   149
static void
renatofilho@20
   150
mmyth_tvplayer_finalize (GObject *object)
renatofilho@20
   151
{
renatofilho@20
   152
	g_signal_handlers_destroy (object);
renatofilho@20
   153
renatofilho@20
   154
	MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (object);
renatofilho@20
   155
renatofilho@20
   156
	g_debug ("[%s] Finalizing tvplayer", __FUNCTION__);
renatofilho@20
   157
	
renatofilho@20
   158
	if (tvplayer->videow != NULL) {
renatofilho@20
   159
		if (g_signal_handler_is_connected (tvplayer->videow, 
renatofilho@20
   160
						tvplayer->expose_handler)) {
renatofilho@20
   161
			g_signal_handler_disconnect (tvplayer->videow,
renatofilho@20
   162
				tvplayer->expose_handler);
renatofilho@20
   163
		}
renatofilho@20
   164
		g_object_unref (tvplayer->videow);
renatofilho@20
   165
	}
renatofilho@20
   166
	
rosfran@64
   167
	if ( tvplayer->recorder != NULL )
rosfran@64
   168
		g_object_unref (tvplayer->recorder);
renatofilho@20
   169
	if ( tvplayer->tvchain != NULL )
renatofilho@20
   170
		g_object_unref (tvplayer->tvchain);
renatofilho@20
   171
	if ( tvplayer->proginfo != NULL )
renatofilho@20
   172
		g_object_unref (tvplayer->proginfo);	
renatofilho@20
   173
renatofilho@20
   174
	// Release Gstreamer elements
renatofilho@20
   175
	if ( tvplayer->gst_pipeline != NULL )
renatofilho@20
   176
		g_object_unref (tvplayer->gst_pipeline);	
renatofilho@20
   177
	if ( tvplayer->gst_source != NULL )
renatofilho@20
   178
		g_object_unref (tvplayer->gst_source);	
renatofilho@20
   179
	if ( tvplayer->gst_videodec != NULL )
renatofilho@20
   180
		g_object_unref (tvplayer->gst_videodec);	
rosfran@64
   181
	if ( tvplayer->gst_videocolortrs != NULL )
rosfran@64
   182
		g_object_unref (tvplayer->gst_videocolortrs);
renatofilho@20
   183
	if ( tvplayer->gst_videosink != NULL )
renatofilho@20
   184
		g_object_unref (tvplayer->gst_videosink);	
rosfran@64
   185
	if ( tvplayer->videoqueue1 != NULL )
rosfran@64
   186
		g_object_unref (tvplayer->videoqueue1);
rosfran@64
   187
	if ( tvplayer->videoqueue2 != NULL )
rosfran@64
   188
		g_object_unref (tvplayer->videoqueue2);
rosfran@64
   189
	if ( tvplayer->audioqueue1 != NULL )
rosfran@64
   190
		g_object_unref (tvplayer->audioqueue1);	
rosfran@64
   191
	if ( tvplayer->audioqueue2 != NULL )
rosfran@64
   192
		g_object_unref (tvplayer->audioqueue2);	
renatofilho@20
   193
renatofilho@20
   194
	G_OBJECT_CLASS (mmyth_tvplayer_parent_class)->finalize (object);
renatofilho@20
   195
}
renatofilho@20
   196
renatofilho@20
   197
/** Creates a new instance of MMythTVPlayer. 
renatofilho@20
   198
 * 
renatofilho@20
   199
 * @return a new instance of MMythTVPlayer.
renatofilho@20
   200
 */
renatofilho@20
   201
MMythTVPlayer *
renatofilho@20
   202
mmyth_tvplayer_new ()
renatofilho@20
   203
{
renatofilho@20
   204
    MMythTVPlayer *tvplayer = 
renatofilho@20
   205
        MMYTH_TVPLAYER (g_object_new(MMYTH_TVPLAYER_TYPE, NULL));
renatofilho@20
   206
    
renatofilho@20
   207
    return tvplayer;
renatofilho@20
   208
}
renatofilho@20
   209
renatofilho@20
   210
/** Initializes the tv player.
renatofilho@20
   211
 *
renatofilho@20
   212
 * @param tvplayer the object instance.
renatofilho@20
   213
 * @return gboolean TRUE if the pipeline was created 
renatofilho@20
   214
 * successfully, FALSE otherwise.
renatofilho@20
   215
 */
renatofilho@20
   216
gboolean
renatofilho@20
   217
mmyth_tvplayer_initialize (MMythTVPlayer *tvplayer)
renatofilho@20
   218
{
renatofilho@20
   219
	
renatofilho@20
   220
    if (!mmyth_tvplayer_create_pipeline (tvplayer)) {
renatofilho@20
   221
    	g_warning ("[%s] Error while creating pipeline. TV Player not initialized", __FUNCTION__);
renatofilho@20
   222
		return FALSE;
renatofilho@20
   223
	} else {
renatofilho@20
   224
		g_debug ("[%s] GStreamer pipeline created", __FUNCTION__);	
renatofilho@20
   225
    }
renatofilho@20
   226
renatofilho@20
   227
	return TRUE;
renatofilho@20
   228
}
renatofilho@20
   229
renatofilho@20
   230
/** Creates the GStreamer pipeline used by the player.
renatofilho@20
   231
 *
renatofilho@20
   232
 * @param tvplayer the object instance.
renatofilho@20
   233
 * @return gboolean TRUE if the pipeline was created 
renatofilho@20
   234
 * successfully, FALSE otherwise.
renatofilho@20
   235
 */
renatofilho@20
   236
static gboolean
renatofilho@20
   237
mmyth_tvplayer_create_pipeline (MMythTVPlayer* tvplayer)
renatofilho@20
   238
{
renatofilho@20
   239
    GstElement *pipeline;
renatofilho@20
   240
    GstElement *source, *parser;
renatofilho@20
   241
    GstElement *videodec, *videosink;
rosfran@64
   242
    GstElement *videocolortrs;
renatofilho@20
   243
#ifndef MAEMO_PLATFORM    
renatofilho@20
   244
    GstElement *audiodec, *audioconv;
renatofilho@20
   245
#endif
renatofilho@20
   246
    GstElement *audiosink;
rosfran@64
   247
    GstElement *videoqueue1, *videoqueue2, *audioqueue1, *audioqueue2;
renatofilho@20
   248
renatofilho@20
   249
    g_debug ("MMythTVPlayer: Setting the Gstreamer pipeline\n");
renatofilho@20
   250
	
renatofilho@20
   251
    pipeline = gst_pipeline_new ("video-player");
renatofilho@20
   252
    source = gst_element_factory_make ("mythtvsrc", "myth-source");
rosfran@64
   253
    parser = gst_element_factory_make ("nuvdemux", "nuv-demux");
renatofilho@20
   254
renatofilho@20
   255
    /* Gstreamer Video elements */
rosfran@64
   256
    videoqueue1 = gst_element_factory_make ("queue", "video-queue1");
rosfran@64
   257
    videodec = gst_element_factory_make ("divxdec", "video-decoder");
rosfran@64
   258
    videoqueue2 = gst_element_factory_make ("queue", "video-queue2");
rosfran@64
   259
    videocolortrs = gst_element_factory_make ("ffmpegcolorspace", "image-color-transforms");
rosfran@64
   260
renatofilho@20
   261
#ifdef MAEMO_PLATFORM
renatofilho@20
   262
    videosink = gst_element_factory_make ("sdlvideosink", "image-output");
renatofilho@20
   263
#else
renatofilho@20
   264
    videosink = gst_element_factory_make ("xvimagesink", "image-output");
renatofilho@20
   265
#endif
renatofilho@20
   266
    
renatofilho@20
   267
    /* Gstreamer Audio elements */
rosfran@64
   268
    audioqueue1 = gst_element_factory_make ("queue", "audio-queue1");    
rosfran@64
   269
    audioqueue2 = gst_element_factory_make ("queue", "audio-queue2");
renatofilho@20
   270
#ifdef MAEMO_PLATFORM    
renatofilho@20
   271
    audiosink = gst_element_factory_make ("dspmp3sink", "audio-output");
renatofilho@20
   272
#else    
rosfran@64
   273
    audiodec = gst_element_factory_make ("mad", "audio-decoder");
renatofilho@20
   274
    audioconv = gst_element_factory_make ("audioconvert", "audio-converter");
renatofilho@20
   275
    audiosink = gst_element_factory_make ("alsasink", "audio-output");
renatofilho@20
   276
#endif    
renatofilho@20
   277
    
renatofilho@20
   278
    if (!(pipeline && source && parser && videodec && videosink) ||
rosfran@64
   279
    	!(videoqueue1 && videoqueue2 && audioqueue1 && audioqueue2 && audiosink)) {
renatofilho@20
   280
        /* FIXME: hanlde the error correctly */
renatofilho@20
   281
        /* video_alignment is not being created (below) 
renatofilho@20
   282
           and is causing problems to the ui */
renatofilho@20
   283
renatofilho@20
   284
	    tvplayer->gst_pipeline = NULL;
renatofilho@20
   285
	    tvplayer->gst_videodec = NULL;
renatofilho@20
   286
	    tvplayer->gst_videosink = NULL;
rosfran@64
   287
	    tvplayer->gst_videocolortrs = NULL;
renatofilho@20
   288
           
renatofilho@20
   289
        g_warning ("GstElement creation error!\n");
renatofilho@20
   290
        return FALSE;
renatofilho@20
   291
    }
renatofilho@20
   292
renatofilho@20
   293
#ifndef MAEMO_PLATFORM    
renatofilho@20
   294
    if (!(audiodec && audioconv)) {
renatofilho@20
   295
        g_warning ("GstElement for audio stream creation error!");
renatofilho@20
   296
        return FALSE;
renatofilho@20
   297
    }
renatofilho@20
   298
#endif    
renatofilho@20
   299
    
renatofilho@20
   300
    tvplayer->gst_pipeline = pipeline;
renatofilho@20
   301
    tvplayer->gst_source = source;
renatofilho@20
   302
    tvplayer->gst_videodec = videodec;
renatofilho@20
   303
    tvplayer->gst_videosink = videosink;
rosfran@64
   304
    tvplayer->gst_videocolortrs = videocolortrs;
renatofilho@20
   305
    g_object_ref (tvplayer->gst_pipeline);
renatofilho@20
   306
    g_object_ref (tvplayer->gst_source);
renatofilho@20
   307
    g_object_ref (tvplayer->gst_videodec);
renatofilho@20
   308
    g_object_ref (tvplayer->gst_videosink);
rosfran@64
   309
    g_object_ref (tvplayer->gst_videocolortrs);
renatofilho@20
   310
rosfran@64
   311
    tvplayer->videoqueue1 = videoqueue1;
rosfran@64
   312
    tvplayer->videoqueue2 = videoqueue2;
rosfran@64
   313
    tvplayer->audioqueue1 = audioqueue1;
rosfran@64
   314
    tvplayer->audioqueue2 = audioqueue2;
rosfran@64
   315
    g_object_ref (tvplayer->videoqueue1);
rosfran@64
   316
    g_object_ref (tvplayer->videoqueue2);
rosfran@64
   317
    g_object_ref (tvplayer->audioqueue1);
rosfran@64
   318
    g_object_ref (tvplayer->audioqueue2);
rosfran@64
   319
  	
renatofilho@20
   320
    g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
renatofilho@20
   321
    g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
renatofilho@20
   322
renatofilho@20
   323
    gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (tvplayer->gst_pipeline)),
renatofilho@20
   324
                       bus_call, tvplayer);
renatofilho@20
   325
rosfran@64
   326
    gst_bin_add_many (GST_BIN (pipeline), source, parser, videoqueue1,
rosfran@64
   327
    			videodec, videoqueue2, videocolortrs, videosink, audioqueue1, 
rosfran@64
   328
			audiodec, audioconv, audioqueue2, audiosink, NULL);
renatofilho@20
   329
renatofilho@20
   330
    {
renatofilho@20
   331
//        GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp", NULL);
renatofilho@20
   332
//        gst_element_link_filtered(source, parser, rtpcaps);
renatofilho@20
   333
    }
renatofilho@20
   334
    
renatofilho@20
   335
    gst_element_link (source, parser);
rosfran@64
   336
    gst_element_link_many (videoqueue1, videodec, videoqueue2, videocolortrs, videosink, NULL);
rosfran@64
   337
    gst_element_link_many (audioqueue1, audiodec, audioconv, audioqueue2, audiosink, NULL);
renatofilho@20
   338
    
renatofilho@20
   339
    g_signal_connect (parser, "pad-added", G_CALLBACK (new_pad_cb), tvplayer);
renatofilho@20
   340
    
renatofilho@20
   341
    return TRUE;
renatofilho@20
   342
}
renatofilho@20
   343
renatofilho@20
   344
/** Configures the backend and the tv player 
renatofilho@20
   345
 * for playing the recorded content A/V.
renatofilho@20
   346
 *
renatofilho@20
   347
 * FIXME: Change filename to program info or other structure about the recorded
renatofilho@20
   348
 *
renatofilho@20
   349
 * @param tvplayer the object instance.
renatofilho@20
   350
 * @param filename the file uri of the recorded content to be played.
renatofilho@20
   351
 * @return TRUE if successfull, FALSE if any error happens.
renatofilho@20
   352
 */
renatofilho@20
   353
gboolean
renatofilho@20
   354
mmyth_tvplayer_record_setup (MMythTVPlayer *tvplayer, gchar *filename)
renatofilho@20
   355
{
renatofilho@20
   356
	GMythSettings *msettings = gmyth_context_get_settings();
renatofilho@20
   357
	
renatofilho@20
   358
	// FIXME: we should receive the uri instead of filename
renatofilho@20
   359
	GString *hostname = gmyth_settings_get_backend_hostname (msettings);
renatofilho@20
   360
	int port = gmyth_settings_get_backend_port(msettings);
renatofilho@20
   361
	
renatofilho@20
   362
	GString *fullpath = g_string_new ("myth://");
renatofilho@20
   363
	g_string_append_printf (fullpath, "%s:%d/%s", hostname->str, port, filename);
renatofilho@20
   364
	
renatofilho@20
   365
	tvplayer->is_livetv = FALSE;
renatofilho@20
   366
renatofilho@20
   367
	g_debug ("[%s] Setting record uri to gstreamer pipeline to %s", __FUNCTION__, fullpath->str);
renatofilho@20
   368
		
renatofilho@20
   369
    g_object_set (G_OBJECT (tvplayer->gst_source), "location",
renatofilho@20
   370
          fullpath->str, NULL);
renatofilho@20
   371
          
renatofilho@20
   372
    return TRUE;
renatofilho@20
   373
}
renatofilho@20
   374
renatofilho@20
   375
/** Configures the backend and the tv player 
renatofilho@20
   376
 * for playing the live tv.
renatofilho@20
   377
 *
renatofilho@20
   378
 * @param tvplayer the object instance.
renatofilho@20
   379
 * @return TRUE if successfull, FALSE if any error happens.
renatofilho@20
   380
 */
renatofilho@20
   381
gboolean
renatofilho@20
   382
mmyth_tvplayer_livetv_setup (MMythTVPlayer *tvplayer)
renatofilho@20
   383
{
renatofilho@20
   384
	GMythSettings *msettings = gmyth_context_get_settings ();
renatofilho@20
   385
	gboolean res = TRUE;
renatofilho@20
   386
renatofilho@20
   387
	res = gmyth_context_check_connection();
renatofilho@20
   388
	if (!res) {
renatofilho@20
   389
		g_warning ("[%s] LiveTV can not connect to backend", __FUNCTION__);	
renatofilho@20
   390
		res = FALSE;
renatofilho@20
   391
		goto error;
renatofilho@20
   392
	}
renatofilho@20
   393
renatofilho@20
   394
	tvplayer->backend_hostname = gmyth_settings_get_backend_hostname(msettings);
renatofilho@20
   395
	tvplayer->backend_port = gmyth_settings_get_backend_port (msettings);
renatofilho@20
   396
renatofilho@20
   397
	tvplayer->local_hostname  = g_string_new("");    
renatofilho@20
   398
	gmyth_context_get_local_hostname (tvplayer->local_hostname);
renatofilho@20
   399
renatofilho@20
   400
	if ( tvplayer->local_hostname == NULL ) {
renatofilho@20
   401
		res = FALSE;
renatofilho@20
   402
		goto error;
renatofilho@20
   403
	}
renatofilho@20
   404
renatofilho@20
   405
	// Gets the remote encoder num
rosfran@64
   406
	tvplayer->recorder = remote_request_next_free_recorder (-1);
renatofilho@20
   407
rosfran@64
   408
	if ( tvplayer->recorder == NULL ) {
renatofilho@20
   409
		g_warning ("[%s] None remote encoder available", __FUNCTION__);
renatofilho@20
   410
		res = FALSE;
renatofilho@20
   411
		goto error;
renatofilho@20
   412
	}
renatofilho@20
   413
renatofilho@20
   414
	// Creates livetv chain handler
renatofilho@20
   415
	tvplayer->tvchain = GMYTH_TVCHAIN ( g_object_new(GMYTH_TVCHAIN_TYPE, NULL) );
renatofilho@20
   416
	gmyth_tvchain_initialize ( tvplayer->tvchain, tvplayer->local_hostname );
renatofilho@20
   417
renatofilho@20
   418
	if ( tvplayer->tvchain == NULL || tvplayer->tvchain->tvchain_id == NULL ) {
renatofilho@20
   419
		res = FALSE;
renatofilho@20
   420
		goto error;
renatofilho@20
   421
	}
renatofilho@20
   422
renatofilho@20
   423
	// Init remote encoder. Opens its control socket.
rosfran@64
   424
	res = gmyth_recorder_setup(tvplayer->recorder);
renatofilho@20
   425
	if ( !res ) {
renatofilho@20
   426
		g_warning ("[%s] Fail while setting remote encoder\n", __FUNCTION__);
renatofilho@20
   427
		res = FALSE;
renatofilho@20
   428
		goto error;
renatofilho@20
   429
	}
renatofilho@20
   430
	// Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly)
rosfran@64
   431
	res = gmyth_recorder_spawntv ( tvplayer->recorder,
renatofilho@20
   432
			gmyth_tvchain_get_id(tvplayer->tvchain) );
renatofilho@20
   433
	if (!res) {
renatofilho@20
   434
		g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__);
renatofilho@20
   435
		res = FALSE;
renatofilho@20
   436
		goto error;
renatofilho@20
   437
	}
renatofilho@20
   438
renatofilho@20
   439
	// Reload all TV chain from Mysql database.
renatofilho@20
   440
	gmyth_tvchain_reload_all (tvplayer->tvchain);
renatofilho@20
   441
renatofilho@20
   442
	if ( tvplayer->tvchain == NULL ) {
renatofilho@20
   443
		res = FALSE;
renatofilho@20
   444
		goto error;
renatofilho@20
   445
	}
renatofilho@20
   446
renatofilho@20
   447
	// Get program info from database using chanid and starttime
renatofilho@20
   448
	tvplayer->proginfo = gmyth_tvchain_get_program_at (tvplayer->tvchain, -1);
renatofilho@20
   449
	if ( tvplayer->proginfo == NULL ) {
renatofilho@20
   450
		g_warning ("[%s] LiveTV not successfully started.\n", __FUNCTION__ );
renatofilho@20
   451
		res = FALSE;
renatofilho@20
   452
		goto error;
renatofilho@20
   453
	} else {
renatofilho@20
   454
		g_debug ("[%s] MythLiveTV: All requests to backend to start TV were OK.\n", __FUNCTION__ );
renatofilho@20
   455
	}
renatofilho@20
   456
renatofilho@20
   457
	return res;
renatofilho@20
   458
renatofilho@20
   459
error:
renatofilho@20
   460
	if ( tvplayer->backend_hostname != NULL ) {
renatofilho@20
   461
		g_string_free( tvplayer->backend_hostname, TRUE );
renatofilho@20
   462
		res = FALSE;
renatofilho@20
   463
	}
renatofilho@20
   464
renatofilho@20
   465
	if ( tvplayer->local_hostname != NULL ) {
renatofilho@20
   466
		g_string_free( tvplayer->local_hostname, TRUE );
renatofilho@20
   467
		res = FALSE;
renatofilho@20
   468
	}
renatofilho@20
   469
rosfran@64
   470
	if ( tvplayer->recorder != NULL ) {
rosfran@64
   471
		g_object_unref (tvplayer->recorder);
rosfran@64
   472
		tvplayer->recorder = NULL;
renatofilho@20
   473
	}
renatofilho@20
   474
renatofilho@20
   475
	if ( tvplayer->tvchain != NULL ) {
renatofilho@20
   476
		g_object_unref (tvplayer->tvchain);
renatofilho@20
   477
		tvplayer->tvchain = NULL;
renatofilho@20
   478
	}
renatofilho@20
   479
renatofilho@20
   480
	if ( tvplayer->proginfo != NULL ) {
renatofilho@20
   481
		g_object_unref (tvplayer->proginfo);
renatofilho@20
   482
		tvplayer->proginfo = NULL;
renatofilho@20
   483
	}
renatofilho@20
   484
renatofilho@20
   485
	return res;
renatofilho@20
   486
renatofilho@20
   487
}
renatofilho@20
   488
renatofilho@20
   489
/** Sets the GTK video widget for the tv player. 
renatofilho@20
   490
 *
renatofilho@20
   491
 * @param tvplayer the object instance.
renatofilho@20
   492
 * @param videow the GTK video window.
renatofilho@20
   493
 * @return TRUE if successfull, FALSE if any error happens.
renatofilho@20
   494
 */
renatofilho@20
   495
gboolean
renatofilho@20
   496
mmyth_tvplayer_set_widget (MMythTVPlayer *tvplayer, GtkWidget *videow)
renatofilho@20
   497
{
renatofilho@20
   498
	tvplayer->videow = videow;
renatofilho@20
   499
	g_object_ref (videow);
renatofilho@20
   500
	
renatofilho@20
   501
	g_debug ("[%s] Setting widget for tv player render", __FUNCTION__);
renatofilho@20
   502
	
renatofilho@20
   503
    tvplayer->expose_handler = g_signal_connect (tvplayer->videow, "expose-event", 
renatofilho@20
   504
                                                 G_CALLBACK (expose_cb), tvplayer);
renatofilho@20
   505
renatofilho@20
   506
    //g_signal_connect(miptv_ui->videow, "size_request", G_CALLBACK(cb_preferred_video_size), miptv_ui);
renatofilho@20
   507
renatofilho@20
   508
    return TRUE;
renatofilho@20
   509
}
renatofilho@20
   510
renatofilho@20
   511
static gboolean
renatofilho@20
   512
bus_call (GstBus * bus, GstMessage * msg, gpointer data)
renatofilho@20
   513
{
renatofilho@20
   514
    //MMythTVPlayer *tvplayer = MMYTH_TVPLAYER ( data );
renatofilho@20
   515
    //GMainLoop *loop = tvplayer->loop;
renatofilho@20
   516
renatofilho@20
   517
    switch (GST_MESSAGE_TYPE (msg)) {
renatofilho@20
   518
        case GST_MESSAGE_EOS:
renatofilho@20
   519
			printf ("End of stream\n");
renatofilho@20
   520
            //g_idle_add ((GSourceFunc) idle_eos, data);
renatofilho@20
   521
            gst_element_set_state ( GST_ELEMENT (GST_MESSAGE_SRC (msg)), GST_STATE_NULL );
rosfran@25
   522
	    gst_element_set_locked_state ( GST_ELEMENT (GST_MESSAGE_SRC (msg)), TRUE );
renatofilho@20
   523
            break;
renatofilho@20
   524
        case GST_MESSAGE_ERROR:
renatofilho@20
   525
        {
renatofilho@20
   526
                gchar *debug;
renatofilho@20
   527
                GError *err;
renatofilho@20
   528
renatofilho@20
   529
                gst_message_parse_error (msg, &err, &debug);
renatofilho@20
   530
                g_free (debug);
renatofilho@20
   531
renatofilho@20
   532
                printf ("Error: %s\n", err->message);
renatofilho@20
   533
                g_error_free (err);
renatofilho@20
   534
renatofilho@20
   535
                //g_main_loop_quit (loop);
renatofilho@20
   536
        }
renatofilho@20
   537
            break;
renatofilho@20
   538
        default:
renatofilho@20
   539
            printf (gst_message_type_get_name (GST_MESSAGE_TYPE (msg)));
renatofilho@20
   540
            printf ("\n");
renatofilho@20
   541
            break;
renatofilho@20
   542
    }
renatofilho@20
   543
renatofilho@20
   544
    return TRUE;
renatofilho@20
   545
}
renatofilho@20
   546
renatofilho@20
   547
renatofilho@20
   548
#if 0
renatofilho@20
   549
static gboolean
renatofilho@20
   550
idle_state (gpointer data)
renatofilho@20
   551
{
renatofilho@20
   552
    GstPlayerWindowStateChange *st = data;
renatofilho@20
   553
renatofilho@20
   554
    if (st->old_state == GST_STATE_PLAYING) {
renatofilho@20
   555
        if (st->miptv_ui->idle_id != 0) {
renatofilho@20
   556
            g_source_remove (st->miptv_ui->idle_id);
renatofilho@20
   557
            st->miptv_ui->idle_id = 0;
renatofilho@20
   558
        }
renatofilho@20
   559
    }
renatofilho@20
   560
    else if (st->new_state == GST_STATE_PLAYING) {
renatofilho@20
   561
        if (st->miptv_ui->idle_id != 0)
renatofilho@20
   562
            g_source_remove (st->miptv_ui->idle_id);
renatofilho@20
   563
renatofilho@20
   564
        st->miptv_ui->idle_id = g_idle_add (cb_iterate, st->miptv_ui);
renatofilho@20
   565
    }
renatofilho@20
   566
renatofilho@20
   567
    /* new movie loaded? */
renatofilho@20
   568
    if (st->old_state == GST_STATE_READY && st->new_state > GST_STATE_READY) {
renatofilho@20
   569
renatofilho@20
   570
        /* gboolean have_video = FALSE; */
renatofilho@20
   571
renatofilho@20
   572
        gtk_widget_show (st->miptv_ui->videow);
renatofilho@20
   573
renatofilho@20
   574
        gtk_window_resize (GTK_WINDOW (st->miptv_ui->main_window), 1, 1);
renatofilho@20
   575
renatofilho@20
   576
    }
renatofilho@20
   577
renatofilho@20
   578
    /* discarded movie? */
renatofilho@20
   579
    if (st->old_state > GST_STATE_READY && st->new_state == GST_STATE_READY) {
renatofilho@20
   580
renatofilho@20
   581
        if (st->miptv_ui->tagcache) {
renatofilho@20
   582
            gst_tag_list_free (st->miptv_ui->tagcache);
renatofilho@20
   583
            st->miptv_ui->tagcache = NULL;
renatofilho@20
   584
        }
renatofilho@20
   585
    }
renatofilho@20
   586
renatofilho@20
   587
    gst_object_unref (GST_OBJECT (st->play));
renatofilho@20
   588
    //g_object_unref (G_OBJECT (st->win));
renatofilho@20
   589
    g_free (st);
renatofilho@20
   590
renatofilho@20
   591
    /* once */
renatofilho@20
   592
    return FALSE;
renatofilho@20
   593
}
renatofilho@20
   594
renatofilho@20
   595
#endif
renatofilho@20
   596
renatofilho@20
   597
/** Stops playing the current A/V.
renatofilho@20
   598
 *
renatofilho@20
   599
 * FIXME: How to proceed differently between livetv 
renatofilho@20
   600
 * and recorded content?
renatofilho@20
   601
 *
renatofilho@20
   602
 * @param tvplayer the object instance.
renatofilho@20
   603
 * @return void 
renatofilho@20
   604
 */
renatofilho@20
   605
void
renatofilho@20
   606
mmyth_tvplayer_stop_playing (MMythTVPlayer *tvplayer) 
renatofilho@20
   607
{
renatofilho@20
   608
    g_debug ("[%s] Setting gstreamer pipeline state to NULL", __FUNCTION__);
renatofilho@20
   609
renatofilho@20
   610
    gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_NULL);
renatofilho@20
   611
    
renatofilho@20
   612
    if (tvplayer->is_livetv) {
rosfran@64
   613
	    if (!gmyth_recorder_stop_livetv (tvplayer->recorder)) {
renatofilho@20
   614
	    	g_warning ("[%s] Error while stoping remote encoder", __FUNCTION__);	
renatofilho@20
   615
	    }
renatofilho@20
   616
    }
renatofilho@20
   617
}
renatofilho@20
   618
renatofilho@20
   619
/** Queries if the tvplayer is active playing A/V content.
renatofilho@20
   620
 *
renatofilho@20
   621
 * @param tvplayer the object instance.
renatofilho@20
   622
 * @return TRUE if the tvplayer is active, FALSE otherwise.
renatofilho@20
   623
 */
renatofilho@20
   624
gboolean
renatofilho@20
   625
mmyth_tvplayer_is_playing (MMythTVPlayer *tvplayer)
renatofilho@20
   626
{
renatofilho@20
   627
	return (GST_STATE (tvplayer->gst_pipeline) == GST_STATE_PLAYING);
renatofilho@20
   628
}
renatofilho@20
   629
renatofilho@20
   630
/** Static function that sets the tvplayer state to PLAYING.
renatofilho@20
   631
 *
renatofilho@20
   632
 * @param tvplayer the object instance.
renatofilho@20
   633
 * @return TRUE if the tvplayer is active, FALSE otherwise.
renatofilho@20
   634
 */
renatofilho@20
   635
static gboolean
renatofilho@20
   636
idle_play (gpointer data)
renatofilho@20
   637
{
renatofilho@20
   638
    MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (data);
renatofilho@20
   639
renatofilho@20
   640
	g_debug ("MMythTVPlayer: Setting pipeline state to PLAYING\n");
renatofilho@20
   641
renatofilho@20
   642
    gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_PLAYING);
renatofilho@20
   643
renatofilho@20
   644
    return FALSE;
renatofilho@20
   645
}
renatofilho@20
   646
renatofilho@20
   647
/** Start playing A/V with the tvplayer attributes.
renatofilho@20
   648
 *
renatofilho@20
   649
 * @param tvplayer the object instance.
renatofilho@20
   650
 */
renatofilho@20
   651
void
renatofilho@20
   652
mmyth_tvplayer_start_playing (MMythTVPlayer *tvplayer)
renatofilho@20
   653
{
renatofilho@20
   654
renatofilho@20
   655
	// FIXME: Move this to livetv_setup??
renatofilho@20
   656
	if (tvplayer->is_livetv) {
renatofilho@20
   657
renatofilho@20
   658
	#if 0
renatofilho@20
   659
		if (!tvplayer || !(tvplayer->proginfo) || !(tvplayer->local_hostname)
renatofilho@20
   660
				|| !(tvplayer->gst_source)) {
renatofilho@20
   661
			g_warning ("GMythtvPlayer not ready to start playing\n");		
renatofilho@20
   662
		}
renatofilho@20
   663
renatofilho@20
   664
		if (!(tvplayer->proginfo->pathname)) {
renatofilho@20
   665
			g_warning ("[%s] Playback url is null, could not play the myth content", __FUNCTION__);
renatofilho@20
   666
			return;
renatofilho@20
   667
		}
renatofilho@20
   668
renatofilho@20
   669
		g_debug ("MMythTVPlayer: Start playing %s", tvplayer->proginfo->pathname->str);
renatofilho@20
   670
#endif
renatofilho@20
   671
		g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live",
renatofilho@20
   672
				TRUE, NULL);
renatofilho@20
   673
#if 0
renatofilho@20
   674
		if ( tvplayer->tvchain != NULL ) {
renatofilho@20
   675
			GString *str_chainid = gmyth_tvchain_get_id(tvplayer->tvchain);
renatofilho@20
   676
			g_print( "[%s]\tCHAIN ID: %s\n", __FUNCTION__, str_chainid->str );
renatofilho@20
   677
renatofilho@20
   678
			g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-chainid", 
renatofilho@20
   679
					g_strdup( str_chainid->str ), NULL);      
renatofilho@20
   680
			if ( str_chainid!=NULL)
renatofilho@20
   681
				g_string_free( str_chainid, FALSE );
renatofilho@20
   682
		}
renatofilho@20
   683
rosfran@64
   684
		if ( tvplayer->recorder != NULL )	
renatofilho@20
   685
			g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-id",
rosfran@64
   686
					tvplayer->recorder->recorder_num, NULL );
renatofilho@20
   687
		g_debug ("[%s] Setting location to %s", __FUNCTION__, 
renatofilho@20
   688
				tvplayer->proginfo->pathname->str);
renatofilho@20
   689
renatofilho@20
   690
		/* Sets the gstreamer properties acording to the service access address */
renatofilho@20
   691
		g_object_set (G_OBJECT (tvplayer->gst_source), "location",
renatofilho@20
   692
				tvplayer->proginfo->pathname->str, NULL);              
renatofilho@20
   693
#endif
renatofilho@20
   694
	}
renatofilho@20
   695
renatofilho@20
   696
	g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-version",
renatofilho@20
   697
              MYTHTV_VERSION_DEFAULT, NULL);
renatofilho@20
   698
renatofilho@20
   699
    g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-debug",
renatofilho@20
   700
              TRUE, NULL);
renatofilho@20
   701
renatofilho@20
   702
    g_idle_add (idle_play, tvplayer);
renatofilho@20
   703
renatofilho@20
   704
}
renatofilho@20
   705