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