Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / sys / v4l / gstv4lxoverlay.c
1 /* GStreamer
2  *
3  * gstv4lxoverlay.c: X-based overlay interface implementation for V4L
4  *
5  * Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <string.h>
28 #include <sys/stat.h>
29
30 #include <X11/X.h>
31 #include <X11/Xlib.h>
32 #include <X11/extensions/Xv.h>
33 #include <X11/extensions/Xvlib.h>
34
35 #include "gstv4lxoverlay.h"
36 #include "gstv4lelement.h"
37 #include "v4l_calls.h"
38
39 GST_DEBUG_CATEGORY_STATIC (v4lxv_debug);
40 #define GST_CAT_DEFAULT v4lxv_debug
41
42 struct _GstV4lXv
43 {
44   Display *dpy;
45   gint port, idle_id;
46   GMutex *mutex;
47 };
48
49 static void gst_v4l_xoverlay_set_window_handle (GstXOverlay * overlay,
50     guintptr xwindow_id);
51
52 void
53 gst_v4l_xoverlay_interface_init (GstXOverlayClass * klass)
54 {
55   /* default virtual functions */
56   klass->set_window_handle = gst_v4l_xoverlay_set_window_handle;
57
58   GST_DEBUG_CATEGORY_INIT (v4lxv_debug, "v4lxv", 0,
59       "V4L XOverlay interface debugging");
60 }
61
62 static void
63 gst_v4l_xoverlay_open (GstV4lElement * v4lelement)
64 {
65   struct stat s;
66   GstV4lXv *v4lxv;
67   const gchar *name = g_getenv ("DISPLAY");
68   unsigned int ver, rel, req, ev, err, anum;
69   int i, id = 0, first_id = 0, min;
70   XvAdaptorInfo *ai;
71   Display *dpy;
72
73   /* we need a display, obviously */
74   if (!name || !(dpy = XOpenDisplay (name))) {
75     GST_WARNING ("No $DISPLAY set or failed to open - no overlay");
76     return;
77   }
78
79   /* First let's check that XVideo extension is available */
80   if (!XQueryExtension (dpy, "XVideo", &i, &i, &i)) {
81     GST_WARNING ("Xv extension not available - no overlay");
82     XCloseDisplay (dpy);
83     return;
84   }
85
86   /* find port that belongs to this device */
87   if (XvQueryExtension (dpy, &ver, &rel, &req, &ev, &err) != Success) {
88     GST_WARNING ("Xv extension not supported - no overlay");
89     XCloseDisplay (dpy);
90     return;
91   }
92   if (XvQueryAdaptors (dpy, DefaultRootWindow (dpy), &anum, &ai) != Success) {
93     GST_WARNING ("Failed to query Xv adaptors");
94     XCloseDisplay (dpy);
95     return;
96   }
97   if (fstat (v4lelement->video_fd, &s) < 0) {
98     GST_ERROR ("Failed to stat() file descriptor: %s", g_strerror (errno));
99     XCloseDisplay (dpy);
100     return;
101   }
102   min = s.st_rdev & 0xff;
103   for (i = 0; i < anum; i++) {
104     if (!strcmp (ai[i].name, "video4linux")) {
105       if (first_id == 0)
106         first_id = ai[i].base_id;
107
108       /* hmm... */
109       if (first_id != 0 && ai[i].base_id == first_id + min)
110         id = ai[i].base_id;
111     }
112   }
113   XvFreeAdaptorInfo (ai);
114
115   if (id == 0) {
116     GST_WARNING ("Did not find XvPortID for device - no overlay");
117     XCloseDisplay (dpy);
118     return;
119   }
120
121   v4lxv = g_new0 (GstV4lXv, 1);
122   v4lxv->dpy = dpy;
123   v4lxv->port = id;
124   v4lxv->mutex = g_mutex_new ();
125   v4lxv->idle_id = 0;
126   v4lelement->xv = v4lxv;
127
128   if (v4lelement->xwindow_id) {
129     gst_v4l_xoverlay_set_window_handle (GST_X_OVERLAY (v4lelement),
130         v4lelement->xwindow_id);
131   }
132 }
133
134 static void
135 gst_v4l_xoverlay_close (GstV4lElement * v4lelement)
136 {
137   GstV4lXv *v4lxv = v4lelement->xv;
138
139   if (!v4lelement->xv)
140     return;
141
142   if (v4lelement->xwindow_id) {
143     gst_v4l_xoverlay_set_window_handle (GST_X_OVERLAY (v4lelement), 0);
144   }
145
146   XCloseDisplay (v4lxv->dpy);
147   g_mutex_free (v4lxv->mutex);
148   if (v4lxv->idle_id)
149     g_source_remove (v4lxv->idle_id);
150   g_free (v4lxv);
151   v4lelement->xv = NULL;
152 }
153
154 void
155 gst_v4l_xoverlay_start (GstV4lElement * v4lelement)
156 {
157   if (v4lelement->xwindow_id) {
158     gst_v4l_xoverlay_open (v4lelement);
159   }
160 }
161
162 void
163 gst_v4l_xoverlay_stop (GstV4lElement * v4lelement)
164 {
165   gst_v4l_xoverlay_close (v4lelement);
166 }
167
168 static gboolean
169 idle_refresh (gpointer data)
170 {
171   GstV4lElement *v4lelement = GST_V4LELEMENT (data);
172   GstV4lXv *v4lxv = v4lelement->xv;
173   XWindowAttributes attr;
174
175   if (v4lxv) {
176     g_mutex_lock (v4lxv->mutex);
177
178     XGetWindowAttributes (v4lxv->dpy, v4lelement->xwindow_id, &attr);
179     XvPutVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id,
180         DefaultGC (v4lxv->dpy, DefaultScreen (v4lxv->dpy)),
181         0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height);
182
183     v4lxv->idle_id = 0;
184     g_mutex_unlock (v4lxv->mutex);
185   }
186
187   /* once */
188   return FALSE;
189 }
190
191 static void
192 gst_v4l_xoverlay_set_window_handle (GstXOverlay * overlay, guintptr id)
193 {
194   XID xwindow_id = id;
195   GstV4lElement *v4lelement = GST_V4LELEMENT (overlay);
196   GstV4lXv *v4lxv;
197   XWindowAttributes attr;
198   gboolean change = (v4lelement->xwindow_id != xwindow_id);
199
200   GST_LOG_OBJECT (v4lelement, "Changing port to %lx", xwindow_id);
201
202   if (!v4lelement->xv && GST_V4L_IS_OPEN (v4lelement))
203     gst_v4l_xoverlay_open (v4lelement);
204
205   v4lxv = v4lelement->xv;
206
207   if (v4lxv)
208     g_mutex_lock (v4lxv->mutex);
209
210   if (change) {
211     if (v4lelement->xwindow_id && v4lxv) {
212       GST_DEBUG_OBJECT (v4lelement,
213           "Disabling port %lx", v4lelement->xwindow_id);
214
215       XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 0);
216       XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 0);
217       XvStopVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id);
218     }
219
220     v4lelement->xwindow_id = xwindow_id;
221   }
222
223   if (!v4lxv || xwindow_id == 0) {
224     if (v4lxv)
225       g_mutex_unlock (v4lxv->mutex);
226     return;
227   }
228
229   if (change) {
230     GST_DEBUG_OBJECT (v4lelement, "Enabling port %lx", xwindow_id);
231
232     /* draw */
233     XvSelectPortNotify (v4lxv->dpy, v4lxv->port, 1);
234     XvSelectVideoNotify (v4lxv->dpy, v4lelement->xwindow_id, 1);
235   }
236
237   XGetWindowAttributes (v4lxv->dpy, v4lelement->xwindow_id, &attr);
238   XvPutVideo (v4lxv->dpy, v4lxv->port, v4lelement->xwindow_id,
239       DefaultGC (v4lxv->dpy, DefaultScreen (v4lxv->dpy)),
240       0, 0, attr.width, attr.height, 0, 0, attr.width, attr.height);
241
242   if (v4lxv->idle_id)
243     g_source_remove (v4lxv->idle_id);
244   v4lxv->idle_id = g_idle_add (idle_refresh, v4lelement);
245   g_mutex_unlock (v4lxv->mutex);
246 }