2 * Copyright (C) <2005> Luca Ognibene <luogni@tin.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
24 #include "ximageutil.h"
27 gst_meta_ximage_get_info (void)
29 static const GstMetaInfo *meta_ximage_info = NULL;
31 if (meta_ximage_info == NULL) {
33 gst_meta_register ("GstMetaXImageSrc", "GstMetaXImageSrc",
34 sizeof (GstMetaXImage), (GstMetaInitFunction) NULL,
35 (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL,
36 (GstMetaSerializeFunction) NULL, (GstMetaDeserializeFunction) NULL);
38 return meta_ximage_info;
42 static gboolean error_caught = FALSE;
45 ximageutil_handle_xerror (Display * display, XErrorEvent * xevent)
49 XGetErrorText (display, xevent->error_code, error_msg, 1024);
50 GST_DEBUG ("ximageutil failed to use XShm calls. error: %s", error_msg);
55 /* This function checks that it is actually really possible to create an image
58 ximageutil_check_xshm_calls (GstXContext * xcontext)
61 XShmSegmentInfo SHMInfo;
63 int (*handler) (Display *, XErrorEvent *);
64 gboolean result = FALSE;
65 gboolean did_attach = FALSE;
67 g_return_val_if_fail (xcontext != NULL, FALSE);
69 /* Sync to ensure any older errors are already processed */
70 XSync (xcontext->disp, FALSE);
72 /* Set defaults so we don't free these later unnecessarily */
73 SHMInfo.shmaddr = ((void *) -1);
76 /* Setting an error handler to catch failure */
78 handler = XSetErrorHandler (ximageutil_handle_xerror);
80 /* Trying to create a 1x1 ximage */
81 GST_DEBUG ("XShmCreateImage of 1x1");
83 ximage = XShmCreateImage (xcontext->disp, xcontext->visual,
84 xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1);
86 /* Might cause an error, sync to ensure it is noticed */
87 XSync (xcontext->disp, FALSE);
88 if (!ximage || error_caught) {
89 GST_WARNING ("could not XShmCreateImage a 1x1 image");
92 size = ximage->height * ximage->bytes_per_line;
94 SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
95 if (SHMInfo.shmid == -1) {
96 GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
101 SHMInfo.shmaddr = shmat (SHMInfo.shmid, 0, 0);
102 if (SHMInfo.shmaddr == ((void *) -1)) {
103 GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
107 /* Delete the SHM segment. It will actually go away automatically
108 * when we detach now */
109 shmctl (SHMInfo.shmid, IPC_RMID, 0);
111 ximage->data = SHMInfo.shmaddr;
112 SHMInfo.readOnly = FALSE;
114 if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
115 GST_WARNING ("Failed to XShmAttach");
119 /* Sync to ensure we see any errors we caused */
120 XSync (xcontext->disp, FALSE);
124 /* store whether we succeeded in result */
128 /* Sync to ensure we swallow any errors we caused and reset error_caught */
129 XSync (xcontext->disp, FALSE);
130 error_caught = FALSE;
131 XSetErrorHandler (handler);
134 XShmDetach (xcontext->disp, &SHMInfo);
135 XSync (xcontext->disp, FALSE);
137 if (SHMInfo.shmaddr != ((void *) -1))
138 shmdt (SHMInfo.shmaddr);
140 XDestroyImage (ximage);
143 #endif /* HAVE_XSHM */
145 /* This function gets the X Display and global info about it. Everything is
146 stored in our object and will be cleaned when the object is disposed. Note
147 here that caps for supported format are generated without any window or
150 ximageutil_xcontext_get (GstElement * parent, const gchar * display_name)
152 GstXContext *xcontext = NULL;
153 XPixmapFormatValues *px_formats = NULL;
154 gint nb_formats = 0, i;
156 xcontext = g_new0 (GstXContext, 1);
158 xcontext->disp = XOpenDisplay (display_name);
159 GST_DEBUG_OBJECT (parent, "opened display %p", xcontext->disp);
160 if (!xcontext->disp) {
164 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
165 xcontext->screen_num = DefaultScreen (xcontext->disp);
166 xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
167 xcontext->root = DefaultRootWindow (xcontext->disp);
168 xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
169 xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
170 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
172 xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num);
173 xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num);
175 xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num);
176 xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num);
178 xcontext->caps = NULL;
180 GST_DEBUG_OBJECT (parent, "X reports %dx%d pixels and %d mm x %d mm",
181 xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
182 ximageutil_calculate_pixel_aspect_ratio (xcontext);
184 /* We get supported pixmap formats at supported depth */
185 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
188 XCloseDisplay (xcontext->disp);
193 /* We get bpp value corresponding to our running depth */
194 for (i = 0; i < nb_formats; i++) {
195 if (px_formats[i].depth == xcontext->depth)
196 xcontext->bpp = px_formats[i].bits_per_pixel;
201 xcontext->endianness =
202 (ImageByteOrder (xcontext->disp) ==
203 LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
206 /* Search for XShm extension support */
207 if (XShmQueryExtension (xcontext->disp) &&
208 ximageutil_check_xshm_calls (xcontext)) {
209 xcontext->use_xshm = TRUE;
210 GST_DEBUG ("ximageutil is using XShm extension");
212 xcontext->use_xshm = FALSE;
213 GST_DEBUG ("ximageutil is not using XShm extension");
215 #endif /* HAVE_XSHM */
217 /* our caps system handles 24/32bpp RGB as big-endian. */
218 if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
219 xcontext->endianness == G_LITTLE_ENDIAN) {
220 xcontext->endianness = G_BIG_ENDIAN;
221 xcontext->r_mask_output = GUINT32_TO_BE (xcontext->visual->red_mask);
222 xcontext->g_mask_output = GUINT32_TO_BE (xcontext->visual->green_mask);
223 xcontext->b_mask_output = GUINT32_TO_BE (xcontext->visual->blue_mask);
224 if (xcontext->bpp == 24) {
225 xcontext->r_mask_output >>= 8;
226 xcontext->g_mask_output >>= 8;
227 xcontext->b_mask_output >>= 8;
230 xcontext->r_mask_output = xcontext->visual->red_mask;
231 xcontext->g_mask_output = xcontext->visual->green_mask;
232 xcontext->b_mask_output = xcontext->visual->blue_mask;
238 /* This function cleans the X context. Closing the Display and unrefing the
239 caps for supported formats. */
241 ximageutil_xcontext_clear (GstXContext * xcontext)
243 g_return_if_fail (xcontext != NULL);
245 if (xcontext->caps != NULL)
246 gst_caps_unref (xcontext->caps);
249 g_value_unset (xcontext->par);
250 g_free (xcontext->par);
253 XCloseDisplay (xcontext->disp);
258 /* This function calculates the pixel aspect ratio based on the properties
259 * in the xcontext structure and stores it there. */
261 ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext)
264 {1, 1}, /* regular screen */
265 {16, 15}, /* PAL TV */
266 {11, 10}, /* 525 line Rec.601 video */
267 {54, 59} /* 625 line Rec.601 video */
274 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
276 /* first calculate the "real" ratio based on the X values;
277 * which is the "physical" w/h divided by the w/h in pixels of the display */
278 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
279 / (xcontext->heightmm * xcontext->width);
281 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
283 if (xcontext->width == 720 && xcontext->height == 576) {
284 ratio = 4.0 * 576 / (3.0 * 720);
286 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
288 /* now find the one from par[][2] with the lowest delta to the real one */
292 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
293 gdouble this_delta = DELTA (i);
295 if (this_delta < delta) {
301 GST_DEBUG ("Decided on index %d (%d/%d)", index,
302 par[index][0], par[index][1]);
305 g_free (xcontext->par);
306 xcontext->par = g_new0 (GValue, 1);
307 g_value_init (xcontext->par, GST_TYPE_FRACTION);
308 gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]);
309 GST_DEBUG ("set xcontext PAR to %d/%d\n",
310 gst_value_get_fraction_numerator (xcontext->par),
311 gst_value_get_fraction_denominator (xcontext->par));
315 gst_ximagesrc_buffer_dispose (GstBuffer * ximage)
320 g_return_if_fail (ximage != NULL);
322 meta = GST_META_XIMAGE_GET (ximage);
324 parent = meta->parent;
325 if (parent == NULL) {
326 g_warning ("XImageSrcBuffer->ximagesrc == NULL");
330 if (meta->return_func)
331 meta->return_func (parent, ximage);
338 gst_ximage_buffer_free (GstBuffer * ximage)
342 meta = GST_META_XIMAGE_GET (ximage);
344 /* make sure it is not recycled */
347 gst_buffer_unref (ximage);
350 /* This function handles GstXImageSrcBuffer creation depending on XShm availability */
352 gst_ximageutil_ximage_new (GstXContext * xcontext,
353 GstElement * parent, int width, int height, BufferReturnFunc return_func)
355 GstBuffer *ximage = NULL;
357 gboolean succeeded = FALSE;
359 ximage = gst_buffer_new ();
360 GST_MINI_OBJECT_CAST (ximage)->dispose =
361 (GstMiniObjectDisposeFunction) gst_ximagesrc_buffer_dispose;
363 meta = GST_META_XIMAGE_ADD (ximage);
365 meta->height = height;
368 meta->SHMInfo.shmaddr = ((void *) -1);
369 meta->SHMInfo.shmid = -1;
371 if (xcontext->use_xshm) {
372 meta->ximage = XShmCreateImage (xcontext->disp,
373 xcontext->visual, xcontext->depth,
374 ZPixmap, NULL, &meta->SHMInfo, meta->width, meta->height);
376 GST_WARNING_OBJECT (parent,
377 "could not XShmCreateImage a %dx%d image", meta->width, meta->height);
379 /* Retry without XShm */
380 xcontext->use_xshm = FALSE;
384 /* we have to use the returned bytes_per_line for our shm size */
385 meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
386 meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777);
387 if (meta->SHMInfo.shmid == -1)
390 meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, 0, 0);
391 if (meta->SHMInfo.shmaddr == ((void *) -1))
394 /* Delete the SHM segment. It will actually go away automatically
395 * when we detach now */
396 shmctl (meta->SHMInfo.shmid, IPC_RMID, 0);
398 meta->ximage->data = meta->SHMInfo.shmaddr;
399 meta->SHMInfo.readOnly = FALSE;
401 if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
404 XSync (xcontext->disp, FALSE);
407 #endif /* HAVE_XSHM */
409 meta->ximage = XCreateImage (xcontext->disp,
412 ZPixmap, 0, NULL, meta->width, meta->height, xcontext->bpp, 0);
416 /* we have to use the returned bytes_per_line for our image size */
417 meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
418 meta->ximage->data = g_malloc (meta->size);
420 XSync (xcontext->disp, FALSE);
424 GST_BUFFER_DATA (ximage) = (guchar *) meta->ximage->data;
425 GST_BUFFER_SIZE (ximage) = meta->size;
427 /* Keep a ref to our src */
428 meta->parent = gst_object_ref (parent);
429 meta->return_func = return_func;
432 gst_ximage_buffer_free (ximage);
439 /* This function destroys a GstXImageBuffer handling XShm availability */
441 gst_ximageutil_ximage_destroy (GstXContext * xcontext, GstBuffer * ximage)
445 meta = GST_META_XIMAGE_GET (ximage);
447 /* We might have some buffers destroyed after changing state to NULL */
451 g_return_if_fail (ximage != NULL);
454 if (xcontext->use_xshm) {
455 if (meta->SHMInfo.shmaddr != ((void *) -1)) {
456 XShmDetach (xcontext->disp, &meta->SHMInfo);
457 XSync (xcontext->disp, 0);
458 shmdt (meta->SHMInfo.shmaddr);
461 XDestroyImage (meta->ximage);
464 #endif /* HAVE_XSHM */
467 XDestroyImage (meta->ximage);
471 XSync (xcontext->disp, FALSE);
474 /* Release the ref to our parent */
475 gst_object_unref (meta->parent);