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