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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
24 #include "ximageutil.h"
27 gst_meta_ximage_api_get_type (void)
29 static volatile GType type;
30 static const gchar *tags[] = { "memory", NULL };
32 if (g_once_init_enter (&type)) {
33 GType _type = gst_meta_api_type_register ("GstMetaXImageSrcAPI", tags);
34 g_once_init_leave (&type, _type);
40 gst_meta_ximage_init (GstMeta * meta, gpointer params, GstBuffer * buffer)
42 GstMetaXImage *emeta = (GstMetaXImage *) meta;
47 emeta->SHMInfo.shmaddr = ((void *) -1);
48 emeta->SHMInfo.shmid = -1;
49 emeta->SHMInfo.readOnly = TRUE;
51 emeta->width = emeta->height = emeta->size = 0;
52 emeta->return_func = NULL;
58 gst_meta_ximage_get_info (void)
60 static const GstMetaInfo *meta_ximage_info = NULL;
62 if (g_once_init_enter (&meta_ximage_info)) {
63 const GstMetaInfo *meta =
64 gst_meta_register (gst_meta_ximage_api_get_type (), "GstMetaXImageSrc",
65 sizeof (GstMetaXImage), (GstMetaInitFunction) gst_meta_ximage_init,
66 (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL);
67 g_once_init_leave (&meta_ximage_info, meta);
69 return meta_ximage_info;
73 static gboolean error_caught = FALSE;
76 ximageutil_handle_xerror (Display * display, XErrorEvent * xevent)
80 XGetErrorText (display, xevent->error_code, error_msg, 1024);
81 GST_DEBUG ("ximageutil failed to use XShm calls. error: %s", error_msg);
86 /* This function checks that it is actually really possible to create an image
89 ximageutil_check_xshm_calls (GstXContext * xcontext)
92 XShmSegmentInfo SHMInfo;
94 int (*handler) (Display *, XErrorEvent *);
95 gboolean result = FALSE;
96 gboolean did_attach = FALSE;
98 g_return_val_if_fail (xcontext != NULL, FALSE);
100 /* Sync to ensure any older errors are already processed */
101 XSync (xcontext->disp, FALSE);
103 /* Set defaults so we don't free these later unnecessarily */
104 SHMInfo.shmaddr = ((void *) -1);
107 /* Setting an error handler to catch failure */
108 error_caught = FALSE;
109 handler = XSetErrorHandler (ximageutil_handle_xerror);
111 /* Trying to create a 1x1 ximage */
112 GST_DEBUG ("XShmCreateImage of 1x1");
114 ximage = XShmCreateImage (xcontext->disp, xcontext->visual,
115 xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1);
117 /* Might cause an error, sync to ensure it is noticed */
118 XSync (xcontext->disp, FALSE);
119 if (!ximage || error_caught) {
120 GST_WARNING ("could not XShmCreateImage a 1x1 image");
123 size = ximage->height * ximage->bytes_per_line;
125 SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
126 if (SHMInfo.shmid == -1) {
127 GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
132 SHMInfo.shmaddr = shmat (SHMInfo.shmid, 0, 0);
133 if (SHMInfo.shmaddr == ((void *) -1)) {
134 GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
138 /* Delete the SHM segment. It will actually go away automatically
139 * when we detach now */
140 shmctl (SHMInfo.shmid, IPC_RMID, 0);
142 ximage->data = SHMInfo.shmaddr;
143 SHMInfo.readOnly = FALSE;
145 if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
146 GST_WARNING ("Failed to XShmAttach");
150 /* Sync to ensure we see any errors we caused */
151 XSync (xcontext->disp, FALSE);
155 /* store whether we succeeded in result */
159 /* Sync to ensure we swallow any errors we caused and reset error_caught */
160 XSync (xcontext->disp, FALSE);
161 error_caught = FALSE;
162 XSetErrorHandler (handler);
165 XShmDetach (xcontext->disp, &SHMInfo);
166 XSync (xcontext->disp, FALSE);
168 if (SHMInfo.shmaddr != ((void *) -1))
169 shmdt (SHMInfo.shmaddr);
171 XDestroyImage (ximage);
174 #endif /* HAVE_XSHM */
176 /* This function gets the X Display and global info about it. Everything is
177 stored in our object and will be cleaned when the object is disposed. Note
178 here that caps for supported format are generated without any window or
181 ximageutil_xcontext_get (GstElement * parent, const gchar * display_name)
183 GstXContext *xcontext = NULL;
184 XPixmapFormatValues *px_formats = NULL;
185 gint nb_formats = 0, i;
187 xcontext = g_new0 (GstXContext, 1);
189 xcontext->disp = XOpenDisplay (display_name);
190 GST_DEBUG_OBJECT (parent, "opened display %p", xcontext->disp);
191 if (!xcontext->disp) {
195 xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
196 xcontext->visual = DefaultVisualOfScreen (xcontext->screen);
197 xcontext->root = RootWindowOfScreen (xcontext->screen);
198 xcontext->white = WhitePixelOfScreen (xcontext->screen);
199 xcontext->black = BlackPixelOfScreen (xcontext->screen);
200 xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
202 xcontext->width = WidthOfScreen (xcontext->screen);
203 xcontext->height = HeightOfScreen (xcontext->screen);
205 xcontext->widthmm = WidthMMOfScreen (xcontext->screen);
206 xcontext->heightmm = HeightMMOfScreen (xcontext->screen);
208 xcontext->caps = NULL;
210 GST_DEBUG_OBJECT (parent, "X reports %dx%d pixels and %d mm x %d mm",
211 xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
212 ximageutil_calculate_pixel_aspect_ratio (xcontext);
214 /* We get supported pixmap formats at supported depth */
215 px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
218 XCloseDisplay (xcontext->disp);
223 /* We get bpp value corresponding to our running depth */
224 for (i = 0; i < nb_formats; i++) {
225 if (px_formats[i].depth == xcontext->depth)
226 xcontext->bpp = px_formats[i].bits_per_pixel;
231 xcontext->endianness =
232 (ImageByteOrder (xcontext->disp) ==
233 LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
236 /* Search for XShm extension support */
237 if (XShmQueryExtension (xcontext->disp) &&
238 ximageutil_check_xshm_calls (xcontext)) {
239 xcontext->use_xshm = TRUE;
240 GST_DEBUG ("ximageutil is using XShm extension");
242 xcontext->use_xshm = FALSE;
243 GST_DEBUG ("ximageutil is not using XShm extension");
245 #endif /* HAVE_XSHM */
247 /* our caps system handles 24/32bpp RGB as big-endian. */
248 if ((xcontext->bpp == 24 || xcontext->bpp == 32) &&
249 xcontext->endianness == G_LITTLE_ENDIAN) {
250 xcontext->endianness = G_BIG_ENDIAN;
251 xcontext->r_mask_output = GUINT32_TO_BE (xcontext->visual->red_mask);
252 xcontext->g_mask_output = GUINT32_TO_BE (xcontext->visual->green_mask);
253 xcontext->b_mask_output = GUINT32_TO_BE (xcontext->visual->blue_mask);
254 if (xcontext->bpp == 24) {
255 xcontext->r_mask_output >>= 8;
256 xcontext->g_mask_output >>= 8;
257 xcontext->b_mask_output >>= 8;
260 xcontext->r_mask_output = xcontext->visual->red_mask;
261 xcontext->g_mask_output = xcontext->visual->green_mask;
262 xcontext->b_mask_output = xcontext->visual->blue_mask;
268 /* This function cleans the X context. Closing the Display and unrefing the
269 caps for supported formats. */
271 ximageutil_xcontext_clear (GstXContext * xcontext)
273 g_return_if_fail (xcontext != NULL);
275 if (xcontext->caps != NULL)
276 gst_caps_unref (xcontext->caps);
278 XCloseDisplay (xcontext->disp);
283 /* This function calculates the pixel aspect ratio based on the properties
284 * in the xcontext structure and stores it there. */
286 ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext)
289 {1, 1}, /* regular screen */
290 {16, 15}, /* PAL TV */
291 {11, 10}, /* 525 line Rec.601 video */
292 {54, 59} /* 625 line Rec.601 video */
299 #define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
301 /* first calculate the "real" ratio based on the X values;
302 * which is the "physical" w/h divided by the w/h in pixels of the display */
303 ratio = (gdouble) (xcontext->widthmm * xcontext->height)
304 / (xcontext->heightmm * xcontext->width);
306 /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
308 if (xcontext->width == 720 && xcontext->height == 576) {
309 ratio = 4.0 * 576 / (3.0 * 720);
311 GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
313 /* now find the one from par[][2] with the lowest delta to the real one */
317 for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
318 gdouble this_delta = DELTA (i);
320 if (this_delta < delta) {
326 GST_DEBUG ("Decided on index %d (%d/%d)", index,
327 par[index][0], par[index][1]);
329 xcontext->par_n = par[index][0];
330 xcontext->par_d = par[index][1];
331 GST_DEBUG ("set xcontext PAR to %d/%d\n", xcontext->par_n, xcontext->par_d);
335 gst_ximagesrc_buffer_dispose (GstBuffer * ximage)
341 meta = GST_META_XIMAGE_GET (ximage);
343 parent = meta->parent;
344 if (parent == NULL) {
345 g_warning ("XImageSrcBuffer->ximagesrc == NULL");
349 if (meta->return_func)
350 ret = meta->return_func (parent, ximage);
357 gst_ximage_buffer_free (GstBuffer * ximage)
361 meta = GST_META_XIMAGE_GET (ximage);
363 /* make sure it is not recycled */
366 gst_buffer_unref (ximage);
369 /* This function handles GstXImageSrcBuffer creation depending on XShm availability */
371 gst_ximageutil_ximage_new (GstXContext * xcontext,
372 GstElement * parent, int width, int height, BufferReturnFunc return_func)
374 GstBuffer *ximage = NULL;
376 gboolean succeeded = FALSE;
378 ximage = gst_buffer_new ();
379 GST_MINI_OBJECT_CAST (ximage)->dispose =
380 (GstMiniObjectDisposeFunction) gst_ximagesrc_buffer_dispose;
382 meta = GST_META_XIMAGE_ADD (ximage);
384 meta->height = height;
387 meta->SHMInfo.shmaddr = ((void *) -1);
388 meta->SHMInfo.shmid = -1;
390 if (xcontext->use_xshm) {
391 meta->ximage = XShmCreateImage (xcontext->disp,
392 xcontext->visual, xcontext->depth,
393 ZPixmap, NULL, &meta->SHMInfo, meta->width, meta->height);
395 GST_WARNING_OBJECT (parent,
396 "could not XShmCreateImage a %dx%d image", meta->width, meta->height);
398 /* Retry without XShm */
399 xcontext->use_xshm = FALSE;
403 /* we have to use the returned bytes_per_line for our shm size */
404 meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
405 meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777);
406 if (meta->SHMInfo.shmid == -1)
409 meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, 0, 0);
410 if (meta->SHMInfo.shmaddr == ((void *) -1))
413 /* Delete the SHM segment. It will actually go away automatically
414 * when we detach now */
415 shmctl (meta->SHMInfo.shmid, IPC_RMID, 0);
417 meta->ximage->data = meta->SHMInfo.shmaddr;
418 meta->SHMInfo.readOnly = FALSE;
420 if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
423 XSync (xcontext->disp, FALSE);
426 #endif /* HAVE_XSHM */
428 meta->ximage = XCreateImage (xcontext->disp,
431 ZPixmap, 0, NULL, meta->width, meta->height, xcontext->bpp, 0);
435 /* we have to use the returned bytes_per_line for our image size */
436 meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
437 meta->ximage->data = g_malloc (meta->size);
439 XSync (xcontext->disp, FALSE);
443 gst_buffer_append_memory (ximage,
444 gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->ximage->data,
445 meta->size, 0, meta->size, NULL, NULL));
447 /* Keep a ref to our src */
448 meta->parent = gst_object_ref (parent);
449 meta->return_func = return_func;
452 gst_ximage_buffer_free (ximage);
459 /* This function destroys a GstXImageBuffer handling XShm availability */
461 gst_ximageutil_ximage_destroy (GstXContext * xcontext, GstBuffer * ximage)
465 meta = GST_META_XIMAGE_GET (ximage);
467 /* We might have some buffers destroyed after changing state to NULL */
471 g_return_if_fail (ximage != NULL);
474 if (xcontext->use_xshm) {
475 if (meta->SHMInfo.shmaddr != ((void *) -1)) {
476 XShmDetach (xcontext->disp, &meta->SHMInfo);
477 XSync (xcontext->disp, 0);
478 shmdt (meta->SHMInfo.shmaddr);
481 XDestroyImage (meta->ximage);
484 #endif /* HAVE_XSHM */
487 XDestroyImage (meta->ximage);
491 XSync (xcontext->disp, FALSE);
494 /* Release the ref to our parent */
495 gst_object_unref (meta->parent);