diff options
Diffstat (limited to 'sys/ximage/gstximagesrc.c')
-rw-r--r-- | sys/ximage/gstximagesrc.c | 172 |
1 files changed, 167 insertions, 5 deletions
diff --git a/sys/ximage/gstximagesrc.c b/sys/ximage/gstximagesrc.c index 15c7d6ce4..10e81fb3d 100644 --- a/sys/ximage/gstximagesrc.c +++ b/sys/ximage/gstximagesrc.c @@ -62,8 +62,12 @@ GST_ELEMENT_DETAILS ("Ximage video source", "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, " + GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-damaged-raw-rgb, " + "framerate = (fraction) [ 0, MAX ], " + "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], " + "pixel-aspect-ratio = (fraction) [ 0, MAX ];" + "video/x-raw-rgb, " "framerate = (fraction) [ 0, MAX ], " "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], " "pixel-aspect-ratio = (fraction) [ 0, MAX ]")); @@ -364,6 +368,129 @@ composite_pixel (GstXContext * xcontext, guchar * dest, guchar * src) } #endif +static GstBuffer * +gst_ximage_src_ximage_get_damaged (GstXImageSrc * ximagesrc) +{ + GstBuffer *outbuf = NULL; + guint32 requiredsize; + + XEvent ev; + + GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XDamage"); + + do { + XNextEvent (ximagesrc->xcontext->disp, &ev); + + if (ev.type == ximagesrc->damage_event_base + XDamageNotify) { + XserverRegion parts; + XRectangle *rects; + int nrects; + + parts = XFixesCreateRegion (ximagesrc->xcontext->disp, 0, 0); + XDamageSubtract (ximagesrc->xcontext->disp, ximagesrc->damage, None, + parts); + /* Now copy out all of the damaged rectangles. */ + rects = XFixesFetchRegion (ximagesrc->xcontext->disp, parts, &nrects); + if (rects != NULL) { + int i; + + GST_DEBUG ("Calculating required memory"); + for (i = 0; i < nrects; i++) { + if (ximagesrc->endx > ximagesrc->startx && + ximagesrc->endy > ximagesrc->starty) { + /* see if damage area intersects */ + if (rects[i].x + rects[i].width < ximagesrc->startx || + rects[i].x > ximagesrc->endx) { + /* trivial reject */ + } else if (rects[i].y + rects[i].height < ximagesrc->starty || + rects[i].y > ximagesrc->endy) { + /* trivial reject */ + } else { + /* find intersect region */ + int startx, starty, width, height; + + startx = (rects[i].x < ximagesrc->startx) ? ximagesrc->startx : + rects[i].x; + starty = (rects[i].y < ximagesrc->starty) ? ximagesrc->starty : + rects[i].y; + width = (rects[i].x + rects[i].width < ximagesrc->endx) ? + rects[i].x + rects[i].width - startx : + ximagesrc->endx - startx; + height = (rects[i].y + rects[i].height < ximagesrc->endy) ? + rects[i].y + rects[i].height - starty : ximagesrc->endy - + starty; + + requiredsize += (width * height * ximagesrc->xcontext->bpp) / 8; + } + } else { + requiredsize += + (rects[i].width * rects[i].height * ximagesrc->xcontext->bpp) / + 8; + } + } + + GST_DEBUG ("requiredsize : %d bytes, nbrects : %d", requiredsize, + nrects); + outbuf = gst_buffer_new_and_alloc (requiredsize); + + for (i = 0; i < nrects; i++) { + GST_LOG_OBJECT (ximagesrc, + "Damaged sub-region @ %d,%d size %dx%d reported", + rects[i].x, rects[i].y, rects[i].width, rects[i].height); + + /* if we only want a small area, clip this damage region to + * area we want */ + if (ximagesrc->endx > ximagesrc->startx && + ximagesrc->endy > ximagesrc->starty) { + /* see if damage area intersects */ + if (rects[i].x + rects[i].width < ximagesrc->startx || + rects[i].x > ximagesrc->endx) { + /* trivial reject */ + } else if (rects[i].y + rects[i].height < ximagesrc->starty || + rects[i].y > ximagesrc->endy) { + /* trivial reject */ + } else { + /* find intersect region */ + int startx, starty, width, height; + + startx = (rects[i].x < ximagesrc->startx) ? ximagesrc->startx : + rects[i].x; + starty = (rects[i].y < ximagesrc->starty) ? ximagesrc->starty : + rects[i].y; + width = (rects[i].x + rects[i].width < ximagesrc->endx) ? + rects[i].x + rects[i].width - startx : + ximagesrc->endx - startx; + height = (rects[i].y + rects[i].height < ximagesrc->endy) ? + rects[i].y + rects[i].height - starty : ximagesrc->endy - + starty; + + GST_LOG_OBJECT (ximagesrc, + "Retrieving damaged sub-region @ %d,%d size %dx%d as intersect region", + startx, starty, width, height); + XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + startx, starty, width, height, AllPlanes, ZPixmap, + ximage->ximage, startx - ximagesrc->startx, + starty - ximagesrc->starty); + } + } else { + + GST_LOG_OBJECT (ximagesrc, + "Retrieving damaged sub-region @ %d,%d size %dx%d", + rects[i].x, rects[i].y, rects[i].width, rects[i].height); + + XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow, + rects[i].x, rects[i].y, + rects[i].width, rects[i].height, + AllPlanes, ZPixmap, ximage->ximage, rects[i].x, rects[i].y); + } + } + free (rects); + } + } + } while (XPending (ximagesrc->xcontext->disp)); + +} + /* Retrieve an XImageSrcBuffer, preferably from our * pool of existing images and populate it from the window */ static GstXImageSrcBuffer * @@ -406,7 +533,10 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc) xcontext = ximagesrc->xcontext; - caps = gst_caps_new_simple ("video/x-raw-rgb", + caps = + gst_caps_new_simple (ximagesrc->output_damaged ? + "video/x-damaged-raw-rgb" : + "video/x-raw-rgb", "bpp", G_TYPE_INT, xcontext->bpp, "depth", G_TYPE_INT, xcontext->depth, "endianness", G_TYPE_INT, xcontext->endianness, @@ -788,7 +918,10 @@ gst_ximage_src_create (GstPushSrc * bs, GstBuffer ** buf) s->last_frame_no = next_frame_no; GST_OBJECT_UNLOCK (s); - image = gst_ximage_src_ximage_get (s); + if (!s->output_damaged) + image = gst_ximage_src_ximage_get (s); + else + image = gst_ximage_src_ximage_get_damaged (s); if (!image) return GST_FLOW_ERROR; @@ -930,6 +1063,7 @@ gst_ximage_src_get_caps (GstBaseSrc * bs) { GstXImageSrc *s = GST_XIMAGE_SRC (bs); GstXContext *xcontext; + GstCaps *c1, *c2 = NULL; gint width, height; if ((!s->xcontext) && (!gst_ximage_src_open_display (s, s->display_name))) @@ -969,7 +1103,8 @@ gst_ximage_src_get_caps (GstBaseSrc * bs) s->endy = 0; } GST_DEBUG ("width = %d, height=%d", width, height); - return gst_caps_new_simple ("video/x-raw-rgb", + + c1 = 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, @@ -981,6 +1116,26 @@ gst_ximage_src_get_caps (GstBaseSrc * bs) "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); + +#ifdef HAVE_XDAMAGE + if (s->have_xdamage) { + c2 = gst_caps_new_simple ("video/x-damaged-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, width, + "height", G_TYPE_INT, 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); + gst_caps_append (c2, c1); + c1 = c2; + } +#endif + return c1; } static gboolean @@ -1006,6 +1161,11 @@ gst_ximage_src_set_caps (GstBaseSrc * bs, GstCaps * caps) GST_DEBUG_OBJECT (s, "peer wants %d/%d fps", s->fps_n, s->fps_d); + s->output_damaged = + gst_structure_has_name (structure, "video/x-damaged-raw-rgb"); + + GST_DEBUG_OBJECT (s, "outputting damaged region : %d", s->output_damaged); + return TRUE; } @@ -1015,6 +1175,8 @@ gst_ximage_src_fixate (GstPad * pad, GstCaps * caps) gint i; GstStructure *structure; + GST_DEBUG ("Fixating..."); + for (i = 0; i < gst_caps_get_size (caps); ++i) { structure = gst_caps_get_structure (caps, i); |