Port ximagesrc to 0.10 (Closes #304795)

Original commit message from CVS:
* configure.ac:
* sys/Makefile.am:
* sys/ximagesrc/Makefile.am:
* sys/ximagesrc/ximagesrc.c: (gst_ximagesrc_return_buf),
(gst_ximagesrc_open_display), (gst_ximagesrc_start),
(gst_ximagesrc_stop), (gst_ximagesrc_unlock),
(gst_ximagesrc_recalc), (composite_pixel),
(gst_ximagesrc_ximage_get), (gst_ximagesrc_create),
(gst_ximagesrc_set_property), (gst_ximagesrc_get_property),
(gst_ximagesrc_clear_bufpool), (gst_ximagesrc_base_init),
(gst_ximagesrc_dispose), (gst_ximagesrc_finalize),
(gst_ximagesrc_get_caps), (gst_ximagesrc_set_caps),
(gst_ximagesrc_fixate), (gst_ximagesrc_class_init),
(gst_ximagesrc_init), (plugin_init):
* sys/ximagesrc/ximagesrc.h:
* sys/ximagesrc/ximageutil.c: (ximageutil_handle_xerror),
(ximageutil_check_xshm_calls), (ximageutil_xcontext_get),
(ximageutil_xcontext_clear),
(ximageutil_calculate_pixel_aspect_ratio),
(gst_ximagesrc_buffer_finalize), (gst_ximage_buffer_free),
(gst_ximagesrc_buffer_init), (gst_ximagesrc_buffer_class_init),
(gst_ximagesrc_buffer_get_type), (gst_ximageutil_ximage_new),
(gst_ximageutil_ximage_destroy):
* sys/ximagesrc/ximageutil.h:

Port ximagesrc to 0.10 (Closes #304795)
This commit is contained in:
Jan Schmidt 2006-02-20 21:19:59 +00:00
parent 961d07acb1
commit 0c0067a1b0
8 changed files with 1613 additions and 17 deletions

View file

@ -1,3 +1,32 @@
2006-02-20 Jan Schmidt <thaytan@mad.scientist.com>
* configure.ac:
* sys/Makefile.am:
* sys/ximagesrc/Makefile.am:
* sys/ximagesrc/ximagesrc.c: (gst_ximagesrc_return_buf),
(gst_ximagesrc_open_display), (gst_ximagesrc_start),
(gst_ximagesrc_stop), (gst_ximagesrc_unlock),
(gst_ximagesrc_recalc), (composite_pixel),
(gst_ximagesrc_ximage_get), (gst_ximagesrc_create),
(gst_ximagesrc_set_property), (gst_ximagesrc_get_property),
(gst_ximagesrc_clear_bufpool), (gst_ximagesrc_base_init),
(gst_ximagesrc_dispose), (gst_ximagesrc_finalize),
(gst_ximagesrc_get_caps), (gst_ximagesrc_set_caps),
(gst_ximagesrc_fixate), (gst_ximagesrc_class_init),
(gst_ximagesrc_init), (plugin_init):
* sys/ximagesrc/ximagesrc.h:
* sys/ximagesrc/ximageutil.c: (ximageutil_handle_xerror),
(ximageutil_check_xshm_calls), (ximageutil_xcontext_get),
(ximageutil_xcontext_clear),
(ximageutil_calculate_pixel_aspect_ratio),
(gst_ximagesrc_buffer_finalize), (gst_ximage_buffer_free),
(gst_ximagesrc_buffer_init), (gst_ximagesrc_buffer_class_init),
(gst_ximagesrc_buffer_get_type), (gst_ximageutil_ximage_new),
(gst_ximageutil_ximage_destroy):
* sys/ximagesrc/ximageutil.h:
Port ximagesrc to 0.10 (Closes #304795)
2006-02-20 Edgard Lima <edgard.lima@indt.org.br>
* gst/freeze/gstfreeze.c:

View file

@ -384,24 +384,77 @@ return 0;
])
dnl Check for X11
dnl *** X11 ***
translit(dnm, m, l) AM_CONDITIONAL(USE_X, true)
GST_CHECK_FEATURE(X, [X libraries and plugins],
[ximagesrc], [
AC_PATH_XTRA
ac_cflags_save="$CFLAGS"
ac_cppflags_save="$CPPFLAGS"
CFLAGS="$CFLAGS $X_CFLAGS"
CPPFLAGS="$CPPFLAGS $X_CFLAGS"
dnl now try to find the HEADER
AC_CHECK_HEADER(X11/Xlib.h, HAVE_X="yes", HAVE_X="no")
dnl now try to find the HEADER
AC_CHECK_HEADER(X11/Xlib.h, HAVE_X="yes", HAVE_X="no")
AC_PATH_XTRA
if test "x$HAVE_X" = "xno"
then
AC_MSG_NOTICE([cannot find X11 development files])
else
dnl this is much more than we want
X_LIBS="$X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS"
dnl AC_PATH_XTRA only defines the path needed to find the X libs,
dnl it does not add the libs; therefore we add them here
X_LIBS="$X_LIBS -lX11"
AC_SUBST(X_CFLAGS)
AC_SUBST(X_LIBS)
if test "x$HAVE_X" = "xno"
then
AC_MSG_NOTICE([cannot find X11 development files])
else
dnl this is much more than we want
X_LIBS="$X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS"
dnl AC_PATH_XTRA only defines the path needed to find the X libs,
dnl it does not add the libs; therefore we add them here
X_LIBS="$X_LIBS -lX11"
AC_SUBST(X_CFLAGS)
AC_SUBST(X_LIBS)
fi
dnl check for Xfixes
PKG_CHECK_MODULES(XFIXES, xfixes, HAVE_XFIXES="yes", HAVE_XFIXES="no")
if test "x$HAVE_XFIXES" = "xyes"
then
XFIXES_CFLAGS="-DHAVE_XFIXES $XFIXES_CFLAGS"
fi
AC_SUBST(XFIXES_LIBS)
AC_SUBST(XFIXES_CFLAGS)
dnl check for Xdamage
PKG_CHECK_MODULES(XDAMAGE, xdamage, HAVE_XDAMAGE="yes", HAVE_XDAMAGE="no")
if test "x$HAVE_XDAMAGE" = "xyes"
then
XDAMAGE_CFLAGS="-DHAVE_XDAMAGE $XDAMAGE_CFLAGS"
fi
AC_SUBST(XDAMAGE_LIBS)
AC_SUBST(XDAMAGE_CFLAGS)
fi
AC_SUBST(HAVE_X)
CFLAGS="$ac_cflags_save"
CPPFLAGS="$ac_cppflags_save"
])
dnl check for X Shm
translit(dnm, m, l) AM_CONDITIONAL(USE_XSHM, true)
GST_CHECK_FEATURE(XSHM, [X Shared Memory extension], [ximagesrc w/ xshm], [
if test x$HAVE_X = xyes; then
AC_CHECK_LIB(Xext, XShmAttach,
HAVE_XSHM="yes", HAVE_XSHM="no",
$X_LIBS)
if test "x$HAVE_XSHM" = "xyes"; then
XSHM_LIBS="-lXext"
else
dnl On AIX, it is in XextSam instead, but we still need -lXext
AC_CHECK_LIB(XextSam, XShmAttach,
HAVE_XSHM="yes", HAVE_XSHM="no",
$X_LIBS)
if test "x$HAVE_XSHM" = "xyes"; then
XSHM_LIBS="-lXext -lXextSam"
fi
fi
fi
], , [
AC_SUBST(HAVE_XSHM)
AC_SUBST(XSHM_LIBS)
] )
dnl *** BZ2 ***
translit(bz2, m, l) AM_CONDITIONAL(USE_BZ2, true)
@ -661,6 +714,7 @@ gst/qtdemux/Makefile
gst/tta/Makefile
sys/Makefile
sys/glsink/Makefile
sys/ximagesrc/Makefile
examples/Makefile
examples/directfb/Makefile
ext/Makefile

View file

@ -34,6 +34,12 @@ else
GL_DIR=
endif
SUBDIRS = $(GL_DIR)
if USE_X
XIMAGESRC_DIR=ximagesrc
else
XIMAGESRC_DIR=
endif
DIST_SUBDIRS = glsink
SUBDIRS = $(GL_DIR) $(XIMAGESRC_DIR)
DIST_SUBDIRS = glsink ximagesrc

11
sys/ximagesrc/Makefile.am Normal file
View file

@ -0,0 +1,11 @@
plugin_LTLIBRARIES = libgstximagesrc.la
libgstximagesrc_la_SOURCES = ximagesrc.c ximageutil.c
libgstximagesrc_la_CFLAGS = $(GST_CFLAGS) $(X_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS) $(XFIXES_CFLAGS) $(XDAMAGE_CFLAGS)
libgstximagesrc_la_LIBADD = $(X_LIBS) $(XSHM_LIBS) \
$(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) $(XFIXES_LIBS) $(XDAMAGE_LIBS)
libgstximagesrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = ximagesrc.h ximageutil.h

743
sys/ximagesrc/ximagesrc.c Normal file
View file

@ -0,0 +1,743 @@
/* GStreamer
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ximagesrc.h"
#include <string.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
GST_DEBUG_CATEGORY_STATIC (gst_debug_ximagesrc);
#define GST_CAT_DEFAULT gst_debug_ximagesrc
/* elementfactory information */
static GstElementDetails ximagesrc_details =
GST_ELEMENT_DETAILS ("Ximage video source",
"Source/Video",
"Creates a screenshot video stream",
"Lutz Mueller <lutz@users.sourceforge.net>"
"Jan Schmidt <thaytan@mad.scientist.com>");
static GstStaticPadTemplate t =
GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb, "
"framerate = (fraction) [ 0, MAX ], "
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]"));
enum
{
PROP_0,
PROP_DISPLAY_NAME,
PROP_SCREEN_NUM
};
GST_BOILERPLATE (GstXImageSrc, gst_ximagesrc, GstPushSrc, GST_TYPE_PUSH_SRC);
static void gst_ximagesrc_fixate (GstPad * pad, GstCaps * caps);
static void gst_ximagesrc_clear_bufpool (GstXImageSrc * ximagesrc);
/* Called when a buffer is returned from the pipeline */
static void
gst_ximagesrc_return_buf (GstXImageSrc * ximagesrc, GstXImageSrcBuffer * ximage)
{
/* If our geometry changed we can't reuse that image. */
if ((ximage->width != ximagesrc->width) ||
(ximage->height != ximagesrc->height)) {
GST_DEBUG_OBJECT (ximagesrc,
"destroy image %p as its size changed %dx%d vs current %dx%d",
ximage, ximage->width, ximage->height,
ximagesrc->width, ximagesrc->height);
g_mutex_lock (ximagesrc->x_lock);
gst_ximageutil_ximage_destroy (ximagesrc->xcontext, ximage);
g_mutex_unlock (ximagesrc->x_lock);
} else {
/* In that case we can reuse the image and add it to our image pool. */
GST_LOG_OBJECT (ximagesrc, "recycling image %p in pool", ximage);
/* need to increment the refcount again to recycle */
gst_buffer_ref (GST_BUFFER (ximage));
g_mutex_lock (ximagesrc->pool_lock);
ximagesrc->buffer_pool = g_slist_prepend (ximagesrc->buffer_pool, ximage);
g_mutex_unlock (ximagesrc->pool_lock);
}
}
static gboolean
gst_ximagesrc_open_display (GstXImageSrc * s, const gchar * name)
{
g_return_val_if_fail (GST_IS_XIMAGESRC (s), FALSE);
if (s->xcontext != NULL)
return TRUE;
g_mutex_lock (s->x_lock);
s->xcontext = ximageutil_xcontext_get (GST_ELEMENT (s), name);
s->width = s->xcontext->width;
s->height = s->xcontext->height;
/* Always capture root window, for now */
s->xwindow = s->xcontext->root;
#ifdef HAVE_XFIXES
/* check if xfixes supported */
{
int error_base;
if (XFixesQueryExtension (s->xcontext->disp, &s->fixes_event_base,
&error_base)) {
s->have_xfixes = TRUE;
GST_DEBUG_OBJECT (s, "X Server supports XFixes");
} else {
GST_DEBUG_OBJECT (s, "X Server does not support XFixes");
}
}
#ifdef HAVE_XDAMAGE
/* check if xdamage is supported */
{
int error_base;
long evmask = NoEventMask;
if (XDamageQueryExtension (s->xcontext->disp, &s->damage_event_base,
&error_base)) {
s->damage =
XDamageCreate (s->xcontext->disp, s->xwindow,
XDamageReportRawRectangles);
if (s->damage != None) {
s->damage_region = XFixesCreateRegion (s->xcontext->disp, NULL, 0);
if (s->damage_region != None) {
XGCValues values;
GST_DEBUG_OBJECT (s, "Using XDamage extension");
values.subwindow_mode = IncludeInferiors;
s->damage_copy_gc = XCreateGC (s->xcontext->disp,
s->xwindow, GCSubwindowMode, &values);
XSelectInput (s->xcontext->disp, s->xwindow, evmask);
s->have_xdamage = TRUE;
} else {
XDamageDestroy (s->xcontext->disp, s->damage);
s->damage = None;
}
} else
GST_DEBUG_OBJECT (s, "Could not attach to XDamage");
} else {
GST_DEBUG_OBJECT (s, "X Server does not have XDamage extension");
}
}
#endif
#endif
g_mutex_unlock (s->x_lock);
if (s->xcontext == NULL)
return FALSE;
return TRUE;
}
static gboolean
gst_ximagesrc_start (GstBaseSrc * basesrc)
{
GstXImageSrc *s = GST_XIMAGESRC (basesrc);
s->last_frame_no = -1;
return gst_ximagesrc_open_display (s, NULL);
}
static gboolean
gst_ximagesrc_stop (GstBaseSrc * basesrc)
{
GstXImageSrc *src = GST_XIMAGESRC (basesrc);
gst_ximagesrc_clear_bufpool (src);
if (src->xcontext) {
g_mutex_lock (src->x_lock);
ximageutil_xcontext_clear (src->xcontext);
src->xcontext = NULL;
g_mutex_unlock (src->x_lock);
}
return TRUE;
}
static gboolean
gst_ximagesrc_unlock (GstBaseSrc * basesrc)
{
GstXImageSrc *src = GST_XIMAGESRC (basesrc);
/* Awaken the create() func if it's waiting on the clock */
GST_OBJECT_LOCK (src);
if (src->clock_id) {
GST_DEBUG_OBJECT (src, "Waking up waiting clock");
gst_clock_id_unschedule (src->clock_id);
}
GST_OBJECT_UNLOCK (src);
return TRUE;
}
static gboolean
gst_ximagesrc_recalc (GstXImageSrc * src)
{
if (!src->xcontext)
return FALSE;
/* FIXME: Check the display hasn't changed size or something */
/* We could use XQueryPointer to get only the current window. */
return TRUE;
}
/* ifdeff'ed to prevent warnings of not being used when xfixes not there */
#ifdef HAVE_XFIXES
static void
composite_pixel (GstXContext * xcontext, guchar * dest, guchar * src)
{
guint8 r = src[2];
guint8 g = src[1];
guint8 b = src[0];
guint8 a = src[3];
gint dr, dg, db;
guint32 color;
gint r_shift, r_max;
gint g_shift, g_max;
gint b_shift, b_max;
switch (xcontext->bpp) {
case 8:
color = *dest;
break;
case 16:
color = GUINT16_FROM_LE (*(guint32 *) (dest));
break;
case 32:
color = GUINT32_FROM_LE (*(guint32 *) (dest));
break;
default:
g_warning ("bpp %d not supported\n", xcontext->bpp);
color = 0;
}
/* FIXME: move the code that finds shift and max in the _link function */
for (r_shift = 0; !(xcontext->visual->red_mask & (1 << r_shift)); r_shift++);
for (g_shift = 0; !(xcontext->visual->green_mask & (1 << g_shift));
g_shift++);
for (b_shift = 0; !(xcontext->visual->blue_mask & (1 << b_shift)); b_shift++);
r_max = (xcontext->visual->red_mask >> r_shift);
b_max = (xcontext->visual->blue_mask >> b_shift);
g_max = (xcontext->visual->green_mask >> g_shift);
#define RGBXXX_R(x) (((x)>>r_shift) & (r_max))
#define RGBXXX_G(x) (((x)>>g_shift) & (g_max))
#define RGBXXX_B(x) (((x)>>b_shift) & (b_max))
dr = (RGBXXX_R (color) * 255) / r_max;
dg = (RGBXXX_G (color) * 255) / g_max;
db = (RGBXXX_B (color) * 255) / b_max;
dr = (r * a + (0xff - a) * dr) / 0xff;
dg = (g * a + (0xff - a) * dg) / 0xff;
db = (b * a + (0xff - a) * db) / 0xff;
color = (((dr * r_max) / 255) << r_shift) +
(((dg * g_max) / 255) << g_shift) + (((db * b_max) / 255) << b_shift);
switch (xcontext->bpp) {
case 8:
*dest = color;
break;
case 16:
*(guint16 *) (dest) = color;
break;
case 32:
*(guint32 *) (dest) = color;
break;
default:
g_warning ("bpp %d not supported\n", xcontext->bpp);
}
}
#endif
/* Retrieve an XImageSrcBuffer, preferably from our
* pool of existing images and populate it from the window */
static GstXImageSrcBuffer *
gst_ximagesrc_ximage_get (GstXImageSrc * ximagesrc)
{
GstXImageSrcBuffer *ximage = NULL;
g_mutex_lock (ximagesrc->pool_lock);
while (ximagesrc->buffer_pool != NULL) {
ximage = ximagesrc->buffer_pool->data;
if ((ximage->width != ximagesrc->width) ||
(ximage->height != ximagesrc->height)) {
gst_ximage_buffer_free (ximage);
}
ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool,
ximagesrc->buffer_pool);
}
g_mutex_unlock (ximagesrc->pool_lock);
if (ximage == NULL) {
GstXContext *xcontext;
GST_DEBUG_OBJECT (ximagesrc, "creating image (%dx%d)",
ximagesrc->width, ximagesrc->height);
g_mutex_lock (ximagesrc->x_lock);
ximage = gst_ximageutil_ximage_new (ximagesrc->xcontext,
GST_ELEMENT (ximagesrc), ximagesrc->width, ximagesrc->height,
(BufferReturnFunc) (gst_ximagesrc_return_buf));
if (ximage == NULL) {
GST_ELEMENT_ERROR (ximagesrc, RESOURCE, WRITE, (NULL),
("could not create a %dx%d ximage", ximage->width, ximage->height));
g_mutex_unlock (ximagesrc->x_lock);
return NULL;
}
xcontext = ximagesrc->xcontext;
/* FIXME: Include the PAR */
gst_buffer_set_caps (GST_BUFFER (ximage),
gst_caps_new_simple ("video/x-raw-rgb",
"bpp", G_TYPE_INT, xcontext->bpp,
"depth", G_TYPE_INT, xcontext->depth,
"endianness", G_TYPE_INT, xcontext->endianness,
"red_mask", G_TYPE_INT, xcontext->visual->red_mask,
"green_mask", G_TYPE_INT, xcontext->visual->green_mask,
"blue_mask", G_TYPE_INT, xcontext->visual->blue_mask,
"width", G_TYPE_INT, xcontext->width,
"height", G_TYPE_INT, xcontext->height,
"framerate", GST_TYPE_FRACTION, ximagesrc->fps_n, ximagesrc->fps_d,
NULL));
g_mutex_unlock (ximagesrc->x_lock);
}
g_return_val_if_fail (GST_IS_XIMAGESRC (ximagesrc), NULL);
#ifdef HAVE_XDAMAGE
if (ximagesrc->have_xdamage) {
XEvent ev;
GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XDamage");
do {
XNextEvent (ximagesrc->xcontext->disp, &ev);
if (ev.type == ximagesrc->damage_event_base + XDamageNotify) {
XDamageNotifyEvent *dev = (XDamageNotifyEvent *) & ev;
#ifdef HAVE_XSHM
if (ximagesrc->xcontext->use_xshm &&
dev->area.width == ximagesrc->width &&
dev->area.height == ximagesrc->height) {
GST_DEBUG_OBJECT (ximagesrc, "Entire screen was damaged");
XShmGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
ximage->ximage, 0, 0, AllPlanes);
/* No need to collect more events */
while (XPending (ximagesrc->xcontext->disp)) {
XNextEvent (ximagesrc->xcontext->disp, &ev);
}
break;
} else
#endif
{
GST_LOG_OBJECT (ximagesrc,
"Retrieving damaged sub-region @ %d,%d size %dx%d",
dev->area.x, dev->area.y, dev->area.width, dev->area.height);
XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
dev->area.x, dev->area.y,
dev->area.width, dev->area.height,
AllPlanes, ZPixmap, ximage->ximage, dev->area.x, dev->area.y);
}
}
} while (XPending (ximagesrc->xcontext->disp));
XDamageSubtract (ximagesrc->xcontext->disp, ximagesrc->damage, None, None);
} else {
#endif
#ifdef HAVE_XSHM
if (ximagesrc->xcontext->use_xshm) {
GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XShm");
XShmGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
ximage->ximage, 0, 0, AllPlanes);
} else
#endif /* HAVE_XSHM */
{
GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XGetImage");
ximage->ximage = XGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
0, 0, ximagesrc->width, ximagesrc->height, AllPlanes, ZPixmap);
}
#ifdef HAVE_XDAMAGE
}
#endif
#ifdef HAVE_XFIXES
if (ximagesrc->show_pointer && ximagesrc->have_xfixes) {
XFixesCursorImage *cursor_image;
GST_DEBUG_OBJECT (ximagesrc, "Using XFixes to draw cursor");
/* get cursor */
cursor_image = XFixesGetCursorImage (ximagesrc->xcontext->disp);
if (cursor_image != NULL) {
int cx, cy, i, j, count;
cx = cursor_image->x - cursor_image->xhot;
cy = cursor_image->y - cursor_image->yhot;
//count = image->width * image->height;
count = cursor_image->width * cursor_image->height;
for (i = 0; i < count; i++)
cursor_image->pixels[i] = GUINT_TO_LE (cursor_image->pixels[i]);
/* copy those pixels across */
for (j = cy; j < cy + cursor_image->height && j < ximagesrc->height; j++) {
for (i = cx; i < cx + cursor_image->width && i < ximagesrc->width; i++) {
guint8 *src, *dest;
src =
(guint8 *) & (cursor_image->pixels[((j -
cy) * cursor_image->width + (i - cx))]);
dest =
(guint8 *) & (ximage->ximage->data[(j * ximagesrc->width +
i) * (ximagesrc->xcontext->bpp / 8)]);
composite_pixel (ximagesrc->xcontext, (guint8 *) dest,
(guint8 *) src);
}
}
}
}
#endif
return ximage;
}
static GstFlowReturn
gst_ximagesrc_create (GstPushSrc * bs, GstBuffer ** buf)
{
GstXImageSrc *s = GST_XIMAGESRC (bs);
GstXImageSrcBuffer *image;
GstClockTime base_time;
GstClockTime next_capture_ts;
GstClockTime dur;
gint64 next_frame_no;
if (!gst_ximagesrc_recalc (s)) {
/* FIXME: Post error on the bus */
return GST_FLOW_ERROR;
}
if (s->fps_n <= 0 || s->fps_d <= 0)
return GST_FLOW_NOT_NEGOTIATED; /* FPS must be > 0 */
/* Now, we might need to wait for the next multiple of the fps
* before capturing */
GST_OBJECT_LOCK (s);
base_time = GST_ELEMENT_CAST (s)->base_time;
next_capture_ts = gst_clock_get_time (GST_ELEMENT_CLOCK (s));
next_capture_ts -= base_time;
/* Figure out which 'frame number' position we're at, based on the cur time
* and frame rate */
next_frame_no = gst_util_uint64_scale (next_capture_ts,
s->fps_n, GST_SECOND * s->fps_d);
if (next_frame_no == s->last_frame_no) {
GstClockID id;
GstClockReturn ret;
/* Need to wait for the next frame */
next_frame_no += 1;
/* Figure out what the next frame time is */
next_capture_ts = gst_util_uint64_scale (next_frame_no,
s->fps_d * GST_SECOND, s->fps_n);
id = gst_clock_new_single_shot_id (GST_ELEMENT_CLOCK (s),
next_capture_ts + base_time);
s->clock_id = id;
/* release the object lock while waiting */
GST_OBJECT_UNLOCK (s);
GST_DEBUG_OBJECT (s, "Waiting for next frame time %" G_GUINT64_FORMAT,
next_capture_ts);
ret = gst_clock_id_wait (id, NULL);
GST_OBJECT_LOCK (s);
gst_clock_id_unref (id);
s->clock_id = NULL;
if (ret == GST_CLOCK_UNSCHEDULED) {
/* Got woken up by the unlock function */
GST_OBJECT_UNLOCK (s);
return GST_FLOW_WRONG_STATE;
}
/* Duration is a complete 1/fps frame duration */
dur = gst_util_uint64_scale_int (GST_SECOND, s->fps_d, s->fps_n);
} else {
GstClockTime next_frame_ts;
GST_DEBUG_OBJECT (s, "No need to wait for next frame time %"
G_GUINT64_FORMAT " next frame = %" G_GINT64_FORMAT " prev = %"
G_GINT64_FORMAT, next_capture_ts, next_frame_no, s->last_frame_no);
next_frame_ts = gst_util_uint64_scale (next_frame_no + 1,
s->fps_d * GST_SECOND, s->fps_n);
/* Frame duration is from now until the next expected capture time */
dur = next_frame_ts - next_capture_ts;
}
s->last_frame_no = next_frame_no;
GST_OBJECT_UNLOCK (s);
image = gst_ximagesrc_ximage_get (s);
if (!image)
return GST_FLOW_ERROR;
*buf = GST_BUFFER (image);
GST_BUFFER_TIMESTAMP (*buf) = next_capture_ts;
GST_BUFFER_DURATION (*buf) = dur;
return GST_FLOW_OK;
}
static void
gst_ximagesrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstXImageSrc *src = GST_XIMAGESRC (object);
switch (prop_id) {
case PROP_DISPLAY_NAME:
g_free (src->display_name);
src->display_name = g_strdup (g_value_get_string (value));
// src->screen_num = MIN (src->screen_num, ScreenCount (src->display) - 1);
break;
case PROP_SCREEN_NUM:
src->screen_num = g_value_get_uint (value);
// src->screen_num = MIN (src->screen_num, ScreenCount (src->display) - 1);
break;
default:
break;
}
}
static void
gst_ximagesrc_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstXImageSrc *src = GST_XIMAGESRC (object);
switch (prop_id) {
case PROP_DISPLAY_NAME:
if (src->xcontext)
g_value_set_string (value, DisplayString (src->xcontext->disp));
else
g_value_set_string (value, src->display_name);
break;
case PROP_SCREEN_NUM:
g_value_set_uint (value, src->screen_num);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_ximagesrc_clear_bufpool (GstXImageSrc * ximagesrc)
{
g_mutex_lock (ximagesrc->pool_lock);
while (ximagesrc->buffer_pool != NULL) {
GstXImageSrcBuffer *ximage = ximagesrc->buffer_pool->data;
gst_ximage_buffer_free (ximage);
ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool,
ximagesrc->buffer_pool);
}
g_mutex_unlock (ximagesrc->pool_lock);
}
static void
gst_ximagesrc_base_init (gpointer g_class)
{
GstElementClass *ec = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (ec, &ximagesrc_details);
gst_element_class_add_pad_template (ec, gst_static_pad_template_get (&t));
}
static void
gst_ximagesrc_dispose (GObject * object)
{
/* Drop references in the buffer_pool */
gst_ximagesrc_clear_bufpool (GST_XIMAGESRC (object));
}
static void
gst_ximagesrc_finalize (GObject * object)
{
GstXImageSrc *src = GST_XIMAGESRC (object);
if (src->xcontext)
ximageutil_xcontext_clear (src->xcontext);
g_mutex_free (src->pool_lock);
g_mutex_free (src->x_lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstCaps *
gst_ximagesrc_get_caps (GstBaseSrc * bs)
{
GstXImageSrc *s = GST_XIMAGESRC (bs);
GstXContext *xcontext;
if ((!s->xcontext) && (!gst_ximagesrc_open_display (s, NULL)))
return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC (s)->
srcpad));
if (!gst_ximagesrc_recalc (s))
return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC (s)->
srcpad));
xcontext = s->xcontext;
/* FIXME: Add PAR */
return gst_caps_new_simple ("video/x-raw-rgb",
"bpp", G_TYPE_INT, xcontext->bpp,
"depth", G_TYPE_INT, xcontext->depth,
"endianness", G_TYPE_INT, xcontext->endianness,
"red_mask", G_TYPE_INT, xcontext->visual->red_mask,
"green_mask", G_TYPE_INT, xcontext->visual->green_mask,
"blue_mask", G_TYPE_INT, xcontext->visual->blue_mask,
"width", G_TYPE_INT, xcontext->width,
"height", G_TYPE_INT, xcontext->height,
"framerate", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1, NULL);
}
static gboolean
gst_ximagesrc_set_caps (GstBaseSrc * bs, GstCaps * caps)
{
GstXImageSrc *s = GST_XIMAGESRC (bs);
GstStructure *structure;
const GValue *new_fps;
/* If not yet opened, disallow setcaps until later */
if (!s->xcontext)
return FALSE;
/* The only thing that can change is the framerate downstream wants */
structure = gst_caps_get_structure (caps, 0);
new_fps = gst_structure_get_value (structure, "framerate");
if (!new_fps)
return FALSE;
/* Store this FPS for use when generating buffers */
s->fps_n = gst_value_get_fraction_numerator (new_fps);
s->fps_d = gst_value_get_fraction_denominator (new_fps);
GST_DEBUG_OBJECT (s, "peer wants %d/%d fps", s->fps_n, s->fps_d);
return TRUE;
}
static void
gst_ximagesrc_fixate (GstPad * pad, GstCaps * caps)
{
gint i;
GstStructure *structure;
for (i = 0; i < gst_caps_get_size (caps); ++i) {
structure = gst_caps_get_structure (caps, i);
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 25, 1);
}
}
static void
gst_ximagesrc_class_init (GstXImageSrcClass * klass)
{
GObjectClass *gc = G_OBJECT_CLASS (klass);
GstBaseSrcClass *bc = GST_BASE_SRC_CLASS (klass);
GstPushSrcClass *push_class = GST_PUSH_SRC_CLASS (klass);
gc->set_property = gst_ximagesrc_set_property;
gc->get_property = gst_ximagesrc_get_property;
gc->dispose = gst_ximagesrc_dispose;
gc->finalize = gst_ximagesrc_finalize;
g_object_class_install_property (gc, PROP_DISPLAY_NAME,
g_param_spec_string ("display_name", "Display", "X Display name", NULL,
G_PARAM_READWRITE));
g_object_class_install_property (gc, PROP_SCREEN_NUM,
g_param_spec_uint ("screen_num", "Screen number", "X Screen number",
0, G_MAXINT, 0, G_PARAM_READWRITE));
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
push_class->create = gst_ximagesrc_create;
bc->get_caps = gst_ximagesrc_get_caps;
bc->set_caps = gst_ximagesrc_set_caps;
bc->start = gst_ximagesrc_start;
bc->stop = gst_ximagesrc_stop;
bc->unlock = gst_ximagesrc_unlock;
}
static void
gst_ximagesrc_init (GstXImageSrc * ximagesrc, GstXImageSrcClass * klass)
{
gst_base_src_set_live (GST_BASE_SRC (ximagesrc), TRUE);
gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (ximagesrc),
gst_ximagesrc_fixate);
ximagesrc->pool_lock = g_mutex_new ();
ximagesrc->x_lock = g_mutex_new ();
}
static gboolean
plugin_init (GstPlugin * plugin)
{
gboolean ret;
GST_DEBUG_CATEGORY_INIT (gst_debug_ximagesrc, "ximagesrc", 0,
"ximagesrc element debug");
ret = gst_element_register (plugin, "ximagesrc", GST_RANK_NONE,
GST_TYPE_XIMAGESRC);
return ret;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"ximagesrc",
"XFree86 video input plugin based on standard Xlib calls",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)

97
sys/ximagesrc/ximagesrc.h Normal file
View file

@ -0,0 +1,97 @@
/* screenshotsrc: Screenshot plugin for GStreamer
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_XIMAGESRC_H__
#define __GST_XIMAGESRC_H__
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
#include "ximageutil.h"
#ifdef HAVE_XFIXES
#include <X11/extensions/Xfixes.h>
#endif
#ifdef HAVE_XDAMAGE
#include <X11/extensions/Xdamage.h>
#endif
G_BEGIN_DECLS
#define GST_TYPE_XIMAGESRC (gst_ximagesrc_get_type())
#define GST_XIMAGESRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XIMAGESRC,GstXImageSrc))
#define GST_XIMAGESRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XIMAGESRC,GstXImageSrc))
#define GST_IS_XIMAGESRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XIMAGESRC))
#define GST_IS_XIMAGESRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XIMAGESRC))
typedef struct _GstXImageSrc GstXImageSrc;
typedef struct _GstXImageSrcClass GstXImageSrcClass;
GType gst_ximagesrc_get_type (void) G_GNUC_CONST;
struct _GstXImageSrc
{
GstPushSrc parent;
/* Information on display */
GstXContext *xcontext;
gint width;
gint height;
Window xwindow;
gchar *display_name;
guint screen_num;
/* Desired output framerate */
gint fps_n;
gint fps_d;
/* for framerate sync */
GstClockID clock_id;
gint64 last_frame_no;
/* Protect X Windows calls */
GMutex *x_lock;
/* Gathered pool of emitted buffers */
GMutex *pool_lock;
GSList *buffer_pool;
/* XFixes and XDamage support */
gboolean have_xfixes;
gboolean have_xdamage;
gboolean show_pointer;
#ifdef HAVE_XFIXES
int fixes_event_base;
#endif
#ifdef HAVE_XDAMAGE
Damage damage;
int damage_event_base;
XserverRegion damage_region;
GC damage_copy_gc;
#endif
};
struct _GstXImageSrcClass
{
GstPushSrcClass parent_class;
};
G_END_DECLS
#endif /* __GST_XIMAGESRC_H__ */

482
sys/ximagesrc/ximageutil.c Normal file
View file

@ -0,0 +1,482 @@
/* GStreamer
* Copyright (C) <2005> Luca Ognibene <luogni@tin.it>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ximageutil.h"
#ifdef HAVE_XSHM
static gboolean error_caught = FALSE;
static int
ximageutil_handle_xerror (Display * display, XErrorEvent * xevent)
{
char error_msg[1024];
XGetErrorText (display, xevent->error_code, error_msg, 1024);
GST_DEBUG ("ximageutil failed to use XShm calls. error: %s", error_msg);
error_caught = TRUE;
return 0;
}
/* This function checks that it is actually really possible to create an image
using XShm */
gboolean
ximageutil_check_xshm_calls (GstXContext * xcontext)
{
XImage *ximage;
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 (ximageutil_handle_xerror);
/* Trying to create a 1x1 ximage */
GST_DEBUG ("XShmCreateImage of 1x1");
ximage = XShmCreateImage (xcontext->disp, xcontext->visual,
xcontext->depth, ZPixmap, NULL, &SHMInfo, 1, 1);
/* Might cause an error, sync to ensure it is noticed */
XSync (xcontext->disp, FALSE);
if (!ximage || error_caught) {
GST_WARNING ("could not XShmCreateImage a 1x1 image");
goto beach;
}
size = ximage->height * ximage->bytes_per_line;
SHMInfo.shmid = shmget (IPC_PRIVATE, size, IPC_CREAT | 0777);
if (SHMInfo.shmid == -1) {
GST_WARNING ("could not get shared memory of %d bytes", size);
goto beach;
}
SHMInfo.shmaddr = shmat (SHMInfo.shmid, 0, 0);
if (SHMInfo.shmaddr == ((void *) -1)) {
GST_WARNING ("Failed to shmat: %s", g_strerror (errno));
goto beach;
}
/* Delete the SHM segment. It will actually go away automatically
* when we detach now */
shmctl (SHMInfo.shmid, IPC_RMID, 0);
ximage->data = SHMInfo.shmaddr;
SHMInfo.readOnly = FALSE;
if (XShmAttach (xcontext->disp, &SHMInfo) == 0) {
GST_WARNING ("Failed to XShmAttach");
goto beach;
}
/* Sync to ensure we see any errors we caused */
XSync (xcontext->disp, FALSE);
if (!error_caught) {
did_attach = TRUE;
/* store whether we succeeded in result */
result = TRUE;
}
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) {
XShmDetach (xcontext->disp, &SHMInfo);
XSync (xcontext->disp, FALSE);
}
if (SHMInfo.shmaddr != ((void *) -1))
shmdt (SHMInfo.shmaddr);
if (ximage)
XDestroyImage (ximage);
return result;
}
#endif /* HAVE_XSHM */
/* 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 */
GstXContext *
ximageutil_xcontext_get (GstElement * parent, const gchar * display_name)
{
GstXContext *xcontext = NULL;
XPixmapFormatValues *px_formats = NULL;
gint nb_formats = 0, i;
xcontext = g_new0 (GstXContext, 1);
xcontext->disp = XOpenDisplay (display_name);
if (!xcontext->disp) {
g_free (xcontext);
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);
xcontext->caps = NULL;
GST_DEBUG_OBJECT (parent, "X reports %dx%d pixels and %d mm x %d mm",
xcontext->width, xcontext->height, xcontext->widthmm, xcontext->heightmm);
ximageutil_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_free (xcontext);
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;
#ifdef HAVE_XSHM
/* Search for XShm extension support */
if (XShmQueryExtension (xcontext->disp) &&
ximageutil_check_xshm_calls (xcontext)) {
xcontext->use_xshm = TRUE;
GST_DEBUG ("ximageutil is using XShm extension");
} else {
xcontext->use_xshm = FALSE;
GST_DEBUG ("ximageutil is not using XShm extension");
}
#endif /* HAVE_XSHM */
/* 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;
}
}
return xcontext;
}
/* This function cleans the X context. Closing the Display and unrefing the
caps for supported formats. */
void
ximageutil_xcontext_clear (GstXContext * xcontext)
{
g_return_if_fail (xcontext != NULL);
if (xcontext->caps != NULL)
gst_caps_unref (xcontext->caps);
if (xcontext->par) {
g_value_unset (xcontext->par);
g_free (xcontext->par);
}
XCloseDisplay (xcontext->disp);
g_free (xcontext);
}
/* This function calculates the pixel aspect ratio based on the properties
* in the xcontext structure and stores it there. */
void
ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext)
{
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 */
};
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));
}
static void
gst_ximagesrc_buffer_finalize (GstXImageSrcBuffer * ximage)
{
GstElement *parent;
g_return_if_fail (ximage != NULL);
parent = ximage->parent;
if (parent == NULL) {
g_warning ("XImageSrcBuffer->ximagesrc == NULL");
goto beach;
}
if (ximage->return_func)
ximage->return_func (parent, ximage);
beach:
return;
}
void
gst_ximage_buffer_free (GstXImageSrcBuffer * ximage)
{
/* make sure it is not recycled */
ximage->width = -1;
ximage->height = -1;
gst_buffer_unref (GST_BUFFER (ximage));
}
static void
gst_ximagesrc_buffer_init (GstXImageSrcBuffer * ximage_buffer, gpointer g_class)
{
#ifdef HAVE_XSHM
ximage_buffer->SHMInfo.shmaddr = ((void *) -1);
ximage_buffer->SHMInfo.shmid = -1;
#endif
}
static void
gst_ximagesrc_buffer_class_init (gpointer g_class, gpointer class_data)
{
GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
gst_ximagesrc_buffer_finalize;
}
GType
gst_ximagesrc_buffer_get_type (void)
{
static GType _gst_ximagesrc_buffer_type;
if (G_UNLIKELY (_gst_ximagesrc_buffer_type == 0)) {
static const GTypeInfo ximagesrc_buffer_info = {
sizeof (GstBufferClass),
NULL,
NULL,
gst_ximagesrc_buffer_class_init,
NULL,
NULL,
sizeof (GstXImageSrcBuffer),
0,
(GInstanceInitFunc) gst_ximagesrc_buffer_init,
NULL
};
_gst_ximagesrc_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
"GstXImageSrcBuffer", &ximagesrc_buffer_info, 0);
}
return _gst_ximagesrc_buffer_type;
}
/* This function handles GstXImageSrcBuffer creation depending on XShm availability */
GstXImageSrcBuffer *
gst_ximageutil_ximage_new (GstXContext * xcontext,
GstElement * parent, int width, int height, BufferReturnFunc return_func)
{
GstXImageSrcBuffer *ximage = NULL;
gboolean succeeded = FALSE;
ximage =
(GstXImageSrcBuffer *) gst_mini_object_new (GST_TYPE_XIMAGESRC_BUFFER);
ximage->width = width;
ximage->height = height;
#ifdef HAVE_XSHM
if (xcontext->use_xshm) {
ximage->ximage = XShmCreateImage (xcontext->disp,
xcontext->visual, xcontext->depth,
ZPixmap, NULL, &ximage->SHMInfo, ximage->width, ximage->height);
if (!ximage->ximage) {
goto beach;
}
/* we have to use the returned bytes_per_line for our shm size */
ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height;
ximage->SHMInfo.shmid = shmget (IPC_PRIVATE, ximage->size,
IPC_CREAT | 0777);
if (ximage->SHMInfo.shmid == -1)
goto beach;
ximage->SHMInfo.shmaddr = shmat (ximage->SHMInfo.shmid, 0, 0);
if (ximage->SHMInfo.shmaddr == ((void *) -1))
goto beach;
/* Delete the SHM segment. It will actually go away automatically
* when we detach now */
shmctl (ximage->SHMInfo.shmid, IPC_RMID, 0);
ximage->ximage->data = ximage->SHMInfo.shmaddr;
ximage->SHMInfo.readOnly = FALSE;
if (XShmAttach (xcontext->disp, &ximage->SHMInfo) == 0)
goto beach;
XSync (xcontext->disp, FALSE);
} else
#endif /* HAVE_XSHM */
{
ximage->ximage = XCreateImage (xcontext->disp,
xcontext->visual,
xcontext->depth,
ZPixmap, 0, NULL, ximage->width, ximage->height, xcontext->bpp, 0);
if (!ximage->ximage)
goto beach;
/* we have to use the returned bytes_per_line for our image size */
ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height;
ximage->ximage->data = g_malloc (ximage->size);
XSync (xcontext->disp, FALSE);
}
succeeded = TRUE;
GST_BUFFER_DATA (ximage) = (guchar *) ximage->ximage->data;
GST_BUFFER_SIZE (ximage) = ximage->size;
/* Keep a ref to our src */
ximage->parent = gst_object_ref (parent);
ximage->return_func = return_func;
beach:
if (!succeeded) {
gst_ximage_buffer_free (ximage);
ximage = NULL;
}
return ximage;
}
/* This function destroys a GstXImageBuffer handling XShm availability */
void
gst_ximageutil_ximage_destroy (GstXContext * xcontext,
GstXImageSrcBuffer * ximage)
{
/* We might have some buffers destroyed after changing state to NULL */
if (!xcontext)
goto beach;
g_return_if_fail (ximage != NULL);
#ifdef HAVE_XSHM
if (xcontext->use_xshm) {
if (ximage->SHMInfo.shmaddr != ((void *) -1)) {
XShmDetach (xcontext->disp, &ximage->SHMInfo);
XSync (xcontext->disp, 0);
shmdt (ximage->SHMInfo.shmaddr);
}
if (ximage->ximage)
XDestroyImage (ximage->ximage);
} else
#endif /* HAVE_XSHM */
{
if (ximage->ximage) {
XDestroyImage (ximage->ximage);
}
}
XSync (xcontext->disp, FALSE);
beach:
if (ximage->parent) {
/* Release the ref to our parent */
gst_object_unref (ximage->parent);
ximage->parent = NULL;
}
return;
}

174
sys/ximagesrc/ximageutil.h Normal file
View file

@ -0,0 +1,174 @@
/* GStreamer
* Copyright (C) <2005> Luca Ognibene <luogni@tin.it>
*
* 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., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_XIMAGEUTIL_H__
#define __GST_XIMAGEUTIL_H__
#include <gst/gst.h>
#ifdef HAVE_XSHM
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#endif /* HAVE_XSHM */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#ifdef HAVE_XSHM
#include <X11/extensions/XShm.h>
#endif /* HAVE_XSHM */
#include <string.h>
#include <math.h>
G_BEGIN_DECLS
typedef struct _GstXContext GstXContext;
typedef struct _GstXWindow GstXWindow;
typedef struct _GstXImage GstXImage;
typedef struct _GstXImageSrcBuffer GstXImageSrcBuffer;
/* Global X Context stuff */
/**
* 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
* @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;
GstCaps *caps;
};
/**
* 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 #GstXOverlay 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;
};
gboolean ximageutil_check_xshm_calls (GstXContext * xcontext);
GstXContext *ximageutil_xcontext_get (GstElement *parent,
const gchar *display_name);
void ximageutil_xcontext_clear (GstXContext *xcontext);
void ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext);
/* custom ximagesrc buffer, copied from ximagesink */
/* BufferReturnFunc is called when a buffer is finalised */
typedef void (*BufferReturnFunc) (GstElement *parent, GstXImageSrcBuffer *buf);
/**
* GstXImageSrcBuffer:
* @parent: a reference to the element we belong to
* @ximage: the XImage of this buffer
* @width: the width in pixels of XImage @ximage
* @height: the height in pixels of XImage @ximage
* @size: the size in bytes of XImage @ximage
*
* Subclass of #GstBuffer containing additional information about an XImage.
*/
struct _GstXImageSrcBuffer {
GstBuffer buffer;
/* Reference to the ximagesrc we belong to */
GstElement *parent;
XImage *ximage;
#ifdef HAVE_XSHM
XShmSegmentInfo SHMInfo;
#endif /* HAVE_XSHM */
gint width, height;
size_t size;
BufferReturnFunc return_func;
};
GstXImageSrcBuffer *gst_ximageutil_ximage_new (GstXContext *xcontext,
GstElement *parent, int width, int height, BufferReturnFunc return_func);
void gst_ximageutil_ximage_destroy (GstXContext *xcontext,
GstXImageSrcBuffer * ximage);
/* Call to manually release a buffer */
void gst_ximage_buffer_free (GstXImageSrcBuffer *ximage);
#define GST_TYPE_XIMAGESRC_BUFFER (gst_ximagesrc_buffer_get_type())
#define GST_IS_XIMAGESRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XIMAGESRC_BUFFER))
#define GST_XIMAGESRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBuffer))
#define GST_XIMAGESRC_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBufferClass))
G_END_DECLS
#endif /* __GST_XIMAGEUTIL_H__ */