From 0cf392837d6660e05b54ea0b8682471359bf35d1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 13 Mar 2013 11:13:58 +0100 Subject: [PATCH] xvimagesink: use xvcontext for allocation Make a new refcounted xvcontext object that handles the X connection. Use the xvcontext to allocate images and windows. Move some code around so that all X calls are made from the xvcontext object. Make a GstXvImageAllocator object that allocates images from the xvcontext. We can implement a copy function now for these memory objects now. Make the bufferpool use the xvimageallocator object for its images. --- sys/xvimage/Makefile.am | 4 +- sys/xvimage/xvcontext.c | 1119 ++++++++++++++++++++++++++++++++ sys/xvimage/xvcontext.h | 247 +++++++ sys/xvimage/xvimage.c | 3 + sys/xvimage/xvimageallocator.c | 651 +++++++++++++++++++ sys/xvimage/xvimageallocator.h | 69 ++ sys/xvimage/xvimagepool.c | 579 +---------------- sys/xvimage/xvimagepool.h | 62 +- sys/xvimage/xvimagesink.c | 1392 +++++++--------------------------------- sys/xvimage/xvimagesink.h | 159 +---- 10 files changed, 2362 insertions(+), 1923 deletions(-) create mode 100644 sys/xvimage/xvcontext.c create mode 100644 sys/xvimage/xvcontext.h create mode 100644 sys/xvimage/xvimageallocator.c create mode 100644 sys/xvimage/xvimageallocator.h diff --git a/sys/xvimage/Makefile.am b/sys/xvimage/Makefile.am index 170b7b8..79bf82e 100644 --- a/sys/xvimage/Makefile.am +++ b/sys/xvimage/Makefile.am @@ -1,6 +1,6 @@ plugin_LTLIBRARIES = libgstxvimagesink.la -libgstxvimagesink_la_SOURCES = xvimagesink.c xvimage.c xvimagepool.c +libgstxvimagesink_la_SOURCES = xvimagesink.c xvimage.c xvimagepool.c xvimageallocator.c xvcontext.c libgstxvimagesink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(X_CFLAGS) libgstxvimagesink_la_LIBADD = \ $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_API_VERSION).la \ @@ -11,4 +11,4 @@ libgstxvimagesink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstxvimagesink_la_DEPENDENCIES = $(top_builddir)/gst-libs/gst/video/libgstvideo-$(GST_API_VERSION).la libgstxvimagesink_la_LIBTOOLFLAGS = --tag=disable-static -noinst_HEADERS = xvimagesink.h xvimagepool.h +noinst_HEADERS = xvimagesink.h xvimagepool.h xvimageallocator.h xvcontext.h diff --git a/sys/xvimage/xvcontext.c b/sys/xvimage/xvcontext.c new file mode 100644 index 0000000..52f3dc5 --- /dev/null +++ b/sys/xvimage/xvcontext.c @@ -0,0 +1,1119 @@ +/* GStreamer + * Copyright (C) <2005> Julien Moutte + * <2009>,<2010> Stefan Kost + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/* for developers: there are two useful tools : xvinfo and xvattr */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* Object header */ +#include "xvcontext.h" + +/* Debugging category */ +#include + +/* for XkbKeycodeToKeysym */ +#include + +GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvcontext); +GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE); +#define GST_CAT_DEFAULT gst_debug_xvcontext + +void +gst_xvcontext_config_clear (GstXvContextConfig * config) +{ + if (config->display_name) { + g_free (config->display_name); + config->display_name = NULL; + } + config->adaptor_nr = -1; +} + +GST_DEFINE_MINI_OBJECT_TYPE (GstXvContext, gst_xvcontext); + +typedef struct +{ + unsigned long flags; + unsigned long functions; + unsigned long decorations; + long input_mode; + unsigned long status; +} +MotifWmHints, MwmHints; + +#define MWM_HINTS_DECORATIONS (1L << 1) + + +static void +gst_lookup_xv_port_from_adaptor (GstXvContext * context, + XvAdaptorInfo * adaptors, guint adaptor_nr) +{ + gint j; + gint res; + + /* Do we support XvImageMask ? */ + if (!(adaptors[adaptor_nr].type & XvImageMask)) { + GST_DEBUG ("XV Adaptor %s has no support for XvImageMask", + adaptors[adaptor_nr].name); + return; + } + + /* We found such an adaptor, looking for an available port */ + for (j = 0; j < adaptors[adaptor_nr].num_ports && !context->xv_port_id; j++) { + /* We try to grab the port */ + res = XvGrabPort (context->disp, adaptors[adaptor_nr].base_id + j, 0); + if (Success == res) { + context->xv_port_id = adaptors[adaptor_nr].base_id + j; + GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_nr].name, + adaptors[adaptor_nr].num_ports); + } else { + GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j, + adaptors[adaptor_nr].name, res); + } + } +} + +/* This function generates a caps with all supported format by the first + Xv grabable port we find. We store each one of the supported formats in a + format list and append the format to a newly created caps that we return + If this function does not return NULL because of an error, it also grabs + the port via XvGrabPort */ +static GstCaps * +gst_xvcontext_get_xv_support (GstXvContext * context, + const GstXvContextConfig * config, GError ** error) +{ + gint i; + XvAdaptorInfo *adaptors; + gint nb_formats; + XvImageFormatValues *formats = NULL; + guint nb_encodings; + XvEncodingInfo *encodings = NULL; + gulong max_w = G_MAXINT, max_h = G_MAXINT; + GstCaps *caps = NULL; + GstCaps *rgb_caps = NULL; + + g_return_val_if_fail (context != NULL, NULL); + + /* First let's check that XVideo extension is available */ + if (!XQueryExtension (context->disp, "XVideo", &i, &i, &i)) + goto no_xv; + + /* Then we get adaptors list */ + if (Success != XvQueryAdaptors (context->disp, context->root, + &context->nb_adaptors, &adaptors)) + goto no_adaptors; + + context->xv_port_id = 0; + + GST_DEBUG ("Found %u XV adaptor(s)", context->nb_adaptors); + + context->adaptors = + (gchar **) g_malloc0 (context->nb_adaptors * sizeof (gchar *)); + + /* Now fill up our adaptor name array */ + for (i = 0; i < context->nb_adaptors; i++) { + context->adaptors[i] = g_strdup (adaptors[i].name); + } + + if (config->adaptor_nr != -1 && config->adaptor_nr < context->nb_adaptors) { + /* Find xv port from user defined adaptor */ + gst_lookup_xv_port_from_adaptor (context, adaptors, config->adaptor_nr); + } + + if (!context->xv_port_id) { + /* Now search for an adaptor that supports XvImageMask */ + for (i = 0; i < context->nb_adaptors && !context->xv_port_id; i++) { + gst_lookup_xv_port_from_adaptor (context, adaptors, i); + context->adaptor_nr = i; + } + } + + XvFreeAdaptorInfo (adaptors); + + if (!context->xv_port_id) + goto no_ports; + + /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */ + { + int count, todo = 3; + XvAttribute *const attr = XvQueryPortAttributes (context->disp, + context->xv_port_id, &count); + static const char autopaint[] = "XV_AUTOPAINT_COLORKEY"; + static const char dbl_buffer[] = "XV_DOUBLE_BUFFER"; + static const char colorkey[] = "XV_COLORKEY"; + + GST_DEBUG ("Checking %d Xv port attributes", count); + + context->have_autopaint_colorkey = FALSE; + context->have_double_buffer = FALSE; + context->have_colorkey = FALSE; + + for (i = 0; ((i < count) && todo); i++) { + GST_DEBUG ("Got attribute %s", attr[i].name); + + if (!strcmp (attr[i].name, autopaint)) { + const Atom atom = XInternAtom (context->disp, autopaint, False); + + /* turn on autopaint colorkey */ + XvSetPortAttribute (context->disp, context->xv_port_id, atom, + (config->autopaint_colorkey ? 1 : 0)); + todo--; + context->have_autopaint_colorkey = TRUE; + } else if (!strcmp (attr[i].name, dbl_buffer)) { + const Atom atom = XInternAtom (context->disp, dbl_buffer, False); + + XvSetPortAttribute (context->disp, context->xv_port_id, atom, + (config->double_buffer ? 1 : 0)); + todo--; + context->have_double_buffer = TRUE; + } else if (!strcmp (attr[i].name, colorkey)) { + /* Set the colorkey, default is something that is dark but hopefully + * won't randomly appear on the screen elsewhere (ie not black or greys) + * can be overridden by setting "colorkey" property + */ + const Atom atom = XInternAtom (context->disp, colorkey, False); + guint32 ckey = 0; + gboolean set_attr = TRUE; + guint cr, cg, cb; + + /* set a colorkey in the right format RGB565/RGB888 + * We only handle these 2 cases, because they're the only types of + * devices we've encountered. If we don't recognise it, leave it alone + */ + cr = (config->colorkey >> 16); + cg = (config->colorkey >> 8) & 0xFF; + cb = (config->colorkey) & 0xFF; + switch (context->depth) { + case 16: /* RGB 565 */ + cr >>= 3; + cg >>= 2; + cb >>= 3; + ckey = (cr << 11) | (cg << 5) | cb; + break; + case 24: + case 32: /* RGB 888 / ARGB 8888 */ + ckey = (cr << 16) | (cg << 8) | cb; + break; + default: + GST_DEBUG ("Unknown bit depth %d for Xv Colorkey - not adjusting", + context->depth); + set_attr = FALSE; + break; + } + + if (set_attr) { + ckey = CLAMP (ckey, (guint32) attr[i].min_value, + (guint32) attr[i].max_value); + GST_LOG ("Setting color key for display depth %d to 0x%x", + context->depth, ckey); + + XvSetPortAttribute (context->disp, context->xv_port_id, atom, + (gint) ckey); + } + todo--; + context->have_colorkey = TRUE; + } + } + + XFree (attr); + } + + /* Get the list of encodings supported by the adapter and look for the + * XV_IMAGE encoding so we can determine the maximum width and height + * supported */ + XvQueryEncodings (context->disp, context->xv_port_id, &nb_encodings, + &encodings); + + for (i = 0; i < nb_encodings; i++) { + GST_LOG ("Encoding %d, name %s, max wxh %lux%lu rate %d/%d", + i, encodings[i].name, encodings[i].width, encodings[i].height, + encodings[i].rate.numerator, encodings[i].rate.denominator); + if (strcmp (encodings[i].name, "XV_IMAGE") == 0) { + max_w = encodings[i].width; + max_h = encodings[i].height; + } + } + + XvFreeEncodingInfo (encodings); + + /* We get all image formats supported by our port */ + formats = XvListImageFormats (context->disp, + context->xv_port_id, &nb_formats); + caps = gst_caps_new_empty (); + for (i = 0; i < nb_formats; i++) { + GstCaps *format_caps = NULL; + gboolean is_rgb_format = FALSE; + GstVideoFormat vformat; + + /* We set the image format of the context to an existing one. This + is just some valid image format for making our xshm calls check before + caps negotiation really happens. */ + context->im_format = formats[i].id; + + switch (formats[i].type) { + case XvRGB: + { + XvImageFormatValues *fmt = &(formats[i]); + gint endianness; + + endianness = + (fmt->byte_order == LSBFirst ? G_LITTLE_ENDIAN : G_BIG_ENDIAN); + + vformat = gst_video_format_from_masks (fmt->depth, fmt->bits_per_pixel, + endianness, fmt->red_mask, fmt->green_mask, fmt->blue_mask, 0); + if (vformat == GST_VIDEO_FORMAT_UNKNOWN) + break; + + format_caps = gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, gst_video_format_to_string (vformat), + "width", GST_TYPE_INT_RANGE, 1, max_w, + "height", GST_TYPE_INT_RANGE, 1, max_h, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + + is_rgb_format = TRUE; + break; + } + case XvYUV: + { + vformat = gst_video_format_from_fourcc (formats[i].id); + if (vformat == GST_VIDEO_FORMAT_UNKNOWN) + break; + + format_caps = gst_caps_new_simple ("video/x-raw", + "format", G_TYPE_STRING, gst_video_format_to_string (vformat), + "width", GST_TYPE_INT_RANGE, 1, max_w, + "height", GST_TYPE_INT_RANGE, 1, max_h, + "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); + break; + } + default: + vformat = GST_VIDEO_FORMAT_UNKNOWN; + g_assert_not_reached (); + break; + } + + if (format_caps) { + GstXvImageFormat *format = NULL; + + format = g_new0 (GstXvImageFormat, 1); + if (format) { + format->format = formats[i].id; + format->vformat = vformat; + format->caps = gst_caps_copy (format_caps); + context->formats_list = g_list_append (context->formats_list, format); + } + + if (is_rgb_format) { + if (rgb_caps == NULL) + rgb_caps = format_caps; + else + gst_caps_append (rgb_caps, format_caps); + } else + gst_caps_append (caps, format_caps); + } + } + + /* Collected all caps into either the caps or rgb_caps structures. + * Append rgb_caps on the end of YUV, so that YUV is always preferred */ + if (rgb_caps) + gst_caps_append (caps, rgb_caps); + + if (formats) + XFree (formats); + + GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps); + + if (gst_caps_is_empty (caps)) + goto no_caps; + + return caps; + + /* ERRORS */ +no_xv: + { + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_SETTINGS, + ("XVideo extension is not available")); + return NULL; + } +no_adaptors: + { + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_SETTINGS, + ("Failed getting XV adaptors list")); + return NULL; + } +no_ports: + { + context->adaptor_nr = -1; + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_BUSY, + ("No Xv Port available")); + return NULL; + } +no_caps: + { + gst_caps_unref (caps); + g_set_error (error, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE, + ("No supported format found")); + return NULL; + } +} + +/* This function calculates the pixel aspect ratio based on the properties + * in the context structure and stores it there. */ +static void +gst_xvcontext_calculate_pixel_aspect_ratio (GstXvContext * context) +{ + static const gint par[][2] = { + {1, 1}, /* regular screen */ + {16, 15}, /* PAL TV */ + {11, 10}, /* 525 line Rec.601 video */ + {54, 59}, /* 625 line Rec.601 video */ + {64, 45}, /* 1280x1024 on 16:9 display */ + {5, 3}, /* 1280x1024 on 4:3 display */ + {4, 3} /* 800x600 on 16:9 display */ + }; + gint i; + gint index; + gdouble ratio; + gdouble delta; + +#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1]))) + + /* first calculate the "real" ratio based on the X values; + * which is the "physical" w/h divided by the w/h in pixels of the display */ + ratio = (gdouble) (context->widthmm * context->height) + / (context->heightmm * context->width); + + /* DirectFB's X in 720x576 reports the physical dimensions wrong, so + * override here */ + if (context->width == 720 && context->height == 576) { + ratio = 4.0 * 576 / (3.0 * 720); + } + GST_DEBUG ("calculated pixel aspect ratio: %f", ratio); + + /* now find the one from par[][2] with the lowest delta to the real one */ + delta = DELTA (0); + index = 0; + + for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) { + gdouble this_delta = DELTA (i); + + if (this_delta < delta) { + index = i; + delta = this_delta; + } + } + + GST_DEBUG ("Decided on index %d (%d/%d)", index, + par[index][0], par[index][1]); + + g_free (context->par); + context->par = g_new0 (GValue, 1); + g_value_init (context->par, GST_TYPE_FRACTION); + gst_value_set_fraction (context->par, par[index][0], par[index][1]); + GST_DEBUG ("set context PAR to %d/%d", + gst_value_get_fraction_numerator (context->par), + gst_value_get_fraction_denominator (context->par)); +} + +#ifdef HAVE_XSHM +/* X11 stuff */ +static gboolean error_caught = FALSE; + +static int +gst_xvimage_handle_xerror (Display * display, XErrorEvent * xevent) +{ + char error_msg[1024]; + + XGetErrorText (display, xevent->error_code, error_msg, 1024); + GST_DEBUG ("xvimage triggered an XError. error: %s", error_msg); + error_caught = TRUE; + return 0; +} + +/* This function checks that it is actually really possible to create an image + using XShm */ +static gboolean +gst_xvcontext_check_xshm_calls (GstXvContext * context) +{ + XvImage *xvimage; + XShmSegmentInfo SHMInfo; + size_t size; + int (*handler) (Display *, XErrorEvent *); + gboolean result = FALSE; + gboolean did_attach = FALSE; + + g_return_val_if_fail (context != NULL, FALSE); + + /* Sync to ensure any older errors are already processed */ + XSync (context->disp, FALSE); + + /* Set defaults so we don't free these later unnecessarily */ + SHMInfo.shmaddr = ((void *) -1); + SHMInfo.shmid = -1; + + /* Setting an error handler to catch failure */ + error_caught = FALSE; + handler = XSetErrorHandler (gst_xvimage_handle_xerror); + + /* Trying to create a 1x1 picture */ + GST_DEBUG ("XvShmCreateImage of 1x1"); + xvimage = XvShmCreateImage (context->disp, context->xv_port_id, + context->im_format, NULL, 1, 1, &SHMInfo); + + /* Might cause an error, sync to ensure it is noticed */ + XSync (context->disp, FALSE); + if (!xvimage || error_caught) { + GST_WARNING ("could not XvShmCreateImage a 1x1 image"); + goto beach; + } + size = xvimage->data_size; + SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); + if (SHMInfo.shmid == -1) { + GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", + size); + goto beach; + } + + SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); + if (SHMInfo.shmaddr == ((void *) -1)) { + GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); + /* Clean up the shared memory segment */ + shmctl (SHMInfo.shmid, IPC_RMID, NULL); + goto beach; + } + + xvimage->data = SHMInfo.shmaddr; + SHMInfo.readOnly = FALSE; + + if (XShmAttach (context->disp, &SHMInfo) == 0) { + GST_WARNING ("Failed to XShmAttach"); + /* Clean up the shared memory segment */ + shmctl (SHMInfo.shmid, IPC_RMID, NULL); + goto beach; + } + + /* Sync to ensure we see any errors we caused */ + XSync (context->disp, FALSE); + + /* Delete the shared memory segment as soon as everyone is attached. + * This way, it will be deleted as soon as we detach later, and not + * leaked if we crash. */ + shmctl (SHMInfo.shmid, IPC_RMID, NULL); + + if (!error_caught) { + GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid, + SHMInfo.shmseg); + + did_attach = TRUE; + /* store whether we succeeded in result */ + result = TRUE; + } else { + GST_WARNING ("MIT-SHM extension check failed at XShmAttach. " + "Not using shared memory."); + } + +beach: + /* Sync to ensure we swallow any errors we caused and reset error_caught */ + XSync (context->disp, FALSE); + + error_caught = FALSE; + XSetErrorHandler (handler); + + if (did_attach) { + GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx", + SHMInfo.shmid, SHMInfo.shmseg); + XShmDetach (context->disp, &SHMInfo); + XSync (context->disp, FALSE); + } + if (SHMInfo.shmaddr != ((void *) -1)) + shmdt (SHMInfo.shmaddr); + if (xvimage) + XFree (xvimage); + return result; +} +#endif /* HAVE_XSHM */ + +static GstXvContext * +gst_xvcontext_copy (GstXvContext * context) +{ + return NULL; +} + +static void +gst_xvcontext_free (GstXvContext * context) +{ + GList *formats_list, *channels_list; + gint i = 0; + + GST_LOG ("free %p", context); + + formats_list = context->formats_list; + + while (formats_list) { + GstXvImageFormat *format = formats_list->data; + + gst_caps_unref (format->caps); + g_free (format); + formats_list = g_list_next (formats_list); + } + + if (context->formats_list) + g_list_free (context->formats_list); + + channels_list = context->channels_list; + + while (channels_list) { + GstColorBalanceChannel *channel = channels_list->data; + + g_object_unref (channel); + channels_list = g_list_next (channels_list); + } + + if (context->channels_list) + g_list_free (context->channels_list); + + if (context->caps) + gst_caps_unref (context->caps); + if (context->last_caps) + gst_caps_unref (context->last_caps); + + for (i = 0; i < context->nb_adaptors; i++) { + g_free (context->adaptors[i]); + } + + g_free (context->adaptors); + + g_free (context->par); + + GST_DEBUG ("Closing display and freeing X Context"); + + if (context->xv_port_id) + XvUngrabPort (context->disp, context->xv_port_id, 0); + + if (context->disp) + XCloseDisplay (context->disp); + + g_mutex_clear (&context->lock); + + g_slice_free1 (sizeof (GstXvContext), context); +} + + +/* This function gets the X Display and global info about it. Everything is + stored in our object and will be cleaned when the object is disposed. Note + here that caps for supported format are generated without any window or + image creation */ +GstXvContext * +gst_xvcontext_new (GstXvContextConfig * config, GError ** error) +{ + GstXvContext *context = NULL; + XPixmapFormatValues *px_formats = NULL; + gint nb_formats = 0, i, j, N_attr; + XvAttribute *xv_attr; + Atom prop_atom; + const char *channels[4] = { "XV_HUE", "XV_SATURATION", + "XV_BRIGHTNESS", "XV_CONTRAST" + }; + + g_return_val_if_fail (config != NULL, NULL); + + context = g_slice_new0 (GstXvContext); + + gst_mini_object_init (GST_MINI_OBJECT_CAST (context), 0, + gst_xvcontext_get_type (), + (GstMiniObjectCopyFunction) gst_xvcontext_copy, + (GstMiniObjectDisposeFunction) NULL, + (GstMiniObjectFreeFunction) gst_xvcontext_free); + + g_mutex_init (&context->lock); + context->im_format = 0; + context->adaptor_nr = -1; + + if (!(context->disp = XOpenDisplay (config->display_name))) + goto no_display; + + context->screen = DefaultScreenOfDisplay (context->disp); + context->screen_num = DefaultScreen (context->disp); + context->visual = DefaultVisual (context->disp, context->screen_num); + context->root = DefaultRootWindow (context->disp); + context->white = XWhitePixel (context->disp, context->screen_num); + context->black = XBlackPixel (context->disp, context->screen_num); + context->depth = DefaultDepthOfScreen (context->screen); + + context->width = DisplayWidth (context->disp, context->screen_num); + context->height = DisplayHeight (context->disp, context->screen_num); + context->widthmm = DisplayWidthMM (context->disp, context->screen_num); + context->heightmm = DisplayHeightMM (context->disp, context->screen_num); + + GST_DEBUG ("X reports %dx%d pixels and %d mm x %d mm", + context->width, context->height, context->widthmm, context->heightmm); + + gst_xvcontext_calculate_pixel_aspect_ratio (context); + /* We get supported pixmap formats at supported depth */ + px_formats = XListPixmapFormats (context->disp, &nb_formats); + + if (!px_formats) + goto no_pixel_formats; + + /* We get bpp value corresponding to our running depth */ + for (i = 0; i < nb_formats; i++) { + if (px_formats[i].depth == context->depth) + context->bpp = px_formats[i].bits_per_pixel; + } + + XFree (px_formats); + + context->endianness = + (ImageByteOrder (context->disp) == + LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN; + + /* our caps system handles 24/32bpp RGB as big-endian. */ + if ((context->bpp == 24 || context->bpp == 32) && + context->endianness == G_LITTLE_ENDIAN) { + context->endianness = G_BIG_ENDIAN; + context->visual->red_mask = GUINT32_TO_BE (context->visual->red_mask); + context->visual->green_mask = GUINT32_TO_BE (context->visual->green_mask); + context->visual->blue_mask = GUINT32_TO_BE (context->visual->blue_mask); + if (context->bpp == 24) { + context->visual->red_mask >>= 8; + context->visual->green_mask >>= 8; + context->visual->blue_mask >>= 8; + } + } + + if (!(context->caps = gst_xvcontext_get_xv_support (context, config, error))) + goto no_caps; + + /* Search for XShm extension support */ +#ifdef HAVE_XSHM + if (XShmQueryExtension (context->disp) && + gst_xvcontext_check_xshm_calls (context)) { + context->use_xshm = TRUE; + GST_DEBUG ("xvimagesink is using XShm extension"); + } else +#endif /* HAVE_XSHM */ + { + context->use_xshm = FALSE; + GST_DEBUG ("xvimagesink is not using XShm extension"); + } + + xv_attr = XvQueryPortAttributes (context->disp, context->xv_port_id, &N_attr); + + /* Generate the channels list */ + for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) { + XvAttribute *matching_attr = NULL; + + /* Retrieve the property atom if it exists. If it doesn't exist, + * the attribute itself must not either, so we can skip */ + prop_atom = XInternAtom (context->disp, channels[i], True); + if (prop_atom == None) + continue; + + if (xv_attr != NULL) { + for (j = 0; j < N_attr && matching_attr == NULL; ++j) + if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name)) + matching_attr = xv_attr + j; + } + + if (matching_attr) { + GstColorBalanceChannel *channel; + + channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); + channel->label = g_strdup (channels[i]); + channel->min_value = matching_attr ? matching_attr->min_value : -1000; + channel->max_value = matching_attr ? matching_attr->max_value : 1000; + + context->channels_list = g_list_append (context->channels_list, channel); + + /* If the colorbalance settings have not been touched we get Xv values + as defaults and update our internal variables */ + if (!config->cb_changed) { + gint val; + + XvGetPortAttribute (context->disp, context->xv_port_id, + prop_atom, &val); + /* Normalize val to [-1000, 1000] */ + val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) / + (double) (channel->max_value - channel->min_value)); + + if (!g_ascii_strcasecmp (channels[i], "XV_HUE")) + config->hue = val; + else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION")) + config->saturation = val; + else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS")) + config->brightness = val; + else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST")) + config->contrast = val; + } + } + } + + if (xv_attr) + XFree (xv_attr); + + return context; + + /* ERRORS */ +no_display: + { + gst_xvcontext_unref (context); + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE, + "Could not open display %s", config->display_name); + return NULL; + } +no_pixel_formats: + { + gst_xvcontext_unref (context); + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_SETTINGS, + ("Could not get pixel formats")); + return NULL; + } +no_caps: + { + gst_xvcontext_unref (context); + return NULL; + } +} + +void +gst_xvcontext_set_synchronous (GstXvContext * context, gboolean synchronous) +{ + /* call XSynchronize with the current value of synchronous */ + GST_DEBUG ("XSynchronize called with %s", synchronous ? "TRUE" : "FALSE"); + XSynchronize (context->disp, synchronous); +} + +void +gst_xvcontext_update_colorbalance (GstXvContext * context, + GstXvContextConfig * config) +{ + GList *channels = NULL; + + /* Don't set the attributes if they haven't been changed, to avoid + * rounding errors changing the values */ + if (!config->cb_changed) + return; + + /* For each channel of the colorbalance we calculate the correct value + doing range conversion and then set the Xv port attribute to match our + values. */ + channels = context->channels_list; + + while (channels) { + if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) { + GstColorBalanceChannel *channel = NULL; + Atom prop_atom; + gint value = 0; + gdouble convert_coef; + + channel = GST_COLOR_BALANCE_CHANNEL (channels->data); + g_object_ref (channel); + + /* Our range conversion coef */ + convert_coef = (channel->max_value - channel->min_value) / 2000.0; + + if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { + value = config->hue; + } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { + value = config->saturation; + } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { + value = config->contrast; + } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { + value = config->brightness; + } else { + g_warning ("got an unknown channel %s", channel->label); + g_object_unref (channel); + return; + } + + /* Committing to Xv port */ + g_mutex_lock (&context->lock); + prop_atom = XInternAtom (context->disp, channel->label, True); + if (prop_atom != None) { + int xv_value; + xv_value = + floor (0.5 + (value + 1000) * convert_coef + channel->min_value); + XvSetPortAttribute (context->disp, + context->xv_port_id, prop_atom, xv_value); + } + g_mutex_unlock (&context->lock); + + g_object_unref (channel); + } + channels = g_list_next (channels); + } +} + +/* This function tries to get a format matching with a given caps in the + supported list of formats we generated in gst_xvimagesink_get_xv_support */ +gint +gst_xvcontext_get_format_from_info (GstXvContext * context, GstVideoInfo * info) +{ + GList *list = NULL; + + list = context->formats_list; + + while (list) { + GstXvImageFormat *format = list->data; + + if (format && format->vformat == GST_VIDEO_INFO_FORMAT (info)) + return format->format; + + list = g_list_next (list); + } + return -1; +} + +GstXWindow * +gst_xvcontext_create_xwindow (GstXvContext * context, gint width, gint height) +{ + GstXWindow *window; + Atom wm_delete; + Atom hints_atom = None; + + g_return_val_if_fail (GST_IS_XVCONTEXT (context), NULL); + + window = g_slice_new0 (GstXWindow); + + window->context = gst_xvcontext_ref (context); + window->render_rect.x = window->render_rect.y = 0; + window->render_rect.w = width; + window->render_rect.h = height; + window->have_render_rect = FALSE; + + window->width = width; + window->height = height; + window->internal = TRUE; + + g_mutex_lock (&context->lock); + + window->win = XCreateSimpleWindow (context->disp, + context->root, 0, 0, width, height, 0, 0, context->black); + + /* We have to do that to prevent X from redrawing the background on + * ConfigureNotify. This takes away flickering of video when resizing. */ + XSetWindowBackgroundPixmap (context->disp, window->win, None); + + /* Tell the window manager we'd like delete client messages instead of + * being killed */ + wm_delete = XInternAtom (context->disp, "WM_DELETE_WINDOW", True); + if (wm_delete != None) { + (void) XSetWMProtocols (context->disp, window->win, &wm_delete, 1); + } + + hints_atom = XInternAtom (context->disp, "_MOTIF_WM_HINTS", True); + if (hints_atom != None) { + MotifWmHints *hints; + + hints = g_malloc0 (sizeof (MotifWmHints)); + + hints->flags |= MWM_HINTS_DECORATIONS; + hints->decorations = 1 << 0; + + XChangeProperty (context->disp, window->win, + hints_atom, hints_atom, 32, PropModeReplace, + (guchar *) hints, sizeof (MotifWmHints) / sizeof (long)); + + XSync (context->disp, FALSE); + + g_free (hints); + } + + window->gc = XCreateGC (context->disp, window->win, 0, NULL); + + XMapRaised (context->disp, window->win); + + XSync (context->disp, FALSE); + + g_mutex_unlock (&context->lock); + + return window; +} + +GstXWindow * +gst_xvcontext_create_xwindow_from_xid (GstXvContext * context, XID xid) +{ + GstXWindow *window; + XWindowAttributes attr; + + window = g_slice_new0 (GstXWindow); + window->win = xid; + window->context = gst_xvcontext_ref (context); + + /* Set the event we want to receive and create a GC */ + g_mutex_lock (&context->lock); + + XGetWindowAttributes (context->disp, window->win, &attr); + + window->width = attr.width; + window->height = attr.height; + window->internal = FALSE; + + window->have_render_rect = FALSE; + window->render_rect.x = window->render_rect.y = 0; + window->render_rect.w = attr.width; + window->render_rect.h = attr.height; + + window->gc = XCreateGC (context->disp, window->win, 0, NULL); + g_mutex_unlock (&context->lock); + + return window; +} + +void +gst_xwindow_destroy (GstXWindow * window) +{ + GstXvContext *context; + + g_return_if_fail (window != NULL); + + context = window->context; + + g_mutex_lock (&context->lock); + + /* If we did not create that window we just free the GC and let it live */ + if (window->internal) + XDestroyWindow (context->disp, window->win); + else + XSelectInput (context->disp, window->win, 0); + + XFreeGC (context->disp, window->gc); + + XSync (context->disp, FALSE); + + g_mutex_unlock (&context->lock); + + gst_xvcontext_unref (context); + + g_slice_free1 (sizeof (GstXWindow), window); +} + +void +gst_xwindow_set_event_handling (GstXWindow * window, gboolean handle_events) +{ + GstXvContext *context; + + g_return_if_fail (window != NULL); + + context = window->context; + + g_mutex_lock (&context->lock); + if (handle_events) { + if (window->internal) { + XSelectInput (context->disp, window->win, + ExposureMask | StructureNotifyMask | PointerMotionMask | + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); + } else { + XSelectInput (context->disp, window->win, + ExposureMask | StructureNotifyMask | PointerMotionMask | + KeyPressMask | KeyReleaseMask); + } + } else { + XSelectInput (context->disp, window->win, 0); + } + g_mutex_unlock (&context->lock); +} + +void +gst_xwindow_set_title (GstXWindow * window, const gchar * title) +{ + GstXvContext *context; + + g_return_if_fail (window != NULL); + + context = window->context; + + /* we have a window */ + if (window->internal && title) { + XTextProperty xproperty; + + if ((XStringListToTextProperty (((char **) &title), 1, &xproperty)) != 0) { + XSetWMName (context->disp, window->win, &xproperty); + XFree (xproperty.value); + } + } +} + +void +gst_xwindow_update_geometry (GstXWindow * window) +{ + XWindowAttributes attr; + GstXvContext *context; + + g_return_if_fail (window != NULL); + + context = window->context; + + /* Update the window geometry */ + g_mutex_lock (&context->lock); + XGetWindowAttributes (context->disp, window->win, &attr); + + window->width = attr.width; + window->height = attr.height; + + if (!window->have_render_rect) { + window->render_rect.x = window->render_rect.y = 0; + window->render_rect.w = attr.width; + window->render_rect.h = attr.height; + } + + g_mutex_unlock (&context->lock); +} + + +void +gst_xwindow_clear (GstXWindow * window) +{ + GstXvContext *context; + + g_return_if_fail (window != NULL); + + context = window->context; + + g_mutex_lock (&context->lock); + + XvStopVideo (context->disp, context->xv_port_id, window->win); + + XSync (context->disp, FALSE); + + g_mutex_unlock (&context->lock); +} + +void +gst_xwindow_set_render_rectangle (GstXWindow * window, + gint x, gint y, gint width, gint height) +{ + g_return_if_fail (window != NULL); + + if (width >= 0 && height >= 0) { + window->render_rect.x = x; + window->render_rect.y = y; + window->render_rect.w = width; + window->render_rect.h = height; + window->have_render_rect = TRUE; + } else { + window->render_rect.x = 0; + window->render_rect.y = 0; + window->render_rect.w = window->width; + window->render_rect.h = window->height; + window->have_render_rect = FALSE; + } +} diff --git a/sys/xvimage/xvcontext.h b/sys/xvimage/xvcontext.h new file mode 100644 index 0000000..2289787 --- /dev/null +++ b/sys/xvimage/xvcontext.h @@ -0,0 +1,247 @@ +/* GStreamer + * Copyright (C) <2005> Julien Moutte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_XVCONTEXT_H__ +#define __GST_XVCONTEXT_H__ + +#ifdef HAVE_XSHM +#include +#include +#include +#endif /* HAVE_XSHM */ + +#include +#include + +#ifdef HAVE_XSHM +#include +#endif /* HAVE_XSHM */ + +#include +#include + +#include +#include +#include + +#include + +G_BEGIN_DECLS + +typedef struct _GstXvContextConfig GstXvContextConfig; +typedef struct _GstXvImageFormat GstXvImageFormat; +typedef struct _GstXvContext GstXvContext; + +/** + * GstXvContextConfig: + * + * current configuration of the context + */ +struct _GstXvContextConfig +{ + gchar *display_name; + guint adaptor_nr; + + /* port attributes */ + gboolean autopaint_colorkey; + gint colorkey; + + gboolean double_buffer; + + gint brightness; + gint contrast; + gint hue; + gint saturation; + gboolean cb_changed; +}; + +/** + * GstXvImageFormat: + * @format: the image format + * @caps: generated #GstCaps for this image format + * + * Structure storing image format to #GstCaps association. + */ +struct _GstXvImageFormat +{ + gint format; + GstVideoFormat vformat; + GstCaps *caps; +}; + +#define GST_TYPE_XVCONTEXT (gst_xvcontext_get_type()) +#define GST_IS_XVCONTEXT(obj) (GST_IS_MINI_OBJECT_TYPE(obj, GST_TYPE_XVCONTEXT)) +#define GST_XVCONTEXT_CAST(obj) ((GstXvContext *)obj) +#define GST_XVCONTEXT(obj) (GST_XVCONTEXT_CAST(obj)) + +/* + * GstXvContext: + * @disp: the X11 Display of this context + * @screen: the default Screen of Display @disp + * @screen_num: the Screen number of @screen + * @visual: the default Visual of Screen @screen + * @root: the root Window of Display @disp + * @white: the value of a white pixel on Screen @screen + * @black: the value of a black pixel on Screen @screen + * @depth: the color depth of Display @disp + * @bpp: the number of bits per pixel on Display @disp + * @endianness: the endianness of image bytes on Display @disp + * @width: the width in pixels of Display @disp + * @height: the height in pixels of Display @disp + * @widthmm: the width in millimeters of Display @disp + * @heightmm: the height in millimeters of Display @disp + * @par: the pixel aspect ratio calculated from @width, @widthmm and @height, + * @heightmm ratio + * @use_xshm: used to known wether of not XShm extension is usable or not even + * if the Extension is present + * @xv_port_id: the XVideo port ID + * @im_format: used to store at least a valid format for XShm calls checks + * @formats_list: list of supported image formats on @xv_port_id + * @channels_list: list of #GstColorBalanceChannels + * @caps: the #GstCaps that Display @disp can accept + * + * Structure used to store various informations collected/calculated for a + * Display. + */ +struct _GstXvContext +{ + GstMiniObject parent; + + GMutex lock; + + Display *disp; + + Screen *screen; + gint screen_num; + + Visual *visual; + + Window root; + + gulong white, black; + + gint depth; + gint bpp; + gint endianness; + + gint width, height; + gint widthmm, heightmm; + GValue *par; /* calculated pixel aspect ratio */ + + gboolean use_xshm; + + XvPortID xv_port_id; + guint nb_adaptors; + gchar **adaptors; + guint adaptor_nr; + gint im_format; + + /* port features */ + gboolean have_autopaint_colorkey; + gboolean have_colorkey; + gboolean have_double_buffer; + + GList *formats_list; + + GList *channels_list; + + GstCaps *caps; + + /* Optimisation storage for buffer_alloc return */ + GstCaps *last_caps; + gint last_format; + gint last_width; + gint last_height; +}; + +GType gst_xvcontext_get_type (void); + +void gst_xvcontext_config_clear (GstXvContextConfig *config); + +GstXvContext * gst_xvcontext_new (GstXvContextConfig *config, GError **error); + +/* refcounting */ +static inline GstXvContext * +gst_xvcontext_ref (GstXvContext * xvcontext) +{ + return GST_XVCONTEXT_CAST (gst_mini_object_ref (GST_MINI_OBJECT_CAST ( + xvcontext))); +} + +static inline void +gst_xvcontext_unref (GstXvContext * xvcontext) +{ + gst_mini_object_unref (GST_MINI_OBJECT_CAST (xvcontext)); +} + +gint gst_xvcontext_get_format_from_info (GstXvContext * xvcontext, + GstVideoInfo * info); + + +void gst_xvcontext_set_synchronous (GstXvContext * xvcontext, + gboolean synchronous); +void gst_xvcontext_update_colorbalance (GstXvContext * xvcontext, + GstXvContextConfig * config); + + +typedef struct _GstXWindow GstXWindow; + +/* + * GstXWindow: + * @win: the Window ID of this X11 window + * @width: the width in pixels of Window @win + * @height: the height in pixels of Window @win + * @internal: used to remember if Window @win was created internally or passed + * through the #GstVideoOverlay interface + * @gc: the Graphical Context of Window @win + * + * Structure used to store informations about a Window. + */ +struct _GstXWindow +{ + GstXvContext *context; + + Window win; + gint width, height; + gboolean have_render_rect; + GstVideoRectangle render_rect; + gboolean internal; + GC gc; +}; + +G_END_DECLS + +GstXWindow * gst_xvcontext_create_xwindow (GstXvContext * context, + gint width, gint height); +GstXWindow * gst_xvcontext_create_xwindow_from_xid (GstXvContext * context, XID xid); + +void gst_xwindow_destroy (GstXWindow * window); + +void gst_xwindow_set_event_handling (GstXWindow * window, gboolean handle_events); +void gst_xwindow_set_title (GstXWindow * window, const gchar * title); + +void gst_xwindow_update_geometry (GstXWindow * window); +void gst_xwindow_clear (GstXWindow * window); + +void gst_xwindow_set_render_rectangle (GstXWindow * window, + gint x, gint y, gint width, gint height); + + + +#endif /* __GST_XVCONTEXT_H__ */ diff --git a/sys/xvimage/xvimage.c b/sys/xvimage/xvimage.c index a812fd5..e8851f1 100644 --- a/sys/xvimage/xvimage.c +++ b/sys/xvimage/xvimage.c @@ -23,6 +23,7 @@ #include "xvimagesink.h" +GST_DEBUG_CATEGORY (gst_debug_xvcontext); GST_DEBUG_CATEGORY (gst_debug_xvimagepool); GST_DEBUG_CATEGORY (gst_debug_xvimagesink); GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE); @@ -34,6 +35,8 @@ plugin_init (GstPlugin * plugin) GST_RANK_PRIMARY, GST_TYPE_XVIMAGESINK)) return FALSE; + GST_DEBUG_CATEGORY_INIT (gst_debug_xvcontext, "xcontext", 0, + "xcontext miniobject"); GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagesink, "xvimagesink", 0, "xvimagesink element"); GST_DEBUG_CATEGORY_INIT (gst_debug_xvimagepool, "xvimagepool", 0, diff --git a/sys/xvimage/xvimageallocator.c b/sys/xvimage/xvimageallocator.c new file mode 100644 index 0000000..0fefcfd --- /dev/null +++ b/sys/xvimage/xvimageallocator.c @@ -0,0 +1,651 @@ +/* GStreamer + * Copyright (C) <2005> Julien Moutte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_XSHM +#include +#include +#include +#endif /* HAVE_XSHM */ + +#include +#include + +#ifdef HAVE_XSHM +#include +#endif /* HAVE_XSHM */ + +#include +#include + +/* Object header */ +#include "xvimageallocator.h" + +/* Debugging category */ +#include + +/* Helper functions */ +#include + + +GST_DEBUG_CATEGORY_STATIC (gst_debug_xvimageallocator); +#define GST_CAT_DEFAULT gst_debug_xvimageallocator + +struct _GstXvImageMemory +{ + GstMemory parent; + + gint im_format; + GstVideoRectangle crop; + + XvImage *xvimage; + +#ifdef HAVE_XSHM + XShmSegmentInfo SHMInfo; +#endif /* HAVE_XSHM */ +}; + + +struct _GstXvImageAllocator +{ + GstAllocator parent; + + GstXvContext *context; +}; + +struct _GstXvImageAllocatorClass +{ + GstAllocatorClass parent_class; +}; + +gboolean +gst_xvimage_memory_is_from_context (GstMemory * mem, GstXvContext * context) +{ + GstXvImageAllocator *alloc; + + if (!GST_IS_XVIMAGE_ALLOCATOR (mem->allocator)) + return FALSE; + + alloc = GST_XVIMAGE_ALLOCATOR_CAST (mem->allocator); + + if (alloc->context != context) + return FALSE; + + return TRUE; +} + +gint +gst_xvimage_memory_get_format (GstXvImageMemory * xvmem) +{ + g_return_val_if_fail (xvmem != NULL, FALSE); + + return xvmem->im_format; +} + +XvImage * +gst_xvimage_memory_get_xvimage (GstXvImageMemory * xvmem) +{ + g_return_val_if_fail (xvmem != NULL, FALSE); + + return xvmem->xvimage; +} + +gboolean +gst_xvimage_memory_get_crop (GstXvImageMemory * xvmem, GstVideoRectangle * crop) +{ + g_return_val_if_fail (xvmem != NULL, FALSE); + + if (crop) + *crop = xvmem->crop; + + return TRUE; +} + + +/* X11 stuff */ +static gboolean error_caught = FALSE; + +static int +gst_xvimage_handle_xerror (Display * display, XErrorEvent * xevent) +{ + char error_msg[1024]; + + XGetErrorText (display, xevent->error_code, error_msg, 1024); + GST_DEBUG ("xvimage triggered an XError. error: %s", error_msg); + error_caught = TRUE; + return 0; +} + +static GstMemory * +gst_xvimage_allocator_dummy_alloc (GstAllocator * allocator, gsize size, + GstAllocationParams * params) +{ + return NULL; +} + +static void +gst_xvimage_allocator_free (GstAllocator * allocator, GstMemory * gmem) +{ + GstXvImageMemory *mem = (GstXvImageMemory *) gmem; + GstXvImageAllocator *alloc = (GstXvImageAllocator *) allocator; + GstXvContext *context; + + if (gmem->parent) + goto sub_mem; + + context = alloc->context; + + GST_DEBUG_OBJECT (allocator, "free memory %p", mem); + + g_mutex_lock (&context->lock); + +#ifdef HAVE_XSHM + if (context->use_xshm) { + if (mem->SHMInfo.shmaddr != ((void *) -1)) { + GST_DEBUG_OBJECT (allocator, "XServer ShmDetaching from 0x%x id 0x%lx", + mem->SHMInfo.shmid, mem->SHMInfo.shmseg); + XShmDetach (context->disp, &mem->SHMInfo); + XSync (context->disp, FALSE); + shmdt (mem->SHMInfo.shmaddr); + mem->SHMInfo.shmaddr = (void *) -1; + } + if (mem->xvimage) + XFree (mem->xvimage); + } else +#endif /* HAVE_XSHM */ + { + if (mem->xvimage) { + g_free (mem->xvimage->data); + XFree (mem->xvimage); + } + } + + XSync (context->disp, FALSE); + + g_mutex_unlock (&context->lock); + +sub_mem: + g_slice_free (GstXvImageMemory, mem); +} + +static gpointer +gst_xvimage_memory_map (GstXvImageMemory * mem, gsize maxsize, + GstMapFlags flags) +{ + return mem->xvimage->data + mem->parent.offset; +} + +static gboolean +gst_xvimage_memory_unmap (GstXvImageMemory * mem) +{ + return TRUE; +} + +static GstXvImageMemory * +gst_xvimage_memory_share (GstXvImageMemory * mem, gssize offset, gsize size) +{ + GstXvImageMemory *sub; + GstMemory *parent; + + /* We can only share the complete memory */ + if (offset != 0) + return NULL; + if (size != -1 && size != mem->xvimage->data_size) + return NULL; + + GST_DEBUG ("share memory %p", mem); + + /* find the real parent */ + if ((parent = mem->parent.parent) == NULL) + parent = (GstMemory *) mem; + + if (size == -1) + size = mem->parent.size - offset; + + /* the shared memory is always readonly */ + sub = g_slice_new (GstXvImageMemory); + + gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) | + GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->parent.allocator, + &mem->parent, mem->parent.maxsize, mem->parent.align, + mem->parent.offset + offset, size); + + sub->im_format = mem->im_format; + sub->crop = mem->crop; + sub->xvimage = mem->xvimage; +#ifdef HAVE_XSHM + sub->SHMInfo = mem->SHMInfo; +#endif + + return sub; +} + +static GstXvImageMemory * +gst_xvimage_memory_copy (GstMemory * gmem, gssize offset, gsize size) +{ + GstXvImageMemory *mem, *copy; + + mem = (GstXvImageMemory *) gmem; + + /* We can only copy the complete memory */ + if (offset != 0) + return NULL; + if (size != -1 && size != mem->xvimage->data_size) + return NULL; + + GST_DEBUG ("copy memory %p", mem); + + copy = (GstXvImageMemory *) + gst_xvimage_allocator_alloc (GST_XVIMAGE_ALLOCATOR_CAST (gmem->allocator), + mem->im_format, mem->xvimage->width, mem->xvimage->height, &mem->crop, + NULL); + + memcpy (copy->xvimage->data + copy->parent.offset, + mem->xvimage->data + mem->parent.offset, mem->xvimage->data_size); + + return copy; +} + +#define gst_xvimage_allocator_parent_class parent_class +G_DEFINE_TYPE (GstXvImageAllocator, gst_xvimage_allocator, GST_TYPE_ALLOCATOR); + +static void gst_xvimage_allocator_finalize (GObject * object); + +#define GST_XVIMAGE_ALLOCATOR_NAME "xvimage" + +static void +gst_xvimage_allocator_class_init (GstXvImageAllocatorClass * klass) +{ + GObjectClass *gobject_class; + GstAllocatorClass *allocator_class; + + gobject_class = (GObjectClass *) klass; + allocator_class = (GstAllocatorClass *) klass; + + gobject_class->finalize = gst_xvimage_allocator_finalize; + + allocator_class->alloc = gst_xvimage_allocator_dummy_alloc; + allocator_class->free = gst_xvimage_allocator_free; + + GST_DEBUG_CATEGORY_INIT (gst_debug_xvimageallocator, "xvimageallocator", 0, + "xvimageallocator object"); +} + +static void +gst_xvimage_allocator_init (GstXvImageAllocator * allocator) +{ + GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); + + alloc->mem_type = GST_XVIMAGE_ALLOCATOR_NAME; + alloc->mem_map = (GstMemoryMapFunction) gst_xvimage_memory_map; + alloc->mem_unmap = (GstMemoryUnmapFunction) gst_xvimage_memory_unmap; + alloc->mem_share = (GstMemoryShareFunction) gst_xvimage_memory_share; + alloc->mem_copy = (GstMemoryShareFunction) gst_xvimage_memory_copy; + /* fallback is_span */ + + GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); +} + +static void +gst_xvimage_allocator_finalize (GObject * object) +{ + GstXvImageAllocator *alloc = GST_XVIMAGE_ALLOCATOR (object); + + GST_DEBUG_OBJECT (object, "finalize"); + + gst_xvcontext_unref (alloc->context); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +GstXvImageAllocator * +gst_xvimage_allocator_new (GstXvContext * context) +{ + GstXvImageAllocator *alloc; + + g_return_val_if_fail (GST_IS_XVCONTEXT (context), NULL); + + alloc = g_object_new (GST_TYPE_XVIMAGE_ALLOCATOR, NULL); + alloc->context = gst_xvcontext_ref (context); + + return alloc; +} + +GstXvContext * +gst_xvimage_allocator_peek_context (GstXvImageAllocator * allocator) +{ + g_return_val_if_fail (GST_IS_XVIMAGE_ALLOCATOR (allocator), NULL); + + return allocator->context; +} + +GstMemory * +gst_xvimage_allocator_alloc (GstXvImageAllocator * allocator, gint im_format, + gint padded_width, gint padded_height, GstVideoRectangle * crop, + GError ** error) +{ + int (*handler) (Display *, XErrorEvent *); + gboolean success = FALSE; + GstXvContext *context; + gint align = 15, offset; + GstXvImageMemory *mem; + + context = allocator->context; + + mem = g_slice_new (GstXvImageMemory); + + mem->im_format = im_format; +#ifdef HAVE_XSHM + mem->SHMInfo.shmaddr = ((void *) -1); + mem->SHMInfo.shmid = -1; +#endif + mem->crop = *crop; + + GST_DEBUG_OBJECT (allocator, "creating image %p (%dx%d) cropped %dx%d-%dx%d", + mem, padded_width, padded_height, crop->x, crop->y, crop->w, crop->h); + + g_mutex_lock (&context->lock); + + /* Setting an error handler to catch failure */ + error_caught = FALSE; + handler = XSetErrorHandler (gst_xvimage_handle_xerror); + +#ifdef HAVE_XSHM + if (context->use_xshm) { + int expected_size; + + mem->xvimage = XvShmCreateImage (context->disp, + context->xv_port_id, im_format, NULL, padded_width, padded_height, + &mem->SHMInfo); + if (!mem->xvimage || error_caught) { + g_mutex_unlock (&context->lock); + + /* Reset error flag */ + error_caught = FALSE; + + /* Push a warning */ + GST_WARNING_OBJECT (allocator, + "could not XShmCreateImage a %dx%d image", padded_width, + padded_height); + + /* Retry without XShm */ + context->use_xshm = FALSE; + + /* Hold X mutex again to try without XShm */ + g_mutex_lock (&context->lock); + goto no_xshm; + } + + /* we have to use the returned data_size for our shm size */ + GST_LOG_OBJECT (allocator, "XShm image size is %d", + mem->xvimage->data_size); + + /* calculate the expected size. This is only for sanity checking the + * number we get from X. */ + switch (im_format) { + case GST_MAKE_FOURCC ('I', '4', '2', '0'): + case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): + { + gint pitches[3]; + gint offsets[3]; + guint plane; + + offsets[0] = 0; + pitches[0] = GST_ROUND_UP_4 (padded_width); + offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (padded_height); + pitches[1] = GST_ROUND_UP_8 (padded_width) / 2; + offsets[2] = + offsets[1] + pitches[1] * GST_ROUND_UP_2 (padded_height) / 2; + pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2; + + expected_size = + offsets[2] + pitches[2] * GST_ROUND_UP_2 (padded_height) / 2; + + for (plane = 0; plane < mem->xvimage->num_planes; plane++) { + GST_DEBUG_OBJECT (allocator, + "Plane %u has a expected pitch of %d bytes, " "offset of %d", + plane, pitches[plane], offsets[plane]); + } + break; + } + case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): + case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): + expected_size = padded_height * GST_ROUND_UP_4 (padded_width * 2); + break; + default: + expected_size = 0; + break; + } + if (expected_size != 0 && mem->xvimage->data_size != expected_size) { + GST_WARNING_OBJECT (allocator, + "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)", + mem->xvimage->data_size, expected_size); + } + + /* Be verbose about our XvImage stride */ + { + guint plane; + + for (plane = 0; plane < mem->xvimage->num_planes; plane++) { + GST_DEBUG_OBJECT (allocator, "Plane %u has a pitch of %d bytes, " + "offset of %d", plane, mem->xvimage->pitches[plane], + mem->xvimage->offsets[plane]); + } + } + + /* get shared memory */ + mem->SHMInfo.shmid = + shmget (IPC_PRIVATE, mem->xvimage->data_size + align, IPC_CREAT | 0777); + if (mem->SHMInfo.shmid == -1) + goto shmget_failed; + + /* attach */ + mem->SHMInfo.shmaddr = shmat (mem->SHMInfo.shmid, NULL, 0); + if (mem->SHMInfo.shmaddr == ((void *) -1)) + goto shmat_failed; + + /* now we can set up the image data */ + mem->xvimage->data = mem->SHMInfo.shmaddr; + mem->SHMInfo.readOnly = FALSE; + + if (XShmAttach (context->disp, &mem->SHMInfo) == 0) + goto xattach_failed; + + XSync (context->disp, FALSE); + + /* Delete the shared memory segment as soon as we everyone is attached. + * This way, it will be deleted as soon as we detach later, and not + * leaked if we crash. */ + shmctl (mem->SHMInfo.shmid, IPC_RMID, NULL); + + GST_DEBUG_OBJECT (allocator, "XServer ShmAttached to 0x%x, id 0x%lx", + mem->SHMInfo.shmid, mem->SHMInfo.shmseg); + } else + no_xshm: +#endif /* HAVE_XSHM */ + { + mem->xvimage = XvCreateImage (context->disp, + context->xv_port_id, im_format, NULL, padded_width, padded_height); + if (!mem->xvimage || error_caught) + goto create_failed; + + /* we have to use the returned data_size for our image size */ + mem->xvimage->data = g_malloc (mem->xvimage->data_size + align); + + XSync (context->disp, FALSE); + } + + if ((offset = ((guintptr) mem->xvimage->data & align))) + offset = (align + 1) - offset; + + GST_DEBUG_OBJECT (allocator, "memory %p, align %d, offset %d", + mem->xvimage->data, align, offset); + + /* Reset error handler */ + error_caught = FALSE; + XSetErrorHandler (handler); + + gst_memory_init (GST_MEMORY_CAST (mem), 0, + GST_ALLOCATOR_CAST (allocator), NULL, mem->xvimage->data_size + align, + align, offset, mem->xvimage->data_size); + + g_mutex_unlock (&context->lock); + + success = TRUE; + +beach: + if (!success) { + g_slice_free (GstXvImageMemory, mem); + mem = NULL; + } + + return GST_MEMORY_CAST (mem); + + /* ERRORS */ +create_failed: + { + g_mutex_unlock (&context->lock); + /* Reset error handler */ + error_caught = FALSE; + XSetErrorHandler (handler); + /* Push an error */ + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE, + "could not XvShmCreateImage a %dx%d image", padded_width, + padded_height); + goto beach; + } +#ifdef HAVE_XSHM +shmget_failed: + { + g_mutex_unlock (&context->lock); + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE, + "could not get shared memory of %d bytes", mem->xvimage->data_size); + goto beach; + } +shmat_failed: + { + g_mutex_unlock (&context->lock); + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE, + "Failed to shmat: %s", g_strerror (errno)); + /* Clean up the shared memory segment */ + shmctl (mem->SHMInfo.shmid, IPC_RMID, NULL); + goto beach; + } +xattach_failed: + { + /* Clean up the shared memory segment */ + shmctl (mem->SHMInfo.shmid, IPC_RMID, NULL); + g_mutex_unlock (&context->lock); + + g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE, + "Failed to XShmAttach"); + goto beach; + } +#endif +} + +/* We are called with the x_lock taken */ +static void +gst_xwindow_draw_borders (GstXWindow * window, GstVideoRectangle * rect) +{ + gint t1, t2; + GstXvContext *context; + + g_return_if_fail (window != NULL); + g_return_if_fail (rect != NULL); + + context = window->context; + + XSetForeground (context->disp, window->gc, context->black); + + /* Left border */ + if (rect->x > window->render_rect.x) { + XFillRectangle (context->disp, window->win, window->gc, + window->render_rect.x, window->render_rect.y, + rect->x - window->render_rect.x, window->render_rect.h); + } + + /* Right border */ + t1 = rect->x + rect->w; + t2 = window->render_rect.x + window->render_rect.w; + if (t1 < t2) { + XFillRectangle (context->disp, window->win, window->gc, + t1, window->render_rect.y, t2 - t1, window->render_rect.h); + } + + /* Top border */ + if (rect->y > window->render_rect.y) { + XFillRectangle (context->disp, window->win, window->gc, + window->render_rect.x, window->render_rect.y, + window->render_rect.w, rect->y - window->render_rect.y); + } + + /* Bottom border */ + t1 = rect->y + rect->h; + t2 = window->render_rect.y + window->render_rect.h; + if (t1 < t2) { + XFillRectangle (context->disp, window->win, window->gc, + window->render_rect.x, t1, window->render_rect.w, t2 - t1); + } +} + +void +gst_xvimage_memory_render (GstXvImageMemory * mem, GstVideoRectangle * src_crop, + GstXWindow * window, GstVideoRectangle * dst_crop, gboolean draw_border) +{ + GstXvContext *context; + XvImage *xvimage; + + context = window->context; + + g_mutex_lock (&context->lock); + xvimage = gst_xvimage_memory_get_xvimage (mem); + + if (draw_border) { + gst_xwindow_draw_borders (window, dst_crop); + } +#ifdef HAVE_XSHM + if (context->use_xshm) { + GST_LOG ("XvShmPutImage with image %dx%d and window %dx%d, from xvimage %" + GST_PTR_FORMAT, src_crop->w, src_crop->h, + window->render_rect.w, window->render_rect.h, mem); + + XvShmPutImage (context->disp, + context->xv_port_id, + window->win, + window->gc, xvimage, + src_crop->x, src_crop->y, src_crop->w, src_crop->h, + dst_crop->x, dst_crop->y, dst_crop->w, dst_crop->h, FALSE); + } else +#endif /* HAVE_XSHM */ + { + XvPutImage (context->disp, + context->xv_port_id, + window->win, + window->gc, xvimage, + src_crop->x, src_crop->y, src_crop->w, src_crop->h, + dst_crop->x, dst_crop->y, dst_crop->w, dst_crop->h); + } + XSync (context->disp, FALSE); + + g_mutex_unlock (&context->lock); +} diff --git a/sys/xvimage/xvimageallocator.h b/sys/xvimage/xvimageallocator.h new file mode 100644 index 0000000..c5fb9c8 --- /dev/null +++ b/sys/xvimage/xvimageallocator.h @@ -0,0 +1,69 @@ +/* GStreamer + * Copyright (C) <2005> Julien Moutte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_XVIMAGEALLOCATOR_H__ +#define __GST_XVIMAGEALLOCATOR_H__ + +typedef struct _GstXvImageMemory GstXvImageMemory; + +typedef struct _GstXvImageAllocator GstXvImageAllocator; +typedef struct _GstXvImageAllocatorClass GstXvImageAllocatorClass; + +#include "xvcontext.h" + +G_BEGIN_DECLS + +/* allocator functions */ +#define GST_TYPE_XVIMAGE_ALLOCATOR (gst_xvimage_allocator_get_type()) +#define GST_IS_XVIMAGE_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_ALLOCATOR)) +#define GST_XVIMAGE_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XVIMAGE_ALLOCATOR, GstXvImageAllocator)) +#define GST_XVIMAGE_ALLOCATOR_CAST(obj) ((GstXvImageAllocator*)(obj)) + +GType gst_xvimage_allocator_get_type (void); + +/* the allocator */ +GstXvImageAllocator * gst_xvimage_allocator_new (GstXvContext * context); + +GstXvContext * gst_xvimage_allocator_peek_context (GstXvImageAllocator * allocator); + +GstMemory * gst_xvimage_allocator_alloc (GstXvImageAllocator * allocator, + gint im_format, + gint padded_width, + gint padded_height, + GstVideoRectangle *crop, + GError ** error); + +/* memory from the allocator */ +gboolean gst_xvimage_memory_is_from_context (GstMemory *mem, + GstXvContext * context); + +gint gst_xvimage_memory_get_format (GstXvImageMemory *mem); +XvImage * gst_xvimage_memory_get_xvimage (GstXvImageMemory *mem); +gboolean gst_xvimage_memory_get_crop (GstXvImageMemory *mem, + GstVideoRectangle *crop); + +void gst_xvimage_memory_render (GstXvImageMemory *mem, + GstVideoRectangle *src_crop, + GstXWindow *window, + GstVideoRectangle *dst_crop, + gboolean draw_border); + +G_END_DECLS + +#endif /*__GST_XVIMAGEALLOCATOR_H__*/ diff --git a/sys/xvimage/xvimagepool.c b/sys/xvimage/xvimagepool.c index 3a85682..244a51a 100644 --- a/sys/xvimage/xvimagepool.c +++ b/sys/xvimage/xvimagepool.c @@ -22,7 +22,8 @@ #endif /* Object header */ -#include "xvimagesink.h" +#include "xvimagepool.h" +#include "xvimageallocator.h" /* Debugging category */ #include @@ -39,8 +40,11 @@ GST_DEBUG_CATEGORY_EXTERN (gst_debug_xvimagepool); struct _GstXvImageBufferPoolPrivate { + GstXvImageAllocator *allocator; + GstCaps *caps; gint im_format; + GstVideoRectangle crop; GstVideoInfo info; GstVideoAlignment align; guint padded_width; @@ -49,524 +53,6 @@ struct _GstXvImageBufferPoolPrivate gboolean need_alignment; }; -/* X11 stuff */ -static gboolean error_caught = FALSE; - -static int -gst_xvimagesink_handle_xerror (Display * display, XErrorEvent * xevent) -{ - char error_msg[1024]; - - XGetErrorText (display, xevent->error_code, error_msg, 1024); - GST_DEBUG ("xvimagesink triggered an XError. error: %s", error_msg); - error_caught = TRUE; - return 0; -} - -static GstMemory * -gst_xvimage_memory_alloc (GstAllocator * allocator, gsize size, - GstAllocationParams * params) -{ - return NULL; -} - -static void -gst_xvimage_memory_free (GstAllocator * allocator, GstMemory * gmem) -{ - GstXvImageMemory *mem = (GstXvImageMemory *) gmem; - GstXvImageSink *xvimagesink; - - if (gmem->parent) - goto sub_mem; - - xvimagesink = mem->sink; - - GST_DEBUG_OBJECT (xvimagesink, "free memory %p", mem); - - /* Hold the object lock to ensure the XContext doesn't disappear */ - GST_OBJECT_LOCK (xvimagesink); - /* We might have some buffers destroyed after changing state to NULL */ - if (xvimagesink->xcontext == NULL) { - GST_DEBUG_OBJECT (xvimagesink, "Destroying XvImage after Xcontext"); -#ifdef HAVE_XSHM - /* Need to free the shared memory segment even if the x context - * was already cleaned up */ - if (mem->SHMInfo.shmaddr != ((void *) -1)) { - shmdt (mem->SHMInfo.shmaddr); - } -#endif - if (mem->xvimage) - XFree (mem->xvimage); - goto beach; - } - - g_mutex_lock (&xvimagesink->x_lock); - -#ifdef HAVE_XSHM - if (xvimagesink->xcontext->use_xshm) { - if (mem->SHMInfo.shmaddr != ((void *) -1)) { - GST_DEBUG_OBJECT (xvimagesink, "XServer ShmDetaching from 0x%x id 0x%lx", - mem->SHMInfo.shmid, mem->SHMInfo.shmseg); - XShmDetach (xvimagesink->xcontext->disp, &mem->SHMInfo); - XSync (xvimagesink->xcontext->disp, FALSE); - shmdt (mem->SHMInfo.shmaddr); - mem->SHMInfo.shmaddr = (void *) -1; - } - if (mem->xvimage) - XFree (mem->xvimage); - } else -#endif /* HAVE_XSHM */ - { - if (mem->xvimage) { - g_free (mem->xvimage->data); - XFree (mem->xvimage); - } - } - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (&xvimagesink->x_lock); - -beach: - GST_OBJECT_UNLOCK (xvimagesink); - - gst_object_unref (mem->sink); - -sub_mem: - g_slice_free (GstXvImageMemory, mem); -} - -static gpointer -xvimage_memory_map (GstXvImageMemory * mem, gsize maxsize, GstMapFlags flags) -{ - return mem->xvimage->data + mem->parent.offset; -} - -static gboolean -xvimage_memory_unmap (GstXvImageMemory * mem) -{ - return TRUE; -} - -static GstXvImageMemory * -xvimage_memory_share (GstXvImageMemory * mem, gssize offset, gsize size) -{ - GstXvImageMemory *sub; - GstMemory *parent; - - /* We can only share the complete memory */ - if (offset != 0) - return NULL; - if (size != -1 && size != mem->size) - return NULL; - - /* find the real parent */ - if ((parent = mem->parent.parent) == NULL) - parent = (GstMemory *) mem; - - if (size == -1) - size = mem->parent.size - offset; - - /* the shared memory is always readonly */ - sub = g_slice_new (GstXvImageMemory); - - gst_memory_init (GST_MEMORY_CAST (sub), GST_MINI_OBJECT_FLAGS (parent) | - GST_MINI_OBJECT_FLAG_LOCK_READONLY, mem->parent.allocator, - &mem->parent, mem->parent.maxsize, mem->parent.align, - mem->parent.offset + offset, size); - sub->sink = mem->sink; - sub->xvimage = mem->xvimage; - sub->SHMInfo = mem->SHMInfo; - sub->x = mem->x; - sub->y = mem->y; - sub->width = mem->width; - sub->height = mem->height; - - return sub; -} - -typedef GstAllocator GstXvImageMemoryAllocator; -typedef GstAllocatorClass GstXvImageMemoryAllocatorClass; - -GType xvimage_memory_allocator_get_type (void); -G_DEFINE_TYPE (GstXvImageMemoryAllocator, xvimage_memory_allocator, - GST_TYPE_ALLOCATOR); - -#define GST_XVIMAGE_ALLOCATOR_NAME "xvimage" -#define GST_TYPE_XVIMAGE_MEMORY_ALLOCATOR (xvimage_memory_allocator_get_type()) -#define GST_IS_XVIMAGE_MEMORY_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_MEMORY_ALLOCATOR)) - -static void -xvimage_memory_allocator_class_init (GstXvImageMemoryAllocatorClass * klass) -{ - GstAllocatorClass *allocator_class; - - allocator_class = (GstAllocatorClass *) klass; - - allocator_class->alloc = gst_xvimage_memory_alloc; - allocator_class->free = gst_xvimage_memory_free; -} - -static void -xvimage_memory_allocator_init (GstXvImageMemoryAllocator * allocator) -{ - GstAllocator *alloc = GST_ALLOCATOR_CAST (allocator); - - alloc->mem_type = GST_XVIMAGE_ALLOCATOR_NAME; - alloc->mem_map = (GstMemoryMapFunction) xvimage_memory_map; - alloc->mem_unmap = (GstMemoryUnmapFunction) xvimage_memory_unmap; - alloc->mem_share = (GstMemoryShareFunction) xvimage_memory_share; - /* fallback copy and is_span */ - - GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); -} - -static GstMemory * -xvimage_memory_alloc (GstXvImageBufferPool * xvpool) -{ - GstXvImageSink *xvimagesink; - int (*handler) (Display *, XErrorEvent *); - gboolean success = FALSE; - GstXContext *xcontext; - gint width, height, im_format, align = 15, offset; - GstXvImageBufferPoolPrivate *priv; - GstXvImageMemory *mem; - - priv = xvpool->priv; - xvimagesink = xvpool->sink; - xcontext = xvimagesink->xcontext; - - width = priv->padded_width; - height = priv->padded_height; - im_format = priv->im_format; - - mem = g_slice_new (GstXvImageMemory); - -#ifdef HAVE_XSHM - mem->SHMInfo.shmaddr = ((void *) -1); - mem->SHMInfo.shmid = -1; -#endif - mem->x = priv->align.padding_left; - mem->y = priv->align.padding_top; - mem->width = priv->info.width; - mem->height = priv->info.height; - mem->sink = gst_object_ref (xvimagesink); - mem->im_format = im_format; - - GST_DEBUG_OBJECT (xvimagesink, "creating image %p (%dx%d)", mem, - width, height); - - g_mutex_lock (&xvimagesink->x_lock); - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); - -#ifdef HAVE_XSHM - if (xcontext->use_xshm) { - int expected_size; - - mem->xvimage = XvShmCreateImage (xcontext->disp, - xcontext->xv_port_id, im_format, NULL, width, height, &mem->SHMInfo); - if (!mem->xvimage || error_caught) { - g_mutex_unlock (&xvimagesink->x_lock); - - /* Reset error flag */ - error_caught = FALSE; - - /* Push a warning */ - GST_ELEMENT_WARNING (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - width, height), - ("could not XShmCreateImage a %dx%d image", width, height)); - - /* Retry without XShm */ - xvimagesink->xcontext->use_xshm = FALSE; - - /* Hold X mutex again to try without XShm */ - g_mutex_lock (&xvimagesink->x_lock); - goto no_xshm; - } - - /* we have to use the returned data_size for our shm size */ - mem->size = mem->xvimage->data_size; - GST_LOG_OBJECT (xvimagesink, "XShm image size is %" G_GSIZE_FORMAT, - mem->size); - - /* calculate the expected size. This is only for sanity checking the - * number we get from X. */ - switch (im_format) { - case GST_MAKE_FOURCC ('I', '4', '2', '0'): - case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): - { - gint pitches[3]; - gint offsets[3]; - guint plane; - - offsets[0] = 0; - pitches[0] = GST_ROUND_UP_4 (width); - offsets[1] = offsets[0] + pitches[0] * GST_ROUND_UP_2 (height); - pitches[1] = GST_ROUND_UP_8 (width) / 2; - offsets[2] = offsets[1] + pitches[1] * GST_ROUND_UP_2 (height) / 2; - pitches[2] = GST_ROUND_UP_8 (pitches[0]) / 2; - - expected_size = offsets[2] + pitches[2] * GST_ROUND_UP_2 (height) / 2; - - for (plane = 0; plane < mem->xvimage->num_planes; plane++) { - GST_DEBUG_OBJECT (xvimagesink, - "Plane %u has a expected pitch of %d bytes, " "offset of %d", - plane, pitches[plane], offsets[plane]); - } - break; - } - case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): - case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): - expected_size = height * GST_ROUND_UP_4 (width * 2); - break; - default: - expected_size = 0; - break; - } - if (expected_size != 0 && mem->size != expected_size) { - GST_WARNING_OBJECT (xvimagesink, - "unexpected XShm image size (got %" G_GSIZE_FORMAT ", expected %d)", - mem->size, expected_size); - } - - /* Be verbose about our XvImage stride */ - { - guint plane; - - for (plane = 0; plane < mem->xvimage->num_planes; plane++) { - GST_DEBUG_OBJECT (xvimagesink, "Plane %u has a pitch of %d bytes, " - "offset of %d", plane, mem->xvimage->pitches[plane], - mem->xvimage->offsets[plane]); - } - } - - /* get shared memory */ - mem->SHMInfo.shmid = - shmget (IPC_PRIVATE, mem->size + align, IPC_CREAT | 0777); - if (mem->SHMInfo.shmid == -1) - goto shmget_failed; - - /* attach */ - mem->SHMInfo.shmaddr = shmat (mem->SHMInfo.shmid, NULL, 0); - if (mem->SHMInfo.shmaddr == ((void *) -1)) - goto shmat_failed; - - /* now we can set up the image data */ - mem->xvimage->data = mem->SHMInfo.shmaddr; - mem->SHMInfo.readOnly = FALSE; - - if (XShmAttach (xcontext->disp, &mem->SHMInfo) == 0) - goto xattach_failed; - - XSync (xcontext->disp, FALSE); - - /* Delete the shared memory segment as soon as we everyone is attached. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (mem->SHMInfo.shmid, IPC_RMID, NULL); - - GST_DEBUG_OBJECT (xvimagesink, "XServer ShmAttached to 0x%x, id 0x%lx", - mem->SHMInfo.shmid, mem->SHMInfo.shmseg); - } else - no_xshm: -#endif /* HAVE_XSHM */ - { - mem->xvimage = XvCreateImage (xcontext->disp, - xcontext->xv_port_id, im_format, NULL, width, height); - if (!mem->xvimage || error_caught) - goto create_failed; - - /* we have to use the returned data_size for our image size */ - mem->size = mem->xvimage->data_size; - mem->xvimage->data = g_malloc (mem->size + align); - - XSync (xcontext->disp, FALSE); - } - - if ((offset = ((guintptr) mem->xvimage->data & align))) - offset = (align + 1) - offset; - - GST_DEBUG_OBJECT (xvimagesink, "memory %p, align %d, offset %d", - mem->xvimage->data, align, offset); - - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - - gst_memory_init (GST_MEMORY_CAST (mem), GST_MEMORY_FLAG_NO_SHARE, - xvpool->allocator, NULL, mem->size + align, align, offset, mem->size); - - g_mutex_unlock (&xvimagesink->x_lock); - - success = TRUE; - -beach: - if (!success) { - g_slice_free (GstXvImageMemory, mem); - mem = NULL; - } - - return GST_MEMORY_CAST (mem); - - /* ERRORS */ -create_failed: - { - g_mutex_unlock (&xvimagesink->x_lock); - /* Reset error handler */ - error_caught = FALSE; - XSetErrorHandler (handler); - /* Push an error */ - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - width, height), - ("could not XvShmCreateImage a %dx%d image", width, height)); - goto beach; - } -#ifdef HAVE_XSHM -shmget_failed: - { - g_mutex_unlock (&xvimagesink->x_lock); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - width, height), - ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - mem->size)); - goto beach; - } -shmat_failed: - { - g_mutex_unlock (&xvimagesink->x_lock); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - width, height), ("Failed to shmat: %s", g_strerror (errno))); - /* Clean up the shared memory segment */ - shmctl (mem->SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } -xattach_failed: - { - /* Clean up the shared memory segment */ - shmctl (mem->SHMInfo.shmid, IPC_RMID, NULL); - g_mutex_unlock (&xvimagesink->x_lock); - - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - width, height), ("Failed to XShmAttach")); - goto beach; - } -#endif -} - -#ifdef HAVE_XSHM -/* This function checks that it is actually really possible to create an image - using XShm */ -gboolean -gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink, - GstXContext * xcontext) -{ - XvImage *xvimage; - XShmSegmentInfo SHMInfo; - size_t size; - int (*handler) (Display *, XErrorEvent *); - gboolean result = FALSE; - gboolean did_attach = FALSE; - - g_return_val_if_fail (xcontext != NULL, FALSE); - - /* Sync to ensure any older errors are already processed */ - XSync (xcontext->disp, FALSE); - - /* Set defaults so we don't free these later unnecessarily */ - SHMInfo.shmaddr = ((void *) -1); - SHMInfo.shmid = -1; - - /* Setting an error handler to catch failure */ - error_caught = FALSE; - handler = XSetErrorHandler (gst_xvimagesink_handle_xerror); - - /* Trying to create a 1x1 picture */ - GST_DEBUG ("XvShmCreateImage of 1x1"); - xvimage = XvShmCreateImage (xcontext->disp, xcontext->xv_port_id, - xcontext->im_format, NULL, 1, 1, &SHMInfo); - - /* Might cause an error, sync to ensure it is noticed */ - XSync (xcontext->disp, FALSE); - if (!xvimage || error_caught) { - GST_WARNING ("could not XvShmCreateImage a 1x1 image"); - goto beach; - } - size = xvimage->data_size; - - SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777); - if (SHMInfo.shmid == -1) { - GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes", - size); - goto beach; - } - - SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0); - if (SHMInfo.shmaddr == ((void *) -1)) { - GST_WARNING ("Failed to shmat: %s", g_strerror (errno)); - /* Clean up the shared memory segment */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - xvimage->data = SHMInfo.shmaddr; - SHMInfo.readOnly = FALSE; - - if (XShmAttach (xcontext->disp, &SHMInfo) == 0) { - GST_WARNING ("Failed to XShmAttach"); - /* Clean up the shared memory segment */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - goto beach; - } - - /* Sync to ensure we see any errors we caused */ - XSync (xcontext->disp, FALSE); - - /* Delete the shared memory segment as soon as everyone is attached. - * This way, it will be deleted as soon as we detach later, and not - * leaked if we crash. */ - shmctl (SHMInfo.shmid, IPC_RMID, NULL); - - if (!error_caught) { - GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid, - SHMInfo.shmseg); - - did_attach = TRUE; - /* store whether we succeeded in result */ - result = TRUE; - } else { - GST_WARNING ("MIT-SHM extension check failed at XShmAttach. " - "Not using shared memory."); - } - -beach: - /* Sync to ensure we swallow any errors we caused and reset error_caught */ - XSync (xcontext->disp, FALSE); - - error_caught = FALSE; - XSetErrorHandler (handler); - - if (did_attach) { - GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx", - SHMInfo.shmid, SHMInfo.shmseg); - XShmDetach (xcontext->disp, &SHMInfo); - XSync (xcontext->disp, FALSE); - } - if (SHMInfo.shmaddr != ((void *) -1)) - shmdt (SHMInfo.shmaddr); - if (xvimage) - XFree (xvimage); - return result; -} -#endif /* HAVE_XSHM */ - /* bufferpool */ static void gst_xvimage_buffer_pool_finalize (GObject * object); @@ -594,6 +80,7 @@ xvimage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) GstXvImageBufferPoolPrivate *priv = xvpool->priv; GstVideoInfo info; GstCaps *caps; + GstXvContext *context; if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)) goto wrong_config; @@ -608,7 +95,9 @@ xvimage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT, info.width, info.height, caps); - priv->im_format = gst_xvimagesink_get_format_from_info (xvpool->sink, &info); + context = gst_xvimage_allocator_peek_context (priv->allocator); + + priv->im_format = gst_xvcontext_get_format_from_info (context, &info); if (priv->im_format == -1) goto unknown_format; @@ -650,6 +139,10 @@ xvimage_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) priv->align.padding_bottom; priv->info = info; + priv->crop.x = priv->align.padding_left; + priv->crop.y = priv->align.padding_top; + priv->crop.w = priv->info.width; + priv->crop.h = priv->info.height; return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config); @@ -672,12 +165,8 @@ wrong_caps: } unknown_format: { - GST_WARNING_OBJECT (xvpool->sink, "failed to get format from caps %" + GST_WARNING_OBJECT (pool, "failed to get format from caps %" GST_PTR_FORMAT, caps); - GST_ELEMENT_ERROR (xvpool->sink, RESOURCE, WRITE, - ("Failed to create output image buffer of %dx%d pixels", - priv->info.width, priv->info.height), - ("Invalid input caps %" GST_PTR_FORMAT, caps)); return FALSE;; } } @@ -696,7 +185,10 @@ xvimage_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer, info = &priv->info; xvimage = gst_buffer_new (); - mem = xvimage_memory_alloc (xvpool); + + mem = gst_xvimage_allocator_alloc (priv->allocator, priv->im_format, + priv->padded_width, priv->padded_height, &priv->crop, NULL); + if (mem == NULL) { gst_buffer_unref (xvimage); goto no_buffer; @@ -724,15 +216,12 @@ no_buffer: } GstBufferPool * -gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink) +gst_xvimage_buffer_pool_new (GstXvImageAllocator * allocator) { GstXvImageBufferPool *pool; - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - pool = g_object_new (GST_TYPE_XVIMAGE_BUFFER_POOL, NULL); - pool->sink = gst_object_ref (xvimagesink); - pool->allocator = g_object_new (GST_TYPE_XVIMAGE_MEMORY_ALLOCATOR, NULL); + pool->priv->allocator = gst_object_ref (allocator); GST_LOG_OBJECT (pool, "new XvImage buffer pool %p", pool); @@ -770,32 +259,8 @@ gst_xvimage_buffer_pool_finalize (GObject * object) if (priv->caps) gst_caps_unref (priv->caps); - gst_object_unref (pool->sink); - g_object_unref (pool->allocator); + if (priv->allocator) + gst_object_unref (priv->allocator); G_OBJECT_CLASS (gst_xvimage_buffer_pool_parent_class)->finalize (object); } - -/* This function tries to get a format matching with a given caps in the - supported list of formats we generated in gst_xvimagesink_get_xv_support */ -gint -gst_xvimagesink_get_format_from_info (GstXvImageSink * xvimagesink, - GstVideoInfo * info) -{ - GList *list = NULL; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), 0); - - list = xvimagesink->xcontext->formats_list; - - while (list) { - GstXvImageFormat *format = list->data; - - if (format && format->vformat == GST_VIDEO_INFO_FORMAT (info)) - return format->format; - - list = g_list_next (list); - } - - return -1; -} diff --git a/sys/xvimage/xvimagepool.h b/sys/xvimage/xvimagepool.h index d281f8a..855c224 100644 --- a/sys/xvimage/xvimagepool.h +++ b/sys/xvimage/xvimagepool.h @@ -20,63 +20,16 @@ #ifndef __GST_XVIMAGEPOOL_H__ #define __GST_XVIMAGEPOOL_H__ -#ifdef HAVE_XSHM -#include -#include -#include -#endif /* HAVE_XSHM */ - -#include -#include - -#ifdef HAVE_XSHM -#include -#endif /* HAVE_XSHM */ - -#include -#include +#include +#include "xvimageallocator.h" G_BEGIN_DECLS -typedef struct _GstXvImageMemory GstXvImageMemory; - typedef struct _GstXvImageBufferPool GstXvImageBufferPool; typedef struct _GstXvImageBufferPoolClass GstXvImageBufferPoolClass; typedef struct _GstXvImageBufferPoolPrivate GstXvImageBufferPoolPrivate; -#include "xvimagesink.h" - -/** - * GstXvImageMemory: - * @sink: a reference to the our #GstXvImageSink - * @xvimage: the XvImage of this buffer - * @width: the width in pixels of XvImage @xvimage - * @height: the height in pixels of XvImage @xvimage - * @im_format: the format of XvImage @xvimage - * @size: the size in bytes of XvImage @xvimage - * - * Subclass of #GstMemory containing additional information about an XvImage. - */ -struct _GstXvImageMemory -{ - GstMemory parent; - - /* Reference to the xvimagesink we belong to */ - GstXvImageSink *sink; - - XvImage *xvimage; - -#ifdef HAVE_XSHM - XShmSegmentInfo SHMInfo; -#endif /* HAVE_XSHM */ - - gint x, y; - gint width, height; - gint im_format; - size_t size; -}; - /* buffer pool functions */ #define GST_TYPE_XVIMAGE_BUFFER_POOL (gst_xvimage_buffer_pool_get_type()) #define GST_IS_XVIMAGE_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XVIMAGE_BUFFER_POOL)) @@ -87,9 +40,6 @@ struct _GstXvImageBufferPool { GstBufferPool bufferpool; - GstXvImageSink *sink; - GstAllocator *allocator; - GstXvImageBufferPoolPrivate *priv; }; @@ -100,13 +50,7 @@ struct _GstXvImageBufferPoolClass GType gst_xvimage_buffer_pool_get_type (void); -GstBufferPool *gst_xvimage_buffer_pool_new (GstXvImageSink * xvimagesink); - -gboolean gst_xvimagesink_check_xshm_calls (GstXvImageSink * xvimagesink, - GstXContext * xcontext); - -gint gst_xvimagesink_get_format_from_info (GstXvImageSink * xvimagesink, - GstVideoInfo * info); +GstBufferPool * gst_xvimage_buffer_pool_new (GstXvImageAllocator *allocator); G_END_DECLS diff --git a/sys/xvimage/xvimagesink.c b/sys/xvimage/xvimagesink.c index 76db6b4..d62f111 100644 --- a/sys/xvimage/xvimagesink.c +++ b/sys/xvimage/xvimagesink.c @@ -123,6 +123,7 @@ /* Object header */ #include "xvimagesink.h" +#include "xvimageallocator.h" /* Debugging category */ #include @@ -146,7 +147,8 @@ MotifWmHints, MwmHints; #define MWM_HINTS_DECORATIONS (1L << 1) -static void gst_xvimagesink_reset (GstXvImageSink * xvimagesink); +static gboolean gst_xvimagesink_open (GstXvImageSink * xvimagesink); +static void gst_xvimagesink_close (GstXvImageSink * xvimagesink); static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink); static void gst_xvimagesink_expose (GstVideoOverlay * overlay); @@ -218,50 +220,6 @@ G_DEFINE_TYPE_WITH_CODE (GstXvImageSink, gst_xvimagesink, GST_TYPE_VIDEO_SINK, /* ============================================================= */ -/* We are called with the x_lock taken */ -static void -gst_xvimagesink_xwindow_draw_borders (GstXvImageSink * xvimagesink, - GstXWindow * xwindow, GstVideoRectangle rect) -{ - gint t1, t2; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - g_return_if_fail (xwindow != NULL); - - XSetForeground (xvimagesink->xcontext->disp, xwindow->gc, - xvimagesink->xcontext->black); - - /* Left border */ - if (rect.x > xvimagesink->render_rect.x) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - xvimagesink->render_rect.x, xvimagesink->render_rect.y, - rect.x - xvimagesink->render_rect.x, xvimagesink->render_rect.h); - } - - /* Right border */ - t1 = rect.x + rect.w; - t2 = xvimagesink->render_rect.x + xvimagesink->render_rect.w; - if (t1 < t2) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - t1, xvimagesink->render_rect.y, t2 - t1, xvimagesink->render_rect.h); - } - - /* Top border */ - if (rect.y > xvimagesink->render_rect.y) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - xvimagesink->render_rect.x, xvimagesink->render_rect.y, - xvimagesink->render_rect.w, rect.y - xvimagesink->render_rect.y); - } - - /* Bottom border */ - t1 = rect.y + rect.h; - t2 = xvimagesink->render_rect.y + xvimagesink->render_rect.h; - if (t1 < t2) { - XFillRectangle (xvimagesink->xcontext->disp, xwindow->win, xwindow->gc, - xvimagesink->render_rect.x, t1, xvimagesink->render_rect.w, t2 - t1); - } -} - /* This function puts a GstXvImage on a GstXvImageSink's window. Returns FALSE * if no window was available */ static gboolean @@ -272,12 +230,14 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage) GstVideoRectangle result; gboolean draw_border = FALSE; GstVideoRectangle src, dst; + GstVideoRectangle mem_crop; + GstXWindow *xwindow; /* We take the flow_lock. If expose is in there we don't want to run concurrently from the data flow thread */ g_mutex_lock (&xvimagesink->flow_lock); - if (G_UNLIKELY (xvimagesink->xwindow == NULL)) { + if (G_UNLIKELY ((xwindow = xvimagesink->xwindow) == NULL)) { g_mutex_unlock (&xvimagesink->flow_lock); return FALSE; } @@ -285,7 +245,8 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage) /* Draw borders when displaying the first frame. After this draw borders only on expose event or after a size change. */ if (!xvimagesink->cur_image || xvimagesink->redraw_border) { - draw_border = TRUE; + draw_border = xvimagesink->draw_borders; + xvimagesink->redraw_border = FALSE; } /* Store a reference to the last image we put, lose the previous one */ @@ -310,21 +271,19 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage) } mem = (GstXvImageMemory *) gst_buffer_peek_memory (xvimage, 0); + gst_xvimage_memory_get_crop (mem, &mem_crop); crop = gst_buffer_get_video_crop_meta (xvimage); if (crop) { - src.x = crop->x + mem->x; - src.y = crop->y + mem->y; + src.x = crop->x + mem_crop.x; + src.y = crop->y + mem_crop.y; src.w = crop->width; src.h = crop->height; GST_LOG_OBJECT (xvimagesink, "crop %dx%d-%dx%d", crop->x, crop->y, crop->width, crop->height); } else { - src.x = mem->x; - src.y = mem->y; - src.w = mem->width; - src.h = mem->height; + src = mem_crop; } if (xvimagesink->keep_aspect) { @@ -335,92 +294,23 @@ gst_xvimagesink_xvimage_put (GstXvImageSink * xvimagesink, GstBuffer * xvimage) * which case the image will be scaled to fit the negotiated size. */ s.w = GST_VIDEO_SINK_WIDTH (xvimagesink); s.h = GST_VIDEO_SINK_HEIGHT (xvimagesink); - dst.w = xvimagesink->render_rect.w; - dst.h = xvimagesink->render_rect.h; + dst.w = xwindow->render_rect.w; + dst.h = xwindow->render_rect.h; gst_video_sink_center_rect (s, dst, &result, TRUE); - result.x += xvimagesink->render_rect.x; - result.y += xvimagesink->render_rect.y; + result.x += xwindow->render_rect.x; + result.y += xwindow->render_rect.y; } else { - memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle)); + memcpy (&result, &xwindow->render_rect, sizeof (GstVideoRectangle)); } - g_mutex_lock (&xvimagesink->x_lock); - - if (draw_border && xvimagesink->draw_borders) { - gst_xvimagesink_xwindow_draw_borders (xvimagesink, xvimagesink->xwindow, - result); - xvimagesink->redraw_border = FALSE; - } -#ifdef HAVE_XSHM - if (xvimagesink->xcontext->use_xshm) { - GST_LOG_OBJECT (xvimagesink, - "XvShmPutImage with image %dx%d and window %dx%d, from xvimage %" - GST_PTR_FORMAT, mem->width, mem->height, - xvimagesink->render_rect.w, xvimagesink->render_rect.h, xvimage); - - XvShmPutImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimagesink->xwindow->win, - xvimagesink->xwindow->gc, mem->xvimage, - src.x, src.y, src.w, src.h, - result.x, result.y, result.w, result.h, FALSE); - } else -#endif /* HAVE_XSHM */ - { - XvPutImage (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, - xvimagesink->xwindow->win, - xvimagesink->xwindow->gc, mem->xvimage, - src.x, src.y, src.w, src.h, result.x, result.y, result.w, result.h); - } - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (&xvimagesink->x_lock); + gst_xvimage_memory_render (mem, &src, xwindow, &result, draw_border); g_mutex_unlock (&xvimagesink->flow_lock); return TRUE; } -static gboolean -gst_xvimagesink_xwindow_decorate (GstXvImageSink * xvimagesink, - GstXWindow * window) -{ - Atom hints_atom = None; - MotifWmHints *hints; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), FALSE); - g_return_val_if_fail (window != NULL, FALSE); - - g_mutex_lock (&xvimagesink->x_lock); - - hints_atom = XInternAtom (xvimagesink->xcontext->disp, "_MOTIF_WM_HINTS", - True); - if (hints_atom == None) { - g_mutex_unlock (&xvimagesink->x_lock); - return FALSE; - } - - hints = g_malloc0 (sizeof (MotifWmHints)); - - hints->flags |= MWM_HINTS_DECORATIONS; - hints->decorations = 1 << 0; - - XChangeProperty (xvimagesink->xcontext->disp, window->win, - hints_atom, hints_atom, 32, PropModeReplace, - (guchar *) hints, sizeof (MotifWmHints) / sizeof (long)); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (&xvimagesink->x_lock); - - g_free (hints); - - return TRUE; -} - static void gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink, GstXWindow * xwindow, const gchar * media_title) @@ -431,34 +321,24 @@ gst_xvimagesink_xwindow_set_title (GstXvImageSink * xvimagesink, } if (xwindow) { /* we have a window */ - if (xwindow->internal) { - XTextProperty xproperty; - const gchar *app_name; - const gchar *title = NULL; - gchar *title_mem = NULL; - - /* set application name as a title */ - app_name = g_get_application_name (); - - if (app_name && xvimagesink->media_title) { - title = title_mem = g_strconcat (xvimagesink->media_title, " : ", - app_name, NULL); - } else if (app_name) { - title = app_name; - } else if (xvimagesink->media_title) { - title = xvimagesink->media_title; - } - - if (title) { - if ((XStringListToTextProperty (((char **) &title), 1, - &xproperty)) != 0) { - XSetWMName (xvimagesink->xcontext->disp, xwindow->win, &xproperty); - XFree (xproperty.value); - } - - g_free (title_mem); - } + const gchar *app_name; + const gchar *title = NULL; + gchar *title_mem = NULL; + + /* set application name as a title */ + app_name = g_get_application_name (); + + if (app_name && xvimagesink->media_title) { + title = title_mem = g_strconcat (xvimagesink->media_title, " : ", + app_name, NULL); + } else if (app_name) { + title = app_name; + } else if (xvimagesink->media_title) { + title = xvimagesink->media_title; } + + gst_xwindow_set_title (xwindow, title); + g_free (title_mem); } } @@ -469,60 +349,18 @@ gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, gint width, gint height) { GstXWindow *xwindow = NULL; - XGCValues values; + GstXvContext *context; g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - xwindow = g_new0 (GstXWindow, 1); - - xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0; - xvimagesink->render_rect.w = width; - xvimagesink->render_rect.h = height; + context = xvimagesink->context; - xwindow->width = width; - xwindow->height = height; - xwindow->internal = TRUE; - - g_mutex_lock (&xvimagesink->x_lock); - - xwindow->win = XCreateSimpleWindow (xvimagesink->xcontext->disp, - xvimagesink->xcontext->root, - 0, 0, width, height, 0, 0, xvimagesink->xcontext->black); - - /* We have to do that to prevent X from redrawing the background on - * ConfigureNotify. This takes away flickering of video when resizing. */ - XSetWindowBackgroundPixmap (xvimagesink->xcontext->disp, xwindow->win, None); + xwindow = gst_xvcontext_create_xwindow (context, width, height); /* set application name as a title */ gst_xvimagesink_xwindow_set_title (xvimagesink, xwindow, NULL); - if (xvimagesink->handle_events) { - Atom wm_delete; - - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - - /* Tell the window manager we'd like delete client messages instead of - * being killed */ - wm_delete = XInternAtom (xvimagesink->xcontext->disp, - "WM_DELETE_WINDOW", True); - if (wm_delete != None) { - (void) XSetWMProtocols (xvimagesink->xcontext->disp, xwindow->win, - &wm_delete, 1); - } - } - - xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, - xwindow->win, 0, &values); - - XMapRaised (xvimagesink->xcontext->disp, xwindow->win); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (&xvimagesink->x_lock); - - gst_xvimagesink_xwindow_decorate (xvimagesink, xwindow); + gst_xwindow_set_event_handling (xwindow, xvimagesink->handle_events); gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (xvimagesink), xwindow->win); @@ -530,144 +368,32 @@ gst_xvimagesink_xwindow_new (GstXvImageSink * xvimagesink, return xwindow; } -/* This function destroys a GstXWindow */ -static void -gst_xvimagesink_xwindow_destroy (GstXvImageSink * xvimagesink, - GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - g_mutex_lock (&xvimagesink->x_lock); - - /* If we did not create that window we just free the GC and let it live */ - if (xwindow->internal) - XDestroyWindow (xvimagesink->xcontext->disp, xwindow->win); - else - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, 0); - - XFreeGC (xvimagesink->xcontext->disp, xwindow->gc); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (&xvimagesink->x_lock); - - g_free (xwindow); -} - static void gst_xvimagesink_xwindow_update_geometry (GstXvImageSink * xvimagesink) { - XWindowAttributes attr; - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); /* Update the window geometry */ - g_mutex_lock (&xvimagesink->x_lock); - if (G_UNLIKELY (xvimagesink->xwindow == NULL)) { - g_mutex_unlock (&xvimagesink->x_lock); - return; - } - - XGetWindowAttributes (xvimagesink->xcontext->disp, - xvimagesink->xwindow->win, &attr); - - xvimagesink->xwindow->width = attr.width; - xvimagesink->xwindow->height = attr.height; - - if (!xvimagesink->have_render_rect) { - xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0; - xvimagesink->render_rect.w = attr.width; - xvimagesink->render_rect.h = attr.height; - } - - g_mutex_unlock (&xvimagesink->x_lock); -} - -static void -gst_xvimagesink_xwindow_clear (GstXvImageSink * xvimagesink, - GstXWindow * xwindow) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - g_mutex_lock (&xvimagesink->x_lock); - - XvStopVideo (xvimagesink->xcontext->disp, xvimagesink->xcontext->xv_port_id, - xwindow->win); - - XSync (xvimagesink->xcontext->disp, FALSE); - - g_mutex_unlock (&xvimagesink->x_lock); + g_mutex_lock (&xvimagesink->flow_lock); + if (G_LIKELY (xvimagesink->xwindow)) + gst_xwindow_update_geometry (xvimagesink->xwindow); + g_mutex_unlock (&xvimagesink->flow_lock); } /* This function commits our internal colorbalance settings to our grabbed Xv - port. If the xcontext is not initialized yet it simply returns */ + port. If the context is not initialized yet it simply returns */ static void gst_xvimagesink_update_colorbalance (GstXvImageSink * xvimagesink) { - GList *channels = NULL; + GstXvContext *context; g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); /* If we haven't initialized the X context we can't update anything */ - if (xvimagesink->xcontext == NULL) + if ((context = xvimagesink->context) == NULL) return; - /* Don't set the attributes if they haven't been changed, to avoid - * rounding errors changing the values */ - if (!xvimagesink->cb_changed) - return; - - /* For each channel of the colorbalance we calculate the correct value - doing range conversion and then set the Xv port attribute to match our - values. */ - channels = xvimagesink->xcontext->channels_list; - - while (channels) { - if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) { - GstColorBalanceChannel *channel = NULL; - Atom prop_atom; - gint value = 0; - gdouble convert_coef; - - channel = GST_COLOR_BALANCE_CHANNEL (channels->data); - g_object_ref (channel); - - /* Our range conversion coef */ - convert_coef = (channel->max_value - channel->min_value) / 2000.0; - - if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { - value = xvimagesink->hue; - } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { - value = xvimagesink->saturation; - } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { - value = xvimagesink->contrast; - } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { - value = xvimagesink->brightness; - } else { - g_warning ("got an unknown channel %s", channel->label); - g_object_unref (channel); - return; - } - - /* Committing to Xv port */ - g_mutex_lock (&xvimagesink->x_lock); - prop_atom = - XInternAtom (xvimagesink->xcontext->disp, channel->label, True); - if (prop_atom != None) { - int xv_value; - xv_value = - floor (0.5 + (value + 1000) * convert_coef + channel->min_value); - XvSetPortAttribute (xvimagesink->xcontext->disp, - xvimagesink->xcontext->xv_port_id, prop_atom, xv_value); - } - g_mutex_unlock (&xvimagesink->x_lock); - - g_object_unref (channel); - } - channels = g_list_next (channels); - } + gst_xvcontext_update_colorbalance (context, &xvimagesink->config); } /* This function handles XEvents that might be in the queue. It generates @@ -689,10 +415,10 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) /* We get all pointer motion events, only the last position is interesting. */ g_mutex_lock (&xvimagesink->flow_lock); - g_mutex_lock (&xvimagesink->x_lock); - while (XCheckWindowEvent (xvimagesink->xcontext->disp, + g_mutex_lock (&xvimagesink->context->lock); + while (XCheckWindowEvent (xvimagesink->context->disp, xvimagesink->xwindow->win, PointerMotionMask, &e)) { - g_mutex_unlock (&xvimagesink->x_lock); + g_mutex_unlock (&xvimagesink->context->lock); g_mutex_unlock (&xvimagesink->flow_lock); switch (e.type) { @@ -705,11 +431,11 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) break; } g_mutex_lock (&xvimagesink->flow_lock); - g_mutex_lock (&xvimagesink->x_lock); + g_mutex_lock (&xvimagesink->context->lock); } if (pointer_moved) { - g_mutex_unlock (&xvimagesink->x_lock); + g_mutex_unlock (&xvimagesink->context->lock); g_mutex_unlock (&xvimagesink->flow_lock); GST_DEBUG ("xvimagesink pointer moved over window at %d,%d", @@ -718,11 +444,11 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) "mouse-move", 0, e.xbutton.x, e.xbutton.y); g_mutex_lock (&xvimagesink->flow_lock); - g_mutex_lock (&xvimagesink->x_lock); + g_mutex_lock (&xvimagesink->context->lock); } /* We get all events on our window to throw them upstream */ - while (XCheckWindowEvent (xvimagesink->xcontext->disp, + while (XCheckWindowEvent (xvimagesink->context->disp, xvimagesink->xwindow->win, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask, &e)) { @@ -730,7 +456,7 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) const char *key_str = NULL; /* We lock only for the X function call */ - g_mutex_unlock (&xvimagesink->x_lock); + g_mutex_unlock (&xvimagesink->context->lock); g_mutex_unlock (&xvimagesink->flow_lock); switch (e.type) { @@ -754,15 +480,15 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) case KeyRelease: /* Key pressed/released over our window. We send upstream events for interactivity/navigation */ - g_mutex_lock (&xvimagesink->x_lock); - keysym = XkbKeycodeToKeysym (xvimagesink->xcontext->disp, + g_mutex_lock (&xvimagesink->context->lock); + keysym = XkbKeycodeToKeysym (xvimagesink->context->disp, e.xkey.keycode, 0, 0); if (keysym != NoSymbol) { key_str = XKeysymToString (keysym); } else { key_str = "unknown"; } - g_mutex_unlock (&xvimagesink->x_lock); + g_mutex_unlock (&xvimagesink->context->lock); GST_DEBUG_OBJECT (xvimagesink, "key %d pressed over window at %d,%d (%s)", e.xkey.keycode, e.xkey.x, e.xkey.y, key_str); @@ -774,20 +500,24 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) e.type); } g_mutex_lock (&xvimagesink->flow_lock); - g_mutex_lock (&xvimagesink->x_lock); + g_mutex_lock (&xvimagesink->context->lock); } /* Handle Expose */ - while (XCheckWindowEvent (xvimagesink->xcontext->disp, + while (XCheckWindowEvent (xvimagesink->context->disp, xvimagesink->xwindow->win, ExposureMask | StructureNotifyMask, &e)) { switch (e.type) { case Expose: exposed = TRUE; break; case ConfigureNotify: - g_mutex_unlock (&xvimagesink->x_lock); + g_mutex_unlock (&xvimagesink->context->lock); + g_mutex_unlock (&xvimagesink->flow_lock); + gst_xvimagesink_xwindow_update_geometry (xvimagesink); - g_mutex_lock (&xvimagesink->x_lock); + + g_mutex_lock (&xvimagesink->flow_lock); + g_mutex_lock (&xvimagesink->context->lock); configured = TRUE; break; default: @@ -796,34 +526,34 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) } if (xvimagesink->handle_expose && (exposed || configured)) { - g_mutex_unlock (&xvimagesink->x_lock); + g_mutex_unlock (&xvimagesink->context->lock); g_mutex_unlock (&xvimagesink->flow_lock); gst_xvimagesink_expose (GST_VIDEO_OVERLAY (xvimagesink)); g_mutex_lock (&xvimagesink->flow_lock); - g_mutex_lock (&xvimagesink->x_lock); + g_mutex_lock (&xvimagesink->context->lock); } /* Handle Display events */ - while (XPending (xvimagesink->xcontext->disp)) { - XNextEvent (xvimagesink->xcontext->disp, &e); + while (XPending (xvimagesink->context->disp)) { + XNextEvent (xvimagesink->context->disp, &e); switch (e.type) { case ClientMessage:{ Atom wm_delete; - wm_delete = XInternAtom (xvimagesink->xcontext->disp, + wm_delete = XInternAtom (xvimagesink->context->disp, "WM_DELETE_WINDOW", True); if (wm_delete != None && wm_delete == (Atom) e.xclient.data.l[0]) { /* Handle window deletion by posting an error on the bus */ GST_ELEMENT_ERROR (xvimagesink, RESOURCE, NOT_FOUND, ("Output window was closed"), (NULL)); - g_mutex_unlock (&xvimagesink->x_lock); - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); + g_mutex_unlock (&xvimagesink->context->lock); + gst_xwindow_destroy (xvimagesink->xwindow); xvimagesink->xwindow = NULL; - g_mutex_lock (&xvimagesink->x_lock); + g_mutex_lock (&xvimagesink->context->lock); } break; } @@ -832,314 +562,10 @@ gst_xvimagesink_handle_xevents (GstXvImageSink * xvimagesink) } } - g_mutex_unlock (&xvimagesink->x_lock); + g_mutex_unlock (&xvimagesink->context->lock); g_mutex_unlock (&xvimagesink->flow_lock); } -static void -gst_lookup_xv_port_from_adaptor (GstXContext * xcontext, - XvAdaptorInfo * adaptors, int adaptor_no) -{ - gint j; - gint res; - - /* Do we support XvImageMask ? */ - if (!(adaptors[adaptor_no].type & XvImageMask)) { - GST_DEBUG ("XV Adaptor %s has no support for XvImageMask", - adaptors[adaptor_no].name); - return; - } - - /* We found such an adaptor, looking for an available port */ - for (j = 0; j < adaptors[adaptor_no].num_ports && !xcontext->xv_port_id; j++) { - /* We try to grab the port */ - res = XvGrabPort (xcontext->disp, adaptors[adaptor_no].base_id + j, 0); - if (Success == res) { - xcontext->xv_port_id = adaptors[adaptor_no].base_id + j; - GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_no].name, - adaptors[adaptor_no].num_ports); - } else { - GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j, - adaptors[adaptor_no].name, res); - } - } -} - -/* This function generates a caps with all supported format by the first - Xv grabable port we find. We store each one of the supported formats in a - format list and append the format to a newly created caps that we return - If this function does not return NULL because of an error, it also grabs - the port via XvGrabPort */ -static GstCaps * -gst_xvimagesink_get_xv_support (GstXvImageSink * xvimagesink, - GstXContext * xcontext) -{ - gint i; - XvAdaptorInfo *adaptors; - gint nb_formats; - XvImageFormatValues *formats = NULL; - guint nb_encodings; - XvEncodingInfo *encodings = NULL; - gulong max_w = G_MAXINT, max_h = G_MAXINT; - GstCaps *caps = NULL; - GstCaps *rgb_caps = NULL; - - g_return_val_if_fail (xcontext != NULL, NULL); - - /* First let's check that XVideo extension is available */ - if (!XQueryExtension (xcontext->disp, "XVideo", &i, &i, &i)) { - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, - ("Could not initialise Xv output"), - ("XVideo extension is not available")); - return NULL; - } - - /* Then we get adaptors list */ - if (Success != XvQueryAdaptors (xcontext->disp, xcontext->root, - &xcontext->nb_adaptors, &adaptors)) { - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, - ("Could not initialise Xv output"), - ("Failed getting XV adaptors list")); - return NULL; - } - - xcontext->xv_port_id = 0; - - GST_DEBUG ("Found %u XV adaptor(s)", xcontext->nb_adaptors); - - xcontext->adaptors = - (gchar **) g_malloc0 (xcontext->nb_adaptors * sizeof (gchar *)); - - /* Now fill up our adaptor name array */ - for (i = 0; i < xcontext->nb_adaptors; i++) { - xcontext->adaptors[i] = g_strdup (adaptors[i].name); - } - - if (xvimagesink->adaptor_no != -1 && - xvimagesink->adaptor_no < xcontext->nb_adaptors) { - /* Find xv port from user defined adaptor */ - gst_lookup_xv_port_from_adaptor (xcontext, adaptors, - xvimagesink->adaptor_no); - } - - if (!xcontext->xv_port_id) { - /* Now search for an adaptor that supports XvImageMask */ - for (i = 0; i < xcontext->nb_adaptors && !xcontext->xv_port_id; i++) { - gst_lookup_xv_port_from_adaptor (xcontext, adaptors, i); - xvimagesink->adaptor_no = i; - } - } - - XvFreeAdaptorInfo (adaptors); - - if (!xcontext->xv_port_id) { - xvimagesink->adaptor_no = -1; - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, BUSY, - ("Could not initialise Xv output"), ("No port available")); - return NULL; - } - - /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */ - { - int count, todo = 3; - XvAttribute *const attr = XvQueryPortAttributes (xcontext->disp, - xcontext->xv_port_id, &count); - static const char autopaint[] = "XV_AUTOPAINT_COLORKEY"; - static const char dbl_buffer[] = "XV_DOUBLE_BUFFER"; - static const char colorkey[] = "XV_COLORKEY"; - - GST_DEBUG_OBJECT (xvimagesink, "Checking %d Xv port attributes", count); - - xvimagesink->have_autopaint_colorkey = FALSE; - xvimagesink->have_double_buffer = FALSE; - xvimagesink->have_colorkey = FALSE; - - for (i = 0; ((i < count) && todo); i++) - if (!strcmp (attr[i].name, autopaint)) { - const Atom atom = XInternAtom (xcontext->disp, autopaint, False); - - /* turn on autopaint colorkey */ - XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, - (xvimagesink->autopaint_colorkey ? 1 : 0)); - todo--; - xvimagesink->have_autopaint_colorkey = TRUE; - } else if (!strcmp (attr[i].name, dbl_buffer)) { - const Atom atom = XInternAtom (xcontext->disp, dbl_buffer, False); - - XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, - (xvimagesink->double_buffer ? 1 : 0)); - todo--; - xvimagesink->have_double_buffer = TRUE; - } else if (!strcmp (attr[i].name, colorkey)) { - /* Set the colorkey, default is something that is dark but hopefully - * won't randomly appear on the screen elsewhere (ie not black or greys) - * can be overridden by setting "colorkey" property - */ - const Atom atom = XInternAtom (xcontext->disp, colorkey, False); - guint32 ckey = 0; - gboolean set_attr = TRUE; - guint cr, cg, cb; - - /* set a colorkey in the right format RGB565/RGB888 - * We only handle these 2 cases, because they're the only types of - * devices we've encountered. If we don't recognise it, leave it alone - */ - cr = (xvimagesink->colorkey >> 16); - cg = (xvimagesink->colorkey >> 8) & 0xFF; - cb = (xvimagesink->colorkey) & 0xFF; - switch (xcontext->depth) { - case 16: /* RGB 565 */ - cr >>= 3; - cg >>= 2; - cb >>= 3; - ckey = (cr << 11) | (cg << 5) | cb; - break; - case 24: - case 32: /* RGB 888 / ARGB 8888 */ - ckey = (cr << 16) | (cg << 8) | cb; - break; - default: - GST_DEBUG_OBJECT (xvimagesink, - "Unknown bit depth %d for Xv Colorkey - not adjusting", - xcontext->depth); - set_attr = FALSE; - break; - } - - if (set_attr) { - ckey = CLAMP (ckey, (guint32) attr[i].min_value, - (guint32) attr[i].max_value); - GST_LOG_OBJECT (xvimagesink, - "Setting color key for display depth %d to 0x%x", - xcontext->depth, ckey); - - XvSetPortAttribute (xcontext->disp, xcontext->xv_port_id, atom, - (gint) ckey); - } - todo--; - xvimagesink->have_colorkey = TRUE; - } - - XFree (attr); - } - - /* Get the list of encodings supported by the adapter and look for the - * XV_IMAGE encoding so we can determine the maximum width and height - * supported */ - XvQueryEncodings (xcontext->disp, xcontext->xv_port_id, &nb_encodings, - &encodings); - - for (i = 0; i < nb_encodings; i++) { - GST_LOG_OBJECT (xvimagesink, - "Encoding %d, name %s, max wxh %lux%lu rate %d/%d", - i, encodings[i].name, encodings[i].width, encodings[i].height, - encodings[i].rate.numerator, encodings[i].rate.denominator); - if (strcmp (encodings[i].name, "XV_IMAGE") == 0) { - max_w = encodings[i].width; - max_h = encodings[i].height; - } - } - - XvFreeEncodingInfo (encodings); - - /* We get all image formats supported by our port */ - formats = XvListImageFormats (xcontext->disp, - xcontext->xv_port_id, &nb_formats); - caps = gst_caps_new_empty (); - for (i = 0; i < nb_formats; i++) { - GstCaps *format_caps = NULL; - gboolean is_rgb_format = FALSE; - GstVideoFormat vformat; - - /* We set the image format of the xcontext to an existing one. This - is just some valid image format for making our xshm calls check before - caps negotiation really happens. */ - xcontext->im_format = formats[i].id; - - switch (formats[i].type) { - case XvRGB: - { - XvImageFormatValues *fmt = &(formats[i]); - gint endianness; - - endianness = - (fmt->byte_order == LSBFirst ? G_LITTLE_ENDIAN : G_BIG_ENDIAN); - - vformat = gst_video_format_from_masks (fmt->depth, fmt->bits_per_pixel, - endianness, fmt->red_mask, fmt->green_mask, fmt->blue_mask, 0); - if (vformat == GST_VIDEO_FORMAT_UNKNOWN) - break; - - format_caps = gst_caps_new_simple ("video/x-raw", - "format", G_TYPE_STRING, gst_video_format_to_string (vformat), - "width", GST_TYPE_INT_RANGE, 1, max_w, - "height", GST_TYPE_INT_RANGE, 1, max_h, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - - is_rgb_format = TRUE; - break; - } - case XvYUV: - { - vformat = gst_video_format_from_fourcc (formats[i].id); - if (vformat == GST_VIDEO_FORMAT_UNKNOWN) - break; - - format_caps = gst_caps_new_simple ("video/x-raw", - "format", G_TYPE_STRING, gst_video_format_to_string (vformat), - "width", GST_TYPE_INT_RANGE, 1, max_w, - "height", GST_TYPE_INT_RANGE, 1, max_h, - "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL); - break; - } - default: - vformat = GST_VIDEO_FORMAT_UNKNOWN; - g_assert_not_reached (); - break; - } - - if (format_caps) { - GstXvImageFormat *format = NULL; - - format = g_new0 (GstXvImageFormat, 1); - if (format) { - format->format = formats[i].id; - format->vformat = vformat; - format->caps = gst_caps_copy (format_caps); - xcontext->formats_list = g_list_append (xcontext->formats_list, format); - } - - if (is_rgb_format) { - if (rgb_caps == NULL) - rgb_caps = format_caps; - else - gst_caps_append (rgb_caps, format_caps); - } else - gst_caps_append (caps, format_caps); - } - } - - /* Collected all caps into either the caps or rgb_caps structures. - * Append rgb_caps on the end of YUV, so that YUV is always preferred */ - if (rgb_caps) - gst_caps_append (caps, rgb_caps); - - if (formats) - XFree (formats); - - GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps); - - if (gst_caps_is_empty (caps)) { - gst_caps_unref (caps); - XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0); - GST_ELEMENT_ERROR (xvimagesink, STREAM, WRONG_TYPE, (NULL), - ("No supported format found")); - return NULL; - } - - return caps; -} - static gpointer gst_xvimagesink_event_thread (GstXvImageSink * xvimagesink) { @@ -1168,7 +594,7 @@ gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink) GThread *thread = NULL; /* don't start the thread too early */ - if (xvimagesink->xcontext == NULL) { + if (xvimagesink->context == NULL) { return; } @@ -1200,314 +626,6 @@ gst_xvimagesink_manage_event_thread (GstXvImageSink * xvimagesink) } - -/* This function calculates the pixel aspect ratio based on the properties - * in the xcontext structure and stores it there. */ -static void -gst_xvimagesink_calculate_pixel_aspect_ratio (GstXContext * xcontext) -{ - static const gint par[][2] = { - {1, 1}, /* regular screen */ - {16, 15}, /* PAL TV */ - {11, 10}, /* 525 line Rec.601 video */ - {54, 59}, /* 625 line Rec.601 video */ - {64, 45}, /* 1280x1024 on 16:9 display */ - {5, 3}, /* 1280x1024 on 4:3 display */ - {4, 3} /* 800x600 on 16:9 display */ - }; - gint i; - gint index; - gdouble ratio; - gdouble delta; - -#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1]))) - - /* first calculate the "real" ratio based on the X values; - * which is the "physical" w/h divided by the w/h in pixels of the display */ - ratio = (gdouble) (xcontext->widthmm * xcontext->height) - / (xcontext->heightmm * xcontext->width); - - /* DirectFB's X in 720x576 reports the physical dimensions wrong, so - * override here */ - if (xcontext->width == 720 && xcontext->height == 576) { - ratio = 4.0 * 576 / (3.0 * 720); - } - GST_DEBUG ("calculated pixel aspect ratio: %f", ratio); - - /* now find the one from par[][2] with the lowest delta to the real one */ - delta = DELTA (0); - index = 0; - - for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) { - gdouble this_delta = DELTA (i); - - if (this_delta < delta) { - index = i; - delta = this_delta; - } - } - - GST_DEBUG ("Decided on index %d (%d/%d)", index, - par[index][0], par[index][1]); - - g_free (xcontext->par); - xcontext->par = g_new0 (GValue, 1); - g_value_init (xcontext->par, GST_TYPE_FRACTION); - gst_value_set_fraction (xcontext->par, par[index][0], par[index][1]); - GST_DEBUG ("set xcontext PAR to %d/%d", - gst_value_get_fraction_numerator (xcontext->par), - gst_value_get_fraction_denominator (xcontext->par)); -} - -/* This function gets the X Display and global info about it. Everything is - stored in our object and will be cleaned when the object is disposed. Note - here that caps for supported format are generated without any window or - image creation */ -static GstXContext * -gst_xvimagesink_xcontext_get (GstXvImageSink * xvimagesink) -{ - GstXContext *xcontext = NULL; - XPixmapFormatValues *px_formats = NULL; - gint nb_formats = 0, i, j, N_attr; - XvAttribute *xv_attr; - Atom prop_atom; - const char *channels[4] = { "XV_HUE", "XV_SATURATION", - "XV_BRIGHTNESS", "XV_CONTRAST" - }; - - g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - - xcontext = g_new0 (GstXContext, 1); - xcontext->im_format = 0; - - g_mutex_lock (&xvimagesink->x_lock); - - xcontext->disp = XOpenDisplay (xvimagesink->display_name); - - if (!xcontext->disp) { - g_mutex_unlock (&xvimagesink->x_lock); - g_free (xcontext); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, WRITE, - ("Could not initialise Xv output"), ("Could not open display")); - return NULL; - } - - xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); - xcontext->screen_num = DefaultScreen (xcontext->disp); - xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); - xcontext->root = DefaultRootWindow (xcontext->disp); - xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num); - xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num); - xcontext->depth = DefaultDepthOfScreen (xcontext->screen); - - xcontext->width = DisplayWidth (xcontext->disp, xcontext->screen_num); - xcontext->height = DisplayHeight (xcontext->disp, xcontext->screen_num); - xcontext->widthmm = DisplayWidthMM (xcontext->disp, xcontext->screen_num); - xcontext->heightmm = DisplayHeightMM (xcontext->disp, xcontext->screen_num); - - GST_DEBUG_OBJECT (xvimagesink, "X reports %dx%d pixels and %d mm x %d mm", - xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm); - - gst_xvimagesink_calculate_pixel_aspect_ratio (xcontext); - /* We get supported pixmap formats at supported depth */ - px_formats = XListPixmapFormats (xcontext->disp, &nb_formats); - - if (!px_formats) { - XCloseDisplay (xcontext->disp); - g_mutex_unlock (&xvimagesink->x_lock); - g_free (xcontext->par); - g_free (xcontext); - GST_ELEMENT_ERROR (xvimagesink, RESOURCE, SETTINGS, - ("Could not initialise Xv output"), ("Could not get pixel formats")); - return NULL; - } - - /* We get bpp value corresponding to our running depth */ - for (i = 0; i < nb_formats; i++) { - if (px_formats[i].depth == xcontext->depth) - xcontext->bpp = px_formats[i].bits_per_pixel; - } - - XFree (px_formats); - - xcontext->endianness = - (ImageByteOrder (xcontext->disp) == - LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN; - - /* our caps system handles 24/32bpp RGB as big-endian. */ - if ((xcontext->bpp == 24 || xcontext->bpp == 32) && - xcontext->endianness == G_LITTLE_ENDIAN) { - xcontext->endianness = G_BIG_ENDIAN; - xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask); - xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask); - xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask); - if (xcontext->bpp == 24) { - xcontext->visual->red_mask >>= 8; - xcontext->visual->green_mask >>= 8; - xcontext->visual->blue_mask >>= 8; - } - } - - xcontext->caps = gst_xvimagesink_get_xv_support (xvimagesink, xcontext); - - /* Search for XShm extension support */ -#ifdef HAVE_XSHM - if (XShmQueryExtension (xcontext->disp) && - gst_xvimagesink_check_xshm_calls (xvimagesink, xcontext)) { - xcontext->use_xshm = TRUE; - GST_DEBUG ("xvimagesink is using XShm extension"); - } else -#endif /* HAVE_XSHM */ - { - xcontext->use_xshm = FALSE; - GST_DEBUG ("xvimagesink is not using XShm extension"); - } - - if (!xcontext->caps) { - XCloseDisplay (xcontext->disp); - g_mutex_unlock (&xvimagesink->x_lock); - g_free (xcontext->par); - g_free (xcontext); - /* GST_ELEMENT_ERROR is thrown by gst_xvimagesink_get_xv_support */ - return NULL; - } - - xv_attr = XvQueryPortAttributes (xcontext->disp, - xcontext->xv_port_id, &N_attr); - - - /* Generate the channels list */ - for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) { - XvAttribute *matching_attr = NULL; - - /* Retrieve the property atom if it exists. If it doesn't exist, - * the attribute itself must not either, so we can skip */ - prop_atom = XInternAtom (xcontext->disp, channels[i], True); - if (prop_atom == None) - continue; - - if (xv_attr != NULL) { - for (j = 0; j < N_attr && matching_attr == NULL; ++j) - if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name)) - matching_attr = xv_attr + j; - } - - if (matching_attr) { - GstColorBalanceChannel *channel; - - channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL); - channel->label = g_strdup (channels[i]); - channel->min_value = matching_attr ? matching_attr->min_value : -1000; - channel->max_value = matching_attr ? matching_attr->max_value : 1000; - - xcontext->channels_list = g_list_append (xcontext->channels_list, - channel); - - /* If the colorbalance settings have not been touched we get Xv values - as defaults and update our internal variables */ - if (!xvimagesink->cb_changed) { - gint val; - - XvGetPortAttribute (xcontext->disp, xcontext->xv_port_id, - prop_atom, &val); - /* Normalize val to [-1000, 1000] */ - val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) / - (double) (channel->max_value - channel->min_value)); - - if (!g_ascii_strcasecmp (channels[i], "XV_HUE")) - xvimagesink->hue = val; - else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION")) - xvimagesink->saturation = val; - else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS")) - xvimagesink->brightness = val; - else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST")) - xvimagesink->contrast = val; - } - } - } - - if (xv_attr) - XFree (xv_attr); - - g_mutex_unlock (&xvimagesink->x_lock); - - return xcontext; -} - -/* This function cleans the X context. Closing the Display, releasing the XV - port and unrefing the caps for supported formats. */ -static void -gst_xvimagesink_xcontext_clear (GstXvImageSink * xvimagesink) -{ - GList *formats_list, *channels_list; - GstXContext *xcontext; - gint i = 0; - - g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); - - GST_OBJECT_LOCK (xvimagesink); - if (xvimagesink->xcontext == NULL) { - GST_OBJECT_UNLOCK (xvimagesink); - return; - } - - /* Take the XContext from the sink and clean it up */ - xcontext = xvimagesink->xcontext; - xvimagesink->xcontext = NULL; - - GST_OBJECT_UNLOCK (xvimagesink); - - - formats_list = xcontext->formats_list; - - while (formats_list) { - GstXvImageFormat *format = formats_list->data; - - gst_caps_unref (format->caps); - g_free (format); - formats_list = g_list_next (formats_list); - } - - if (xcontext->formats_list) - g_list_free (xcontext->formats_list); - - channels_list = xcontext->channels_list; - - while (channels_list) { - GstColorBalanceChannel *channel = channels_list->data; - - g_object_unref (channel); - channels_list = g_list_next (channels_list); - } - - if (xcontext->channels_list) - g_list_free (xcontext->channels_list); - - gst_caps_unref (xcontext->caps); - if (xcontext->last_caps) - gst_caps_replace (&xcontext->last_caps, NULL); - - for (i = 0; i < xcontext->nb_adaptors; i++) { - g_free (xcontext->adaptors[i]); - } - - g_free (xcontext->adaptors); - - g_free (xcontext->par); - - g_mutex_lock (&xvimagesink->x_lock); - - GST_DEBUG_OBJECT (xvimagesink, "Closing display and freeing X Context"); - - XvUngrabPort (xcontext->disp, xcontext->xv_port_id, 0); - - XCloseDisplay (xcontext->disp); - - g_mutex_unlock (&xvimagesink->x_lock); - - g_free (xcontext); -} - /* Element stuff */ static GstCaps * @@ -1518,12 +636,12 @@ gst_xvimagesink_getcaps (GstBaseSink * bsink, GstCaps * filter) xvimagesink = GST_XVIMAGESINK (bsink); - if (xvimagesink->xcontext) { + if (xvimagesink->context) { if (filter) - return gst_caps_intersect_full (filter, xvimagesink->xcontext->caps, + return gst_caps_intersect_full (filter, xvimagesink->context->caps, GST_CAPS_INTERSECT_FIRST); else - return gst_caps_ref (xvimagesink->xcontext->caps); + return gst_caps_ref (xvimagesink->context->caps); } caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (xvimagesink)); @@ -1542,6 +660,7 @@ static gboolean gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) { GstXvImageSink *xvimagesink; + GstXvContext *context; GstStructure *structure; GstBufferPool *newpool, *oldpool; GstVideoInfo info; @@ -1550,15 +669,15 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) gint display_par_n, display_par_d; /* display's PAR */ guint num, den; gint size; - static GstAllocationParams params = { 0, 15, 0, 0, }; xvimagesink = GST_XVIMAGESINK (bsink); + context = xvimagesink->context; GST_DEBUG_OBJECT (xvimagesink, "In setcaps. Possible caps %" GST_PTR_FORMAT ", setting caps %" - GST_PTR_FORMAT, xvimagesink->xcontext->caps, caps); + GST_PTR_FORMAT, context->caps, caps); - if (!gst_caps_can_intersect (xvimagesink->xcontext->caps, caps)) + if (!gst_caps_can_intersect (context->caps, caps)) goto incompatible_caps; if (!gst_video_info_from_caps (&info, caps)) @@ -1570,7 +689,7 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) xvimagesink->video_width = info.width; xvimagesink->video_height = info.height; - im_format = gst_xvimagesink_get_format_from_info (xvimagesink, &info); + im_format = gst_xvcontext_get_format_from_info (context, &info); if (im_format == -1) goto invalid_format; @@ -1654,11 +773,10 @@ gst_xvimagesink_setcaps (GstBaseSink * bsink, GstCaps * caps) xvimagesink->redraw_border = TRUE; /* create a new pool for the new configuration */ - newpool = gst_xvimage_buffer_pool_new (xvimagesink); + newpool = gst_xvimage_buffer_pool_new (xvimagesink->allocator); structure = gst_buffer_pool_get_config (newpool); gst_buffer_pool_config_set_params (structure, caps, size, 2, 0); - gst_buffer_pool_config_set_allocator (structure, NULL, ¶ms); if (!gst_buffer_pool_set_config (newpool, structure)) goto config_failed; @@ -1715,37 +833,13 @@ gst_xvimagesink_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstXvImageSink *xvimagesink; - GstXContext *xcontext = NULL; xvimagesink = GST_XVIMAGESINK (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: - /* Initializing the XContext */ - if (xvimagesink->xcontext == NULL) { - xcontext = gst_xvimagesink_xcontext_get (xvimagesink); - if (xcontext == NULL) { - ret = GST_STATE_CHANGE_FAILURE; - goto beach; - } - GST_OBJECT_LOCK (xvimagesink); - if (xcontext) - xvimagesink->xcontext = xcontext; - GST_OBJECT_UNLOCK (xvimagesink); - } - - /* update object's par with calculated one if not set yet */ - if (!xvimagesink->par) { - xvimagesink->par = g_new0 (GValue, 1); - gst_value_init_and_copy (xvimagesink->par, xvimagesink->xcontext->par); - GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR"); - } - /* call XSynchronize with the current value of synchronous */ - GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s", - xvimagesink->synchronous ? "TRUE" : "FALSE"); - XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous); - gst_xvimagesink_update_colorbalance (xvimagesink); - gst_xvimagesink_manage_event_thread (xvimagesink); + if (!gst_xvimagesink_open (xvimagesink)) + goto error; break; case GST_STATE_CHANGE_READY_TO_PAUSED: break; @@ -1773,14 +867,17 @@ gst_xvimagesink_change_state (GstElement * element, GstStateChange transition) g_mutex_unlock (&xvimagesink->flow_lock); break; case GST_STATE_CHANGE_READY_TO_NULL: - gst_xvimagesink_reset (xvimagesink); + gst_xvimagesink_close (xvimagesink); break; default: break; } - -beach: return ret; + +error: + { + return GST_STATE_CHANGE_FAILURE; + } } static void @@ -1811,14 +908,12 @@ gst_xvimagesink_show_frame (GstVideoSink * vsink, GstBuffer * buf) GstFlowReturn res; GstXvImageSink *xvimagesink; GstBuffer *to_put; - GstXvImageMemory *mem; + GstMemory *mem; xvimagesink = GST_XVIMAGESINK (vsink); - if (gst_buffer_n_memory (buf) == 1 - && (mem = (GstXvImageMemory *) gst_buffer_peek_memory (buf, 0)) - && g_strcmp0 (mem->parent.allocator->mem_type, "xvimage") == 0 - && mem->sink == xvimagesink) { + if (gst_buffer_n_memory (buf) == 1 && (mem = gst_buffer_peek_memory (buf, 0)) + && gst_xvimage_memory_is_from_context (mem, xvimagesink->context)) { /* If this buffer has been allocated using our buffer management we simply put the ximage which is in the PRIVATE pointer */ GST_LOG_OBJECT (xvimagesink, "buffer %p from our pool, writing directly", @@ -1981,7 +1076,7 @@ gst_xvimagesink_propose_allocation (GstBaseSink * bsink, GstQuery * query) goto invalid_caps; GST_DEBUG_OBJECT (xvimagesink, "create new pool"); - pool = gst_xvimage_buffer_pool_new (xvimagesink); + pool = gst_xvimage_buffer_pool_new (xvimagesink->allocator); /* the normal size of a frame */ size = info.size; @@ -2034,13 +1129,14 @@ gst_xvimagesink_navigation_send_event (GstNavigation * navigation, GstEvent *event; GstVideoRectangle src, dst, result; gdouble x, y, xscale = 1.0, yscale = 1.0; + GstXWindow *xwindow; event = gst_event_new_navigation (structure); /* We take the flow_lock while we look at the window */ g_mutex_lock (&xvimagesink->flow_lock); - if (!xvimagesink->xwindow) { + if (!(xwindow = xvimagesink->xwindow)) { g_mutex_unlock (&xvimagesink->flow_lock); return; } @@ -2050,14 +1146,14 @@ gst_xvimagesink_navigation_send_event (GstNavigation * navigation, that respect pixel aspect ratios */ src.w = GST_VIDEO_SINK_WIDTH (xvimagesink); src.h = GST_VIDEO_SINK_HEIGHT (xvimagesink); - dst.w = xvimagesink->render_rect.w; - dst.h = xvimagesink->render_rect.h; + dst.w = xwindow->render_rect.w; + dst.h = xwindow->render_rect.h; gst_video_sink_center_rect (src, dst, &result, TRUE); - result.x += xvimagesink->render_rect.x; - result.y += xvimagesink->render_rect.y; + result.x += xwindow->render_rect.x; + result.y += xwindow->render_rect.y; } else { - memcpy (&result, &xvimagesink->render_rect, sizeof (GstVideoRectangle)); + memcpy (&result, &xwindow->render_rect, sizeof (GstVideoRectangle)); } g_mutex_unlock (&xvimagesink->flow_lock); @@ -2098,6 +1194,7 @@ gst_xvimagesink_set_window_handle (GstVideoOverlay * overlay, guintptr id) XID xwindow_id = id; GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); GstXWindow *xwindow = NULL; + GstXvContext *context; g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); @@ -2110,18 +1207,21 @@ gst_xvimagesink_set_window_handle (GstVideoOverlay * overlay, guintptr id) } /* If the element has not initialized the X11 context try to do so */ - if (!xvimagesink->xcontext && - !(xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink))) { + if (!xvimagesink->context && + !(xvimagesink->context = + gst_xvcontext_new (&xvimagesink->config, NULL))) { g_mutex_unlock (&xvimagesink->flow_lock); /* we have thrown a GST_ELEMENT_ERROR now */ return; } + context = xvimagesink->context; + gst_xvimagesink_update_colorbalance (xvimagesink); /* If a window is there already we destroy it */ if (xvimagesink->xwindow) { - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); + gst_xwindow_destroy (xvimagesink->xwindow); xvimagesink->xwindow = NULL; } @@ -2137,33 +1237,8 @@ gst_xvimagesink_set_window_handle (GstVideoOverlay * overlay, guintptr id) GST_VIDEO_SINK_HEIGHT (xvimagesink)); } } else { - XWindowAttributes attr; - - xwindow = g_new0 (GstXWindow, 1); - xwindow->win = xwindow_id; - - /* Set the event we want to receive and create a GC */ - g_mutex_lock (&xvimagesink->x_lock); - - XGetWindowAttributes (xvimagesink->xcontext->disp, xwindow->win, &attr); - - xwindow->width = attr.width; - xwindow->height = attr.height; - xwindow->internal = FALSE; - if (!xvimagesink->have_render_rect) { - xvimagesink->render_rect.x = xvimagesink->render_rect.y = 0; - xvimagesink->render_rect.w = attr.width; - xvimagesink->render_rect.h = attr.height; - } - if (xvimagesink->handle_events) { - XSelectInput (xvimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask); - } - - xwindow->gc = XCreateGC (xvimagesink->xcontext->disp, - xwindow->win, 0, NULL); - g_mutex_unlock (&xvimagesink->x_lock); + xwindow = gst_xvcontext_create_xwindow_from_xid (context, xwindow_id); + gst_xwindow_set_event_handling (xwindow, xvimagesink->handle_events); } if (xwindow) @@ -2188,33 +1263,10 @@ gst_xvimagesink_set_event_handling (GstVideoOverlay * overlay, { GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); - xvimagesink->handle_events = handle_events; - g_mutex_lock (&xvimagesink->flow_lock); - - if (G_UNLIKELY (!xvimagesink->xwindow)) { - g_mutex_unlock (&xvimagesink->flow_lock); - return; - } - - g_mutex_lock (&xvimagesink->x_lock); - - if (handle_events) { - if (xvimagesink->xwindow->internal) { - XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); - } else { - XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, - ExposureMask | StructureNotifyMask | PointerMotionMask | - KeyPressMask | KeyReleaseMask); - } - } else { - XSelectInput (xvimagesink->xcontext->disp, xvimagesink->xwindow->win, 0); - } - - g_mutex_unlock (&xvimagesink->x_lock); - + xvimagesink->handle_events = handle_events; + if (G_LIKELY (xvimagesink->xwindow)) + gst_xwindow_set_event_handling (xvimagesink->xwindow, handle_events); g_mutex_unlock (&xvimagesink->flow_lock); } @@ -2224,20 +1276,11 @@ gst_xvimagesink_set_render_rectangle (GstVideoOverlay * overlay, gint x, gint y, { GstXvImageSink *xvimagesink = GST_XVIMAGESINK (overlay); - /* FIXME: how about some locking? */ - if (width >= 0 && height >= 0) { - xvimagesink->render_rect.x = x; - xvimagesink->render_rect.y = y; - xvimagesink->render_rect.w = width; - xvimagesink->render_rect.h = height; - xvimagesink->have_render_rect = TRUE; - } else { - xvimagesink->render_rect.x = 0; - xvimagesink->render_rect.y = 0; - xvimagesink->render_rect.w = xvimagesink->xwindow->width; - xvimagesink->render_rect.h = xvimagesink->xwindow->height; - xvimagesink->have_render_rect = FALSE; - } + g_mutex_lock (&xvimagesink->flow_lock); + if (G_LIKELY (xvimagesink->xwindow)) + gst_xwindow_set_render_rectangle (xvimagesink->xwindow, x, y, width, + height); + g_mutex_unlock (&xvimagesink->flow_lock); } static void @@ -2256,8 +1299,8 @@ gst_xvimagesink_colorbalance_list_channels (GstColorBalance * balance) g_return_val_if_fail (GST_IS_XVIMAGESINK (xvimagesink), NULL); - if (xvimagesink->xcontext) - return xvimagesink->xcontext->channels_list; + if (xvimagesink->context) + return xvimagesink->context->channels_list; else return NULL; } @@ -2271,20 +1314,20 @@ gst_xvimagesink_colorbalance_set_value (GstColorBalance * balance, g_return_if_fail (GST_IS_XVIMAGESINK (xvimagesink)); g_return_if_fail (channel->label != NULL); - xvimagesink->cb_changed = TRUE; + xvimagesink->config.cb_changed = TRUE; /* Normalize val to [-1000, 1000] */ value = floor (0.5 + -1000 + 2000 * (value - channel->min_value) / (double) (channel->max_value - channel->min_value)); if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { - xvimagesink->hue = value; + xvimagesink->config.hue = value; } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { - xvimagesink->saturation = value; + xvimagesink->config.saturation = value; } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { - xvimagesink->contrast = value; + xvimagesink->config.contrast = value; } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { - xvimagesink->brightness = value; + xvimagesink->config.brightness = value; } else { g_warning ("got an unknown channel %s", channel->label); return; @@ -2304,13 +1347,13 @@ gst_xvimagesink_colorbalance_get_value (GstColorBalance * balance, g_return_val_if_fail (channel->label != NULL, 0); if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) { - value = xvimagesink->hue; + value = xvimagesink->config.hue; } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) { - value = xvimagesink->saturation; + value = xvimagesink->config.saturation; } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) { - value = xvimagesink->contrast; + value = xvimagesink->config.contrast; } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) { - value = xvimagesink->brightness; + value = xvimagesink->config.brightness; } else { g_warning ("got an unknown channel %s", channel->label); } @@ -2372,9 +1415,9 @@ gst_xvimagesink_probe_probe_property (GstPropertyProbe * probe, case PROP_COLORKEY: GST_DEBUG_OBJECT (xvimagesink, "probing device list and get capabilities"); - if (!xvimagesink->xcontext) { - GST_DEBUG_OBJECT (xvimagesink, "generating xcontext"); - xvimagesink->xcontext = gst_xvimagesink_xcontext_get (xvimagesink); + if (!xvimagesink->context) { + GST_DEBUG_OBJECT (xvimagesink, "generating context"); + xvimagesink->context = gst_xvimagesink_context_get (xvimagesink); } break; default: @@ -2395,7 +1438,7 @@ gst_xvimagesink_probe_needs_probe (GstPropertyProbe * probe, case PROP_AUTOPAINT_COLORKEY: case PROP_DOUBLE_BUFFER: case PROP_COLORKEY: - if (xvimagesink->xcontext != NULL) { + if (xvimagesink->context != NULL) { ret = FALSE; } else { ret = TRUE; @@ -2416,8 +1459,8 @@ gst_xvimagesink_probe_get_values (GstPropertyProbe * probe, GstXvImageSink *xvimagesink = GST_XVIMAGESINK (probe); GValueArray *array = NULL; - if (G_UNLIKELY (!xvimagesink->xcontext)) { - GST_WARNING_OBJECT (xvimagesink, "we don't have any xcontext, can't " + if (G_UNLIKELY (!xvimagesink->context)) { + GST_WARNING_OBJECT (xvimagesink, "we don't have any context, can't " "get values"); goto beach; } @@ -2428,10 +1471,10 @@ gst_xvimagesink_probe_get_values (GstPropertyProbe * probe, guint i; GValue value = { 0 }; - array = g_value_array_new (xvimagesink->xcontext->nb_adaptors); + array = g_value_array_new (xvimagesink->context->nb_adaptors); g_value_init (&value, G_TYPE_STRING); - for (i = 0; i < xvimagesink->xcontext->nb_adaptors; i++) { + for (i = 0; i < xvimagesink->context->nb_adaptors; i++) { gchar *adaptor_id_s = g_strdup_printf ("%u", i); g_value_set_string (&value, adaptor_id_s); @@ -2516,34 +1559,34 @@ gst_xvimagesink_set_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_HUE: - xvimagesink->hue = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; + xvimagesink->config.hue = g_value_get_int (value); + xvimagesink->config.cb_changed = TRUE; gst_xvimagesink_update_colorbalance (xvimagesink); break; case PROP_CONTRAST: - xvimagesink->contrast = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; + xvimagesink->config.contrast = g_value_get_int (value); + xvimagesink->config.cb_changed = TRUE; gst_xvimagesink_update_colorbalance (xvimagesink); break; case PROP_BRIGHTNESS: - xvimagesink->brightness = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; + xvimagesink->config.brightness = g_value_get_int (value); + xvimagesink->config.cb_changed = TRUE; gst_xvimagesink_update_colorbalance (xvimagesink); break; case PROP_SATURATION: - xvimagesink->saturation = g_value_get_int (value); - xvimagesink->cb_changed = TRUE; + xvimagesink->config.saturation = g_value_get_int (value); + xvimagesink->config.cb_changed = TRUE; gst_xvimagesink_update_colorbalance (xvimagesink); break; case PROP_DISPLAY: - xvimagesink->display_name = g_strdup (g_value_get_string (value)); + g_free (xvimagesink->config.display_name); + xvimagesink->config.display_name = g_strdup (g_value_get_string (value)); break; case PROP_SYNCHRONOUS: xvimagesink->synchronous = g_value_get_boolean (value); - if (xvimagesink->xcontext) { - XSynchronize (xvimagesink->xcontext->disp, xvimagesink->synchronous); - GST_DEBUG_OBJECT (xvimagesink, "XSynchronize called with %s", - xvimagesink->synchronous ? "TRUE" : "FALSE"); + if (xvimagesink->context) { + gst_xvcontext_set_synchronous (xvimagesink->context, + xvimagesink->synchronous); } break; case PROP_PIXEL_ASPECT_RATIO: @@ -2567,7 +1610,7 @@ gst_xvimagesink_set_property (GObject * object, guint prop_id, gst_xvimagesink_manage_event_thread (xvimagesink); break; case PROP_DEVICE: - xvimagesink->adaptor_no = atoi (g_value_get_string (value)); + xvimagesink->config.adaptor_nr = atoi (g_value_get_string (value)); break; case PROP_HANDLE_EXPOSE: xvimagesink->handle_expose = g_value_get_boolean (value); @@ -2577,10 +1620,10 @@ gst_xvimagesink_set_property (GObject * object, guint prop_id, xvimagesink->double_buffer = g_value_get_boolean (value); break; case PROP_AUTOPAINT_COLORKEY: - xvimagesink->autopaint_colorkey = g_value_get_boolean (value); + xvimagesink->config.autopaint_colorkey = g_value_get_boolean (value); break; case PROP_COLORKEY: - xvimagesink->colorkey = g_value_get_int (value); + xvimagesink->config.colorkey = g_value_get_int (value); break; case PROP_DRAW_BORDERS: xvimagesink->draw_borders = g_value_get_boolean (value); @@ -2603,19 +1646,19 @@ gst_xvimagesink_get_property (GObject * object, guint prop_id, switch (prop_id) { case PROP_HUE: - g_value_set_int (value, xvimagesink->hue); + g_value_set_int (value, xvimagesink->config.hue); break; case PROP_CONTRAST: - g_value_set_int (value, xvimagesink->contrast); + g_value_set_int (value, xvimagesink->config.contrast); break; case PROP_BRIGHTNESS: - g_value_set_int (value, xvimagesink->brightness); + g_value_set_int (value, xvimagesink->config.brightness); break; case PROP_SATURATION: - g_value_set_int (value, xvimagesink->saturation); + g_value_set_int (value, xvimagesink->config.saturation); break; case PROP_DISPLAY: - g_value_set_string (value, xvimagesink->display_name); + g_value_set_string (value, xvimagesink->config.display_name); break; case PROP_SYNCHRONOUS: g_value_set_boolean (value, xvimagesink->synchronous); @@ -2632,16 +1675,17 @@ gst_xvimagesink_get_property (GObject * object, guint prop_id, break; case PROP_DEVICE: { - char *adaptor_no_s = g_strdup_printf ("%u", xvimagesink->adaptor_no); + char *adaptor_nr_s = + g_strdup_printf ("%u", xvimagesink->config.adaptor_nr); - g_value_set_string (value, adaptor_no_s); - g_free (adaptor_no_s); + g_value_set_string (value, adaptor_nr_s); + g_free (adaptor_nr_s); break; } case PROP_DEVICE_NAME: - if (xvimagesink->xcontext && xvimagesink->xcontext->adaptors) { + if (xvimagesink->context && xvimagesink->context->adaptors) { g_value_set_string (value, - xvimagesink->xcontext->adaptors[xvimagesink->adaptor_no]); + xvimagesink->context->adaptors[xvimagesink->config.adaptor_nr]); } else { g_value_set_string (value, NULL); } @@ -2653,10 +1697,10 @@ gst_xvimagesink_get_property (GObject * object, guint prop_id, g_value_set_boolean (value, xvimagesink->double_buffer); break; case PROP_AUTOPAINT_COLORKEY: - g_value_set_boolean (value, xvimagesink->autopaint_colorkey); + g_value_set_boolean (value, xvimagesink->config.autopaint_colorkey); break; case PROP_COLORKEY: - g_value_set_int (value, xvimagesink->colorkey); + g_value_set_int (value, xvimagesink->config.colorkey); break; case PROP_DRAW_BORDERS: g_value_set_boolean (value, xvimagesink->draw_borders); @@ -2679,10 +1723,50 @@ gst_xvimagesink_get_property (GObject * object, guint prop_id, } } +static gboolean +gst_xvimagesink_open (GstXvImageSink * xvimagesink) +{ + GstXvContext *context; + GError *error = NULL; + + /* Initializing the XvContext */ + if (!(context = gst_xvcontext_new (&xvimagesink->config, &error))) + goto no_context; + + GST_OBJECT_LOCK (xvimagesink); + xvimagesink->context = context; + /* make an allocator for this context */ + xvimagesink->allocator = gst_xvimage_allocator_new (context); + GST_OBJECT_UNLOCK (xvimagesink); + + /* update object's par with calculated one if not set yet */ + if (!xvimagesink->par) { + xvimagesink->par = g_new0 (GValue, 1); + gst_value_init_and_copy (xvimagesink->par, xvimagesink->context->par); + GST_DEBUG_OBJECT (xvimagesink, "set calculated PAR on object's PAR"); + } + /* call XSynchronize with the current value of synchronous */ + gst_xvcontext_set_synchronous (xvimagesink->context, + xvimagesink->synchronous); + gst_xvimagesink_update_colorbalance (xvimagesink); + gst_xvimagesink_manage_event_thread (xvimagesink); + + return TRUE; + +no_context: + { + gst_element_message_full (GST_ELEMENT (xvimagesink), GST_MESSAGE_ERROR, + error->domain, error->code, g_strdup ("Could not initialise Xv output"), + error->message, __FILE__, GST_FUNCTION, __LINE__); + return FALSE; + } +} + static void -gst_xvimagesink_reset (GstXvImageSink * xvimagesink) +gst_xvimagesink_close (GstXvImageSink * xvimagesink) { GThread *thread; + GstXvContext *context; GST_OBJECT_LOCK (xvimagesink); xvimagesink->running = FALSE; @@ -2708,17 +1792,25 @@ gst_xvimagesink_reset (GstXvImageSink * xvimagesink) } if (xvimagesink->xwindow) { - gst_xvimagesink_xwindow_clear (xvimagesink, xvimagesink->xwindow); - gst_xvimagesink_xwindow_destroy (xvimagesink, xvimagesink->xwindow); + gst_xwindow_clear (xvimagesink->xwindow); + gst_xwindow_destroy (xvimagesink->xwindow); xvimagesink->xwindow = NULL; } g_mutex_unlock (&xvimagesink->flow_lock); - xvimagesink->render_rect.x = xvimagesink->render_rect.y = - xvimagesink->render_rect.w = xvimagesink->render_rect.h = 0; - xvimagesink->have_render_rect = FALSE; + if (xvimagesink->allocator) { + gst_object_unref (xvimagesink->allocator); + xvimagesink->allocator = NULL; + } - gst_xvimagesink_xcontext_clear (xvimagesink); + GST_OBJECT_LOCK (xvimagesink); + /* grab context and mark it as NULL */ + context = xvimagesink->context; + xvimagesink->context = NULL; + GST_OBJECT_UNLOCK (xvimagesink); + + if (context) + gst_xvcontext_unref (context); } /* Finalize is called only once, dispose can be called multiple times. @@ -2731,18 +1823,14 @@ gst_xvimagesink_finalize (GObject * object) xvimagesink = GST_XVIMAGESINK (object); - gst_xvimagesink_reset (xvimagesink); + gst_xvimagesink_close (xvimagesink); - if (xvimagesink->display_name) { - g_free (xvimagesink->display_name); - xvimagesink->display_name = NULL; - } + gst_xvcontext_config_clear (&xvimagesink->config); if (xvimagesink->par) { g_free (xvimagesink->par); xvimagesink->par = NULL; } - g_mutex_clear (&xvimagesink->x_lock); g_mutex_clear (&xvimagesink->flow_lock); g_free (xvimagesink->media_title); @@ -2752,40 +1840,38 @@ gst_xvimagesink_finalize (GObject * object) static void gst_xvimagesink_init (GstXvImageSink * xvimagesink) { - xvimagesink->display_name = NULL; - xvimagesink->adaptor_no = 0; - xvimagesink->xcontext = NULL; + xvimagesink->config.display_name = NULL; + xvimagesink->config.adaptor_nr = 0; + xvimagesink->config.autopaint_colorkey = TRUE; + xvimagesink->config.double_buffer = TRUE; + /* on 16bit displays this becomes r,g,b = 1,2,3 + * on 24bit displays this becomes r,g,b = 8,8,16 + * as a port atom value */ + xvimagesink->config.colorkey = (8 << 16) | (8 << 8) | 16; + xvimagesink->config.hue = xvimagesink->config.saturation = 0; + xvimagesink->config.contrast = xvimagesink->config.brightness = 0; + xvimagesink->config.cb_changed = FALSE; + + xvimagesink->context = NULL; xvimagesink->xwindow = NULL; xvimagesink->cur_image = NULL; - xvimagesink->hue = xvimagesink->saturation = 0; - xvimagesink->contrast = xvimagesink->brightness = 0; - xvimagesink->cb_changed = FALSE; - xvimagesink->fps_n = 0; xvimagesink->fps_d = 0; xvimagesink->video_width = 0; xvimagesink->video_height = 0; - g_mutex_init (&xvimagesink->x_lock); g_mutex_init (&xvimagesink->flow_lock); xvimagesink->pool = NULL; xvimagesink->synchronous = FALSE; - xvimagesink->double_buffer = TRUE; xvimagesink->running = FALSE; xvimagesink->keep_aspect = TRUE; xvimagesink->handle_events = TRUE; xvimagesink->par = NULL; xvimagesink->handle_expose = TRUE; - xvimagesink->autopaint_colorkey = TRUE; - /* on 16bit displays this becomes r,g,b = 1,2,3 - * on 24bit displays this becomes r,g,b = 8,8,16 - * as a port atom value - */ - xvimagesink->colorkey = (8 << 16) | (8 << 8) | 16; xvimagesink->draw_borders = TRUE; } diff --git a/sys/xvimage/xvimagesink.h b/sys/xvimage/xvimagesink.h index d7b7eb0..aefb667 100644 --- a/sys/xvimage/xvimagesink.h +++ b/sys/xvimage/xvimagesink.h @@ -22,26 +22,6 @@ #include -#ifdef HAVE_XSHM -#include -#include -#include -#endif /* HAVE_XSHM */ - -#include -#include - -#ifdef HAVE_XSHM -#include -#endif /* HAVE_XSHM */ - -#include -#include - -#include -#include -#include - /* Helper functions */ #include @@ -56,122 +36,18 @@ G_BEGIN_DECLS (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_XVIMAGESINK)) #define GST_IS_XVIMAGESINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_XVIMAGESINK)) -typedef struct _GstXContext GstXContext; -typedef struct _GstXWindow GstXWindow; -typedef struct _GstXvImageFormat GstXvImageFormat; typedef struct _GstXvImageSink GstXvImageSink; typedef struct _GstXvImageSinkClass GstXvImageSinkClass; +#include "xvimageallocator.h" #include "xvimagepool.h" - -/* - * GstXContext: - * @disp: the X11 Display of this context - * @screen: the default Screen of Display @disp - * @screen_num: the Screen number of @screen - * @visual: the default Visual of Screen @screen - * @root: the root Window of Display @disp - * @white: the value of a white pixel on Screen @screen - * @black: the value of a black pixel on Screen @screen - * @depth: the color depth of Display @disp - * @bpp: the number of bits per pixel on Display @disp - * @endianness: the endianness of image bytes on Display @disp - * @width: the width in pixels of Display @disp - * @height: the height in pixels of Display @disp - * @widthmm: the width in millimeters of Display @disp - * @heightmm: the height in millimeters of Display @disp - * @par: the pixel aspect ratio calculated from @width, @widthmm and @height, - * @heightmm ratio - * @use_xshm: used to known wether of not XShm extension is usable or not even - * if the Extension is present - * @xv_port_id: the XVideo port ID - * @im_format: used to store at least a valid format for XShm calls checks - * @formats_list: list of supported image formats on @xv_port_id - * @channels_list: list of #GstColorBalanceChannels - * @caps: the #GstCaps that Display @disp can accept - * - * Structure used to store various informations collected/calculated for a - * Display. - */ -struct _GstXContext -{ - Display *disp; - - Screen *screen; - gint screen_num; - - Visual *visual; - - Window root; - - gulong white, black; - - gint depth; - gint bpp; - gint endianness; - - gint width, height; - gint widthmm, heightmm; - GValue *par; /* calculated pixel aspect ratio */ - - gboolean use_xshm; - - XvPortID xv_port_id; - guint nb_adaptors; - gchar **adaptors; - gint im_format; - - GList *formats_list; - GList *channels_list; - - GstCaps *caps; - - /* Optimisation storage for buffer_alloc return */ - GstCaps *last_caps; - gint last_format; - gint last_width; - gint last_height; -}; - -/* - * GstXWindow: - * @win: the Window ID of this X11 window - * @width: the width in pixels of Window @win - * @height: the height in pixels of Window @win - * @internal: used to remember if Window @win was created internally or passed - * through the #GstVideoOverlay interface - * @gc: the Graphical Context of Window @win - * - * Structure used to store informations about a Window. - */ -struct _GstXWindow -{ - Window win; - gint width, height; - gboolean internal; - GC gc; -}; - -/** - * GstXvImageFormat: - * @format: the image format - * @caps: generated #GstCaps for this image format - * - * Structure storing image format to #GstCaps association. - */ -struct _GstXvImageFormat -{ - gint format; - GstVideoFormat vformat; - GstCaps *caps; -}; - +#include "xvcontext.h" /** * GstXvImageSink: * @display_name: the name of the Display we want to render to - * @xcontext: our instance's #GstXContext + * @xvcontext: our instance's #GstXvContext * @xwindow: the #GstXWindow we are rendering to * @cur_image: a reference to the last #GstXvImage that was put to @xwindow. It * is used when Expose events are received to redraw the latest video frame @@ -183,7 +59,7 @@ struct _GstXvImageFormat * mode * @flow_lock: used to protect data flow routines from external calls such as * events from @event_thread or methods from the #GstVideoOverlay interface - * @par: used to override calculated pixel aspect ratio from @xcontext + * @par: used to override calculated pixel aspect ratio from @xvcontext * @pool_lock: used to protect the buffer pool * @image_pool: a list of #GstXvImageBuffer that could be reused at next buffer * allocation call @@ -207,10 +83,9 @@ struct _GstXvImageSink /* Our element stuff */ GstVideoSink videosink; - char *display_name; - guint adaptor_no; - - GstXContext *xcontext; + GstXvContextConfig config; + GstXvContext *context; + GstXvImageAllocator *allocator; GstXWindow *xwindow; GstBuffer *cur_image; @@ -223,7 +98,6 @@ struct _GstXvImageSink gint fps_n; gint fps_d; - GMutex x_lock; GMutex flow_lock; /* object-set pixel aspect ratio */ @@ -239,32 +113,13 @@ struct _GstXvImageSink gboolean handle_events; gboolean handle_expose; - gint brightness; - gint contrast; - gint hue; - gint saturation; - gboolean cb_changed; - /* size of incoming video, used as the size for XvImage */ guint video_width, video_height; - /* port attributes */ - gboolean autopaint_colorkey; - gint colorkey; - gboolean draw_borders; - /* port features */ - gboolean have_autopaint_colorkey; - gboolean have_colorkey; - gboolean have_double_buffer; - /* stream metadata */ gchar *media_title; - - /* target video rectangle */ - GstVideoRectangle render_rect; - gboolean have_render_rect; }; struct _GstXvImageSinkClass -- 2.7.4