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