[svn r205] Fixes error on segment event sinding.
4 * @file gmyth/mmyth_tvplayer.c
6 * @brief <p> This component provides playback of the remote A/V using
9 * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
10 * @author Hallyson Luiz de Morais Melo <hallyson.melo@indt.org.br>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "mmyth_tvplayer.h"
33 #include "gmyth_context.h"
34 #include "gmyth_remote_util.h"
36 typedef struct _GstPlayerWindowStateChange
39 GstState old_state, new_state;
40 MMythTVPlayer *tvplayer;
41 } GstPlayerWindowStateChange;
43 typedef struct _GstPlayerWindowTagFound
47 MMythTVPlayer *tvplayer;
48 } GstPlayerWindowTagFound;
51 static gboolean idle_state (gpointer data);
53 static gboolean bus_call (GstBus * bus, GstMessage * msg, gpointer data);
55 static void mmyth_tvplayer_class_init (MMythTVPlayerClass *klass);
56 static void mmyth_tvplayer_init (MMythTVPlayer *object);
58 static void mmyth_tvplayer_dispose (GObject *object);
59 static void mmyth_tvplayer_finalize (GObject *object);
61 G_DEFINE_TYPE(MMythTVPlayer, mmyth_tvplayer, G_TYPE_OBJECT)
63 static gboolean mmyth_tvplayer_create_pipeline (MMythTVPlayer* tvplayer);
64 static void new_pad_cb (GstElement *element,
65 GstPad *pad, gpointer data);
67 static gboolean expose_cb (GtkWidget * widget,
68 GdkEventExpose * event,
72 mmyth_tvplayer_class_init (MMythTVPlayerClass *klass)
74 GObjectClass *gobject_class;
76 gobject_class = (GObjectClass *) klass;
78 gobject_class->dispose = mmyth_tvplayer_dispose;
79 gobject_class->finalize = mmyth_tvplayer_finalize;
83 new_pad_cb (GstElement *element, GstPad *pad, gpointer data)
85 MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (data);
89 s = gst_caps_to_string (pad->caps);
92 ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->audioqueue1, "sink"));
94 ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->videoqueue1, "sink"));
101 expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
103 MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (user_data);
105 if (tvplayer && tvplayer->videow) {
106 gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (tvplayer->gst_videosink),
107 GDK_WINDOW_XWINDOW (widget->window));
111 g_warning ("MMythTVPlayer expose called before setting video window\n");
117 mmyth_tvplayer_init (MMythTVPlayer *tvplayer)
119 tvplayer->gst_pipeline = NULL;
120 tvplayer->gst_source = NULL;
121 tvplayer->gst_videodec = NULL;
122 tvplayer->gst_videosink = NULL;
123 tvplayer->gst_videocolortrs = NULL;
124 tvplayer->videoqueue1 = NULL;
125 tvplayer->videoqueue2 = NULL;
126 tvplayer->audioqueue1 = NULL;
127 tvplayer->audioqueue2 = NULL;
129 /* GTKWidget for rendering the video */
130 tvplayer->videow = NULL;
131 tvplayer->expose_handler = 0;
133 tvplayer->backend_hostname = NULL;
134 tvplayer->backend_port = 0;
135 tvplayer->local_hostname = NULL;
137 tvplayer->recorder = NULL;
138 tvplayer->tvchain = NULL;
139 tvplayer->proginfo = NULL;
143 mmyth_tvplayer_dispose (GObject *object)
146 G_OBJECT_CLASS (mmyth_tvplayer_parent_class)->dispose (object);
150 mmyth_tvplayer_finalize (GObject *object)
152 g_signal_handlers_destroy (object);
154 MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (object);
156 g_debug ("[%s] Finalizing tvplayer", __FUNCTION__);
158 if (tvplayer->videow != NULL) {
159 if (g_signal_handler_is_connected (tvplayer->videow,
160 tvplayer->expose_handler)) {
161 g_signal_handler_disconnect (tvplayer->videow,
162 tvplayer->expose_handler);
164 g_object_unref (tvplayer->videow);
167 if ( tvplayer->recorder != NULL )
168 g_object_unref (tvplayer->recorder);
169 if ( tvplayer->tvchain != NULL )
170 g_object_unref (tvplayer->tvchain);
171 if ( tvplayer->proginfo != NULL )
172 g_object_unref (tvplayer->proginfo);
174 // Release Gstreamer elements
175 if ( tvplayer->gst_pipeline != NULL )
176 g_object_unref (tvplayer->gst_pipeline);
177 if ( tvplayer->gst_source != NULL )
178 g_object_unref (tvplayer->gst_source);
179 if ( tvplayer->gst_videodec != NULL )
180 g_object_unref (tvplayer->gst_videodec);
181 if ( tvplayer->gst_videocolortrs != NULL )
182 g_object_unref (tvplayer->gst_videocolortrs);
183 if ( tvplayer->gst_videosink != NULL )
184 g_object_unref (tvplayer->gst_videosink);
185 if ( tvplayer->videoqueue1 != NULL )
186 g_object_unref (tvplayer->videoqueue1);
187 if ( tvplayer->videoqueue2 != NULL )
188 g_object_unref (tvplayer->videoqueue2);
189 if ( tvplayer->audioqueue1 != NULL )
190 g_object_unref (tvplayer->audioqueue1);
191 if ( tvplayer->audioqueue2 != NULL )
192 g_object_unref (tvplayer->audioqueue2);
194 G_OBJECT_CLASS (mmyth_tvplayer_parent_class)->finalize (object);
197 /** Creates a new instance of MMythTVPlayer.
199 * @return a new instance of MMythTVPlayer.
202 mmyth_tvplayer_new ()
204 MMythTVPlayer *tvplayer =
205 MMYTH_TVPLAYER (g_object_new(MMYTH_TVPLAYER_TYPE, NULL));
210 /** Initializes the tv player.
212 * @param tvplayer the object instance.
213 * @return gboolean TRUE if the pipeline was created
214 * successfully, FALSE otherwise.
217 mmyth_tvplayer_initialize (MMythTVPlayer *tvplayer)
220 if (!mmyth_tvplayer_create_pipeline (tvplayer)) {
221 g_warning ("[%s] Error while creating pipeline. TV Player not initialized", __FUNCTION__);
224 g_debug ("[%s] GStreamer pipeline created", __FUNCTION__);
230 /** Creates the GStreamer pipeline used by the player.
232 * @param tvplayer the object instance.
233 * @return gboolean TRUE if the pipeline was created
234 * successfully, FALSE otherwise.
237 mmyth_tvplayer_create_pipeline (MMythTVPlayer* tvplayer)
239 GstElement *pipeline;
240 GstElement *source, *parser;
241 GstElement *videodec, *videosink;
242 GstElement *videocolortrs;
243 #ifndef MAEMO_PLATFORM
244 GstElement *audiodec, *audioconv;
246 GstElement *audiosink;
247 GstElement *videoqueue1, *videoqueue2, *audioqueue1, *audioqueue2;
249 g_debug ("MMythTVPlayer: Setting the Gstreamer pipeline\n");
251 pipeline = gst_pipeline_new ("video-player");
252 source = gst_element_factory_make ("mythtvsrc", "myth-source");
253 parser = gst_element_factory_make ("nuvdemux", "nuv-demux");
255 /* Gstreamer Video elements */
256 videoqueue1 = gst_element_factory_make ("queue", "video-queue1");
257 videodec = gst_element_factory_make ("ffdec_mpeg4", "video-decoder");
258 videoqueue2 = gst_element_factory_make ("queue", "video-queue2");
259 videocolortrs = gst_element_factory_make ("ffmpegcolorspace", "image-color-transforms");
261 #ifdef MAEMO_PLATFORM
262 videosink = gst_element_factory_make ("sdlvideosink", "image-output");
264 videosink = gst_element_factory_make ("xvimagesink", "image-output");
267 /* Gstreamer Audio elements */
268 audioqueue1 = gst_element_factory_make ("queue", "audio-queue1");
269 audioqueue2 = gst_element_factory_make ("queue", "audio-queue2");
270 #ifdef MAEMO_PLATFORM
271 audiosink = gst_element_factory_make ("dspmp3sink", "audio-output");
273 audiodec = gst_element_factory_make ("mad", "audio-decoder");
274 audioconv = gst_element_factory_make ("audioconvert", "audio-converter");
275 audiosink = gst_element_factory_make ("alsasink", "audio-output");
278 if (!(pipeline && source && parser && videodec && videosink) ||
279 !(videoqueue1 && videoqueue2 && audioqueue1 && audioqueue2 && audiosink)) {
280 /* FIXME: hanlde the error correctly */
281 /* video_alignment is not being created (below)
282 and is causing problems to the ui */
284 tvplayer->gst_pipeline = NULL;
285 tvplayer->gst_videodec = NULL;
286 tvplayer->gst_videosink = NULL;
287 tvplayer->gst_videocolortrs = NULL;
289 g_warning ("GstElement creation error!\n");
293 #ifndef MAEMO_PLATFORM
294 if (!(audiodec && audioconv)) {
295 g_warning ("GstElement for audio stream creation error!");
300 tvplayer->gst_pipeline = pipeline;
301 tvplayer->gst_source = source;
302 tvplayer->gst_videodec = videodec;
303 tvplayer->gst_videosink = videosink;
304 tvplayer->gst_videocolortrs = videocolortrs;
305 g_object_ref (tvplayer->gst_pipeline);
306 g_object_ref (tvplayer->gst_source);
307 g_object_ref (tvplayer->gst_videodec);
308 g_object_ref (tvplayer->gst_videosink);
309 g_object_ref (tvplayer->gst_videocolortrs);
311 tvplayer->videoqueue1 = videoqueue1;
312 tvplayer->videoqueue2 = videoqueue2;
313 tvplayer->audioqueue1 = audioqueue1;
314 tvplayer->audioqueue2 = audioqueue2;
315 g_object_ref (tvplayer->videoqueue1);
316 g_object_ref (tvplayer->videoqueue2);
317 g_object_ref (tvplayer->audioqueue1);
318 g_object_ref (tvplayer->audioqueue2);
320 g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
321 g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL);
323 gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (tvplayer->gst_pipeline)),
326 gst_bin_add_many (GST_BIN (pipeline), source, parser, videoqueue1,
327 videodec, videoqueue2, videocolortrs, videosink, audioqueue1,
328 audiodec, audioconv, audioqueue2, audiosink, NULL);
331 // GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp", NULL);
332 // gst_element_link_filtered(source, parser, rtpcaps);
335 gst_element_link (source, parser);
336 gst_element_link_many (videoqueue1, videodec, videoqueue2, videocolortrs, videosink, NULL);
337 gst_element_link_many (audioqueue1, audiodec, audioconv, audioqueue2, audiosink, NULL);
339 g_signal_connect (parser, "pad-added", G_CALLBACK (new_pad_cb), tvplayer);
344 /** Configures the backend and the tv player
345 * for playing the recorded content A/V.
347 * FIXME: Change filename to program info or other structure about the recorded
349 * @param tvplayer the object instance.
350 * @param filename the file uri of the recorded content to be played.
351 * @return TRUE if successfull, FALSE if any error happens.
354 mmyth_tvplayer_record_setup (MMythTVPlayer *tvplayer, gchar *filename)
356 GMythSettings *msettings = gmyth_context_get_settings();
358 // FIXME: we should receive the uri instead of filename
359 GString *hostname = gmyth_settings_get_backend_hostname (msettings);
360 int port = gmyth_settings_get_backend_port(msettings);
362 GString *fullpath = g_string_new ("myth://");
363 g_string_append_printf (fullpath, "%s:%d/%s", hostname->str, port, filename);
365 tvplayer->is_livetv = FALSE;
367 g_debug ("[%s] Setting record uri to gstreamer pipeline to %s", __FUNCTION__, fullpath->str);
369 g_object_set (G_OBJECT (tvplayer->gst_source), "location",
370 fullpath->str, NULL);
375 /** Configures the backend and the tv player
376 * for playing the live tv.
378 * @param tvplayer the object instance.
379 * @return TRUE if successfull, FALSE if any error happens.
382 mmyth_tvplayer_livetv_setup (MMythTVPlayer *tvplayer)
384 GMythSettings *msettings = gmyth_context_get_settings ();
387 res = gmyth_context_check_connection();
389 g_warning ("[%s] LiveTV can not connect to backend", __FUNCTION__);
394 tvplayer->backend_hostname = gmyth_settings_get_backend_hostname(msettings);
395 tvplayer->backend_port = gmyth_settings_get_backend_port (msettings);
397 tvplayer->local_hostname = g_string_new("");
398 gmyth_context_get_local_hostname (tvplayer->local_hostname);
400 if ( tvplayer->local_hostname == NULL ) {
405 // Gets the remote encoder num
406 tvplayer->recorder = remote_request_next_free_recorder (-1);
408 if ( tvplayer->recorder == NULL ) {
409 g_warning ("[%s] None remote encoder available", __FUNCTION__);
414 // Creates livetv chain handler
415 tvplayer->tvchain = GMYTH_TVCHAIN ( g_object_new(GMYTH_TVCHAIN_TYPE, NULL) );
416 gmyth_tvchain_initialize ( tvplayer->tvchain, tvplayer->local_hostname );
418 if ( tvplayer->tvchain == NULL || tvplayer->tvchain->tvchain_id == NULL ) {
423 // Init remote encoder. Opens its control socket.
424 res = gmyth_recorder_setup(tvplayer->recorder);
426 g_warning ("[%s] Fail while setting remote encoder\n", __FUNCTION__);
430 // Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly)
431 res = gmyth_recorder_spawntv ( tvplayer->recorder,
432 gmyth_tvchain_get_id(tvplayer->tvchain) );
434 g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__);
439 // Reload all TV chain from Mysql database.
440 gmyth_tvchain_reload_all (tvplayer->tvchain);
442 if ( tvplayer->tvchain == NULL ) {
447 // Get program info from database using chanid and starttime
448 tvplayer->proginfo = gmyth_tvchain_get_program_at (tvplayer->tvchain, -1);
449 if ( tvplayer->proginfo == NULL ) {
450 g_warning ("[%s] LiveTV not successfully started.\n", __FUNCTION__ );
454 g_debug ("[%s] MythLiveTV: All requests to backend to start TV were OK.\n", __FUNCTION__ );
460 if ( tvplayer->backend_hostname != NULL ) {
461 g_string_free( tvplayer->backend_hostname, TRUE );
465 if ( tvplayer->local_hostname != NULL ) {
466 g_string_free( tvplayer->local_hostname, TRUE );
470 if ( tvplayer->recorder != NULL ) {
471 g_object_unref (tvplayer->recorder);
472 tvplayer->recorder = NULL;
475 if ( tvplayer->tvchain != NULL ) {
476 g_object_unref (tvplayer->tvchain);
477 tvplayer->tvchain = NULL;
480 if ( tvplayer->proginfo != NULL ) {
481 g_object_unref (tvplayer->proginfo);
482 tvplayer->proginfo = NULL;
489 /** Sets the GTK video widget for the tv player.
491 * @param tvplayer the object instance.
492 * @param videow the GTK video window.
493 * @return TRUE if successfull, FALSE if any error happens.
496 mmyth_tvplayer_set_widget (MMythTVPlayer *tvplayer, GtkWidget *videow)
498 tvplayer->videow = videow;
499 g_object_ref (videow);
501 g_debug ("[%s] Setting widget for tv player render", __FUNCTION__);
503 tvplayer->expose_handler = g_signal_connect (tvplayer->videow, "expose-event",
504 G_CALLBACK (expose_cb), tvplayer);
506 //g_signal_connect(miptv_ui->videow, "size_request", G_CALLBACK(cb_preferred_video_size), miptv_ui);
512 bus_call (GstBus * bus, GstMessage * msg, gpointer data)
514 //MMythTVPlayer *tvplayer = MMYTH_TVPLAYER ( data );
515 //GMainLoop *loop = tvplayer->loop;
517 switch (GST_MESSAGE_TYPE (msg)) {
518 case GST_MESSAGE_EOS:
519 printf ("End of stream\n");
520 //g_idle_add ((GSourceFunc) idle_eos, data);
521 gst_element_set_state ( GST_ELEMENT (GST_MESSAGE_SRC (msg)), GST_STATE_NULL );
522 gst_element_set_locked_state ( GST_ELEMENT (GST_MESSAGE_SRC (msg)), TRUE );
524 case GST_MESSAGE_ERROR:
529 gst_message_parse_error (msg, &err, &debug);
532 printf ("Error: %s\n", err->message);
535 //g_main_loop_quit (loop);
539 printf (gst_message_type_get_name (GST_MESSAGE_TYPE (msg)));
550 idle_state (gpointer data)
552 GstPlayerWindowStateChange *st = data;
554 if (st->old_state == GST_STATE_PLAYING) {
555 if (st->miptv_ui->idle_id != 0) {
556 g_source_remove (st->miptv_ui->idle_id);
557 st->miptv_ui->idle_id = 0;
560 else if (st->new_state == GST_STATE_PLAYING) {
561 if (st->miptv_ui->idle_id != 0)
562 g_source_remove (st->miptv_ui->idle_id);
564 st->miptv_ui->idle_id = g_idle_add (cb_iterate, st->miptv_ui);
567 /* new movie loaded? */
568 if (st->old_state == GST_STATE_READY && st->new_state > GST_STATE_READY) {
570 /* gboolean have_video = FALSE; */
572 gtk_widget_show (st->miptv_ui->videow);
574 gtk_window_resize (GTK_WINDOW (st->miptv_ui->main_window), 1, 1);
578 /* discarded movie? */
579 if (st->old_state > GST_STATE_READY && st->new_state == GST_STATE_READY) {
581 if (st->miptv_ui->tagcache) {
582 gst_tag_list_free (st->miptv_ui->tagcache);
583 st->miptv_ui->tagcache = NULL;
587 gst_object_unref (GST_OBJECT (st->play));
588 //g_object_unref (G_OBJECT (st->win));
597 /** Stops playing the current A/V.
599 * FIXME: How to proceed differently between livetv
600 * and recorded content?
602 * @param tvplayer the object instance.
606 mmyth_tvplayer_stop_playing (MMythTVPlayer *tvplayer)
608 g_debug ("[%s] Setting gstreamer pipeline state to NULL", __FUNCTION__);
610 gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_NULL);
612 if (tvplayer->is_livetv) {
613 if (!gmyth_recorder_stop_livetv (tvplayer->recorder)) {
614 g_warning ("[%s] Error while stoping remote encoder", __FUNCTION__);
619 /** Queries if the tvplayer is active playing A/V content.
621 * @param tvplayer the object instance.
622 * @return TRUE if the tvplayer is active, FALSE otherwise.
625 mmyth_tvplayer_is_playing (MMythTVPlayer *tvplayer)
627 return (GST_STATE (tvplayer->gst_pipeline) == GST_STATE_PLAYING);
630 /** Static function that sets the tvplayer state to PLAYING.
632 * @param tvplayer the object instance.
633 * @return TRUE if the tvplayer is active, FALSE otherwise.
636 idle_play (gpointer data)
638 MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (data);
640 g_debug ("MMythTVPlayer: Setting pipeline state to PLAYING\n");
642 gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_PLAYING);
647 /** Start playing A/V with the tvplayer attributes.
649 * @param tvplayer the object instance.
652 mmyth_tvplayer_start_playing (MMythTVPlayer *tvplayer)
655 // FIXME: Move this to livetv_setup??
656 if (tvplayer->is_livetv) {
659 if (!tvplayer || !(tvplayer->proginfo) || !(tvplayer->local_hostname)
660 || !(tvplayer->gst_source)) {
661 g_warning ("GMythtvPlayer not ready to start playing\n");
664 if (!(tvplayer->proginfo->pathname)) {
665 g_warning ("[%s] Playback url is null, could not play the myth content", __FUNCTION__);
669 g_debug ("MMythTVPlayer: Start playing %s", tvplayer->proginfo->pathname->str);
671 g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live",
674 if ( tvplayer->tvchain != NULL ) {
675 GString *str_chainid = gmyth_tvchain_get_id(tvplayer->tvchain);
676 g_print( "[%s]\tCHAIN ID: %s\n", __FUNCTION__, str_chainid->str );
678 g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-chainid",
679 g_strdup( str_chainid->str ), NULL);
680 if ( str_chainid!=NULL)
681 g_string_free( str_chainid, FALSE );
684 if ( tvplayer->recorder != NULL )
685 g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-id",
686 tvplayer->recorder->recorder_num, NULL );
687 g_debug ("[%s] Setting location to %s", __FUNCTION__,
688 tvplayer->proginfo->pathname->str);
690 /* Sets the gstreamer properties acording to the service access address */
691 g_object_set (G_OBJECT (tvplayer->gst_source), "location",
692 tvplayer->proginfo->pathname->str, NULL);
696 g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-version",
697 MYTHTV_VERSION_DEFAULT, NULL);
699 g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-debug",
702 g_idle_add (idle_play, tvplayer);