moved ximagesrc to good

Original commit message from CVS:
moved ximagesrc to good
This commit is contained in:
Thomas Vander Stichele 2006-04-28 19:23:20 +00:00
parent b0ba6af066
commit 161d53e6da
16 changed files with 147 additions and 1806 deletions

View file

@ -1,3 +1,22 @@
2006-04-28 Thomas Vander Stichele <thomas at apestaart dot org>
* configure.ac:
* docs/plugins/gst-plugins-bad-plugins-decl-list.txt:
* docs/plugins/gst-plugins-bad-plugins-decl.txt:
* docs/plugins/gst-plugins-bad-plugins-docs.sgml:
* docs/plugins/gst-plugins-bad-plugins-undocumented.txt:
* sys/Makefile.am:
* sys/ximagesrc/Makefile.am:
* sys/ximagesrc/ximagesrc.c:
* sys/ximagesrc/ximagesrc.h:
* sys/ximagesrc/ximageutil.c:
* sys/ximagesrc/ximageutil.h:
* tests/Makefile.am:
* tests/icles/.cvsignore:
* tests/icles/Makefile.am:
* tests/icles/ximagesrc-test.c:
moved ximagesrc to good (See #336756)
2006-04-28 Tim-Philipp Müller <tim at centricular dot net>
* ext/faad/gstfaad.c: (gst_faad_init), (aac_rate_idx),

View file

@ -204,81 +204,6 @@ GST_CHECK_FEATURE(OPENGL, [Open GL], glsink, [
CPPFLAGS="$save_CPPFLAGS"
LIBS="$save_LIBS"
dnl Check for X11
translit(dnm, m, l) AM_CONDITIONAL(USE_X, true)
GST_CHECK_FEATURE(X, [X libraries and plugins],
[ximagesrc], [
AC_PATH_XTRA
dnl now try to find the HEADER
ac_cflags_save="$CFLAGS"
ac_cppflags_save="$CPPFLAGS"
CFLAGS="$CFLAGS $X_CFLAGS"
CPPFLAGS="$CPPFLAGS $X_CFLAGS"
AC_CHECK_HEADER(X11/Xlib.h, HAVE_X="yes", HAVE_X="no")
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)
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 FIXME: this should be rolled into the test above, it's just an additional
dnl feature of the ximagesrc plug-in
dnl check for X Shm
translit(dnm, m, l) AM_CONDITIONAL(USE_XSHM, true)
GST_CHECK_FEATURE(XSHM, [X Shared Memory extension], [], [
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 *** Video 4 Linux 2 ***
dnl for information about the header/define, see sys/v4l2/gstv4l2element.h
dnl renamed to GST_V4L2 because of some conflict with kernel headers
@ -723,7 +648,6 @@ gst-libs/Makefile
gst-libs/gst/Makefile
sys/Makefile
sys/glsink/Makefile
sys/ximagesrc/Makefile
sys/v4l2/Makefile
examples/Makefile
examples/directfb/Makefile

View file

@ -17,17 +17,30 @@ GST_DFBVIDEOSINK_CLASS
GST_IS_DFBVIDEOSINK_CLASS
</SECTION>
<SECTION>
<FILE>ximagesrc</FILE>
<TITLE>GstXImageSrc</TITLE>
GstXImageSrc
<SUBSECTION Standard>
GST_XIMAGESRC
GST_IS_XIMAGESRC
GST_TYPE_XIMAGESRC
gst_ximagesrc_get_type
GST_XIMAGESRC_CLASS
GST_IS_XIMAGESRC_CLASS
</SECTION>
<SECTION>
<FILE>gsttaglib</FILE>
GstTagLibMuxPriv
<TITLE>GstTagLibMux</TITLE>
GstTagLibMux
<SUBSECTION Standard>
GST_TAGLIB_MUX
GST_IS_TAGLIB_MUX
GST_TYPE_TAGLIB_MUX
GST_TAG_LIB_MUX
GST_IS_TAG_LIB_MUX
GST_TYPE_TAG_LIB_MUX
gst_tag_lib_mux_get_type
GST_TAGLIB_MUX_CLASS
GST_IS_TAGLIB_MUX_CLASS
GST_TAG_LIB_MUX_CLASS
GST_IS_TAG_LIB_MUX_CLASS
</SECTION>

View file

@ -133,6 +133,92 @@ void
<RETURNS>GType </RETURNS>
void
</FUNCTION>
<MACRO>
<NAME>GST_TYPE_XIMAGESRC</NAME>
#define GST_TYPE_XIMAGESRC (gst_ximagesrc_get_type())
</MACRO>
<MACRO>
<NAME>GST_XIMAGESRC</NAME>
#define GST_XIMAGESRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XIMAGESRC,GstXImageSrc))
</MACRO>
<MACRO>
<NAME>GST_XIMAGESRC_CLASS</NAME>
#define GST_XIMAGESRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XIMAGESRC,GstXImageSrc))
</MACRO>
<MACRO>
<NAME>GST_IS_XIMAGESRC</NAME>
#define GST_IS_XIMAGESRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XIMAGESRC))
</MACRO>
<MACRO>
<NAME>GST_IS_XIMAGESRC_CLASS</NAME>
#define GST_IS_XIMAGESRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XIMAGESRC))
</MACRO>
<STRUCT>
<NAME>GstXImageSrc</NAME>
</STRUCT>
<STRUCT>
<NAME>GstXImageSrcClass</NAME>
</STRUCT>
<FUNCTION>
<NAME>gst_ximagesrc_get_type</NAME>
<RETURNS>GType </RETURNS>
void
</FUNCTION>
<STRUCT>
<NAME>GstXImageSrc</NAME>
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;
XFixesCursorImage *cursor_image;
#endif
#ifdef HAVE_XDAMAGE
Damage damage;
int damage_event_base;
XserverRegion damage_region;
GC damage_copy_gc;
#endif
};
</STRUCT>
<STRUCT>
<NAME>GstXImageSrcClass</NAME>
struct _GstXImageSrcClass
{
GstPushSrcClass parent_class;
};
</STRUCT>
<STRUCT>
<NAME>GstTagLibMuxPriv</NAME>
</STRUCT>
@ -157,29 +243,29 @@ typedef struct _GstTagLibMuxClass {
} GstTagLibMuxClass;
</STRUCT>
<MACRO>
<NAME>GST_TYPE_TAGLIB_MUX</NAME>
#define GST_TYPE_TAGLIB_MUX \
<NAME>GST_TYPE_TAG_LIB_MUX</NAME>
#define GST_TYPE_TAG_LIB_MUX \
(gst_tag_lib_mux_get_type())
</MACRO>
<MACRO>
<NAME>GST_TAGLIB_MUX</NAME>
#define GST_TAGLIB_MUX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TAGLIB_MUX,GstTagLibMux))
<NAME>GST_TAG_LIB_MUX</NAME>
#define GST_TAG_LIB_MUX(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TAG_LIB_MUX,GstTagLibMux))
</MACRO>
<MACRO>
<NAME>GST_TAGLIB_MUX_CLASS</NAME>
#define GST_TAGLIB_MUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TAGLIB_MUX,GstTagLibMuxClass))
<NAME>GST_TAG_LIB_MUX_CLASS</NAME>
#define GST_TAG_LIB_MUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TAG_LIB_MUX,GstTagLibMuxClass))
</MACRO>
<MACRO>
<NAME>GST_IS_TAGLIB_MUX</NAME>
#define GST_IS_TAGLIB_MUX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TAGLIB_MUX))
<NAME>GST_IS_TAG_LIB_MUX</NAME>
#define GST_IS_TAG_LIB_MUX(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TAG_LIB_MUX))
</MACRO>
<MACRO>
<NAME>GST_IS_TAGLIB_MUX_CLASS</NAME>
#define GST_IS_TAGLIB_MUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TAGLIB_MUX))
<NAME>GST_IS_TAG_LIB_MUX_CLASS</NAME>
#define GST_IS_TAG_LIB_MUX_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TAG_LIB_MUX))
</MACRO>
<FUNCTION>
<NAME>gst_tag_lib_mux_get_type</NAME>

View file

@ -36,7 +36,6 @@
<xi:include href="xml/plugin-taglib.xml" />
<xi:include href="xml/plugin-tta.xml" />
<xi:include href="xml/plugin-video4linux2.xml" />
<xi:include href="xml/plugin-ximagesrc.xml" />
<xi:include href="xml/plugin-xingheader.xml" />
</chapter>

View file

@ -1,9 +1,10 @@
92% symbol docs coverage.
11 symbols documented.
83% symbol docs coverage.
10 symbols documented.
0 symbols incomplete.
1 not documented.
2 not documented.
GstTagLibMux
element-tagid3v2mux:Short_Description

View file

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

View file

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

View file

@ -1,829 +0,0 @@
/* GStreamer
*
* Copyright (C) 2006 Zaheer Merali <zaheerabbas at merali dot org>
*
* 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.
*/
/**
* SECTION:element-ximagesrc
* @short_description: a source that captures your X Display
*
* <refsect2>
* <para>
* This element captures your X Display and creates raw RGB video. It uses
* the XDamage extension if available to only capture areas of the screen that
* have changed since the last frame. It uses the XFixes extension if
* available to also capture your mouse pointer. By default it will fixate to
* 25 frames per second.
* </para>
* <title>Example pipelines</title>
* <para>
* <programlisting>
* gst-launch -v ximagesrc ! video/x-raw-rgb,framerate=5/1 ! ffmpegcolorspace ! theoraenc ! oggmux ! filesink location=desktop.ogg
* </programlisting>
* Encodes your X display to an Ogg theora video at 5 frames per second.
* </para>
* </refsect2>
*/
#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>
#include <gst/gst.h>
#include <gst/gst-i18n-plugin.h>
GST_DEBUG_CATEGORY_STATIC (gst_debug_ximage_src);
#define GST_CAT_DEFAULT gst_debug_ximage_src
/* elementfactory information */
static const 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>, "
"Zaheer Merali <zaheerabbas at merali dot org>");
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 ], "
"pixel-aspect-ratio = (fraction) [ 0, MAX ]"));
enum
{
PROP_0,
PROP_DISPLAY_NAME,
PROP_SCREEN_NUM,
PROP_SHOW_POINTER
};
GST_BOILERPLATE (GstXImageSrc, gst_ximage_src, GstPushSrc, GST_TYPE_PUSH_SRC);
static void gst_ximage_src_fixate (GstPad * pad, GstCaps * caps);
static void gst_ximage_src_clear_bufpool (GstXImageSrc * ximagesrc);
/* Called when a buffer is returned from the pipeline */
static void
gst_ximage_src_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_ximage_src_open_display (GstXImageSrc * s, const gchar * name)
{
g_return_val_if_fail (GST_IS_XIMAGE_SRC (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_ximage_src_start (GstBaseSrc * basesrc)
{
GstXImageSrc *s = GST_XIMAGE_SRC (basesrc);
s->last_frame_no = -1;
return gst_ximage_src_open_display (s, NULL);
}
static gboolean
gst_ximage_src_stop (GstBaseSrc * basesrc)
{
GstXImageSrc *src = GST_XIMAGE_SRC (basesrc);
gst_ximage_src_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_ximage_src_unlock (GstBaseSrc * basesrc)
{
GstXImageSrc *src = GST_XIMAGE_SRC (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_ximage_src_recalc (GstXImageSrc * src)
{
if (!src->xcontext)
return FALSE;
/* Maybe later we can check the display hasn't changed size */
/* We could use XQueryPointer to get only the current window. */
return TRUE;
}
#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];
guint8 dr, dg, db;
guint32 color;
gint r_shift, r_max, r_shift_out;
gint g_shift, g_max, g_shift_out;
gint b_shift, b_max, b_shift_out;
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:
/* Should not reach here */
g_assert_not_reached ();
}
/* possible optimisation:
* 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++);
for (r_shift_out = 0; !(xcontext->visual->red_mask & (1 << r_shift_out));
r_shift_out++);
for (g_shift_out = 0; !(xcontext->visual->green_mask & (1 << g_shift_out));
g_shift_out++);
for (b_shift_out = 0; !(xcontext->visual->blue_mask & (1 << b_shift_out));
b_shift_out++);
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_out) +
(((dg * g_max) / 255) << g_shift_out) +
(((db * b_max) / 255) << b_shift_out);
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_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
{
GstXImageSrcBuffer *ximage = NULL;
GstCaps *caps = 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_ximage_src_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;
caps = 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->r_mask_output,
"green_mask", G_TYPE_INT, xcontext->g_mask_output,
"blue_mask", G_TYPE_INT, xcontext->b_mask_output,
"width", G_TYPE_INT, xcontext->width,
"height", G_TYPE_INT, xcontext->height,
"framerate", GST_TYPE_FRACTION, ximagesrc->fps_n, ximagesrc->fps_d,
"pixel-aspect-ratio", GST_TYPE_FRACTION,
gst_value_get_fraction_numerator (xcontext->par),
gst_value_get_fraction_denominator (xcontext->par), NULL);
gst_buffer_set_caps (GST_BUFFER (ximage), caps);
g_mutex_unlock (ximagesrc->x_lock);
}
g_return_val_if_fail (GST_IS_XIMAGE_SRC (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);
#ifdef HAVE_XFIXES
/* re-get area where last mouse pointer was */
if (ximagesrc->cursor_image) {
gint x, y, width, height;
x = ximagesrc->cursor_image->x - ximagesrc->cursor_image->xhot;
y = ximagesrc->cursor_image->y - ximagesrc->cursor_image->yhot;
width = ximagesrc->cursor_image->width;
height = ximagesrc->cursor_image->height;
/* bounds checking */
if (x < 0)
x = 0;
if (y < 0)
y = 0;
if (x + width > ximagesrc->width)
width = ximagesrc->width - x;
if (y + height > ximagesrc->height)
height = ximagesrc->height - y;
g_assert (x >= 0);
g_assert (y >= 0);
GST_DEBUG_OBJECT (ximagesrc, "Removing cursor from %d,%d", x, y);
XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
x, y, width, height, AllPlanes, ZPixmap, ximage->ximage, x, y);
}
#endif
} 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) {
GST_DEBUG_OBJECT (ximagesrc, "Using XFixes to draw cursor");
/* get cursor */
ximagesrc->cursor_image = XFixesGetCursorImage (ximagesrc->xcontext->disp);
if (ximagesrc->cursor_image != NULL) {
int cx, cy, i, j, count;
cx = ximagesrc->cursor_image->x - ximagesrc->cursor_image->xhot;
cy = ximagesrc->cursor_image->y - ximagesrc->cursor_image->yhot;
count = ximagesrc->cursor_image->width * ximagesrc->cursor_image->height;
for (i = 0; i < count; i++)
ximagesrc->cursor_image->pixels[i] =
GUINT_TO_LE (ximagesrc->cursor_image->pixels[i]);
/* copy those pixels across */
for (j = cy;
j < cy + ximagesrc->cursor_image->height && j < ximagesrc->height;
j++) {
for (i = cx;
i < cx + ximagesrc->cursor_image->width && i < ximagesrc->width;
i++) {
guint8 *src, *dest;
src =
(guint8 *) & (ximagesrc->cursor_image->pixels[((j -
cy) * ximagesrc->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_ximage_src_create (GstPushSrc * bs, GstBuffer ** buf)
{
GstXImageSrc *s = GST_XIMAGE_SRC (bs);
GstXImageSrcBuffer *image;
GstClockTime base_time;
GstClockTime next_capture_ts;
GstClockTime dur;
gint64 next_frame_no;
if (!gst_ximage_src_recalc (s)) {
GST_ELEMENT_ERROR (s, RESOURCE, FAILED,
(_("Changing resolution at runtime is not yet supported.")), (NULL));
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_ximage_src_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_ximage_src_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstXImageSrc *src = GST_XIMAGE_SRC (object);
switch (prop_id) {
case PROP_DISPLAY_NAME:
g_free (src->display_name);
src->display_name = g_strdup (g_value_get_string (value));
break;
case PROP_SCREEN_NUM:
src->screen_num = g_value_get_uint (value);
break;
case PROP_SHOW_POINTER:
src->show_pointer = g_value_get_boolean (value);
break;
default:
break;
}
}
static void
gst_ximage_src_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstXImageSrc *src = GST_XIMAGE_SRC (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;
case PROP_SHOW_POINTER:
g_value_set_boolean (value, src->show_pointer);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_ximage_src_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_ximage_src_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_ximage_src_dispose (GObject * object)
{
/* Drop references in the buffer_pool */
gst_ximage_src_clear_bufpool (GST_XIMAGE_SRC (object));
}
static void
gst_ximage_src_finalize (GObject * object)
{
GstXImageSrc *src = GST_XIMAGE_SRC (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_ximage_src_get_caps (GstBaseSrc * bs)
{
GstXImageSrc *s = GST_XIMAGE_SRC (bs);
GstXContext *xcontext;
if ((!s->xcontext) && (!gst_ximage_src_open_display (s, NULL)))
return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC (s)->
srcpad));
if (!gst_ximage_src_recalc (s))
return gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC (s)->
srcpad));
xcontext = s->xcontext;
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->r_mask_output,
"green_mask", G_TYPE_INT, xcontext->g_mask_output,
"blue_mask", G_TYPE_INT, xcontext->b_mask_output,
"width", G_TYPE_INT, xcontext->width,
"height", G_TYPE_INT, xcontext->height,
"framerate", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1,
"pixel-aspect-ratio", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1,
NULL);
}
static gboolean
gst_ximage_src_set_caps (GstBaseSrc * bs, GstCaps * caps)
{
GstXImageSrc *s = GST_XIMAGE_SRC (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_ximage_src_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_ximage_src_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_ximage_src_set_property;
gc->get_property = gst_ximage_src_get_property;
gc->dispose = gst_ximage_src_dispose;
gc->finalize = gst_ximage_src_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));
g_object_class_install_property (gc, PROP_SHOW_POINTER,
g_param_spec_boolean ("show_pointer", "Show Mouse Pointer",
"Show mouse pointer (if XFixes extension enabled)", TRUE,
G_PARAM_READWRITE));
parent_class = g_type_class_peek_parent (klass);
push_class->create = gst_ximage_src_create;
bc->get_caps = gst_ximage_src_get_caps;
bc->set_caps = gst_ximage_src_set_caps;
bc->start = gst_ximage_src_start;
bc->stop = gst_ximage_src_stop;
bc->unlock = gst_ximage_src_unlock;
}
static void
gst_ximage_src_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_ximage_src_fixate);
ximagesrc->pool_lock = g_mutex_new ();
ximagesrc->x_lock = g_mutex_new ();
ximagesrc->show_pointer = TRUE;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
gboolean ret;
GST_DEBUG_CATEGORY_INIT (gst_debug_ximage_src, "ximagesrc", 0,
"ximagesrc element debug");
ret = gst_element_register (plugin, "ximagesrc", GST_RANK_NONE,
GST_TYPE_XIMAGE_SRC);
return ret;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"ximagesrc",
"X11 video input plugin using standard Xlib calls",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);

View file

@ -1,97 +0,0 @@
/* 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_XIMAGE_SRC_H__
#define __GST_XIMAGE_SRC_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_XIMAGE_SRC (gst_ximage_src_get_type())
#define GST_XIMAGE_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XIMAGE_SRC,GstXImageSrc))
#define GST_XIMAGE_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_XIMAGE_SRC,GstXImageSrc))
#define GST_IS_XIMAGE_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XIMAGE_SRC))
#define GST_IS_XIMAGE_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XIMAGE_SRC))
typedef struct _GstXImageSrc GstXImageSrc;
typedef struct _GstXImageSrcClass GstXImageSrcClass;
GType gst_ximage_src_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;
XFixesCursorImage *cursor_image;
#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_XIMAGE_SRC_H__ */

View file

@ -1,481 +0,0 @@
/* 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);
GST_DEBUG_OBJECT (parent, "opened display 0x%x", xcontext->disp);
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->r_mask_output = GUINT32_TO_BE (xcontext->visual->red_mask);
xcontext->g_mask_output = GUINT32_TO_BE (xcontext->visual->green_mask);
xcontext->b_mask_output = GUINT32_TO_BE (xcontext->visual->blue_mask);
if (xcontext->bpp == 24) {
xcontext->r_mask_output >>= 8;
xcontext->g_mask_output >>= 8;
xcontext->b_mask_output >>= 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]);
if (xcontext->par)
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\n",
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;
}

View file

@ -1,182 +0,0 @@
/* 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;
/* these are the output masks
* for buffers from ximagesrc
* and are in big endian */
guint32 r_mask_output, g_mask_output, b_mask_output;
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_IS_XIMAGESRC_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_XIMAGESRC_BUFFER))
#define GST_XIMAGESRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBuffer))
#define GST_XIMAGESRC_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBufferClass))
#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__ */

View file

@ -4,16 +4,8 @@ else
SUBDIRS_CHECK =
endif
if USE_X
SUBDIRS_ICLES = icles
else
SUBDIRS_ICLES =
endif
SUBDIRS = icles \
$(SUBDIRS_CHECK)
SUBDIRS = \
$(SUBDIRS_CHECK) \
$(SUBDIRS_ICLES)
DIST_SUBDIRS = \
check \
icles
DIST_SUBDIRS = icles \
check

View file

@ -1 +0,0 @@
ximagesrc-test

View file

@ -1,12 +0,0 @@
if USE_X
X_TESTS = ximagesrc-test
ximagesrc_test_SOURCES = ximagesrc-test.c
ximagesrc_test_CFLAGS = $(GST_CFLAGS)
ximagesrc_test_LDFLAGS = $(GST_LIBS)
else
X_TESTS =
endif
noinst_PROGRAMS = $(X_TESTS)

View file

@ -1,71 +0,0 @@
/* GStreamer
* Copyright (C) <2006> Zaheer Abbas Merali <zaheerabbas at merali dot org>
*
* 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 <gst/gst.h>
static GMainLoop *loop;
static gboolean
terminate_playback (GstElement * pipeline)
{
g_print ("Terminating playback\n");
g_main_loop_quit (loop);
return FALSE;
}
int
main (int argc, char **argv)
{
GstElement *pipeline;
GstBus *bus;
GstState state, pending;
GError *error = NULL;
gst_init (&argc, &argv);
pipeline = gst_parse_launch ("ximagesrc ! fakesink", &error);
if (error) {
g_print ("Error while parsing pipeline description: %s\n", error->message);
return -1;
}
loop = g_main_loop_new (NULL, FALSE);
bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* lets check it gets to PLAYING */
g_assert (gst_element_get_state (pipeline, &state, &pending,
GST_CLOCK_TIME_NONE) != GST_STATE_CHANGE_FAILURE);
g_assert (state == GST_STATE_PLAYING || pending == GST_STATE_PLAYING);
/* We want to get out after 5 seconds */
g_timeout_add (5000, (GSourceFunc) terminate_playback, pipeline);
g_main_loop_run (loop);
g_main_loop_unref (loop);
return 0;
}