1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/maemo-ui-old/src/mmyth_tvplayer.c Fri Aug 10 15:20:19 2007 +0100
1.3 @@ -0,0 +1,712 @@
1.4 +/**
1.5 + * GMyth Library
1.6 + *
1.7 + * @file gmyth/mmyth_tvplayer.c
1.8 + *
1.9 + * @brief <p> This component provides playback of the remote A/V using
1.10 + * GStreamer.
1.11 + *
1.12 + * Copyright (C) 2006 INdT - Instituto Nokia de Tecnologia.
1.13 + * @author Hallyson Luiz de Morais Melo <hallyson.melo@indt.org.br>
1.14 + *
1.15 + *//*
1.16 + *
1.17 + * This program is free software; you can redistribute it and/or modify
1.18 + * it under the terms of the GNU Lesser General Public License as published by
1.19 + * the Free Software Foundation; either version 2 of the License, or
1.20 + * (at your option) any later version.
1.21 + *
1.22 + * This program is distributed in the hope that it will be useful,
1.23 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.24 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.25 + * GNU General Public License for more details.
1.26 + *
1.27 + * You should have received a copy of the GNU Lesser General Public License
1.28 + * along with this program; if not, write to the Free Software
1.29 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1.30 + */
1.31 +
1.32 +#include "mmyth_tvplayer.h"
1.33 +
1.34 +#include <gdk/gdkx.h>
1.35 +
1.36 +#include <gmyth/gmyth_remote_util.h>
1.37 +
1.38 +#define MYTHTV_VERSION_DEFAULT 30
1.39 +
1.40 +typedef struct _GstPlayerWindowStateChange {
1.41 + GstElement *play;
1.42 + GstState old_state,
1.43 + new_state;
1.44 + MMythTVPlayer *tvplayer;
1.45 +} GstPlayerWindowStateChange;
1.46 +
1.47 +typedef struct _GstPlayerWindowTagFound {
1.48 + GstElement *play;
1.49 + GstTagList *taglist;
1.50 + MMythTVPlayer *tvplayer;
1.51 +} GstPlayerWindowTagFound;
1.52 +
1.53 +/*
1.54 + * static gboolean idle_state (gpointer data);
1.55 + */
1.56 +static gboolean bus_call(GstBus * bus, GstMessage * msg, gpointer data);
1.57 +
1.58 +static void mmyth_tvplayer_class_init(MMythTVPlayerClass * klass);
1.59 +static void mmyth_tvplayer_init(MMythTVPlayer * object);
1.60 +
1.61 +static void mmyth_tvplayer_dispose(GObject * object);
1.62 +static void mmyth_tvplayer_finalize(GObject * object);
1.63 +
1.64 +G_DEFINE_TYPE(MMythTVPlayer, mmyth_tvplayer, G_TYPE_OBJECT)
1.65 +
1.66 + static gboolean mmyth_tvplayer_create_pipeline(MMythTVPlayer *
1.67 + tvplayer);
1.68 + static void new_pad_cb(GstElement * element, GstPad * pad,
1.69 + gpointer data);
1.70 +
1.71 + static gboolean expose_cb(GtkWidget * widget,
1.72 + GdkEventExpose * event, gpointer user_data);
1.73 +
1.74 + static void
1.75 + mmyth_tvplayer_class_init(MMythTVPlayerClass * klass)
1.76 +{
1.77 + GObjectClass *gobject_class;
1.78 +
1.79 + gobject_class = (GObjectClass *) klass;
1.80 +
1.81 + gobject_class->dispose = mmyth_tvplayer_dispose;
1.82 + gobject_class->finalize = mmyth_tvplayer_finalize;
1.83 +}
1.84 +
1.85 +static void
1.86 +new_pad_cb(GstElement * element, GstPad * pad, gpointer data)
1.87 +{
1.88 + MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(data);
1.89 + GstPadLinkReturn ret;
1.90 + char *s;
1.91 +
1.92 + s = gst_caps_to_string(pad->caps);
1.93 +
1.94 + if (s[0] == 'a') {
1.95 + ret =
1.96 + gst_pad_link(pad,
1.97 + gst_element_get_pad(tvplayer->audioqueue1,
1.98 + "sink"));
1.99 + } else {
1.100 + ret =
1.101 + gst_pad_link(pad,
1.102 + gst_element_get_pad(tvplayer->videoqueue1,
1.103 + "sink"));
1.104 + }
1.105 +
1.106 + g_free(s);
1.107 +}
1.108 +
1.109 +static gboolean
1.110 +expose_cb(GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
1.111 +{
1.112 + MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(user_data);
1.113 +
1.114 + if (tvplayer && tvplayer->videow) {
1.115 + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY
1.116 + (tvplayer->gst_videosink),
1.117 + GDK_WINDOW_XWINDOW(widget->window));
1.118 + return TRUE;
1.119 + }
1.120 +
1.121 + g_warning("MMythTVPlayer expose called before setting video window\n");
1.122 +
1.123 + return FALSE;
1.124 +}
1.125 +
1.126 +static void
1.127 +mmyth_tvplayer_init(MMythTVPlayer * tvplayer)
1.128 +{
1.129 + tvplayer->gst_pipeline = NULL;
1.130 + tvplayer->gst_source = NULL;
1.131 + tvplayer->gst_videodec = NULL;
1.132 + tvplayer->gst_videosink = NULL;
1.133 + tvplayer->gst_videocolortrs = NULL;
1.134 + tvplayer->videoqueue1 = NULL;
1.135 + tvplayer->videoqueue2 = NULL;
1.136 + tvplayer->audioqueue1 = NULL;
1.137 + tvplayer->audioqueue2 = NULL;
1.138 +
1.139 + /*
1.140 + * GTKWidget for rendering the video
1.141 + */
1.142 + tvplayer->videow = NULL;
1.143 + tvplayer->expose_handler = 0;
1.144 +
1.145 + tvplayer->backend_hostname = NULL;
1.146 + tvplayer->backend_port = 0;
1.147 + tvplayer->local_hostname = NULL;
1.148 +
1.149 + tvplayer->recorder = NULL;
1.150 + tvplayer->tvchain = NULL;
1.151 + tvplayer->proginfo = NULL;
1.152 +}
1.153 +
1.154 +static void
1.155 +mmyth_tvplayer_dispose(GObject * object)
1.156 +{
1.157 +
1.158 + G_OBJECT_CLASS(mmyth_tvplayer_parent_class)->dispose(object);
1.159 +}
1.160 +
1.161 +static void
1.162 +mmyth_tvplayer_finalize(GObject * object)
1.163 +{
1.164 + g_signal_handlers_destroy(object);
1.165 +
1.166 + MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(object);
1.167 +
1.168 + g_debug("[%s] Finalizing tvplayer", __FUNCTION__);
1.169 +
1.170 + if (tvplayer->videow != NULL) {
1.171 + if (g_signal_handler_is_connected(tvplayer->videow,
1.172 + tvplayer->expose_handler)) {
1.173 + g_signal_handler_disconnect(tvplayer->videow,
1.174 + tvplayer->expose_handler);
1.175 + }
1.176 + g_object_unref(tvplayer->videow);
1.177 + }
1.178 +
1.179 + if (tvplayer->recorder != NULL)
1.180 + g_object_unref(tvplayer->recorder);
1.181 + if (tvplayer->tvchain != NULL)
1.182 + g_object_unref(tvplayer->tvchain);
1.183 + if (tvplayer->proginfo != NULL)
1.184 + g_object_unref(tvplayer->proginfo);
1.185 +
1.186 + // Release Gstreamer elements
1.187 + if (tvplayer->gst_pipeline != NULL)
1.188 + g_object_unref(tvplayer->gst_pipeline);
1.189 + if (tvplayer->gst_source != NULL)
1.190 + g_object_unref(tvplayer->gst_source);
1.191 + if (tvplayer->gst_videodec != NULL)
1.192 + g_object_unref(tvplayer->gst_videodec);
1.193 + if (tvplayer->gst_videocolortrs != NULL)
1.194 + g_object_unref(tvplayer->gst_videocolortrs);
1.195 + if (tvplayer->gst_videosink != NULL)
1.196 + g_object_unref(tvplayer->gst_videosink);
1.197 + if (tvplayer->videoqueue1 != NULL)
1.198 + g_object_unref(tvplayer->videoqueue1);
1.199 + if (tvplayer->videoqueue2 != NULL)
1.200 + g_object_unref(tvplayer->videoqueue2);
1.201 + if (tvplayer->audioqueue1 != NULL)
1.202 + g_object_unref(tvplayer->audioqueue1);
1.203 + if (tvplayer->audioqueue2 != NULL)
1.204 + g_object_unref(tvplayer->audioqueue2);
1.205 +
1.206 + G_OBJECT_CLASS(mmyth_tvplayer_parent_class)->finalize(object);
1.207 +}
1.208 +
1.209 +/** Creates a new instance of MMythTVPlayer.
1.210 + *
1.211 + * @return a new instance of MMythTVPlayer.
1.212 + */
1.213 +MMythTVPlayer *
1.214 +mmyth_tvplayer_new()
1.215 +{
1.216 + MMythTVPlayer *tvplayer =
1.217 + MMYTH_TVPLAYER(g_object_new(MMYTH_TVPLAYER_TYPE, NULL));
1.218 +
1.219 + return tvplayer;
1.220 +}
1.221 +
1.222 +/** Initializes the tv player.
1.223 + *
1.224 + * @param tvplayer the object instance.
1.225 + * @return gboolean TRUE if the pipeline was created
1.226 + * successfully, FALSE otherwise.
1.227 + */
1.228 +gboolean
1.229 +mmyth_tvplayer_initialize(MMythTVPlayer * tvplayer,
1.230 + GMythBackendInfo * backend_info)
1.231 +{
1.232 + tvplayer->backend_info = backend_info;
1.233 +
1.234 + if (!mmyth_tvplayer_create_pipeline(tvplayer)) {
1.235 + g_warning
1.236 + ("[%s] Error while creating pipeline. TV Player not initialized",
1.237 + __FUNCTION__);
1.238 + return FALSE;
1.239 + } else {
1.240 + g_debug("[%s] GStreamer pipeline created", __FUNCTION__);
1.241 + }
1.242 +
1.243 + return TRUE;
1.244 +}
1.245 +
1.246 +/** Creates the GStreamer pipeline used by the player.
1.247 + *
1.248 + * @param tvplayer the object instance.
1.249 + * @return gboolean TRUE if the pipeline was created
1.250 + * successfully, FALSE otherwise.
1.251 + */
1.252 +static gboolean
1.253 +mmyth_tvplayer_create_pipeline(MMythTVPlayer * tvplayer)
1.254 +{
1.255 + GstElement *pipeline;
1.256 + GstElement *source,
1.257 + *parser;
1.258 + GstElement *videodec,
1.259 + *videosink;
1.260 + GstElement *videocolortrs;
1.261 +#ifndef MAEMO_PLATFORM
1.262 + GstElement *audiodec,
1.263 + *audioconv,
1.264 + *audioqueue2;
1.265 +#endif
1.266 + GstElement *audiosink;
1.267 + GstElement *videoqueue1,
1.268 + *videoqueue2,
1.269 + *audioqueue1;
1.270 +
1.271 + g_debug("MMythTVPlayer: Setting the Gstreamer pipeline\n");
1.272 +
1.273 + pipeline = gst_pipeline_new("video-player");
1.274 + source = gst_element_factory_make("mythtvsrc", "myth-source");
1.275 + parser = gst_element_factory_make("nuvdemux", "nuv-demux");
1.276 +
1.277 + /*
1.278 + * Gstreamer Video elements
1.279 + */
1.280 + videoqueue1 = gst_element_factory_make("queue", "video-queue1");
1.281 + videodec = gst_element_factory_make("ffdec_mpeg4", "video-decoder");
1.282 + videoqueue2 = gst_element_factory_make("queue", "video-queue2");
1.283 + videocolortrs =
1.284 + gst_element_factory_make("ffmpegcolorspace",
1.285 + "image-color-transforms");
1.286 +
1.287 +#ifdef MAEMO_PLATFORM
1.288 + videosink = gst_element_factory_make("sdlvideosink", "image-output");
1.289 +#else
1.290 + videosink = gst_element_factory_make("xvimagesink", "image-output");
1.291 +#endif
1.292 +
1.293 + /*
1.294 + * Gstreamer Audio elements
1.295 + */
1.296 + audioqueue1 = gst_element_factory_make("queue", "audio-queue1");
1.297 +#ifdef MAEMO_PLATFORM
1.298 + audiosink = gst_element_factory_make("dspmp3sink", "audio-output");
1.299 +#else
1.300 + audioqueue2 = gst_element_factory_make("queue", "audio-queue2");
1.301 + audiodec = gst_element_factory_make("mad", "audio-decoder");
1.302 + audioconv =
1.303 + gst_element_factory_make("audioconvert", "audio-converter");
1.304 + audiosink = gst_element_factory_make("alsasink", "audio-output");
1.305 +#endif
1.306 +
1.307 + if (!(pipeline && source && parser && videodec && videosink) ||
1.308 + !(videoqueue1 && videoqueue2 && audioqueue1 && audiosink)) {
1.309 + /*
1.310 + * FIXME: hanlde the error correctly
1.311 + */
1.312 + /*
1.313 + * video_alignment is not being created (below) and is causing
1.314 + * problems to the ui
1.315 + */
1.316 +
1.317 + tvplayer->gst_pipeline = NULL;
1.318 + tvplayer->gst_videodec = NULL;
1.319 + tvplayer->gst_videosink = NULL;
1.320 + tvplayer->gst_videocolortrs = NULL;
1.321 +
1.322 + g_warning("GstElement creation error!\n");
1.323 + return FALSE;
1.324 + }
1.325 +#ifndef MAEMO_PLATFORM
1.326 + if (!(audiodec && audioconv)) {
1.327 + g_warning("GstElement for audio stream creation error!");
1.328 + return FALSE;
1.329 + }
1.330 +#endif
1.331 +
1.332 + tvplayer->gst_pipeline = pipeline;
1.333 + tvplayer->gst_source = source;
1.334 + tvplayer->gst_videodec = videodec;
1.335 + tvplayer->gst_videosink = videosink;
1.336 + tvplayer->gst_videocolortrs = videocolortrs;
1.337 + g_object_ref(tvplayer->gst_pipeline);
1.338 + g_object_ref(tvplayer->gst_source);
1.339 + g_object_ref(tvplayer->gst_videodec);
1.340 + g_object_ref(tvplayer->gst_videosink);
1.341 + g_object_ref(tvplayer->gst_videocolortrs);
1.342 +
1.343 + tvplayer->videoqueue1 = videoqueue1;
1.344 + tvplayer->videoqueue2 = videoqueue2;
1.345 + tvplayer->audioqueue1 = audioqueue1;
1.346 + g_object_ref(tvplayer->videoqueue1);
1.347 + g_object_ref(tvplayer->videoqueue2);
1.348 + g_object_ref(tvplayer->audioqueue1);
1.349 +
1.350 +#ifndef MAEMO_PLATFORM
1.351 + tvplayer->audioqueue2 = audioqueue2;
1.352 + g_object_ref(tvplayer->audioqueue2);
1.353 +#endif
1.354 +
1.355 + // g_object_set (G_OBJECT (videosink), "sync", TRUE, NULL);
1.356 + g_object_set(G_OBJECT(audiosink), "sync", FALSE, NULL);
1.357 +
1.358 + gst_bus_add_watch(gst_pipeline_get_bus
1.359 + (GST_PIPELINE(tvplayer->gst_pipeline)), bus_call,
1.360 + tvplayer);
1.361 +
1.362 + gst_bin_add_many(GST_BIN(pipeline), source, parser, videoqueue1,
1.363 + videodec, videoqueue2, videocolortrs, videosink,
1.364 + NULL);
1.365 +
1.366 +#ifndef MAEMO_PLATFORM
1.367 + gst_bin_add_many(GST_BIN(pipeline), audioqueue1, audiodec, audioconv,
1.368 + audioqueue2, audiosink, NULL);
1.369 +#else
1.370 + gst_bin_add_many(GST_BIN(pipeline), audioqueue1, audiosink, NULL);
1.371 +#endif
1.372 +
1.373 + {
1.374 + // GstCaps *rtpcaps = gst_caps_new_simple ("application/x-rtp",
1.375 + // NULL);
1.376 + // gst_element_link_filtered(source, parser, rtpcaps);
1.377 + }
1.378 +
1.379 + gst_element_link(source, parser);
1.380 + gst_element_link_many(videoqueue1, videodec, videoqueue2,
1.381 + videocolortrs, videosink, NULL);
1.382 +
1.383 +#ifndef MAEMO_PLATFORM
1.384 + gst_element_link_many(videosink, audioqueue1, audiodec, audioconv,
1.385 + audioqueue2, audiosink, NULL);
1.386 +#else
1.387 + gst_element_link_many(videosink, audioqueue1, audiosink, NULL);
1.388 +#endif
1.389 +
1.390 + g_signal_connect(parser, "pad-added", G_CALLBACK(new_pad_cb),
1.391 + tvplayer);
1.392 +
1.393 + return TRUE;
1.394 +}
1.395 +
1.396 +/** Configures the backend and the tv player
1.397 + * for playing the recorded content A/V.
1.398 + *
1.399 + * FIXME: Change filename to program info or other structure about the recorded
1.400 + *
1.401 + * @param tvplayer the object instance.
1.402 + * @param filename the file uri of the recorded content to be played.
1.403 + * @return TRUE if successfull, FALSE if any error happens.
1.404 + */
1.405 +gboolean
1.406 +mmyth_tvplayer_record_setup(MMythTVPlayer * tvplayer,
1.407 + const gchar * filename)
1.408 +{
1.409 + // FIXME: we should receive the uri instead of filename
1.410 + const gchar *hostname =
1.411 + gmyth_backend_info_get_hostname(tvplayer->backend_info);
1.412 + const gint port =
1.413 + gmyth_backend_info_get_port(tvplayer->backend_info);
1.414 +
1.415 + GString *fullpath = g_string_new("myth://");
1.416 + g_string_append_printf(fullpath, "%s:%d/%s", hostname, port, filename);
1.417 +
1.418 + tvplayer->is_livetv = FALSE;
1.419 +
1.420 + g_debug("[%s] Setting record uri to gstreamer pipeline to %s",
1.421 + __FUNCTION__, fullpath->str);
1.422 +
1.423 + g_object_set(G_OBJECT(tvplayer->gst_source), "location",
1.424 + fullpath->str, NULL);
1.425 +
1.426 + return TRUE;
1.427 +}
1.428 +
1.429 +/** Configures the backend and the tv player
1.430 + * for playing the live tv.
1.431 + *
1.432 + * @param tvplayer the object instance.
1.433 + * @return TRUE if successfull, FALSE if any error happens.
1.434 + */
1.435 +gboolean
1.436 +mmyth_tvplayer_livetv_setup(MMythTVPlayer * tvplayer)
1.437 +{
1.438 + gboolean res = TRUE;
1.439 +
1.440 + tvplayer->livetv = gmyth_livetv_new();
1.441 +
1.442 + if (!gmyth_livetv_setup(tvplayer->livetv, tvplayer->backend_info))
1.443 + goto error;
1.444 +
1.445 + return res;
1.446 +
1.447 + error:
1.448 + res = FALSE;
1.449 + if (tvplayer->livetv != NULL) {
1.450 + g_object_unref(tvplayer->livetv);
1.451 + }
1.452 +
1.453 + if (tvplayer->local_hostname != NULL) {
1.454 + g_string_free(tvplayer->local_hostname, TRUE);
1.455 + }
1.456 +
1.457 + if (tvplayer->recorder != NULL) {
1.458 + g_object_unref(tvplayer->recorder);
1.459 + tvplayer->recorder = NULL;
1.460 + }
1.461 +
1.462 + if (tvplayer->tvchain != NULL) {
1.463 + g_object_unref(tvplayer->tvchain);
1.464 + tvplayer->tvchain = NULL;
1.465 + }
1.466 +
1.467 + if (tvplayer->proginfo != NULL) {
1.468 + g_object_unref(tvplayer->proginfo);
1.469 + tvplayer->proginfo = NULL;
1.470 + }
1.471 +
1.472 + return res;
1.473 +
1.474 +}
1.475 +
1.476 +/** Sets the GTK video widget for the tv player.
1.477 + *
1.478 + * @param tvplayer the object instance.
1.479 + * @param videow the GTK video window.
1.480 + * @return TRUE if successfull, FALSE if any error happens.
1.481 + */
1.482 +gboolean
1.483 +mmyth_tvplayer_set_widget(MMythTVPlayer * tvplayer, GtkWidget * videow)
1.484 +{
1.485 + tvplayer->videow = videow;
1.486 + g_object_ref(videow);
1.487 +
1.488 + g_debug("[%s] Setting widget for tv player render", __FUNCTION__);
1.489 +
1.490 + tvplayer->expose_handler =
1.491 + g_signal_connect(tvplayer->videow, "expose-event",
1.492 + G_CALLBACK(expose_cb), tvplayer);
1.493 +
1.494 + // g_signal_connect(miptv_ui->videow, "size_request",
1.495 + // G_CALLBACK(cb_preferred_video_size), miptv_ui);
1.496 +
1.497 + return TRUE;
1.498 +}
1.499 +
1.500 +static gboolean
1.501 +bus_call(GstBus * bus, GstMessage * msg, gpointer data)
1.502 +{
1.503 + // MMythTVPlayer *tvplayer = MMYTH_TVPLAYER ( data );
1.504 + // GMainLoop *loop = tvplayer->loop;
1.505 +
1.506 + switch (GST_MESSAGE_TYPE(msg)) {
1.507 + case GST_MESSAGE_EOS:
1.508 + printf("End of stream\n");
1.509 + // g_idle_add ((GSourceFunc) idle_eos, data);
1.510 + gst_element_set_state(GST_ELEMENT(GST_MESSAGE_SRC(msg)),
1.511 + GST_STATE_NULL);
1.512 + gst_element_set_locked_state(GST_ELEMENT(GST_MESSAGE_SRC(msg)),
1.513 + TRUE);
1.514 + break;
1.515 + case GST_MESSAGE_ERROR:
1.516 + {
1.517 + gchar *debug;
1.518 + GError *err;
1.519 +
1.520 + gst_message_parse_error(msg, &err, &debug);
1.521 + g_free(debug);
1.522 +
1.523 + printf("Error: %s\n", err->message);
1.524 + g_error_free(err);
1.525 +
1.526 + // g_main_loop_quit (loop);
1.527 + }
1.528 + break;
1.529 + default:
1.530 + printf(gst_message_type_get_name(GST_MESSAGE_TYPE(msg)));
1.531 + printf("\n");
1.532 + break;
1.533 + }
1.534 +
1.535 + return TRUE;
1.536 +}
1.537 +
1.538 +
1.539 +#if 0
1.540 +static gboolean
1.541 +idle_state(gpointer data)
1.542 +{
1.543 + GstPlayerWindowStateChange *st = data;
1.544 +
1.545 + if (st->old_state == GST_STATE_PLAYING) {
1.546 + if (st->miptv_ui->idle_id != 0) {
1.547 + g_source_remove(st->miptv_ui->idle_id);
1.548 + st->miptv_ui->idle_id = 0;
1.549 + }
1.550 + } else if (st->new_state == GST_STATE_PLAYING) {
1.551 + if (st->miptv_ui->idle_id != 0)
1.552 + g_source_remove(st->miptv_ui->idle_id);
1.553 +
1.554 + st->miptv_ui->idle_id = g_idle_add(cb_iterate, st->miptv_ui);
1.555 + }
1.556 +
1.557 + /*
1.558 + * new movie loaded?
1.559 + */
1.560 + if (st->old_state == GST_STATE_READY
1.561 + && st->new_state > GST_STATE_READY) {
1.562 +
1.563 + /*
1.564 + * gboolean have_video = FALSE;
1.565 + */
1.566 +
1.567 + gtk_widget_show(st->miptv_ui->videow);
1.568 +
1.569 + gtk_window_resize(GTK_WINDOW(st->miptv_ui->main_window), 1, 1);
1.570 +
1.571 + }
1.572 +
1.573 + /*
1.574 + * discarded movie?
1.575 + */
1.576 + if (st->old_state > GST_STATE_READY
1.577 + && st->new_state == GST_STATE_READY) {
1.578 +
1.579 + if (st->miptv_ui->tagcache) {
1.580 + gst_tag_list_free(st->miptv_ui->tagcache);
1.581 + st->miptv_ui->tagcache = NULL;
1.582 + }
1.583 + }
1.584 +
1.585 + gst_object_unref(GST_OBJECT(st->play));
1.586 + // g_object_unref (G_OBJECT (st->win));
1.587 + g_free(st);
1.588 +
1.589 + /*
1.590 + * once
1.591 + */
1.592 + return FALSE;
1.593 +}
1.594 +
1.595 +#endif
1.596 +
1.597 +/** Stops playing the current A/V.
1.598 + *
1.599 + * FIXME: How to proceed differently between livetv
1.600 + * and recorded content?
1.601 + *
1.602 + * @param tvplayer the object instance.
1.603 + * @return void
1.604 + */
1.605 +void
1.606 +mmyth_tvplayer_stop_playing(MMythTVPlayer * tvplayer)
1.607 +{
1.608 + g_debug("[%s] Setting gstreamer pipeline state to NULL", __FUNCTION__);
1.609 +
1.610 + gst_element_set_state(tvplayer->gst_pipeline, GST_STATE_NULL);
1.611 +
1.612 + if (tvplayer->is_livetv) {
1.613 + if (!gmyth_recorder_stop_livetv(tvplayer->recorder)) {
1.614 + g_warning("[%s] Error while stoping remote encoder",
1.615 + __FUNCTION__);
1.616 + }
1.617 + }
1.618 +}
1.619 +
1.620 +/** Queries if the tvplayer is active playing A/V content.
1.621 + *
1.622 + * @param tvplayer the object instance.
1.623 + * @return TRUE if the tvplayer is active, FALSE otherwise.
1.624 + */
1.625 +gboolean
1.626 +mmyth_tvplayer_is_playing(MMythTVPlayer * tvplayer)
1.627 +{
1.628 + return (GST_STATE(tvplayer->gst_pipeline) == GST_STATE_PLAYING);
1.629 +}
1.630 +
1.631 +/** Static function that sets the tvplayer state to PLAYING.
1.632 + *
1.633 + * @param tvplayer the object instance.
1.634 + * @return TRUE if the tvplayer is active, FALSE otherwise.
1.635 + */
1.636 +static gboolean
1.637 +idle_play(gpointer data)
1.638 +{
1.639 + MMythTVPlayer *tvplayer = MMYTH_TVPLAYER(data);
1.640 +
1.641 + g_debug("MMythTVPlayer: Setting pipeline state to PLAYING\n");
1.642 +
1.643 + gst_element_set_state(tvplayer->gst_pipeline, GST_STATE_PLAYING);
1.644 +
1.645 + return FALSE;
1.646 +}
1.647 +
1.648 +/** Start playing A/V with the tvplayer attributes.
1.649 + *
1.650 + * @param tvplayer the object instance.
1.651 + */
1.652 +void
1.653 +mmyth_tvplayer_start_playing(MMythTVPlayer * tvplayer)
1.654 +{
1.655 +
1.656 + // FIXME: Move this to livetv_setup??
1.657 + if (tvplayer->is_livetv) {
1.658 +
1.659 +#if 0
1.660 + if (!tvplayer || !(tvplayer->proginfo)
1.661 + || !(tvplayer->local_hostname)
1.662 + || !(tvplayer->gst_source)) {
1.663 + g_warning("GMythtvPlayer not ready to start playing\n");
1.664 + }
1.665 +
1.666 + if (!(tvplayer->proginfo->pathname)) {
1.667 + g_warning
1.668 + ("[%s] Playback url is null, could not play the myth content",
1.669 + __FUNCTION__);
1.670 + return;
1.671 + }
1.672 +
1.673 + g_debug("MMythTVPlayer: Start playing %s",
1.674 + tvplayer->proginfo->pathname->str);
1.675 +#endif
1.676 + g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-live",
1.677 + TRUE, NULL);
1.678 +#if 0
1.679 + if (tvplayer->tvchain != NULL) {
1.680 + GString *str_chainid =
1.681 + gmyth_tvchain_get_id(tvplayer->tvchain);
1.682 + g_print("[%s]\tCHAIN ID: %s\n", __FUNCTION__,
1.683 + str_chainid->str);
1.684 +
1.685 + g_object_set(G_OBJECT(tvplayer->gst_source),
1.686 + "mythtv-live-chainid", g_strdup(str_chainid->str),
1.687 + NULL);
1.688 + if (str_chainid != NULL)
1.689 + g_string_free(str_chainid, FALSE);
1.690 + }
1.691 +
1.692 + if (tvplayer->recorder != NULL)
1.693 + g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-live-id",
1.694 + tvplayer->recorder->recorder_num, NULL);
1.695 + g_debug("[%s] Setting location to %s", __FUNCTION__,
1.696 + tvplayer->proginfo->pathname->str);
1.697 +
1.698 + /*
1.699 + * Sets the gstreamer properties acording to the service access
1.700 + * address
1.701 + */
1.702 + g_object_set(G_OBJECT(tvplayer->gst_source), "location",
1.703 + tvplayer->proginfo->pathname->str, NULL);
1.704 +#endif
1.705 + }
1.706 +
1.707 + g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-version",
1.708 + MYTHTV_VERSION_DEFAULT, NULL);
1.709 +
1.710 + g_object_set(G_OBJECT(tvplayer->gst_source), "mythtv-debug",
1.711 + TRUE, NULL);
1.712 +
1.713 + g_idle_add(idle_play, tvplayer);
1.714 +
1.715 +}