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@754: *//*
renatofilho@754: *
renatofilho@754: * This program is free software; you can redistribute it and/or modify
renatofilho@754: * it under the terms of the GNU Lesser General Public License as published by
renatofilho@754: * the Free Software Foundation; either version 2 of the License, or
renatofilho@754: * (at your option) any later version.
renatofilho@754: *
renatofilho@754: * This program is distributed in the hope that it will be useful,
renatofilho@754: * but WITHOUT ANY WARRANTY; without even the implied warranty of
renatofilho@754: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
renatofilho@754: * GNU General Public License for more details.
renatofilho@754: *
renatofilho@754: * You should have received a copy of the GNU Lesser General Public License
renatofilho@754: * along with this program; if not, write to the Free Software
renatofilho@754: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
renatofilho@754: */
renatofilho@20:
renatofilho@20: #include "mmyth_tvplayer.h"
renatofilho@754:
renatofilho@20: #include
renatofilho@20:
rosfran@208: #include
rosfran@208:
rosfran@208: #define MYTHTV_VERSION_DEFAULT 30
renatofilho@20:
renatofilho@754: typedef struct _GstPlayerWindowStateChange {
renatofilho@754: GstElement *play;
renatofilho@754: GstState old_state,
renatofilho@754: new_state;
renatofilho@754: MMythTVPlayer *tvplayer;
renatofilho@20: } GstPlayerWindowStateChange;
renatofilho@20:
renatofilho@754: typedef struct _GstPlayerWindowTagFound {
renatofilho@754: GstElement *play;
renatofilho@754: GstTagList *taglist;
renatofilho@754: MMythTVPlayer *tvplayer;
renatofilho@20: } GstPlayerWindowTagFound;
renatofilho@20:
renatofilho@20: /*
renatofilho@754: * static gboolean idle_state (gpointer data);
renatofilho@754: */
renatofilho@754: static gboolean bus_call(GstBus * bus, GstMessage * msg, gpointer data);
renatofilho@20:
renatofilho@754: static void mmyth_tvplayer_class_init(MMythTVPlayerClass * klass);
renatofilho@754: static void mmyth_tvplayer_init(MMythTVPlayer * object);
renatofilho@20:
renatofilho@754: static void mmyth_tvplayer_dispose(GObject * object);
renatofilho@754: static void mmyth_tvplayer_finalize(GObject * object);
renatofilho@20:
renatofilho@20: G_DEFINE_TYPE(MMythTVPlayer, mmyth_tvplayer, G_TYPE_OBJECT)
renatofilho@20:
renatofilho@754: static gboolean mmyth_tvplayer_create_pipeline(MMythTVPlayer *
renatofilho@754: tvplayer);
renatofilho@754: static void new_pad_cb(GstElement * element, GstPad * pad,
renatofilho@754: gpointer data);
renatofilho@20:
renatofilho@754: static gboolean expose_cb(GtkWidget * widget,
renatofilho@754: GdkEventExpose * event, gpointer user_data);
renatofilho@20:
renatofilho@754: static void
renatofilho@754: mmyth_tvplayer_class_init(MMythTVPlayerClass * klass)
renatofilho@20: {
renatofilho@754: GObjectClass *gobject_class;
renatofilho@20:
renatofilho@754: gobject_class = (GObjectClass *) klass;
rosfran@208:
renatofilho@754: gobject_class->dispose = mmyth_tvplayer_dispose;
renatofilho@754: gobject_class->finalize = mmyth_tvplayer_finalize;
renatofilho@20: }
renatofilho@20:
renatofilho@20: static void
renatofilho@754: new_pad_cb(GstElement * element, GstPad * pad, gpointer data)
renatofilho@20: {
renatofilho@754: MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(data);
renatofilho@754: GstPadLinkReturn ret;
renatofilho@754: char *s;
renatofilho@20:
renatofilho@754: s = gst_caps_to_string(pad->caps);
renatofilho@754:
renatofilho@754: if (s[0] == 'a') {
renatofilho@754: ret =
renatofilho@754: gst_pad_link(pad,
renatofilho@754: gst_element_get_pad(tvplayer->audioqueue1,
renatofilho@754: "sink"));
renatofilho@754: } else {
renatofilho@754: ret =
renatofilho@754: gst_pad_link(pad,
renatofilho@754: gst_element_get_pad(tvplayer->videoqueue1,
renatofilho@754: "sink"));
renatofilho@754: }
renatofilho@754:
renatofilho@754: g_free(s);
renatofilho@20: }
renatofilho@20:
renatofilho@754: static gboolean
renatofilho@754: expose_cb(GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
renatofilho@20: {
renatofilho@754: MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(user_data);
renatofilho@20:
renatofilho@754: if (tvplayer && tvplayer->videow) {
renatofilho@754: gst_x_overlay_set_xwindow_id(GST_X_OVERLAY
renatofilho@754: (tvplayer->gst_videosink),
renatofilho@754: GDK_WINDOW_XWINDOW(widget->window));
renatofilho@754: return TRUE;
renatofilho@754: }
rosfran@64:
renatofilho@754: g_warning("MMythTVPlayer expose called before setting video window\n");
rosfran@64:
renatofilho@754: return FALSE;
renatofilho@20: }
renatofilho@20:
renatofilho@20: static void
renatofilho@754: mmyth_tvplayer_init(MMythTVPlayer * tvplayer)
renatofilho@20: {
renatofilho@754: tvplayer->gst_pipeline = NULL;
renatofilho@754: tvplayer->gst_source = NULL;
renatofilho@754: tvplayer->gst_videodec = NULL;
renatofilho@754: tvplayer->gst_videosink = NULL;
renatofilho@754: tvplayer->gst_videocolortrs = NULL;
renatofilho@754: tvplayer->videoqueue1 = NULL;
renatofilho@754: tvplayer->videoqueue2 = NULL;
renatofilho@754: tvplayer->audioqueue1 = NULL;
renatofilho@754: tvplayer->audioqueue2 = NULL;
rosfran@64:
renatofilho@754: /*
renatofilho@754: * GTKWidget for rendering the video
renatofilho@754: */
renatofilho@754: tvplayer->videow = NULL;
renatofilho@754: tvplayer->expose_handler = 0;
rosfran@64:
renatofilho@754: tvplayer->backend_hostname = NULL;
renatofilho@754: tvplayer->backend_port = 0;
renatofilho@754: tvplayer->local_hostname = NULL;
renatofilho@20:
renatofilho@754: tvplayer->recorder = NULL;
renatofilho@754: tvplayer->tvchain = NULL;
renatofilho@754: tvplayer->proginfo = NULL;
renatofilho@20: }
renatofilho@20:
renatofilho@20: static void
renatofilho@754: mmyth_tvplayer_dispose(GObject * object)
renatofilho@20: {
renatofilho@20:
renatofilho@754: G_OBJECT_CLASS(mmyth_tvplayer_parent_class)->dispose(object);
renatofilho@20: }
renatofilho@20:
renatofilho@20: static void
renatofilho@754: mmyth_tvplayer_finalize(GObject * object)
renatofilho@20: {
renatofilho@754: g_signal_handlers_destroy(object);
renatofilho@20:
renatofilho@754: MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(object);
renatofilho@20:
renatofilho@754: g_debug("[%s] Finalizing tvplayer", __FUNCTION__);
renatofilho@20:
renatofilho@754: if (tvplayer->videow != NULL) {
renatofilho@754: if (g_signal_handler_is_connected(tvplayer->videow,
renatofilho@754: tvplayer->expose_handler)) {
renatofilho@754: g_signal_handler_disconnect(tvplayer->videow,
renatofilho@754: tvplayer->expose_handler);
renatofilho@754: }
renatofilho@754: g_object_unref(tvplayer->videow);
renatofilho@754: }
renatofilho@20:
renatofilho@754: if (tvplayer->recorder != NULL)
renatofilho@754: g_object_unref(tvplayer->recorder);
renatofilho@754: if (tvplayer->tvchain != NULL)
renatofilho@754: g_object_unref(tvplayer->tvchain);
renatofilho@754: if (tvplayer->proginfo != NULL)
renatofilho@754: g_object_unref(tvplayer->proginfo);
renatofilho@754:
renatofilho@754: // Release Gstreamer elements
renatofilho@754: if (tvplayer->gst_pipeline != NULL)
renatofilho@754: g_object_unref(tvplayer->gst_pipeline);
renatofilho@754: if (tvplayer->gst_source != NULL)
renatofilho@754: g_object_unref(tvplayer->gst_source);
renatofilho@754: if (tvplayer->gst_videodec != NULL)
renatofilho@754: g_object_unref(tvplayer->gst_videodec);
renatofilho@754: if (tvplayer->gst_videocolortrs != NULL)
renatofilho@754: g_object_unref(tvplayer->gst_videocolortrs);
renatofilho@754: if (tvplayer->gst_videosink != NULL)
renatofilho@754: g_object_unref(tvplayer->gst_videosink);
renatofilho@754: if (tvplayer->videoqueue1 != NULL)
renatofilho@754: g_object_unref(tvplayer->videoqueue1);
renatofilho@754: if (tvplayer->videoqueue2 != NULL)
renatofilho@754: g_object_unref(tvplayer->videoqueue2);
renatofilho@754: if (tvplayer->audioqueue1 != NULL)
renatofilho@754: g_object_unref(tvplayer->audioqueue1);
renatofilho@754: if (tvplayer->audioqueue2 != NULL)
renatofilho@754: g_object_unref(tvplayer->audioqueue2);
renatofilho@754:
renatofilho@754: 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@754: MMythTVPlayer *
renatofilho@754: mmyth_tvplayer_new()
renatofilho@20: {
renatofilho@754: MMythTVPlayer *tvplayer =
renatofilho@754: MMYTH_TVPLAYER(g_object_new(MMYTH_TVPLAYER_TYPE, NULL));
renatofilho@754:
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@754: mmyth_tvplayer_initialize(MMythTVPlayer * tvplayer,
renatofilho@754: GMythBackendInfo * backend_info)
renatofilho@20: {
renatofilho@754: tvplayer->backend_info = backend_info;
rosfran@208:
renatofilho@754: if (!mmyth_tvplayer_create_pipeline(tvplayer)) {
renatofilho@754: g_warning
renatofilho@754: ("[%s] Error while creating pipeline. TV Player not initialized",
renatofilho@754: __FUNCTION__);
renatofilho@754: return FALSE;
renatofilho@754: } else {
renatofilho@754: g_debug("[%s] GStreamer pipeline created", __FUNCTION__);
renatofilho@754: }
renatofilho@20:
renatofilho@754: 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@754: static gboolean
renatofilho@754: mmyth_tvplayer_create_pipeline(MMythTVPlayer * tvplayer)
renatofilho@20: {
renatofilho@754: GstElement *pipeline;
renatofilho@754: GstElement *source,
renatofilho@754: *parser;
renatofilho@754: GstElement *videodec,
renatofilho@754: *videosink;
renatofilho@754: GstElement *videocolortrs;
renatofilho@754: #ifndef MAEMO_PLATFORM
renatofilho@754: GstElement *audiodec,
renatofilho@754: *audioconv,
renatofilho@754: *audioqueue2;
renatofilho@20: #endif
renatofilho@754: GstElement *audiosink;
renatofilho@754: GstElement *videoqueue1,
renatofilho@754: *videoqueue2,
renatofilho@754: *audioqueue1;
renatofilho@20:
renatofilho@754: g_debug("MMythTVPlayer: Setting the Gstreamer pipeline\n");
renatofilho@20:
renatofilho@754: pipeline = gst_pipeline_new("video-player");
renatofilho@754: source = gst_element_factory_make("mythtvsrc", "myth-source");
renatofilho@754: parser = gst_element_factory_make("nuvdemux", "nuv-demux");
renatofilho@754:
renatofilho@754: /*
renatofilho@754: * Gstreamer Video elements
renatofilho@754: */
renatofilho@754: videoqueue1 = gst_element_factory_make("queue", "video-queue1");
renatofilho@754: videodec = gst_element_factory_make("ffdec_mpeg4", "video-decoder");
renatofilho@754: videoqueue2 = gst_element_factory_make("queue", "video-queue2");
renatofilho@754: videocolortrs =
renatofilho@754: gst_element_factory_make("ffmpegcolorspace",
renatofilho@754: "image-color-transforms");
rosfran@64:
renatofilho@20: #ifdef MAEMO_PLATFORM
renatofilho@754: videosink = gst_element_factory_make("sdlvideosink", "image-output");
renatofilho@20: #else
renatofilho@754: videosink = gst_element_factory_make("xvimagesink", "image-output");
renatofilho@20: #endif
renatofilho@754:
renatofilho@754: /*
renatofilho@754: * Gstreamer Audio elements
renatofilho@754: */
renatofilho@754: audioqueue1 = gst_element_factory_make("queue", "audio-queue1");
renatofilho@754: #ifdef MAEMO_PLATFORM
renatofilho@754: audiosink = gst_element_factory_make("dspmp3sink", "audio-output");
renatofilho@754: #else
renatofilho@754: audioqueue2 = gst_element_factory_make("queue", "audio-queue2");
renatofilho@754: audiodec = gst_element_factory_make("mad", "audio-decoder");
renatofilho@754: audioconv =
renatofilho@754: gst_element_factory_make("audioconvert", "audio-converter");
renatofilho@754: audiosink = gst_element_factory_make("alsasink", "audio-output");
renatofilho@754: #endif
renatofilho@754:
renatofilho@20: if (!(pipeline && source && parser && videodec && videosink) ||
renatofilho@754: !(videoqueue1 && videoqueue2 && audioqueue1 && audiosink)) {
renatofilho@754: /*
renatofilho@754: * FIXME: hanlde the error correctly
renatofilho@754: */
renatofilho@754: /*
renatofilho@754: * video_alignment is not being created (below) and is causing
renatofilho@754: * problems to the ui
renatofilho@754: */
renatofilho@20:
renatofilho@754: tvplayer->gst_pipeline = NULL;
renatofilho@754: tvplayer->gst_videodec = NULL;
renatofilho@754: tvplayer->gst_videosink = NULL;
renatofilho@754: tvplayer->gst_videocolortrs = NULL;
renatofilho@754:
renatofilho@754: g_warning("GstElement creation error!\n");
renatofilho@20: return FALSE;
renatofilho@20: }
renatofilho@754: #ifndef MAEMO_PLATFORM
renatofilho@20: if (!(audiodec && audioconv)) {
renatofilho@754: g_warning("GstElement for audio stream creation error!");
renatofilho@20: return FALSE;
renatofilho@20: }
renatofilho@754: #endif
renatofilho@754:
renatofilho@20: tvplayer->gst_pipeline = pipeline;
renatofilho@20: tvplayer->gst_source = source;
renatofilho@20: tvplayer->gst_videodec = videodec;
renatofilho@20: tvplayer->gst_videosink = videosink;
rosfran@64: tvplayer->gst_videocolortrs = videocolortrs;
renatofilho@754: g_object_ref(tvplayer->gst_pipeline);
renatofilho@754: g_object_ref(tvplayer->gst_source);
renatofilho@754: g_object_ref(tvplayer->gst_videodec);
renatofilho@754: g_object_ref(tvplayer->gst_videosink);
renatofilho@754: g_object_ref(tvplayer->gst_videocolortrs);
renatofilho@20:
rosfran@64: tvplayer->videoqueue1 = videoqueue1;
rosfran@64: tvplayer->videoqueue2 = videoqueue2;
rosfran@64: tvplayer->audioqueue1 = audioqueue1;
renatofilho@754: g_object_ref(tvplayer->videoqueue1);
renatofilho@754: g_object_ref(tvplayer->videoqueue2);
renatofilho@754: g_object_ref(tvplayer->audioqueue1);
renatofilho@754:
rosfran@414: #ifndef MAEMO_PLATFORM
rosfran@415: tvplayer->audioqueue2 = audioqueue2;
renatofilho@754: g_object_ref(tvplayer->audioqueue2);
rosfran@414: #endif
renatofilho@20:
renatofilho@754: // g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
renatofilho@754: g_object_set(G_OBJECT(audiosink), "sync", FALSE, NULL);
renatofilho@20:
renatofilho@754: gst_bus_add_watch(gst_pipeline_get_bus
renatofilho@754: (GST_PIPELINE(tvplayer->gst_pipeline)), bus_call,
renatofilho@754: tvplayer);
renatofilho@754:
renatofilho@754: gst_bin_add_many(GST_BIN(pipeline), source, parser, videoqueue1,
renatofilho@754: videodec, videoqueue2, videocolortrs, videosink,
renatofilho@754: NULL);
rosfran@414:
rosfran@414: #ifndef MAEMO_PLATFORM
renatofilho@754: gst_bin_add_many(GST_BIN(pipeline), audioqueue1, audiodec, audioconv,
renatofilho@754: audioqueue2, audiosink, NULL);
rosfran@414: #else
renatofilho@754: gst_bin_add_many(GST_BIN(pipeline), audioqueue1, audiosink, NULL);
rosfran@414: #endif
renatofilho@20:
renatofilho@20: {
renatofilho@754: // GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp",
renatofilho@754: // NULL);
renatofilho@754: // gst_element_link_filtered(source, parser, rtpcaps);
renatofilho@20: }
renatofilho@754:
renatofilho@754: gst_element_link(source, parser);
renatofilho@754: gst_element_link_many(videoqueue1, videodec, videoqueue2,
renatofilho@754: videocolortrs, videosink, NULL);
renatofilho@754:
rosfran@414: #ifndef MAEMO_PLATFORM
renatofilho@754: gst_element_link_many(videosink, audioqueue1, audiodec, audioconv,
renatofilho@754: audioqueue2, audiosink, NULL);
rosfran@414: #else
renatofilho@754: gst_element_link_many(videosink, audioqueue1, audiosink, NULL);
rosfran@414: #endif
renatofilho@754:
renatofilho@754: g_signal_connect(parser, "pad-added", G_CALLBACK(new_pad_cb),
renatofilho@754: tvplayer);
renatofilho@754:
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@754: mmyth_tvplayer_record_setup(MMythTVPlayer * tvplayer,
renatofilho@754: const gchar * filename)
renatofilho@20: {
renatofilho@754: // FIXME: we should receive the uri instead of filename
renatofilho@754: const gchar *hostname =
renatofilho@754: gmyth_backend_info_get_hostname(tvplayer->backend_info);
renatofilho@754: const gint port =
renatofilho@754: gmyth_backend_info_get_port(tvplayer->backend_info);
renatofilho@20:
renatofilho@754: GString *fullpath = g_string_new("myth://");
renatofilho@754: g_string_append_printf(fullpath, "%s:%d/%s", hostname, port, filename);
renatofilho@754:
renatofilho@754: tvplayer->is_livetv = FALSE;
renatofilho@754:
renatofilho@754: g_debug("[%s] Setting record uri to gstreamer pipeline to %s",
renatofilho@754: __FUNCTION__, fullpath->str);
renatofilho@754:
renatofilho@754: g_object_set(G_OBJECT(tvplayer->gst_source), "location",
renatofilho@754: fullpath->str, NULL);
renatofilho@754:
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@754: mmyth_tvplayer_livetv_setup(MMythTVPlayer * tvplayer)
renatofilho@20: {
renatofilho@754: gboolean res = TRUE;
renatofilho@20:
renatofilho@754: tvplayer->livetv = gmyth_livetv_new();
rosfran@208:
renatofilho@754: if (!gmyth_livetv_setup(tvplayer->livetv, tvplayer->backend_info))
renatofilho@754: goto error;
renatofilho@20:
renatofilho@754: return res;
renatofilho@20:
renatofilho@754: error:
renatofilho@754: res = FALSE;
renatofilho@754: if (tvplayer->livetv != NULL) {
renatofilho@754: g_object_unref(tvplayer->livetv);
renatofilho@754: }
renatofilho@20:
renatofilho@754: if (tvplayer->local_hostname != NULL) {
renatofilho@754: g_string_free(tvplayer->local_hostname, TRUE);
renatofilho@754: }
renatofilho@20:
renatofilho@754: if (tvplayer->recorder != NULL) {
renatofilho@754: g_object_unref(tvplayer->recorder);
renatofilho@754: tvplayer->recorder = NULL;
renatofilho@754: }
renatofilho@20:
renatofilho@754: if (tvplayer->tvchain != NULL) {
renatofilho@754: g_object_unref(tvplayer->tvchain);
renatofilho@754: tvplayer->tvchain = NULL;
renatofilho@754: }
renatofilho@20:
renatofilho@754: if (tvplayer->proginfo != NULL) {
renatofilho@754: g_object_unref(tvplayer->proginfo);
renatofilho@754: tvplayer->proginfo = NULL;
renatofilho@754: }
renatofilho@754:
renatofilho@754: 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@754: mmyth_tvplayer_set_widget(MMythTVPlayer * tvplayer, GtkWidget * videow)
renatofilho@20: {
renatofilho@754: tvplayer->videow = videow;
renatofilho@754: g_object_ref(videow);
renatofilho@20:
renatofilho@754: g_debug("[%s] Setting widget for tv player render", __FUNCTION__);
renatofilho@754:
renatofilho@754: tvplayer->expose_handler =
renatofilho@754: g_signal_connect(tvplayer->videow, "expose-event",
renatofilho@754: G_CALLBACK(expose_cb), tvplayer);
renatofilho@754:
renatofilho@754: // g_signal_connect(miptv_ui->videow, "size_request",
renatofilho@754: // G_CALLBACK(cb_preferred_video_size), miptv_ui);
renatofilho@20:
renatofilho@20: return TRUE;
renatofilho@20: }
renatofilho@20:
renatofilho@754: static gboolean
renatofilho@754: bus_call(GstBus * bus, GstMessage * msg, gpointer data)
renatofilho@20: {
renatofilho@754: // MMythTVPlayer *tvplayer = MMYTH_TVPLAYER ( data );
renatofilho@754: // GMainLoop *loop = tvplayer->loop;
renatofilho@20:
renatofilho@754: switch (GST_MESSAGE_TYPE(msg)) {
renatofilho@754: case GST_MESSAGE_EOS:
renatofilho@754: printf("End of stream\n");
renatofilho@754: // g_idle_add ((GSourceFunc) idle_eos, data);
renatofilho@754: gst_element_set_state(GST_ELEMENT(GST_MESSAGE_SRC(msg)),
renatofilho@754: GST_STATE_NULL);
renatofilho@754: gst_element_set_locked_state(GST_ELEMENT(GST_MESSAGE_SRC(msg)),
renatofilho@754: TRUE);
renatofilho@754: break;
renatofilho@754: case GST_MESSAGE_ERROR:
renatofilho@20: {
renatofilho@754: gchar *debug;
renatofilho@754: GError *err;
renatofilho@20:
renatofilho@754: gst_message_parse_error(msg, &err, &debug);
renatofilho@754: g_free(debug);
renatofilho@20:
renatofilho@754: printf("Error: %s\n", err->message);
renatofilho@754: g_error_free(err);
renatofilho@20:
renatofilho@754: // g_main_loop_quit (loop);
renatofilho@20: }
renatofilho@754: break;
renatofilho@754: default:
renatofilho@754: printf(gst_message_type_get_name(GST_MESSAGE_TYPE(msg)));
renatofilho@754: printf("\n");
renatofilho@754: break;
renatofilho@20: }
renatofilho@20:
renatofilho@20: return TRUE;
renatofilho@20: }
renatofilho@20:
renatofilho@20:
renatofilho@20: #if 0
renatofilho@754: static gboolean
renatofilho@754: 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@754: g_source_remove(st->miptv_ui->idle_id);
renatofilho@20: st->miptv_ui->idle_id = 0;
renatofilho@20: }
renatofilho@754: } else if (st->new_state == GST_STATE_PLAYING) {
renatofilho@20: if (st->miptv_ui->idle_id != 0)
renatofilho@754: g_source_remove(st->miptv_ui->idle_id);
renatofilho@20:
renatofilho@754: st->miptv_ui->idle_id = g_idle_add(cb_iterate, st->miptv_ui);
renatofilho@20: }
renatofilho@20:
renatofilho@754: /*
renatofilho@754: * new movie loaded?
renatofilho@754: */
renatofilho@754: if (st->old_state == GST_STATE_READY
renatofilho@754: && st->new_state > GST_STATE_READY) {
renatofilho@20:
renatofilho@754: /*
renatofilho@754: * gboolean have_video = FALSE;
renatofilho@754: */
renatofilho@20:
renatofilho@754: gtk_widget_show(st->miptv_ui->videow);
renatofilho@20:
renatofilho@754: gtk_window_resize(GTK_WINDOW(st->miptv_ui->main_window), 1, 1);
renatofilho@20:
renatofilho@20: }
renatofilho@20:
renatofilho@754: /*
renatofilho@754: * discarded movie?
renatofilho@754: */
renatofilho@754: if (st->old_state > GST_STATE_READY
renatofilho@754: && st->new_state == GST_STATE_READY) {
renatofilho@20:
renatofilho@20: if (st->miptv_ui->tagcache) {
renatofilho@754: gst_tag_list_free(st->miptv_ui->tagcache);
renatofilho@20: st->miptv_ui->tagcache = NULL;
renatofilho@20: }
renatofilho@20: }
renatofilho@20:
renatofilho@754: gst_object_unref(GST_OBJECT(st->play));
renatofilho@754: // g_object_unref (G_OBJECT (st->win));
renatofilho@754: g_free(st);
renatofilho@20:
renatofilho@754: /*
renatofilho@754: * once
renatofilho@754: */
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@754: mmyth_tvplayer_stop_playing(MMythTVPlayer * tvplayer)
renatofilho@20: {
renatofilho@754: g_debug("[%s] Setting gstreamer pipeline state to NULL", __FUNCTION__);
renatofilho@20:
renatofilho@754: gst_element_set_state(tvplayer->gst_pipeline, GST_STATE_NULL);
renatofilho@754:
renatofilho@20: if (tvplayer->is_livetv) {
renatofilho@754: if (!gmyth_recorder_stop_livetv(tvplayer->recorder)) {
renatofilho@754: g_warning("[%s] Error while stoping remote encoder",
renatofilho@754: __FUNCTION__);
renatofilho@754: }
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@754: mmyth_tvplayer_is_playing(MMythTVPlayer * tvplayer)
renatofilho@20: {
renatofilho@754: 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@754: static gboolean
renatofilho@754: idle_play(gpointer data)
renatofilho@20: {
renatofilho@754: MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(data);
renatofilho@20:
renatofilho@754: g_debug("MMythTVPlayer: Setting pipeline state to PLAYING\n");
renatofilho@20:
renatofilho@754: 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@754: mmyth_tvplayer_start_playing(MMythTVPlayer * tvplayer)
renatofilho@20: {
renatofilho@20:
renatofilho@754: // FIXME: Move this to livetv_setup??
renatofilho@754: if (tvplayer->is_livetv) {
renatofilho@20:
renatofilho@754: #if 0
renatofilho@754: if (!tvplayer || !(tvplayer->proginfo)
renatofilho@754: || !(tvplayer->local_hostname)
renatofilho@754: || !(tvplayer->gst_source)) {
renatofilho@754: g_warning("GMythtvPlayer not ready to start playing\n");
renatofilho@754: }
renatofilho@20:
renatofilho@754: if (!(tvplayer->proginfo->pathname)) {
renatofilho@754: g_warning
renatofilho@754: ("[%s] Playback url is null, could not play the myth content",
renatofilho@754: __FUNCTION__);
renatofilho@754: return;
renatofilho@754: }
renatofilho@20:
renatofilho@754: g_debug("MMythTVPlayer: Start playing %s",
renatofilho@754: tvplayer->proginfo->pathname->str);
renatofilho@20: #endif
renatofilho@754: g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-live",
renatofilho@754: TRUE, NULL);
renatofilho@20: #if 0
renatofilho@754: if (tvplayer->tvchain != NULL) {
renatofilho@754: GString *str_chainid =
renatofilho@754: gmyth_tvchain_get_id(tvplayer->tvchain);
renatofilho@754: g_print("[%s]\tCHAIN ID: %s\n", __FUNCTION__,
renatofilho@754: str_chainid->str);
renatofilho@20:
renatofilho@754: g_object_set(G_OBJECT(tvplayer->gst_source),
renatofilho@754: "mythtv-live-chainid", g_strdup(str_chainid->str),
renatofilho@754: NULL);
renatofilho@754: if (str_chainid != NULL)
renatofilho@754: g_string_free(str_chainid, FALSE);
renatofilho@754: }
renatofilho@20:
renatofilho@754: if (tvplayer->recorder != NULL)
renatofilho@754: g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-live-id",
renatofilho@754: tvplayer->recorder->recorder_num, NULL);
renatofilho@754: g_debug("[%s] Setting location to %s", __FUNCTION__,
renatofilho@754: tvplayer->proginfo->pathname->str);
renatofilho@20:
renatofilho@754: /*
renatofilho@754: * Sets the gstreamer properties acording to the service access
renatofilho@754: * address
renatofilho@754: */
renatofilho@754: g_object_set(G_OBJECT(tvplayer->gst_source), "location",
renatofilho@754: tvplayer->proginfo->pathname->str, NULL);
renatofilho@20: #endif
renatofilho@754: }
renatofilho@20:
renatofilho@754: g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-version",
renatofilho@754: MYTHTV_VERSION_DEFAULT, NULL);
renatofilho@20:
renatofilho@754: g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-debug",
renatofilho@754: TRUE, NULL);
renatofilho@20:
renatofilho@754: g_idle_add(idle_play, tvplayer);
renatofilho@20:
renatofilho@20: }