renatofilho@20: /** renatofilho@20: * GMyth Library renatofilho@20: * renatofilho@20: * @file gmyth/mmyth_tvplayer.c renatofilho@20: * renatofilho@20: * @brief

This component provides playback of the remote A/V using renatofilho@20: * GStreamer. renatofilho@20: * renatofilho@20: * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia. renatofilho@20: * @author Hallyson Luiz de Morais Melo renatofilho@20: * renatofilho@20: *//* renatofilho@20: * renatofilho@20: * This program is free software; you can redistribute it and/or modify renatofilho@20: * it under the terms of the GNU Lesser General Public License as published by renatofilho@20: * the Free Software Foundation; either version 2 of the License, or renatofilho@20: * (at your option) any later version. renatofilho@20: * renatofilho@20: * This program is distributed in the hope that it will be useful, renatofilho@20: * but WITHOUT ANY WARRANTY; without even the implied warranty of renatofilho@20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the renatofilho@20: * GNU General Public License for more details. renatofilho@20: * renatofilho@20: * You should have received a copy of the GNU Lesser General Public License renatofilho@20: * along with this program; if not, write to the Free Software renatofilho@20: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA renatofilho@20: */ renatofilho@20: renatofilho@20: #include "mmyth_tvplayer.h" renatofilho@20: renatofilho@20: #include renatofilho@20: renatofilho@20: #include "gmyth_context.h" renatofilho@20: #include "gmyth_remote_util.h" renatofilho@20: renatofilho@20: typedef struct _GstPlayerWindowStateChange renatofilho@20: { renatofilho@20: GstElement *play; renatofilho@20: GstState old_state, new_state; renatofilho@20: MMythTVPlayer *tvplayer; renatofilho@20: } GstPlayerWindowStateChange; renatofilho@20: renatofilho@20: typedef struct _GstPlayerWindowTagFound renatofilho@20: { renatofilho@20: GstElement *play; renatofilho@20: GstTagList *taglist; renatofilho@20: MMythTVPlayer *tvplayer; renatofilho@20: } GstPlayerWindowTagFound; renatofilho@20: renatofilho@20: /* renatofilho@20: static gboolean idle_state (gpointer data); renatofilho@20: */ renatofilho@20: static gboolean bus_call (GstBus * bus, GstMessage * msg, gpointer data); renatofilho@20: renatofilho@20: static void mmyth_tvplayer_class_init (MMythTVPlayerClass *klass); renatofilho@20: static void mmyth_tvplayer_init (MMythTVPlayer *object); renatofilho@20: renatofilho@20: static void mmyth_tvplayer_dispose (GObject *object); renatofilho@20: static void mmyth_tvplayer_finalize (GObject *object); renatofilho@20: renatofilho@20: G_DEFINE_TYPE(MMythTVPlayer, mmyth_tvplayer, G_TYPE_OBJECT) renatofilho@20: renatofilho@20: static gboolean mmyth_tvplayer_create_pipeline (MMythTVPlayer* tvplayer); renatofilho@20: static void new_pad_cb (GstElement *element, renatofilho@20: GstPad *pad, gpointer data); renatofilho@20: renatofilho@20: static gboolean expose_cb (GtkWidget * widget, renatofilho@20: GdkEventExpose * event, renatofilho@20: gpointer user_data); renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_tvplayer_class_init (MMythTVPlayerClass *klass) renatofilho@20: { renatofilho@20: GObjectClass *gobject_class; renatofilho@20: renatofilho@20: gobject_class = (GObjectClass *) klass; renatofilho@20: renatofilho@20: gobject_class->dispose = mmyth_tvplayer_dispose; renatofilho@20: gobject_class->finalize = mmyth_tvplayer_finalize; renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: new_pad_cb (GstElement *element, GstPad *pad, gpointer data) renatofilho@20: { renatofilho@20: MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (data); renatofilho@20: GstPadLinkReturn ret; renatofilho@20: char *s; renatofilho@20: renatofilho@20: s = gst_caps_to_string (pad->caps); renatofilho@20: renatofilho@20: if ( s[0] == 'a') { renatofilho@20: ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->audioqueue, "sink")); renatofilho@20: } else { renatofilho@20: ret = gst_pad_link (pad, gst_element_get_pad (tvplayer->videoqueue, "sink")); renatofilho@20: } renatofilho@20: renatofilho@20: g_free(s); renatofilho@20: } renatofilho@20: renatofilho@20: static gboolean renatofilho@20: expose_cb (GtkWidget * widget, GdkEventExpose * event, gpointer user_data) renatofilho@20: { renatofilho@20: MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (user_data); renatofilho@20: renatofilho@20: if (tvplayer && tvplayer->videow) { renatofilho@20: gst_x_overlay_set_xwindow_id (GST_X_OVERLAY (tvplayer->gst_videosink), renatofilho@20: GDK_WINDOW_XWINDOW (widget->window)); renatofilho@20: return TRUE; renatofilho@20: } renatofilho@20: renatofilho@20: g_warning ("MMythTVPlayer expose called before setting video window\n"); renatofilho@20: renatofilho@20: return FALSE; renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_tvplayer_init (MMythTVPlayer *tvplayer) renatofilho@20: { renatofilho@20: tvplayer->gst_pipeline = NULL; renatofilho@20: tvplayer->gst_source = NULL; renatofilho@20: tvplayer->gst_videodec = NULL; renatofilho@20: tvplayer->gst_videosink = NULL; renatofilho@20: tvplayer->videoqueue = NULL; renatofilho@20: tvplayer->audioqueue = NULL; renatofilho@20: renatofilho@20: /* GTKWidget for rendering the video */ renatofilho@20: tvplayer->videow = NULL; renatofilho@20: tvplayer->expose_handler = 0; renatofilho@20: renatofilho@20: tvplayer->backend_hostname = NULL; renatofilho@20: tvplayer->backend_port = 0; renatofilho@20: tvplayer->local_hostname = NULL; renatofilho@20: renatofilho@20: tvplayer->remote_encoder = NULL; renatofilho@20: tvplayer->tvchain = NULL; renatofilho@20: tvplayer->proginfo = NULL; renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_tvplayer_dispose (GObject *object) renatofilho@20: { renatofilho@20: renatofilho@20: G_OBJECT_CLASS (mmyth_tvplayer_parent_class)->dispose (object); renatofilho@20: } renatofilho@20: renatofilho@20: static void renatofilho@20: mmyth_tvplayer_finalize (GObject *object) renatofilho@20: { renatofilho@20: g_signal_handlers_destroy (object); renatofilho@20: renatofilho@20: MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (object); renatofilho@20: renatofilho@20: g_debug ("[%s] Finalizing tvplayer", __FUNCTION__); renatofilho@20: renatofilho@20: if (tvplayer->videow != NULL) { renatofilho@20: if (g_signal_handler_is_connected (tvplayer->videow, renatofilho@20: tvplayer->expose_handler)) { renatofilho@20: g_signal_handler_disconnect (tvplayer->videow, renatofilho@20: tvplayer->expose_handler); renatofilho@20: } renatofilho@20: g_object_unref (tvplayer->videow); renatofilho@20: } renatofilho@20: renatofilho@20: if ( tvplayer->remote_encoder != NULL ) renatofilho@20: g_object_unref (tvplayer->remote_encoder); renatofilho@20: if ( tvplayer->tvchain != NULL ) renatofilho@20: g_object_unref (tvplayer->tvchain); renatofilho@20: if ( tvplayer->proginfo != NULL ) renatofilho@20: g_object_unref (tvplayer->proginfo); renatofilho@20: renatofilho@20: // Release Gstreamer elements renatofilho@20: if ( tvplayer->gst_pipeline != NULL ) renatofilho@20: g_object_unref (tvplayer->gst_pipeline); renatofilho@20: if ( tvplayer->gst_source != NULL ) renatofilho@20: g_object_unref (tvplayer->gst_source); renatofilho@20: if ( tvplayer->gst_videodec != NULL ) renatofilho@20: g_object_unref (tvplayer->gst_videodec); renatofilho@20: if ( tvplayer->gst_videosink != NULL ) renatofilho@20: g_object_unref (tvplayer->gst_videosink); renatofilho@20: if ( tvplayer->videoqueue != NULL ) renatofilho@20: g_object_unref (tvplayer->videoqueue); renatofilho@20: if ( tvplayer->audioqueue != NULL ) renatofilho@20: g_object_unref (tvplayer->audioqueue); renatofilho@20: renatofilho@20: G_OBJECT_CLASS (mmyth_tvplayer_parent_class)->finalize (object); renatofilho@20: } renatofilho@20: renatofilho@20: /** Creates a new instance of MMythTVPlayer. renatofilho@20: * renatofilho@20: * @return a new instance of MMythTVPlayer. renatofilho@20: */ renatofilho@20: MMythTVPlayer * renatofilho@20: mmyth_tvplayer_new () renatofilho@20: { renatofilho@20: MMythTVPlayer *tvplayer = renatofilho@20: MMYTH_TVPLAYER (g_object_new(MMYTH_TVPLAYER_TYPE, NULL)); renatofilho@20: renatofilho@20: return tvplayer; renatofilho@20: } renatofilho@20: renatofilho@20: /** Initializes the tv player. renatofilho@20: * renatofilho@20: * @param tvplayer the object instance. renatofilho@20: * @return gboolean TRUE if the pipeline was created renatofilho@20: * successfully, FALSE otherwise. renatofilho@20: */ renatofilho@20: gboolean renatofilho@20: mmyth_tvplayer_initialize (MMythTVPlayer *tvplayer) renatofilho@20: { renatofilho@20: renatofilho@20: if (!mmyth_tvplayer_create_pipeline (tvplayer)) { renatofilho@20: g_warning ("[%s] Error while creating pipeline. TV Player not initialized", __FUNCTION__); renatofilho@20: return FALSE; renatofilho@20: } else { renatofilho@20: g_debug ("[%s] GStreamer pipeline created", __FUNCTION__); renatofilho@20: } renatofilho@20: renatofilho@20: return TRUE; renatofilho@20: } renatofilho@20: renatofilho@20: /** Creates the GStreamer pipeline used by the player. renatofilho@20: * renatofilho@20: * @param tvplayer the object instance. renatofilho@20: * @return gboolean TRUE if the pipeline was created renatofilho@20: * successfully, FALSE otherwise. renatofilho@20: */ renatofilho@20: static gboolean renatofilho@20: mmyth_tvplayer_create_pipeline (MMythTVPlayer* tvplayer) renatofilho@20: { renatofilho@20: GstElement *pipeline; renatofilho@20: GstElement *source, *parser; renatofilho@20: GstElement *videodec, *videosink; renatofilho@20: #ifndef MAEMO_PLATFORM renatofilho@20: GstElement *audiodec, *audioconv; renatofilho@20: #endif renatofilho@20: GstElement *audiosink; renatofilho@20: GstElement *videoqueue, *audioqueue; renatofilho@20: renatofilho@20: g_debug ("MMythTVPlayer: Setting the Gstreamer pipeline\n"); renatofilho@20: renatofilho@20: pipeline = gst_pipeline_new ("video-player"); renatofilho@20: source = gst_element_factory_make ("mythtvsrc", "myth-source"); renatofilho@20: parser = gst_element_factory_make ("ffdemux_nuv", "nuv-demux"); renatofilho@20: renatofilho@20: /* Gstreamer Video elements */ renatofilho@20: videoqueue = gst_element_factory_make ("queue", "video-queue"); renatofilho@20: videodec = gst_element_factory_make ("ffdec_mpeg4", "video-decoder"); renatofilho@20: #ifdef MAEMO_PLATFORM renatofilho@20: videosink = gst_element_factory_make ("sdlvideosink", "image-output"); renatofilho@20: #else renatofilho@20: videosink = gst_element_factory_make ("xvimagesink", "image-output"); renatofilho@20: #endif renatofilho@20: renatofilho@20: /* Gstreamer Audio elements */ renatofilho@20: audioqueue = gst_element_factory_make ("queue", "audio-queue"); renatofilho@20: #ifdef MAEMO_PLATFORM renatofilho@20: audiosink = gst_element_factory_make ("dspmp3sink", "audio-output"); renatofilho@20: #else renatofilho@20: audiodec = gst_element_factory_make ("ffdec_mp3", "audio-decoder"); renatofilho@20: audioconv = gst_element_factory_make ("audioconvert", "audio-converter"); renatofilho@20: audiosink = gst_element_factory_make ("alsasink", "audio-output"); renatofilho@20: #endif renatofilho@20: renatofilho@20: if (!(pipeline && source && parser && videodec && videosink) || renatofilho@20: !(videoqueue && audioqueue && audiosink)) { renatofilho@20: /* FIXME: hanlde the error correctly */ renatofilho@20: /* video_alignment is not being created (below) renatofilho@20: and is causing problems to the ui */ renatofilho@20: renatofilho@20: tvplayer->gst_pipeline = NULL; renatofilho@20: tvplayer->gst_videodec = NULL; renatofilho@20: tvplayer->gst_videosink = NULL; renatofilho@20: renatofilho@20: g_warning ("GstElement creation error!\n"); renatofilho@20: return FALSE; renatofilho@20: } renatofilho@20: renatofilho@20: #ifndef MAEMO_PLATFORM renatofilho@20: if (!(audiodec && audioconv)) { renatofilho@20: g_warning ("GstElement for audio stream creation error!"); renatofilho@20: return FALSE; renatofilho@20: } renatofilho@20: #endif renatofilho@20: renatofilho@20: renatofilho@20: tvplayer->gst_pipeline = pipeline; renatofilho@20: tvplayer->gst_source = source; renatofilho@20: tvplayer->gst_videodec = videodec; renatofilho@20: tvplayer->gst_videosink = videosink; renatofilho@20: g_object_ref (tvplayer->gst_pipeline); renatofilho@20: g_object_ref (tvplayer->gst_source); renatofilho@20: g_object_ref (tvplayer->gst_videodec); renatofilho@20: g_object_ref (tvplayer->gst_videosink); renatofilho@20: renatofilho@20: tvplayer->videoqueue = videoqueue; renatofilho@20: tvplayer->audioqueue = audioqueue; renatofilho@20: g_object_ref (tvplayer->videoqueue); renatofilho@20: g_object_ref (tvplayer->audioqueue); renatofilho@20: renatofilho@20: g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL); renatofilho@20: g_object_set (G_OBJECT (audiosink), "sync", FALSE, NULL); renatofilho@20: renatofilho@20: gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (tvplayer->gst_pipeline)), renatofilho@20: bus_call, tvplayer); renatofilho@20: renatofilho@20: gst_bin_add_many (GST_BIN (pipeline), source, parser, videoqueue, renatofilho@20: videodec, videosink, audioqueue, audiodec, audioconv, audiosink, NULL); renatofilho@20: renatofilho@20: { renatofilho@20: // GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp", NULL); renatofilho@20: // gst_element_link_filtered(source, parser, rtpcaps); renatofilho@20: } renatofilho@20: renatofilho@20: gst_element_link (source, parser); renatofilho@20: gst_element_link_many (videoqueue, videodec, videosink, NULL); renatofilho@20: gst_element_link_many (audioqueue, audiodec, audioconv, audiosink, NULL); renatofilho@20: renatofilho@20: g_signal_connect (parser, "pad-added", G_CALLBACK (new_pad_cb), tvplayer); renatofilho@20: renatofilho@20: return TRUE; renatofilho@20: } renatofilho@20: renatofilho@20: /** Configures the backend and the tv player renatofilho@20: * for playing the recorded content A/V. renatofilho@20: * renatofilho@20: * FIXME: Change filename to program info or other structure about the recorded renatofilho@20: * renatofilho@20: * @param tvplayer the object instance. renatofilho@20: * @param filename the file uri of the recorded content to be played. renatofilho@20: * @return TRUE if successfull, FALSE if any error happens. renatofilho@20: */ renatofilho@20: gboolean renatofilho@20: mmyth_tvplayer_record_setup (MMythTVPlayer *tvplayer, gchar *filename) renatofilho@20: { renatofilho@20: GMythSettings *msettings = gmyth_context_get_settings(); renatofilho@20: renatofilho@20: // FIXME: we should receive the uri instead of filename renatofilho@20: GString *hostname = gmyth_settings_get_backend_hostname (msettings); renatofilho@20: int port = gmyth_settings_get_backend_port(msettings); renatofilho@20: renatofilho@20: GString *fullpath = g_string_new ("myth://"); renatofilho@20: g_string_append_printf (fullpath, "%s:%d/%s", hostname->str, port, filename); renatofilho@20: renatofilho@20: tvplayer->is_livetv = FALSE; renatofilho@20: renatofilho@20: g_debug ("[%s] Setting record uri to gstreamer pipeline to %s", __FUNCTION__, fullpath->str); renatofilho@20: renatofilho@20: g_object_set (G_OBJECT (tvplayer->gst_source), "location", renatofilho@20: fullpath->str, NULL); renatofilho@20: renatofilho@20: return TRUE; renatofilho@20: } renatofilho@20: renatofilho@20: /** Configures the backend and the tv player renatofilho@20: * for playing the live tv. renatofilho@20: * renatofilho@20: * @param tvplayer the object instance. renatofilho@20: * @return TRUE if successfull, FALSE if any error happens. renatofilho@20: */ renatofilho@20: gboolean renatofilho@20: mmyth_tvplayer_livetv_setup (MMythTVPlayer *tvplayer) renatofilho@20: { renatofilho@20: GMythSettings *msettings = gmyth_context_get_settings (); renatofilho@20: gboolean res = TRUE; renatofilho@20: renatofilho@20: res = gmyth_context_check_connection(); renatofilho@20: if (!res) { renatofilho@20: g_warning ("[%s] LiveTV can not connect to backend", __FUNCTION__); renatofilho@20: res = FALSE; renatofilho@20: goto error; renatofilho@20: } renatofilho@20: renatofilho@20: tvplayer->backend_hostname = gmyth_settings_get_backend_hostname(msettings); renatofilho@20: tvplayer->backend_port = gmyth_settings_get_backend_port (msettings); renatofilho@20: renatofilho@20: tvplayer->local_hostname = g_string_new(""); renatofilho@20: gmyth_context_get_local_hostname (tvplayer->local_hostname); renatofilho@20: renatofilho@20: if ( tvplayer->local_hostname == NULL ) { renatofilho@20: res = FALSE; renatofilho@20: goto error; renatofilho@20: } renatofilho@20: renatofilho@20: // Gets the remote encoder num renatofilho@20: tvplayer->remote_encoder = remote_request_next_free_recorder (-1); renatofilho@20: renatofilho@20: if ( tvplayer->remote_encoder == NULL ) { renatofilho@20: g_warning ("[%s] None remote encoder available", __FUNCTION__); renatofilho@20: res = FALSE; renatofilho@20: goto error; renatofilho@20: } renatofilho@20: renatofilho@20: // Creates livetv chain handler renatofilho@20: tvplayer->tvchain = GMYTH_TVCHAIN ( g_object_new(GMYTH_TVCHAIN_TYPE, NULL) ); renatofilho@20: gmyth_tvchain_initialize ( tvplayer->tvchain, tvplayer->local_hostname ); renatofilho@20: renatofilho@20: if ( tvplayer->tvchain == NULL || tvplayer->tvchain->tvchain_id == NULL ) { renatofilho@20: res = FALSE; renatofilho@20: goto error; renatofilho@20: } renatofilho@20: renatofilho@20: // Init remote encoder. Opens its control socket. renatofilho@20: res = gmyth_remote_encoder_setup(tvplayer->remote_encoder); renatofilho@20: if ( !res ) { renatofilho@20: g_warning ("[%s] Fail while setting remote encoder\n", __FUNCTION__); renatofilho@20: res = FALSE; renatofilho@20: goto error; renatofilho@20: } renatofilho@20: // Spawn live tv. Uses the socket to send mythprotocol data to start livetv in the backend (remotelly) renatofilho@20: res = gmyth_remote_encoder_spawntv ( tvplayer->remote_encoder, renatofilho@20: gmyth_tvchain_get_id(tvplayer->tvchain) ); renatofilho@20: if (!res) { renatofilho@20: g_warning ("[%s] Fail while spawn tv\n", __FUNCTION__); renatofilho@20: res = FALSE; renatofilho@20: goto error; renatofilho@20: } renatofilho@20: renatofilho@20: // Reload all TV chain from Mysql database. renatofilho@20: gmyth_tvchain_reload_all (tvplayer->tvchain); renatofilho@20: renatofilho@20: if ( tvplayer->tvchain == NULL ) { renatofilho@20: res = FALSE; renatofilho@20: goto error; renatofilho@20: } renatofilho@20: renatofilho@20: // Get program info from database using chanid and starttime renatofilho@20: tvplayer->proginfo = gmyth_tvchain_get_program_at (tvplayer->tvchain, -1); renatofilho@20: if ( tvplayer->proginfo == NULL ) { renatofilho@20: g_warning ("[%s] LiveTV not successfully started.\n", __FUNCTION__ ); renatofilho@20: res = FALSE; renatofilho@20: goto error; renatofilho@20: } else { renatofilho@20: g_debug ("[%s] MythLiveTV: All requests to backend to start TV were OK.\n", __FUNCTION__ ); renatofilho@20: } renatofilho@20: renatofilho@20: return res; renatofilho@20: renatofilho@20: error: renatofilho@20: if ( tvplayer->backend_hostname != NULL ) { renatofilho@20: g_string_free( tvplayer->backend_hostname, TRUE ); renatofilho@20: res = FALSE; renatofilho@20: } renatofilho@20: renatofilho@20: if ( tvplayer->local_hostname != NULL ) { renatofilho@20: g_string_free( tvplayer->local_hostname, TRUE ); renatofilho@20: res = FALSE; renatofilho@20: } renatofilho@20: renatofilho@20: if ( tvplayer->remote_encoder != NULL ) { renatofilho@20: g_object_unref (tvplayer->remote_encoder); renatofilho@20: tvplayer->remote_encoder = NULL; renatofilho@20: } renatofilho@20: renatofilho@20: if ( tvplayer->tvchain != NULL ) { renatofilho@20: g_object_unref (tvplayer->tvchain); renatofilho@20: tvplayer->tvchain = NULL; renatofilho@20: } renatofilho@20: renatofilho@20: if ( tvplayer->proginfo != NULL ) { renatofilho@20: g_object_unref (tvplayer->proginfo); renatofilho@20: tvplayer->proginfo = NULL; renatofilho@20: } renatofilho@20: renatofilho@20: return res; renatofilho@20: renatofilho@20: } renatofilho@20: renatofilho@20: /** Sets the GTK video widget for the tv player. renatofilho@20: * renatofilho@20: * @param tvplayer the object instance. renatofilho@20: * @param videow the GTK video window. renatofilho@20: * @return TRUE if successfull, FALSE if any error happens. renatofilho@20: */ renatofilho@20: gboolean renatofilho@20: mmyth_tvplayer_set_widget (MMythTVPlayer *tvplayer, GtkWidget *videow) renatofilho@20: { renatofilho@20: tvplayer->videow = videow; renatofilho@20: g_object_ref (videow); renatofilho@20: renatofilho@20: g_debug ("[%s] Setting widget for tv player render", __FUNCTION__); renatofilho@20: renatofilho@20: tvplayer->expose_handler = g_signal_connect (tvplayer->videow, "expose-event", renatofilho@20: G_CALLBACK (expose_cb), tvplayer); renatofilho@20: renatofilho@20: //g_signal_connect(miptv_ui->videow, "size_request", G_CALLBACK(cb_preferred_video_size), miptv_ui); renatofilho@20: renatofilho@20: return TRUE; renatofilho@20: } renatofilho@20: renatofilho@20: static gboolean renatofilho@20: bus_call (GstBus * bus, GstMessage * msg, gpointer data) renatofilho@20: { renatofilho@20: //MMythTVPlayer *tvplayer = MMYTH_TVPLAYER ( data ); renatofilho@20: //GMainLoop *loop = tvplayer->loop; renatofilho@20: renatofilho@20: switch (GST_MESSAGE_TYPE (msg)) { renatofilho@20: case GST_MESSAGE_EOS: renatofilho@20: printf ("End of stream\n"); renatofilho@20: //g_idle_add ((GSourceFunc) idle_eos, data); renatofilho@20: gst_element_set_state ( GST_ELEMENT (GST_MESSAGE_SRC (msg)), GST_STATE_NULL ); renatofilho@20: gst_element_set_locked_state ( GST_ELEMENT (GST_MESSAGE_SRC (msg)), FALSE ); renatofilho@20: break; renatofilho@20: case GST_MESSAGE_ERROR: renatofilho@20: { renatofilho@20: gchar *debug; renatofilho@20: GError *err; renatofilho@20: renatofilho@20: gst_message_parse_error (msg, &err, &debug); renatofilho@20: g_free (debug); renatofilho@20: renatofilho@20: printf ("Error: %s\n", err->message); renatofilho@20: g_error_free (err); renatofilho@20: renatofilho@20: //g_main_loop_quit (loop); renatofilho@20: } renatofilho@20: break; renatofilho@20: default: renatofilho@20: printf (gst_message_type_get_name (GST_MESSAGE_TYPE (msg))); renatofilho@20: printf ("\n"); renatofilho@20: break; renatofilho@20: } renatofilho@20: renatofilho@20: return TRUE; renatofilho@20: } renatofilho@20: renatofilho@20: renatofilho@20: #if 0 renatofilho@20: static gboolean renatofilho@20: idle_state (gpointer data) renatofilho@20: { renatofilho@20: GstPlayerWindowStateChange *st = data; renatofilho@20: renatofilho@20: if (st->old_state == GST_STATE_PLAYING) { renatofilho@20: if (st->miptv_ui->idle_id != 0) { renatofilho@20: g_source_remove (st->miptv_ui->idle_id); renatofilho@20: st->miptv_ui->idle_id = 0; renatofilho@20: } renatofilho@20: } renatofilho@20: else if (st->new_state == GST_STATE_PLAYING) { renatofilho@20: if (st->miptv_ui->idle_id != 0) renatofilho@20: g_source_remove (st->miptv_ui->idle_id); renatofilho@20: renatofilho@20: st->miptv_ui->idle_id = g_idle_add (cb_iterate, st->miptv_ui); renatofilho@20: } renatofilho@20: renatofilho@20: /* new movie loaded? */ renatofilho@20: if (st->old_state == GST_STATE_READY && st->new_state > GST_STATE_READY) { renatofilho@20: renatofilho@20: /* gboolean have_video = FALSE; */ renatofilho@20: renatofilho@20: gtk_widget_show (st->miptv_ui->videow); renatofilho@20: renatofilho@20: gtk_window_resize (GTK_WINDOW (st->miptv_ui->main_window), 1, 1); renatofilho@20: renatofilho@20: } renatofilho@20: renatofilho@20: /* discarded movie? */ renatofilho@20: if (st->old_state > GST_STATE_READY && st->new_state == GST_STATE_READY) { renatofilho@20: renatofilho@20: if (st->miptv_ui->tagcache) { renatofilho@20: gst_tag_list_free (st->miptv_ui->tagcache); renatofilho@20: st->miptv_ui->tagcache = NULL; renatofilho@20: } renatofilho@20: } renatofilho@20: renatofilho@20: gst_object_unref (GST_OBJECT (st->play)); renatofilho@20: //g_object_unref (G_OBJECT (st->win)); renatofilho@20: g_free (st); renatofilho@20: renatofilho@20: /* once */ renatofilho@20: return FALSE; renatofilho@20: } renatofilho@20: renatofilho@20: #endif renatofilho@20: renatofilho@20: /** Stops playing the current A/V. renatofilho@20: * renatofilho@20: * FIXME: How to proceed differently between livetv renatofilho@20: * and recorded content? renatofilho@20: * renatofilho@20: * @param tvplayer the object instance. renatofilho@20: * @return void renatofilho@20: */ renatofilho@20: void renatofilho@20: mmyth_tvplayer_stop_playing (MMythTVPlayer *tvplayer) renatofilho@20: { renatofilho@20: g_debug ("[%s] Setting gstreamer pipeline state to NULL", __FUNCTION__); renatofilho@20: renatofilho@20: gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_NULL); renatofilho@20: renatofilho@20: if (tvplayer->is_livetv) { renatofilho@20: if (!gmyth_remote_encoder_stop_livetv (tvplayer->remote_encoder)) { renatofilho@20: g_warning ("[%s] Error while stoping remote encoder", __FUNCTION__); renatofilho@20: } renatofilho@20: } renatofilho@20: } renatofilho@20: renatofilho@20: /** Queries if the tvplayer is active playing A/V content. renatofilho@20: * renatofilho@20: * @param tvplayer the object instance. renatofilho@20: * @return TRUE if the tvplayer is active, FALSE otherwise. renatofilho@20: */ renatofilho@20: gboolean renatofilho@20: mmyth_tvplayer_is_playing (MMythTVPlayer *tvplayer) renatofilho@20: { renatofilho@20: return (GST_STATE (tvplayer->gst_pipeline) == GST_STATE_PLAYING); renatofilho@20: } renatofilho@20: renatofilho@20: /** Static function that sets the tvplayer state to PLAYING. renatofilho@20: * renatofilho@20: * @param tvplayer the object instance. renatofilho@20: * @return TRUE if the tvplayer is active, FALSE otherwise. renatofilho@20: */ renatofilho@20: static gboolean renatofilho@20: idle_play (gpointer data) renatofilho@20: { renatofilho@20: MMythTVPlayer *tvplayer = MMYTH_TVPLAYER (data); renatofilho@20: renatofilho@20: g_debug ("MMythTVPlayer: Setting pipeline state to PLAYING\n"); renatofilho@20: renatofilho@20: gst_element_set_state (tvplayer->gst_pipeline, GST_STATE_PLAYING); renatofilho@20: renatofilho@20: return FALSE; renatofilho@20: } renatofilho@20: renatofilho@20: /** Start playing A/V with the tvplayer attributes. renatofilho@20: * renatofilho@20: * @param tvplayer the object instance. renatofilho@20: */ renatofilho@20: void renatofilho@20: mmyth_tvplayer_start_playing (MMythTVPlayer *tvplayer) renatofilho@20: { renatofilho@20: renatofilho@20: // FIXME: Move this to livetv_setup?? renatofilho@20: if (tvplayer->is_livetv) { renatofilho@20: renatofilho@20: #if 0 renatofilho@20: if (!tvplayer || !(tvplayer->proginfo) || !(tvplayer->local_hostname) renatofilho@20: || !(tvplayer->gst_source)) { renatofilho@20: g_warning ("GMythtvPlayer not ready to start playing\n"); renatofilho@20: } renatofilho@20: renatofilho@20: if (!(tvplayer->proginfo->pathname)) { renatofilho@20: g_warning ("[%s] Playback url is null, could not play the myth content", __FUNCTION__); renatofilho@20: return; renatofilho@20: } renatofilho@20: renatofilho@20: g_debug ("MMythTVPlayer: Start playing %s", tvplayer->proginfo->pathname->str); renatofilho@20: #endif renatofilho@20: g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live", renatofilho@20: TRUE, NULL); renatofilho@20: #if 0 renatofilho@20: if ( tvplayer->tvchain != NULL ) { renatofilho@20: GString *str_chainid = gmyth_tvchain_get_id(tvplayer->tvchain); renatofilho@20: g_print( "[%s]\tCHAIN ID: %s\n", __FUNCTION__, str_chainid->str ); renatofilho@20: renatofilho@20: g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-chainid", renatofilho@20: g_strdup( str_chainid->str ), NULL); renatofilho@20: if ( str_chainid!=NULL) renatofilho@20: g_string_free( str_chainid, FALSE ); renatofilho@20: } renatofilho@20: renatofilho@20: if ( tvplayer->remote_encoder != NULL ) renatofilho@20: g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-live-id", renatofilho@20: tvplayer->remote_encoder->recorder_num, NULL ); renatofilho@20: g_debug ("[%s] Setting location to %s", __FUNCTION__, renatofilho@20: tvplayer->proginfo->pathname->str); renatofilho@20: renatofilho@20: /* Sets the gstreamer properties acording to the service access address */ renatofilho@20: g_object_set (G_OBJECT (tvplayer->gst_source), "location", renatofilho@20: tvplayer->proginfo->pathname->str, NULL); renatofilho@20: #endif renatofilho@20: } renatofilho@20: renatofilho@20: g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-version", renatofilho@20: MYTHTV_VERSION_DEFAULT, NULL); renatofilho@20: renatofilho@20: g_object_set (G_OBJECT (tvplayer->gst_source), "mythtv-debug", renatofilho@20: TRUE, NULL); renatofilho@20: renatofilho@20: g_idle_add (idle_play, tvplayer); renatofilho@20: renatofilho@20: } renatofilho@20: