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 |
}
|