Blame sys/xvimage/xvcontext.c

Packit 971217
/* GStreamer
Packit 971217
 * Copyright (C) <2005> Julien Moutte <julien@moutte.net>
Packit 971217
 *               <2009>,<2010> Stefan Kost <stefan.kost@nokia.com>
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
/* for developers: there are two useful tools : xvinfo and xvattr */
Packit 971217
Packit 971217
#ifdef HAVE_CONFIG_H
Packit 971217
#include "config.h"
Packit 971217
#endif
Packit 971217
Packit 971217
/* Object header */
Packit 971217
#include "xvcontext.h"
Packit 971217
Packit 971217
/* Debugging category */
Packit 971217
#include <gst/gstinfo.h>
Packit 971217
Packit 971217
/* for XkbKeycodeToKeysym */
Packit 971217
#include <X11/XKBlib.h>
Packit 971217
Packit 971217
GST_DEBUG_CATEGORY_EXTERN (gst_debug_xv_context);
Packit 971217
#define GST_CAT_DEFAULT gst_debug_xv_context
Packit 971217
Packit 971217
void
Packit 971217
gst_xvcontext_config_clear (GstXvContextConfig * config)
Packit 971217
{
Packit 971217
  if (config->display_name) {
Packit 971217
    g_free (config->display_name);
Packit 971217
    config->display_name = NULL;
Packit 971217
  }
Packit 971217
  config->adaptor_nr = -1;
Packit 971217
}
Packit 971217
Packit 971217
GST_DEFINE_MINI_OBJECT_TYPE (GstXvContext, gst_xvcontext);
Packit 971217
Packit 971217
typedef struct
Packit 971217
{
Packit 971217
  unsigned long flags;
Packit 971217
  unsigned long functions;
Packit 971217
  unsigned long decorations;
Packit 971217
  long input_mode;
Packit 971217
  unsigned long status;
Packit 971217
}
Packit 971217
MotifWmHints, MwmHints;
Packit 971217
Packit 971217
#define MWM_HINTS_DECORATIONS   (1L << 1)
Packit 971217
Packit 971217
Packit 971217
static void
Packit 971217
gst_lookup_xv_port_from_adaptor (GstXvContext * context,
Packit 971217
    XvAdaptorInfo * adaptors, guint adaptor_nr)
Packit 971217
{
Packit 971217
  gint j;
Packit 971217
  gint res;
Packit 971217
Packit 971217
  /* Do we support XvImageMask ? */
Packit 971217
  if (!(adaptors[adaptor_nr].type & XvImageMask)) {
Packit 971217
    GST_DEBUG ("XV Adaptor %s has no support for XvImageMask",
Packit 971217
        adaptors[adaptor_nr].name);
Packit 971217
    return;
Packit 971217
  }
Packit 971217
Packit 971217
  /* We found such an adaptor, looking for an available port */
Packit 971217
  for (j = 0; j < adaptors[adaptor_nr].num_ports && !context->xv_port_id; j++) {
Packit 971217
    /* We try to grab the port */
Packit 971217
    res = XvGrabPort (context->disp, adaptors[adaptor_nr].base_id + j, 0);
Packit 971217
    if (Success == res) {
Packit 971217
      context->xv_port_id = adaptors[adaptor_nr].base_id + j;
Packit 971217
      GST_DEBUG ("XV Adaptor %s with %ld ports", adaptors[adaptor_nr].name,
Packit 971217
          adaptors[adaptor_nr].num_ports);
Packit 971217
    } else {
Packit 971217
      GST_DEBUG ("GrabPort %d for XV Adaptor %s failed: %d", j,
Packit 971217
          adaptors[adaptor_nr].name, res);
Packit 971217
    }
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/* This function generates a caps with all supported format by the first
Packit 971217
   Xv grabable port we find. We store each one of the supported formats in a
Packit 971217
   format list and append the format to a newly created caps that we return
Packit 971217
   If this function does not return NULL because of an error, it also grabs
Packit 971217
   the port via XvGrabPort */
Packit 971217
static GstCaps *
Packit 971217
gst_xvcontext_get_xv_support (GstXvContext * context,
Packit 971217
    const GstXvContextConfig * config, GError ** error)
Packit 971217
{
Packit 971217
  gint i;
Packit 971217
  XvAdaptorInfo *adaptors;
Packit 971217
  gint nb_formats;
Packit 971217
  XvImageFormatValues *formats = NULL;
Packit 971217
  guint nb_encodings;
Packit 971217
  XvEncodingInfo *encodings = NULL;
Packit 971217
  gulong max_w = G_MAXINT, max_h = G_MAXINT;
Packit 971217
  GstCaps *caps = NULL;
Packit 971217
  GstCaps *rgb_caps = NULL;
Packit 971217
Packit 971217
  g_return_val_if_fail (context != NULL, NULL);
Packit 971217
Packit 971217
  /* First let's check that XVideo extension is available */
Packit 971217
  if (!XQueryExtension (context->disp, "XVideo", &i, &i, &i))
Packit 971217
    goto no_xv;
Packit 971217
Packit 971217
  /* Then we get adaptors list */
Packit 971217
  if (Success != XvQueryAdaptors (context->disp, context->root,
Packit 971217
          &context->nb_adaptors, &adaptors))
Packit 971217
    goto no_adaptors;
Packit 971217
Packit 971217
  context->xv_port_id = 0;
Packit 971217
Packit 971217
  GST_DEBUG ("Found %u XV adaptor(s)", context->nb_adaptors);
Packit 971217
Packit 971217
  context->adaptors =
Packit 971217
      (gchar **) g_malloc0 (context->nb_adaptors * sizeof (gchar *));
Packit 971217
Packit 971217
  /* Now fill up our adaptor name array */
Packit 971217
  for (i = 0; i < context->nb_adaptors; i++) {
Packit 971217
    context->adaptors[i] = g_strdup (adaptors[i].name);
Packit 971217
  }
Packit 971217
Packit 971217
  if (config->adaptor_nr != -1 && config->adaptor_nr < context->nb_adaptors) {
Packit 971217
    /* Find xv port from user defined adaptor */
Packit 971217
    gst_lookup_xv_port_from_adaptor (context, adaptors, config->adaptor_nr);
Packit 971217
  }
Packit 971217
Packit 971217
  if (!context->xv_port_id) {
Packit 971217
    /* Now search for an adaptor that supports XvImageMask */
Packit 971217
    for (i = 0; i < context->nb_adaptors && !context->xv_port_id; i++) {
Packit 971217
      gst_lookup_xv_port_from_adaptor (context, adaptors, i);
Packit 971217
      context->adaptor_nr = i;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  XvFreeAdaptorInfo (adaptors);
Packit 971217
Packit 971217
  if (!context->xv_port_id)
Packit 971217
    goto no_ports;
Packit 971217
Packit 971217
  /* Set XV_AUTOPAINT_COLORKEY and XV_DOUBLE_BUFFER and XV_COLORKEY */
Packit 971217
  {
Packit 971217
    int count, todo = 4;
Packit 971217
    XvAttribute *const attr = XvQueryPortAttributes (context->disp,
Packit 971217
        context->xv_port_id, &count);
Packit 971217
    static const char autopaint[] = "XV_AUTOPAINT_COLORKEY";
Packit 971217
    static const char dbl_buffer[] = "XV_DOUBLE_BUFFER";
Packit 971217
    static const char colorkey[] = "XV_COLORKEY";
Packit 971217
    static const char iturbt709[] = "XV_ITURBT_709";
Packit 971217
Packit 971217
    GST_DEBUG ("Checking %d Xv port attributes", count);
Packit 971217
Packit 971217
    context->have_autopaint_colorkey = FALSE;
Packit 971217
    context->have_double_buffer = FALSE;
Packit 971217
    context->have_colorkey = FALSE;
Packit 971217
    context->have_iturbt709 = FALSE;
Packit 971217
Packit 971217
    for (i = 0; ((i < count) && todo); i++) {
Packit 971217
      GST_DEBUG ("Got attribute %s", attr[i].name);
Packit 971217
Packit 971217
      if (!strcmp (attr[i].name, autopaint)) {
Packit 971217
        const Atom atom = XInternAtom (context->disp, autopaint, False);
Packit 971217
Packit 971217
        /* turn on autopaint colorkey */
Packit 971217
        XvSetPortAttribute (context->disp, context->xv_port_id, atom,
Packit 971217
            (config->autopaint_colorkey ? 1 : 0));
Packit 971217
        todo--;
Packit 971217
        context->have_autopaint_colorkey = TRUE;
Packit 971217
      } else if (!strcmp (attr[i].name, dbl_buffer)) {
Packit 971217
        const Atom atom = XInternAtom (context->disp, dbl_buffer, False);
Packit 971217
Packit 971217
        XvSetPortAttribute (context->disp, context->xv_port_id, atom,
Packit 971217
            (config->double_buffer ? 1 : 0));
Packit 971217
        todo--;
Packit 971217
        context->have_double_buffer = TRUE;
Packit 971217
      } else if (!strcmp (attr[i].name, colorkey)) {
Packit 971217
        /* Set the colorkey, default is something that is dark but hopefully
Packit 971217
         * won't randomly appear on the screen elsewhere (ie not black or greys)
Packit 971217
         * can be overridden by setting "colorkey" property
Packit 971217
         */
Packit 971217
        const Atom atom = XInternAtom (context->disp, colorkey, False);
Packit 971217
        guint32 ckey = 0;
Packit 971217
        gboolean set_attr = TRUE;
Packit 971217
        guint cr, cg, cb;
Packit 971217
Packit 971217
        /* set a colorkey in the right format RGB565/RGB888
Packit 971217
         * We only handle these 2 cases, because they're the only types of
Packit 971217
         * devices we've encountered. If we don't recognise it, leave it alone
Packit 971217
         */
Packit 971217
        cr = (config->colorkey >> 16);
Packit 971217
        cg = (config->colorkey >> 8) & 0xFF;
Packit 971217
        cb = (config->colorkey) & 0xFF;
Packit 971217
        switch (context->depth) {
Packit 971217
          case 16:             /* RGB 565 */
Packit 971217
            cr >>= 3;
Packit 971217
            cg >>= 2;
Packit 971217
            cb >>= 3;
Packit 971217
            ckey = (cr << 11) | (cg << 5) | cb;
Packit 971217
            break;
Packit 971217
          case 24:
Packit 971217
          case 32:             /* RGB 888 / ARGB 8888 */
Packit 971217
            ckey = (cr << 16) | (cg << 8) | cb;
Packit 971217
            break;
Packit 971217
          default:
Packit 971217
            GST_DEBUG ("Unknown bit depth %d for Xv Colorkey - not adjusting",
Packit 971217
                context->depth);
Packit 971217
            set_attr = FALSE;
Packit 971217
            break;
Packit 971217
        }
Packit 971217
Packit 971217
        if (set_attr) {
Packit 971217
          ckey = CLAMP (ckey, (guint32) attr[i].min_value,
Packit 971217
              (guint32) attr[i].max_value);
Packit 971217
          GST_LOG ("Setting color key for display depth %d to 0x%x",
Packit 971217
              context->depth, ckey);
Packit 971217
Packit 971217
          XvSetPortAttribute (context->disp, context->xv_port_id, atom,
Packit 971217
              (gint) ckey);
Packit 971217
        }
Packit 971217
        todo--;
Packit 971217
        context->have_colorkey = TRUE;
Packit 971217
      } else if (!strcmp (attr[i].name, iturbt709)) {
Packit 971217
        todo--;
Packit 971217
        context->have_iturbt709 = TRUE;
Packit 971217
      }
Packit 971217
    }
Packit 971217
Packit 971217
    XFree (attr);
Packit 971217
  }
Packit 971217
Packit 971217
  /* Get the list of encodings supported by the adapter and look for the
Packit 971217
   * XV_IMAGE encoding so we can determine the maximum width and height
Packit 971217
   * supported */
Packit 971217
  XvQueryEncodings (context->disp, context->xv_port_id, &nb_encodings,
Packit 971217
      &encodings);
Packit 971217
Packit 971217
  for (i = 0; i < nb_encodings; i++) {
Packit 971217
    GST_LOG ("Encoding %d, name %s, max wxh %lux%lu rate %d/%d",
Packit 971217
        i, encodings[i].name, encodings[i].width, encodings[i].height,
Packit 971217
        encodings[i].rate.numerator, encodings[i].rate.denominator);
Packit 971217
    if (strcmp (encodings[i].name, "XV_IMAGE") == 0) {
Packit 971217
      max_w = encodings[i].width;
Packit 971217
      max_h = encodings[i].height;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  XvFreeEncodingInfo (encodings);
Packit 971217
Packit 971217
  /* We get all image formats supported by our port */
Packit 971217
  formats = XvListImageFormats (context->disp,
Packit 971217
      context->xv_port_id, &nb_formats);
Packit 971217
  caps = gst_caps_new_empty ();
Packit 971217
  for (i = 0; i < nb_formats; i++) {
Packit 971217
    GstCaps *format_caps = NULL;
Packit 971217
    gboolean is_rgb_format = FALSE;
Packit 971217
    GstVideoFormat vformat;
Packit 971217
Packit 971217
    /* We set the image format of the context to an existing one. This
Packit 971217
       is just some valid image format for making our xshm calls check before
Packit 971217
       caps negotiation really happens. */
Packit 971217
    context->im_format = formats[i].id;
Packit 971217
Packit 971217
    switch (formats[i].type) {
Packit 971217
      case XvRGB:
Packit 971217
      {
Packit 971217
        XvImageFormatValues *fmt = &(formats[i]);
Packit 971217
        gint endianness;
Packit 971217
Packit 971217
        endianness =
Packit 971217
            (fmt->byte_order == LSBFirst ? G_LITTLE_ENDIAN : G_BIG_ENDIAN);
Packit 971217
Packit 971217
        vformat = gst_video_format_from_masks (fmt->depth, fmt->bits_per_pixel,
Packit 971217
            endianness, fmt->red_mask, fmt->green_mask, fmt->blue_mask, 0);
Packit 971217
        if (vformat == GST_VIDEO_FORMAT_UNKNOWN)
Packit 971217
          break;
Packit 971217
Packit 971217
        format_caps = gst_caps_new_simple ("video/x-raw",
Packit 971217
            "format", G_TYPE_STRING, gst_video_format_to_string (vformat),
Packit 971217
            "width", GST_TYPE_INT_RANGE, 1, max_w,
Packit 971217
            "height", GST_TYPE_INT_RANGE, 1, max_h,
Packit 971217
            "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
Packit 971217
Packit 971217
        is_rgb_format = TRUE;
Packit 971217
        break;
Packit 971217
      }
Packit 971217
      case XvYUV:
Packit 971217
      {
Packit 971217
        vformat = gst_video_format_from_fourcc (formats[i].id);
Packit 971217
        if (vformat == GST_VIDEO_FORMAT_UNKNOWN)
Packit 971217
          break;
Packit 971217
Packit 971217
        format_caps = gst_caps_new_simple ("video/x-raw",
Packit 971217
            "format", G_TYPE_STRING, gst_video_format_to_string (vformat),
Packit 971217
            "width", GST_TYPE_INT_RANGE, 1, max_w,
Packit 971217
            "height", GST_TYPE_INT_RANGE, 1, max_h,
Packit 971217
            "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
Packit 971217
        break;
Packit 971217
      }
Packit 971217
      default:
Packit 971217
        vformat = GST_VIDEO_FORMAT_UNKNOWN;
Packit 971217
        g_assert_not_reached ();
Packit 971217
        break;
Packit 971217
    }
Packit 971217
Packit 971217
    if (format_caps) {
Packit 971217
      GstXvImageFormat *format = NULL;
Packit 971217
Packit 971217
      format = g_new0 (GstXvImageFormat, 1);
Packit 971217
      if (format) {
Packit 971217
        format->format = formats[i].id;
Packit 971217
        format->vformat = vformat;
Packit 971217
        format->caps = gst_caps_copy (format_caps);
Packit 971217
        context->formats_list = g_list_append (context->formats_list, format);
Packit 971217
      }
Packit 971217
Packit 971217
      if (is_rgb_format) {
Packit 971217
        if (rgb_caps == NULL)
Packit 971217
          rgb_caps = format_caps;
Packit 971217
        else
Packit 971217
          gst_caps_append (rgb_caps, format_caps);
Packit 971217
      } else
Packit 971217
        gst_caps_append (caps, format_caps);
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  /* Collected all caps into either the caps or rgb_caps structures.
Packit 971217
   * Append rgb_caps on the end of YUV, so that YUV is always preferred */
Packit 971217
  if (rgb_caps)
Packit 971217
    gst_caps_append (caps, rgb_caps);
Packit 971217
Packit 971217
  if (formats)
Packit 971217
    XFree (formats);
Packit 971217
Packit 971217
  GST_DEBUG ("Generated the following caps: %" GST_PTR_FORMAT, caps);
Packit 971217
Packit 971217
  if (gst_caps_is_empty (caps))
Packit 971217
    goto no_caps;
Packit 971217
Packit 971217
  return caps;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
no_xv:
Packit 971217
  {
Packit 971217
    g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_SETTINGS,
Packit 971217
        ("XVideo extension is not available"));
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
no_adaptors:
Packit 971217
  {
Packit 971217
    g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_SETTINGS,
Packit 971217
        ("Failed getting XV adaptors list"));
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
no_ports:
Packit 971217
  {
Packit 971217
    context->adaptor_nr = -1;
Packit 971217
    g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_BUSY,
Packit 971217
        ("No Xv Port available"));
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
no_caps:
Packit 971217
  {
Packit 971217
    gst_caps_unref (caps);
Packit 971217
    g_set_error (error, GST_STREAM_ERROR, GST_STREAM_ERROR_WRONG_TYPE,
Packit 971217
        ("No supported format found"));
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/* This function calculates the pixel aspect ratio based on the properties
Packit 971217
 * in the context structure and stores it there. */
Packit 971217
static void
Packit 971217
gst_xvcontext_calculate_pixel_aspect_ratio (GstXvContext * context)
Packit 971217
{
Packit 971217
  static const gint par[][2] = {
Packit 971217
    {1, 1},                     /* regular screen */
Packit 971217
    {16, 15},                   /* PAL TV */
Packit 971217
    {11, 10},                   /* 525 line Rec.601 video */
Packit 971217
    {54, 59},                   /* 625 line Rec.601 video */
Packit 971217
    {64, 45},                   /* 1280x1024 on 16:9 display */
Packit 971217
    {5, 3},                     /* 1280x1024 on 4:3 display */
Packit 971217
    {4, 3}                      /*  800x600 on 16:9 display */
Packit 971217
  };
Packit 971217
  gint i;
Packit 971217
  gint index;
Packit 971217
  gdouble ratio;
Packit 971217
  gdouble delta;
Packit 971217
Packit 971217
#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
Packit 971217
Packit 971217
  /* first calculate the "real" ratio based on the X values;
Packit 971217
   * which is the "physical" w/h divided by the w/h in pixels of the display */
Packit 971217
  ratio = (gdouble) (context->widthmm * context->height)
Packit 971217
      / (context->heightmm * context->width);
Packit 971217
Packit 971217
  /* DirectFB's X in 720x576 reports the physical dimensions wrong, so
Packit 971217
   * override here */
Packit 971217
  if (context->width == 720 && context->height == 576) {
Packit 971217
    ratio = 4.0 * 576 / (3.0 * 720);
Packit 971217
  }
Packit 971217
  GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
Packit 971217
Packit 971217
  /* now find the one from par[][2] with the lowest delta to the real one */
Packit 971217
  delta = DELTA (0);
Packit 971217
  index = 0;
Packit 971217
Packit 971217
  for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
Packit 971217
    gdouble this_delta = DELTA (i);
Packit 971217
Packit 971217
    if (this_delta < delta) {
Packit 971217
      index = i;
Packit 971217
      delta = this_delta;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  GST_DEBUG ("Decided on index %d (%d/%d)", index,
Packit 971217
      par[index][0], par[index][1]);
Packit 971217
Packit 971217
  g_free (context->par);
Packit 971217
  context->par = g_new0 (GValue, 1);
Packit 971217
  g_value_init (context->par, GST_TYPE_FRACTION);
Packit 971217
  gst_value_set_fraction (context->par, par[index][0], par[index][1]);
Packit 971217
  GST_DEBUG ("set context PAR to %d/%d",
Packit 971217
      gst_value_get_fraction_numerator (context->par),
Packit 971217
      gst_value_get_fraction_denominator (context->par));
Packit 971217
}
Packit 971217
Packit 971217
#ifdef HAVE_XSHM
Packit 971217
/* X11 stuff */
Packit 971217
static gboolean error_caught = FALSE;
Packit 971217
Packit 971217
static int
Packit 971217
gst_xvimage_handle_xerror (Display * display, XErrorEvent * xevent)
Packit 971217
{
Packit 971217
  char error_msg[1024];
Packit 971217
Packit 971217
  XGetErrorText (display, xevent->error_code, error_msg, 1024);
Packit 971217
  GST_DEBUG ("xvimage triggered an XError. error: %s", error_msg);
Packit 971217
  error_caught = TRUE;
Packit 971217
  return 0;
Packit 971217
}
Packit 971217
Packit 971217
/* This function checks that it is actually really possible to create an image
Packit 971217
   using XShm */
Packit 971217
static gboolean
Packit 971217
gst_xvcontext_check_xshm_calls (GstXvContext * context)
Packit 971217
{
Packit 971217
  XvImage *xvimage;
Packit 971217
  XShmSegmentInfo SHMInfo;
Packit 971217
  size_t size;
Packit 971217
  int (*handler) (Display *, XErrorEvent *);
Packit 971217
  gboolean result = FALSE;
Packit 971217
  gboolean did_attach = FALSE;
Packit 971217
Packit 971217
  g_return_val_if_fail (context != NULL, FALSE);
Packit 971217
Packit 971217
  /* Sync to ensure any older errors are already processed */
Packit 971217
  XSync (context->disp, FALSE);
Packit 971217
Packit 971217
  /* Set defaults so we don't free these later unnecessarily */
Packit 971217
  SHMInfo.shmaddr = ((void *) -1);
Packit 971217
  SHMInfo.shmid = -1;
Packit 971217
Packit 971217
  /* Setting an error handler to catch failure */
Packit 971217
  error_caught = FALSE;
Packit 971217
  handler = XSetErrorHandler (gst_xvimage_handle_xerror);
Packit 971217
Packit 971217
  /* Trying to create a 1x1 picture */
Packit 971217
  GST_DEBUG ("XvShmCreateImage of 1x1");
Packit 971217
  xvimage = XvShmCreateImage (context->disp, context->xv_port_id,
Packit 971217
      context->im_format, NULL, 1, 1, &SHMInfo);
Packit 971217
Packit 971217
  /* Might cause an error, sync to ensure it is noticed */
Packit 971217
  XSync (context->disp, FALSE);
Packit 971217
  if (!xvimage || error_caught) {
Packit 971217
    GST_WARNING ("could not XvShmCreateImage a 1x1 image");
Packit 971217
    goto beach;
Packit 971217
  }
Packit 971217
  size = xvimage->data_size;
Packit 971217
  SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
Packit 971217
  if (SHMInfo.shmid == -1) {
Packit 971217
    GST_WARNING ("could not get shared memory of %" G_GSIZE_FORMAT " bytes",
Packit 971217
        size);
Packit 971217
    goto beach;
Packit 971217
  }
Packit 971217
Packit 971217
  SHMInfo.shmaddr = shmat (SHMInfo.shmid, NULL, 0);
Packit 971217
  if (SHMInfo.shmaddr == ((void *) -1)) {
Packit 971217
    GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
Packit 971217
    /* Clean up the shared memory segment */
Packit 971217
    shmctl (SHMInfo.shmid, IPC_RMID, NULL);
Packit 971217
    goto beach;
Packit 971217
  }
Packit 971217
Packit 971217
  xvimage->data = SHMInfo.shmaddr;
Packit 971217
  SHMInfo.readOnly = FALSE;
Packit 971217
Packit 971217
  if (XShmAttach (context->disp, &SHMInfo) == 0) {
Packit 971217
    GST_WARNING ("Failed to XShmAttach");
Packit 971217
    /* Clean up the shared memory segment */
Packit 971217
    shmctl (SHMInfo.shmid, IPC_RMID, NULL);
Packit 971217
    goto beach;
Packit 971217
  }
Packit 971217
Packit 971217
  /* Sync to ensure we see any errors we caused */
Packit 971217
  XSync (context->disp, FALSE);
Packit 971217
Packit 971217
  /* Delete the shared memory segment as soon as everyone is attached.
Packit 971217
   * This way, it will be deleted as soon as we detach later, and not
Packit 971217
   * leaked if we crash. */
Packit 971217
  shmctl (SHMInfo.shmid, IPC_RMID, NULL);
Packit 971217
Packit 971217
  if (!error_caught) {
Packit 971217
    GST_DEBUG ("XServer ShmAttached to 0x%x, id 0x%lx", SHMInfo.shmid,
Packit 971217
        SHMInfo.shmseg);
Packit 971217
Packit 971217
    did_attach = TRUE;
Packit 971217
    /* store whether we succeeded in result */
Packit 971217
    result = TRUE;
Packit 971217
  } else {
Packit 971217
    GST_WARNING ("MIT-SHM extension check failed at XShmAttach. "
Packit 971217
        "Not using shared memory.");
Packit 971217
  }
Packit 971217
Packit 971217
beach:
Packit 971217
  /* Sync to ensure we swallow any errors we caused and reset error_caught */
Packit 971217
  XSync (context->disp, FALSE);
Packit 971217
Packit 971217
  error_caught = FALSE;
Packit 971217
  XSetErrorHandler (handler);
Packit 971217
Packit 971217
  if (did_attach) {
Packit 971217
    GST_DEBUG ("XServer ShmDetaching from 0x%x id 0x%lx",
Packit 971217
        SHMInfo.shmid, SHMInfo.shmseg);
Packit 971217
    XShmDetach (context->disp, &SHMInfo);
Packit 971217
    XSync (context->disp, FALSE);
Packit 971217
  }
Packit 971217
  if (SHMInfo.shmaddr != ((void *) -1))
Packit 971217
    shmdt (SHMInfo.shmaddr);
Packit 971217
  if (xvimage)
Packit 971217
    XFree (xvimage);
Packit 971217
  return result;
Packit 971217
}
Packit 971217
#endif /* HAVE_XSHM */
Packit 971217
Packit 971217
static GstXvContext *
Packit 971217
gst_xvcontext_copy (GstXvContext * context)
Packit 971217
{
Packit 971217
  return NULL;
Packit 971217
}
Packit 971217
Packit 971217
static void
Packit 971217
gst_xvcontext_free (GstXvContext * context)
Packit 971217
{
Packit 971217
  GList *formats_list, *channels_list;
Packit 971217
  gint i = 0;
Packit 971217
Packit 971217
  GST_LOG ("free %p", context);
Packit 971217
Packit 971217
  formats_list = context->formats_list;
Packit 971217
Packit 971217
  while (formats_list) {
Packit 971217
    GstXvImageFormat *format = formats_list->data;
Packit 971217
Packit 971217
    gst_caps_unref (format->caps);
Packit 971217
    g_free (format);
Packit 971217
    formats_list = g_list_next (formats_list);
Packit 971217
  }
Packit 971217
Packit 971217
  if (context->formats_list)
Packit 971217
    g_list_free (context->formats_list);
Packit 971217
Packit 971217
  channels_list = context->channels_list;
Packit 971217
Packit 971217
  while (channels_list) {
Packit 971217
    GstColorBalanceChannel *channel = channels_list->data;
Packit 971217
Packit 971217
    g_object_unref (channel);
Packit 971217
    channels_list = g_list_next (channels_list);
Packit 971217
  }
Packit 971217
Packit 971217
  if (context->channels_list)
Packit 971217
    g_list_free (context->channels_list);
Packit 971217
Packit 971217
  if (context->caps)
Packit 971217
    gst_caps_unref (context->caps);
Packit 971217
  if (context->last_caps)
Packit 971217
    gst_caps_unref (context->last_caps);
Packit 971217
Packit 971217
  for (i = 0; i < context->nb_adaptors; i++) {
Packit 971217
    g_free (context->adaptors[i]);
Packit 971217
  }
Packit 971217
Packit 971217
  g_free (context->adaptors);
Packit 971217
Packit 971217
  g_free (context->par);
Packit 971217
Packit 971217
  GST_DEBUG ("Closing display and freeing X Context");
Packit 971217
Packit 971217
  if (context->xv_port_id)
Packit 971217
    XvUngrabPort (context->disp, context->xv_port_id, 0);
Packit 971217
Packit 971217
  if (context->disp)
Packit 971217
    XCloseDisplay (context->disp);
Packit 971217
Packit 971217
  g_mutex_clear (&context->lock);
Packit 971217
Packit 971217
  g_slice_free1 (sizeof (GstXvContext), context);
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
/* This function gets the X Display and global info about it. Everything is
Packit 971217
   stored in our object and will be cleaned when the object is disposed. Note
Packit 971217
   here that caps for supported format are generated without any window or
Packit 971217
   image creation */
Packit 971217
GstXvContext *
Packit 971217
gst_xvcontext_new (GstXvContextConfig * config, GError ** error)
Packit 971217
{
Packit 971217
  GstXvContext *context = NULL;
Packit 971217
  XPixmapFormatValues *px_formats = NULL;
Packit 971217
  gint nb_formats = 0, i, j, N_attr;
Packit 971217
  XvAttribute *xv_attr;
Packit 971217
  Atom prop_atom;
Packit 971217
  const char *channels[4] = { "XV_HUE", "XV_SATURATION",
Packit 971217
    "XV_BRIGHTNESS", "XV_CONTRAST"
Packit 971217
  };
Packit 971217
Packit 971217
  g_return_val_if_fail (config != NULL, NULL);
Packit 971217
Packit 971217
  context = g_slice_new0 (GstXvContext);
Packit 971217
Packit 971217
  gst_mini_object_init (GST_MINI_OBJECT_CAST (context), 0,
Packit 971217
      gst_xvcontext_get_type (),
Packit 971217
      (GstMiniObjectCopyFunction) gst_xvcontext_copy,
Packit 971217
      (GstMiniObjectDisposeFunction) NULL,
Packit 971217
      (GstMiniObjectFreeFunction) gst_xvcontext_free);
Packit 971217
Packit 971217
  g_mutex_init (&context->lock);
Packit 971217
  context->im_format = 0;
Packit 971217
  context->adaptor_nr = -1;
Packit 971217
Packit 971217
  if (!(context->disp = XOpenDisplay (config->display_name)))
Packit 971217
    goto no_display;
Packit 971217
Packit 971217
  context->screen = DefaultScreenOfDisplay (context->disp);
Packit 971217
  context->screen_num = DefaultScreen (context->disp);
Packit 971217
  context->visual = DefaultVisual (context->disp, context->screen_num);
Packit 971217
  context->root = DefaultRootWindow (context->disp);
Packit 971217
  context->white = XWhitePixel (context->disp, context->screen_num);
Packit 971217
  context->black = XBlackPixel (context->disp, context->screen_num);
Packit 971217
  context->depth = DefaultDepthOfScreen (context->screen);
Packit 971217
Packit 971217
  context->width = DisplayWidth (context->disp, context->screen_num);
Packit 971217
  context->height = DisplayHeight (context->disp, context->screen_num);
Packit 971217
  context->widthmm = DisplayWidthMM (context->disp, context->screen_num);
Packit 971217
  context->heightmm = DisplayHeightMM (context->disp, context->screen_num);
Packit 971217
Packit 971217
  GST_DEBUG ("X reports %dx%d pixels and %d mm x %d mm",
Packit 971217
      context->width, context->height, context->widthmm, context->heightmm);
Packit 971217
Packit 971217
  gst_xvcontext_calculate_pixel_aspect_ratio (context);
Packit 971217
  /* We get supported pixmap formats at supported depth */
Packit 971217
  px_formats = XListPixmapFormats (context->disp, &nb_formats);
Packit 971217
Packit 971217
  if (!px_formats)
Packit 971217
    goto no_pixel_formats;
Packit 971217
Packit 971217
  /* We get bpp value corresponding to our running depth */
Packit 971217
  for (i = 0; i < nb_formats; i++) {
Packit 971217
    if (px_formats[i].depth == context->depth)
Packit 971217
      context->bpp = px_formats[i].bits_per_pixel;
Packit 971217
  }
Packit 971217
Packit 971217
  XFree (px_formats);
Packit 971217
Packit 971217
  context->endianness =
Packit 971217
      (ImageByteOrder (context->disp) ==
Packit 971217
      LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN;
Packit 971217
Packit 971217
  /* our caps system handles 24/32bpp RGB as big-endian. */
Packit 971217
  if ((context->bpp == 24 || context->bpp == 32) &&
Packit 971217
      context->endianness == G_LITTLE_ENDIAN) {
Packit 971217
    context->endianness = G_BIG_ENDIAN;
Packit 971217
    context->visual->red_mask = GUINT32_TO_BE (context->visual->red_mask);
Packit 971217
    context->visual->green_mask = GUINT32_TO_BE (context->visual->green_mask);
Packit 971217
    context->visual->blue_mask = GUINT32_TO_BE (context->visual->blue_mask);
Packit 971217
    if (context->bpp == 24) {
Packit 971217
      context->visual->red_mask >>= 8;
Packit 971217
      context->visual->green_mask >>= 8;
Packit 971217
      context->visual->blue_mask >>= 8;
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if (!(context->caps = gst_xvcontext_get_xv_support (context, config, error)))
Packit 971217
    goto no_caps;
Packit 971217
Packit 971217
  /* Search for XShm extension support */
Packit 971217
#ifdef HAVE_XSHM
Packit 971217
  if (XShmQueryExtension (context->disp) &&
Packit 971217
      gst_xvcontext_check_xshm_calls (context)) {
Packit 971217
    context->use_xshm = TRUE;
Packit 971217
    GST_DEBUG ("xvimagesink is using XShm extension");
Packit 971217
  } else
Packit 971217
#endif /* HAVE_XSHM */
Packit 971217
  {
Packit 971217
    context->use_xshm = FALSE;
Packit 971217
    GST_DEBUG ("xvimagesink is not using XShm extension");
Packit 971217
  }
Packit 971217
Packit 971217
  xv_attr = XvQueryPortAttributes (context->disp, context->xv_port_id, &N_attr);
Packit 971217
Packit 971217
  /* Generate the channels list */
Packit 971217
  for (i = 0; i < (sizeof (channels) / sizeof (char *)); i++) {
Packit 971217
    XvAttribute *matching_attr = NULL;
Packit 971217
Packit 971217
    /* Retrieve the property atom if it exists. If it doesn't exist,
Packit 971217
     * the attribute itself must not either, so we can skip */
Packit 971217
    prop_atom = XInternAtom (context->disp, channels[i], True);
Packit 971217
    if (prop_atom == None)
Packit 971217
      continue;
Packit 971217
Packit 971217
    if (xv_attr != NULL) {
Packit 971217
      for (j = 0; j < N_attr && matching_attr == NULL; ++j)
Packit 971217
        if (!g_ascii_strcasecmp (channels[i], xv_attr[j].name))
Packit 971217
          matching_attr = xv_attr + j;
Packit 971217
    }
Packit 971217
Packit 971217
    if (matching_attr) {
Packit 971217
      GstColorBalanceChannel *channel;
Packit 971217
Packit 971217
      channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
Packit 971217
      channel->label = g_strdup (channels[i]);
Packit 971217
      channel->min_value = matching_attr->min_value;
Packit 971217
      channel->max_value = matching_attr->max_value;
Packit 971217
Packit 971217
      context->channels_list = g_list_append (context->channels_list, channel);
Packit 971217
Packit 971217
      /* If the colorbalance settings have not been touched we get Xv values
Packit 971217
         as defaults and update our internal variables */
Packit 971217
      if (!config->cb_changed) {
Packit 971217
        gint val;
Packit 971217
Packit 971217
        XvGetPortAttribute (context->disp, context->xv_port_id,
Packit 971217
            prop_atom, &val;;
Packit 971217
        /* Normalize val to [-1000, 1000] */
Packit 971217
        val = floor (0.5 + -1000 + 2000 * (val - channel->min_value) /
Packit 971217
            (double) (channel->max_value - channel->min_value));
Packit 971217
Packit 971217
        if (!g_ascii_strcasecmp (channels[i], "XV_HUE"))
Packit 971217
          config->hue = val;
Packit 971217
        else if (!g_ascii_strcasecmp (channels[i], "XV_SATURATION"))
Packit 971217
          config->saturation = val;
Packit 971217
        else if (!g_ascii_strcasecmp (channels[i], "XV_BRIGHTNESS"))
Packit 971217
          config->brightness = val;
Packit 971217
        else if (!g_ascii_strcasecmp (channels[i], "XV_CONTRAST"))
Packit 971217
          config->contrast = val;
Packit 971217
      }
Packit 971217
    }
Packit 971217
  }
Packit 971217
Packit 971217
  if (xv_attr)
Packit 971217
    XFree (xv_attr);
Packit 971217
Packit 971217
  return context;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
no_display:
Packit 971217
  {
Packit 971217
    gst_xvcontext_unref (context);
Packit 971217
    g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_WRITE,
Packit 971217
        "Could not open display %s", config->display_name);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
no_pixel_formats:
Packit 971217
  {
Packit 971217
    gst_xvcontext_unref (context);
Packit 971217
    g_set_error (error, GST_RESOURCE_ERROR, GST_RESOURCE_ERROR_SETTINGS,
Packit 971217
        ("Could not get pixel formats"));
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
no_caps:
Packit 971217
  {
Packit 971217
    gst_xvcontext_unref (context);
Packit 971217
    return NULL;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_xvcontext_set_synchronous (GstXvContext * context, gboolean synchronous)
Packit 971217
{
Packit 971217
  /* call XSynchronize with the current value of synchronous */
Packit 971217
  GST_DEBUG ("XSynchronize called with %s", synchronous ? "TRUE" : "FALSE");
Packit 971217
  g_mutex_lock (&context->lock);
Packit 971217
  XSynchronize (context->disp, synchronous);
Packit 971217
  g_mutex_unlock (&context->lock);
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_xvcontext_update_colorbalance (GstXvContext * context,
Packit 971217
    GstXvContextConfig * config)
Packit 971217
{
Packit 971217
  GList *channels = NULL;
Packit 971217
Packit 971217
  /* Don't set the attributes if they haven't been changed, to avoid
Packit 971217
   * rounding errors changing the values */
Packit 971217
  if (!config->cb_changed)
Packit 971217
    return;
Packit 971217
Packit 971217
  /* For each channel of the colorbalance we calculate the correct value
Packit 971217
     doing range conversion and then set the Xv port attribute to match our
Packit 971217
     values. */
Packit 971217
  channels = context->channels_list;
Packit 971217
Packit 971217
  while (channels) {
Packit 971217
    if (channels->data && GST_IS_COLOR_BALANCE_CHANNEL (channels->data)) {
Packit 971217
      GstColorBalanceChannel *channel = NULL;
Packit 971217
      Atom prop_atom;
Packit 971217
      gint value = 0;
Packit 971217
      gdouble convert_coef;
Packit 971217
Packit 971217
      channel = GST_COLOR_BALANCE_CHANNEL (channels->data);
Packit 971217
      g_object_ref (channel);
Packit 971217
Packit 971217
      /* Our range conversion coef */
Packit 971217
      convert_coef = (channel->max_value - channel->min_value) / 2000.0;
Packit 971217
Packit 971217
      if (g_ascii_strcasecmp (channel->label, "XV_HUE") == 0) {
Packit 971217
        value = config->hue;
Packit 971217
      } else if (g_ascii_strcasecmp (channel->label, "XV_SATURATION") == 0) {
Packit 971217
        value = config->saturation;
Packit 971217
      } else if (g_ascii_strcasecmp (channel->label, "XV_CONTRAST") == 0) {
Packit 971217
        value = config->contrast;
Packit 971217
      } else if (g_ascii_strcasecmp (channel->label, "XV_BRIGHTNESS") == 0) {
Packit 971217
        value = config->brightness;
Packit 971217
      } else {
Packit 971217
        g_warning ("got an unknown channel %s", channel->label);
Packit 971217
        g_object_unref (channel);
Packit 971217
        return;
Packit 971217
      }
Packit 971217
Packit 971217
      /* Committing to Xv port */
Packit 971217
      g_mutex_lock (&context->lock);
Packit 971217
      prop_atom = XInternAtom (context->disp, channel->label, True);
Packit 971217
      if (prop_atom != None) {
Packit 971217
        int xv_value;
Packit 971217
        xv_value =
Packit 971217
            floor (0.5 + (value + 1000) * convert_coef + channel->min_value);
Packit 971217
        XvSetPortAttribute (context->disp,
Packit 971217
            context->xv_port_id, prop_atom, xv_value);
Packit 971217
      }
Packit 971217
      g_mutex_unlock (&context->lock);
Packit 971217
Packit 971217
      g_object_unref (channel);
Packit 971217
    }
Packit 971217
    channels = g_list_next (channels);
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/* This function tries to get a format matching with a given caps in the
Packit 971217
   supported list of formats we generated in gst_xvimagesink_get_xv_support */
Packit 971217
gint
Packit 971217
gst_xvcontext_get_format_from_info (GstXvContext * context, GstVideoInfo * info)
Packit 971217
{
Packit 971217
  GList *list = NULL;
Packit 971217
Packit 971217
  list = context->formats_list;
Packit 971217
Packit 971217
  while (list) {
Packit 971217
    GstXvImageFormat *format = list->data;
Packit 971217
Packit 971217
    if (format && format->vformat == GST_VIDEO_INFO_FORMAT (info))
Packit 971217
      return format->format;
Packit 971217
Packit 971217
    list = g_list_next (list);
Packit 971217
  }
Packit 971217
  return -1;
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_xvcontext_set_colorimetry (GstXvContext * context,
Packit 971217
    GstVideoColorimetry * colorimetry)
Packit 971217
{
Packit 971217
  Atom prop_atom;
Packit 971217
  int xv_value;
Packit 971217
Packit 971217
  if (!context->have_iturbt709)
Packit 971217
    return;
Packit 971217
Packit 971217
  switch (colorimetry->matrix) {
Packit 971217
    case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
Packit 971217
    case GST_VIDEO_COLOR_MATRIX_BT709:
Packit 971217
      xv_value = 1;
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      xv_value = 0;
Packit 971217
      break;
Packit 971217
  }
Packit 971217
Packit 971217
  g_mutex_lock (&context->lock);
Packit 971217
  prop_atom = XInternAtom (context->disp, "XV_ITURBT_709", True);
Packit 971217
  if (prop_atom != None) {
Packit 971217
    XvSetPortAttribute (context->disp,
Packit 971217
        context->xv_port_id, prop_atom, xv_value);
Packit 971217
  }
Packit 971217
  g_mutex_unlock (&context->lock);
Packit 971217
}
Packit 971217
Packit 971217
GstXWindow *
Packit 971217
gst_xvcontext_create_xwindow (GstXvContext * context, gint width, gint height)
Packit 971217
{
Packit 971217
  GstXWindow *window;
Packit 971217
  Atom wm_delete;
Packit 971217
  Atom hints_atom = None;
Packit 971217
Packit 971217
  g_return_val_if_fail (GST_IS_XVCONTEXT (context), NULL);
Packit 971217
Packit 971217
  window = g_slice_new0 (GstXWindow);
Packit 971217
Packit 971217
  window->context = gst_xvcontext_ref (context);
Packit 971217
  window->render_rect.x = window->render_rect.y = 0;
Packit 971217
  window->render_rect.w = width;
Packit 971217
  window->render_rect.h = height;
Packit 971217
  window->have_render_rect = FALSE;
Packit 971217
Packit 971217
  window->width = width;
Packit 971217
  window->height = height;
Packit 971217
  window->internal = TRUE;
Packit 971217
Packit 971217
  g_mutex_lock (&context->lock);
Packit 971217
Packit 971217
  window->win = XCreateSimpleWindow (context->disp,
Packit 971217
      context->root, 0, 0, width, height, 0, 0, context->black);
Packit 971217
Packit 971217
  /* We have to do that to prevent X from redrawing the background on
Packit 971217
   * ConfigureNotify. This takes away flickering of video when resizing. */
Packit 971217
  XSetWindowBackgroundPixmap (context->disp, window->win, None);
Packit 971217
Packit 971217
  /* Tell the window manager we'd like delete client messages instead of
Packit 971217
   * being killed */
Packit 971217
  wm_delete = XInternAtom (context->disp, "WM_DELETE_WINDOW", True);
Packit 971217
  if (wm_delete != None) {
Packit 971217
    (void) XSetWMProtocols (context->disp, window->win, &wm_delete, 1);
Packit 971217
  }
Packit 971217
Packit 971217
  hints_atom = XInternAtom (context->disp, "_MOTIF_WM_HINTS", True);
Packit 971217
  if (hints_atom != None) {
Packit 971217
    MotifWmHints *hints;
Packit 971217
Packit 971217
    hints = g_malloc0 (sizeof (MotifWmHints));
Packit 971217
Packit 971217
    hints->flags |= MWM_HINTS_DECORATIONS;
Packit 971217
    hints->decorations = 1 << 0;
Packit 971217
Packit 971217
    XChangeProperty (context->disp, window->win,
Packit 971217
        hints_atom, hints_atom, 32, PropModeReplace,
Packit 971217
        (guchar *) hints, sizeof (MotifWmHints) / sizeof (long));
Packit 971217
Packit 971217
    XSync (context->disp, FALSE);
Packit 971217
Packit 971217
    g_free (hints);
Packit 971217
  }
Packit 971217
Packit 971217
  window->gc = XCreateGC (context->disp, window->win, 0, NULL);
Packit 971217
Packit 971217
  XMapRaised (context->disp, window->win);
Packit 971217
Packit 971217
  XSync (context->disp, FALSE);
Packit 971217
Packit 971217
  g_mutex_unlock (&context->lock);
Packit 971217
Packit 971217
  return window;
Packit 971217
}
Packit 971217
Packit 971217
GstXWindow *
Packit 971217
gst_xvcontext_create_xwindow_from_xid (GstXvContext * context, XID xid)
Packit 971217
{
Packit 971217
  GstXWindow *window;
Packit 971217
  XWindowAttributes attr;
Packit 971217
Packit 971217
  window = g_slice_new0 (GstXWindow);
Packit 971217
  window->win = xid;
Packit 971217
  window->context = gst_xvcontext_ref (context);
Packit 971217
Packit 971217
  /* Set the event we want to receive and create a GC */
Packit 971217
  g_mutex_lock (&context->lock);
Packit 971217
Packit 971217
  XGetWindowAttributes (context->disp, window->win, &attr);
Packit 971217
Packit 971217
  window->width = attr.width;
Packit 971217
  window->height = attr.height;
Packit 971217
  window->internal = FALSE;
Packit 971217
Packit 971217
  window->have_render_rect = FALSE;
Packit 971217
  window->render_rect.x = window->render_rect.y = 0;
Packit 971217
  window->render_rect.w = attr.width;
Packit 971217
  window->render_rect.h = attr.height;
Packit 971217
Packit 971217
  window->gc = XCreateGC (context->disp, window->win, 0, NULL);
Packit 971217
  g_mutex_unlock (&context->lock);
Packit 971217
Packit 971217
  return window;
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_xwindow_destroy (GstXWindow * window)
Packit 971217
{
Packit 971217
  GstXvContext *context;
Packit 971217
Packit 971217
  g_return_if_fail (window != NULL);
Packit 971217
Packit 971217
  context = window->context;
Packit 971217
Packit 971217
  g_mutex_lock (&context->lock);
Packit 971217
Packit 971217
  /* If we did not create that window we just free the GC and let it live */
Packit 971217
  if (window->internal)
Packit 971217
    XDestroyWindow (context->disp, window->win);
Packit 971217
  else
Packit 971217
    XSelectInput (context->disp, window->win, 0);
Packit 971217
Packit 971217
  XFreeGC (context->disp, window->gc);
Packit 971217
Packit 971217
  XSync (context->disp, FALSE);
Packit 971217
Packit 971217
  g_mutex_unlock (&context->lock);
Packit 971217
Packit 971217
  gst_xvcontext_unref (context);
Packit 971217
Packit 971217
  g_slice_free1 (sizeof (GstXWindow), window);
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_xwindow_set_event_handling (GstXWindow * window, gboolean handle_events)
Packit 971217
{
Packit 971217
  GstXvContext *context;
Packit 971217
Packit 971217
  g_return_if_fail (window != NULL);
Packit 971217
Packit 971217
  context = window->context;
Packit 971217
Packit 971217
  g_mutex_lock (&context->lock);
Packit 971217
  if (handle_events) {
Packit 971217
    if (window->internal) {
Packit 971217
      XSelectInput (context->disp, window->win,
Packit 971217
          ExposureMask | StructureNotifyMask | PointerMotionMask |
Packit 971217
          KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask);
Packit 971217
    } else {
Packit 971217
      XSelectInput (context->disp, window->win,
Packit 971217
          ExposureMask | StructureNotifyMask | PointerMotionMask |
Packit 971217
          KeyPressMask | KeyReleaseMask);
Packit 971217
    }
Packit 971217
  } else {
Packit 971217
    XSelectInput (context->disp, window->win, 0);
Packit 971217
  }
Packit 971217
  g_mutex_unlock (&context->lock);
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_xwindow_set_title (GstXWindow * window, const gchar * title)
Packit 971217
{
Packit 971217
  GstXvContext *context;
Packit 971217
Packit 971217
  g_return_if_fail (window != NULL);
Packit 971217
Packit 971217
  context = window->context;
Packit 971217
Packit 971217
  /* we have a window */
Packit 971217
  if (window->internal && title) {
Packit 971217
    XTextProperty xproperty;
Packit 971217
    XClassHint *hint = XAllocClassHint ();
Packit 971217
Packit 971217
    if ((XStringListToTextProperty (((char **) &title), 1, &xproperty)) != 0) {
Packit 971217
      XSetWMName (context->disp, window->win, &xproperty);
Packit 971217
      XFree (xproperty.value);
Packit 971217
Packit 971217
      if (hint) {
Packit 971217
        hint->res_name = (char *) title;
Packit 971217
        hint->res_class = (char *) "GStreamer";
Packit 971217
        XSetClassHint (context->disp, window->win, hint);
Packit 971217
      }
Packit 971217
      XFree (hint);
Packit 971217
    }
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_xwindow_update_geometry (GstXWindow * window)
Packit 971217
{
Packit 971217
  XWindowAttributes attr;
Packit 971217
  GstXvContext *context;
Packit 971217
Packit 971217
  g_return_if_fail (window != NULL);
Packit 971217
Packit 971217
  context = window->context;
Packit 971217
Packit 971217
  /* Update the window geometry */
Packit 971217
  g_mutex_lock (&context->lock);
Packit 971217
  XGetWindowAttributes (context->disp, window->win, &attr);
Packit 971217
Packit 971217
  window->width = attr.width;
Packit 971217
  window->height = attr.height;
Packit 971217
Packit 971217
  if (!window->have_render_rect) {
Packit 971217
    window->render_rect.x = window->render_rect.y = 0;
Packit 971217
    window->render_rect.w = attr.width;
Packit 971217
    window->render_rect.h = attr.height;
Packit 971217
  }
Packit 971217
Packit 971217
  g_mutex_unlock (&context->lock);
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
void
Packit 971217
gst_xwindow_clear (GstXWindow * window)
Packit 971217
{
Packit 971217
  GstXvContext *context;
Packit 971217
Packit 971217
  g_return_if_fail (window != NULL);
Packit 971217
Packit 971217
  context = window->context;
Packit 971217
Packit 971217
  g_mutex_lock (&context->lock);
Packit 971217
Packit 971217
  XvStopVideo (context->disp, context->xv_port_id, window->win);
Packit 971217
Packit 971217
  XSync (context->disp, FALSE);
Packit 971217
Packit 971217
  g_mutex_unlock (&context->lock);
Packit 971217
}
Packit 971217
Packit 971217
void
Packit 971217
gst_xwindow_set_render_rectangle (GstXWindow * window,
Packit 971217
    gint x, gint y, gint width, gint height)
Packit 971217
{
Packit 971217
  g_return_if_fail (window != NULL);
Packit 971217
Packit 971217
  if (width >= 0 && height >= 0) {
Packit 971217
    window->render_rect.x = x;
Packit 971217
    window->render_rect.y = y;
Packit 971217
    window->render_rect.w = width;
Packit 971217
    window->render_rect.h = height;
Packit 971217
    window->have_render_rect = TRUE;
Packit 971217
  } else {
Packit 971217
    window->render_rect.x = 0;
Packit 971217
    window->render_rect.y = 0;
Packit 971217
    window->render_rect.w = window->width;
Packit 971217
    window->render_rect.h = window->height;
Packit 971217
    window->have_render_rect = FALSE;
Packit 971217
  }
Packit 971217
}