summaryrefslogtreecommitdiffstats
path: root/xorg/server/module/rdpXv.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg/server/module/rdpXv.c')
-rw-r--r--xorg/server/module/rdpXv.c678
1 files changed, 678 insertions, 0 deletions
diff --git a/xorg/server/module/rdpXv.c b/xorg/server/module/rdpXv.c
new file mode 100644
index 00000000..1557f892
--- /dev/null
+++ b/xorg/server/module/rdpXv.c
@@ -0,0 +1,678 @@
+/*
+Copyright 2014 Jay Sorg
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+XVideo
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* this should be before all X11 .h files */
+#include <xorg-server.h>
+#include <xorgVersion.h>
+
+/* all driver need this */
+#include <xf86.h>
+#include <xf86_OSproc.h>
+
+#include <xf86xv.h>
+#include <X11/extensions/Xv.h>
+#include <fourcc.h>
+
+#include <fb.h>
+
+#include "rdp.h"
+#include "rdpMisc.h"
+#include "rdpReg.h"
+#include "rdpClientCon.h"
+
+#define LOG_LEVEL 1
+#define LLOGLN(_level, _args) \
+ do { if (_level < LOG_LEVEL) { ErrorF _args ; ErrorF("\n"); } } while (0)
+
+#define T_NUM_ENCODINGS 1
+static XF86VideoEncodingRec g_xrdpVidEncodings[T_NUM_ENCODINGS] =
+{ { 0, "XV_IMAGE", 2046, 2046, { 1, 1 } } };
+
+#define T_NUM_FORMATS 1
+static XF86VideoFormatRec g_xrdpVidFormats[T_NUM_FORMATS] =
+{ { 0, TrueColor } };
+
+/* YV12
+ I420
+ 12 bpp planar
+ YUV 4:2:0 8 bit Y plane followed by 8 bit 2x2 subsampled
+ U and V planes. */
+
+/* YUY2
+ UYVY
+ 16 bpp packed
+ YUV 4:2:2 Y sample at every pixel, U and V sampled at
+ every second pixel */
+
+/* XVIMAGE_YV12 FOURCC_YV12 0x32315659 */
+/* XVIMAGE_I420 FOURCC_I420 0x30323449 */
+/* XVIMAGE_YUY2 FOURCC_YUY2 0x32595559 */
+/* XVIMAGE_UYVY FOURCC_UYVY 0x59565955 */
+
+static XF86ImageRec g_xrdpVidImages[] =
+{ XVIMAGE_YV12, XVIMAGE_I420, XVIMAGE_YUY2, XVIMAGE_UYVY };
+
+#define T_MAX_PORTS 1
+
+/*****************************************************************************/
+static int
+xrdpVidPutVideo(ScrnInfoPtr pScrn, short vid_x, short vid_y,
+ short drw_x, short drw_y, short vid_w, short vid_h,
+ short drw_w, short drw_h, RegionPtr clipBoxes,
+ pointer data, DrawablePtr pDraw)
+{
+ LLOGLN(0, ("xrdpVidPutVideo:"));
+ return Success;
+}
+
+/*****************************************************************************/
+static int
+xrdpVidPutStill(ScrnInfoPtr pScrn, short vid_x, short vid_y,
+ short drw_x, short drw_y, short vid_w, short vid_h,
+ short drw_w, short drw_h, RegionPtr clipBoxes,
+ pointer data, DrawablePtr pDraw)
+{
+ LLOGLN(0, ("xrdpVidPutStill:"));
+ return Success;
+}
+
+/*****************************************************************************/
+static int
+xrdpVidGetVideo(ScrnInfoPtr pScrn, short vid_x, short vid_y,
+ short drw_x, short drw_y, short vid_w, short vid_h,
+ short drw_w, short drw_h, RegionPtr clipBoxes,
+ pointer data, DrawablePtr pDraw)
+{
+ LLOGLN(0, ("xrdpVidGetVideo:"));
+ return Success;
+}
+
+/*****************************************************************************/
+static int
+xrdpVidGetStill(ScrnInfoPtr pScrn, short vid_x, short vid_y,
+ short drw_x, short drw_y, short vid_w, short vid_h,
+ short drw_w, short drw_h, RegionPtr clipBoxes,
+ pointer data, DrawablePtr pDraw)
+{
+ LLOGLN(0, ("FBDevTIVidGetStill:"));
+ return Success;
+}
+
+/*****************************************************************************/
+static void
+xrdpVidStopVideo(ScrnInfoPtr pScrn, pointer data, Bool Cleanup)
+{
+ LLOGLN(0, ("xrdpVidStopVideo:"));
+}
+
+/*****************************************************************************/
+static int
+xrdpVidSetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
+ INT32 value, pointer data)
+{
+ LLOGLN(0, ("xrdpVidSetPortAttribute:"));
+ return Success;
+}
+
+/*****************************************************************************/
+static int
+xrdpVidGetPortAttribute(ScrnInfoPtr pScrn, Atom attribute,
+ INT32 *value, pointer data)
+{
+ LLOGLN(0, ("xrdpVidGetPortAttribute:"));
+ return Success;
+}
+
+/*****************************************************************************/
+static void
+xrdpVidQueryBestSize(ScrnInfoPtr pScrn, Bool motion,
+ short vid_w, short vid_h, short drw_w, short drw_h,
+ unsigned int *p_w, unsigned int *p_h, pointer data)
+{
+ LLOGLN(0, ("xrdpVidQueryBestSize:"));
+}
+
+/*****************************************************************************/
+int
+YV12_to_RGB32(unsigned char *yuvs, int width, int height, int *rgbs)
+{
+ int size_total;
+ int y;
+ int u;
+ int v;
+ int c;
+ int d;
+ int e;
+ int r;
+ int g;
+ int b;
+ int t;
+ int i;
+ int j;
+
+ size_total = width * height;
+ for (j = 0; j < height; j++)
+ {
+ for (i = 0; i < width; i++)
+ {
+ y = yuvs[j * width + i];
+ u = yuvs[(j / 2) * (width / 2) + (i / 2) + size_total];
+ v = yuvs[(j / 2) * (width / 2) + (i / 2) + size_total + (size_total / 4)];
+ c = y - 16;
+ d = u - 128;
+ e = v - 128;
+ t = (298 * c + 409 * e + 128) >> 8;
+ b = RDPCLAMP(t, 0, 255);
+ t = (298 * c - 100 * d - 208 * e + 128) >> 8;
+ g = RDPCLAMP(t, 0, 255);
+ t = (298 * c + 516 * d + 128) >> 8;
+ r = RDPCLAMP(t, 0, 255);
+ rgbs[j * width + i] = (r << 16) | (g << 8) | b;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+int
+I420_to_RGB32(unsigned char *yuvs, int width, int height, int *rgbs)
+{
+ int size_total;
+ int y;
+ int u;
+ int v;
+ int c;
+ int d;
+ int e;
+ int r;
+ int g;
+ int b;
+ int t;
+ int i;
+ int j;
+
+ size_total = width * height;
+ for (j = 0; j < height; j++)
+ {
+ for (i = 0; i < width; i++)
+ {
+ y = yuvs[j * width + i];
+ v = yuvs[(j / 2) * (width / 2) + (i / 2) + size_total];
+ u = yuvs[(j / 2) * (width / 2) + (i / 2) + size_total + (size_total / 4)];
+ c = y - 16;
+ d = u - 128;
+ e = v - 128;
+ t = (298 * c + 409 * e + 128) >> 8;
+ b = RDPCLAMP(t, 0, 255);
+ t = (298 * c - 100 * d - 208 * e + 128) >> 8;
+ g = RDPCLAMP(t, 0, 255);
+ t = (298 * c + 516 * d + 128) >> 8;
+ r = RDPCLAMP(t, 0, 255);
+ rgbs[j * width + i] = (r << 16) | (g << 8) | b;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+int
+YUY2_to_RGB32(unsigned char *yuvs, int width, int height, int *rgbs)
+{
+ int y1;
+ int y2;
+ int u;
+ int v;
+ int c;
+ int d;
+ int e;
+ int r;
+ int g;
+ int b;
+ int t;
+ int i;
+ int j;
+
+ for (j = 0; j < height; j++)
+ {
+ for (i = 0; i < width; i++)
+ {
+ y1 = *(yuvs++);
+ v = *(yuvs++);
+ y2 = *(yuvs++);
+ u = *(yuvs++);
+
+ c = y1 - 16;
+ d = u - 128;
+ e = v - 128;
+ t = (298 * c + 409 * e + 128) >> 8;
+ b = RDPCLAMP(t, 0, 255);
+ t = (298 * c - 100 * d - 208 * e + 128) >> 8;
+ g = RDPCLAMP(t, 0, 255);
+ t = (298 * c + 516 * d + 128) >> 8;
+ r = RDPCLAMP(t, 0, 255);
+ rgbs[j * width + i] = (r << 16) | (g << 8) | b;
+
+ i++;
+ c = y2 - 16;
+ d = u - 128;
+ e = v - 128;
+ t = (298 * c + 409 * e + 128) >> 8;
+ b = RDPCLAMP(t, 0, 255);
+ t = (298 * c - 100 * d - 208 * e + 128) >> 8;
+ g = RDPCLAMP(t, 0, 255);
+ t = (298 * c + 516 * d + 128) >> 8;
+ r = RDPCLAMP(t, 0, 255);
+ rgbs[j * width + i] = (r << 16) | (g << 8) | b;
+ }
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+int
+UYVY_to_RGB32(unsigned char *yuvs, int width, int height, int *rgbs)
+{
+ int y1;
+ int y2;
+ int u;
+ int v;
+ int c;
+ int d;
+ int e;
+ int r;
+ int g;
+ int b;
+ int t;
+ int i;
+ int j;
+
+ for (j = 0; j < height; j++)
+ {
+ for (i = 0; i < width; i++)
+ {
+ v = *(yuvs++);
+ y1 = *(yuvs++);
+ u = *(yuvs++);
+ y2 = *(yuvs++);
+
+ c = y1 - 16;
+ d = u - 128;
+ e = v - 128;
+ t = (298 * c + 409 * e + 128) >> 8;
+ b = RDPCLAMP(t, 0, 255);
+ t = (298 * c - 100 * d - 208 * e + 128) >> 8;
+ g = RDPCLAMP(t, 0, 255);
+ t = (298 * c + 516 * d + 128) >> 8;
+ r = RDPCLAMP(t, 0, 255);
+ rgbs[j * width + i] = (r << 16) | (g << 8) | b;
+
+ i++;
+ c = y2 - 16;
+ d = u - 128;
+ e = v - 128;
+ t = (298 * c + 409 * e + 128) >> 8;
+ b = RDPCLAMP(t, 0, 255);
+ t = (298 * c - 100 * d - 208 * e + 128) >> 8;
+ g = RDPCLAMP(t, 0, 255);
+ t = (298 * c + 516 * d + 128) >> 8;
+ r = RDPCLAMP(t, 0, 255);
+ rgbs[j * width + i] = (r << 16) | (g << 8) | b;
+ }
+ }
+ return 0;
+}
+
+#if 0
+/*****************************************************************************/
+static int
+stretch_RGB32_RGB32(int *src, int src_width, int src_height,
+ int src_x, int src_y, int src_w, int src_h,
+ int *dst, int dst_w, int dst_h)
+{
+ int mwidth;
+ int mheight;
+ int index;
+
+ mwidth = RDPMIN(src_width, dst_w);
+ mheight = RDPMIN(src_height, dst_h);
+ for (index = 0; index < mheight; index++)
+ {
+ g_memcpy(dst, src, mwidth * 4);
+ src += src_width;
+ dst += dst_w;
+ }
+ return 0;
+}
+#endif
+
+/*****************************************************************************/
+static int
+stretch_RGB32_RGB32(int *src, int src_width, int src_height,
+ int src_x, int src_y, int src_w, int src_h,
+ int *dst, int dst_w, int dst_h)
+{
+ int index;
+ int jndex;
+ int lndex;
+ int last_lndex;
+ int oh;
+ int ih;
+ int ov;
+ int iv;
+ int pix;
+ int *src32;
+ int *dst32;
+
+ LLOGLN(10, ("stretch_RGB32_RGB32: oh 0x%8.8x ov 0x%8.8x", oh, ov));
+ oh = (src_w << 16) / dst_w;
+ ov = (src_h << 16) / dst_h;
+ iv = ov;
+ lndex = src_y;
+ last_lndex = -1;
+ for (index = 0; index < dst_h; index++)
+ {
+ if (lndex == last_lndex)
+ {
+ /* repeat line */
+ dst32 = dst + index * dst_w;
+ src32 = dst32 - dst_w;
+ g_memcpy(dst32, src32, dst_w * 4);
+ }
+ else
+ {
+ ih = oh;
+ src32 = src + lndex * src_width + src_x;
+ pix = *src32;
+ dst32 = dst + index * dst_w;
+ for (jndex = 0; jndex < dst_w; jndex++)
+ {
+ *dst32 = pix;
+ while (ih > (1 << 16) - 1)
+ {
+ ih -= 1 << 16;
+ src32++;
+ }
+ pix = *src32;
+ ih += oh;
+ dst32++;
+ }
+ }
+ last_lndex = lndex;
+ while (iv > (1 << 16) - 1)
+ {
+ iv -= 1 << 16;
+ lndex++;
+ }
+ iv += ov;
+
+ }
+ LLOGLN(10, ("stretch_RGB32_RGB32: out"));
+ return 0;
+}
+
+/******************************************************************************/
+/* returns error */
+static CARD32
+rdpDeferredXvCleanup(OsTimerPtr timer, CARD32 now, pointer arg)
+{
+ rdpPtr dev;
+
+ LLOGLN(0, ("rdpDeferredXvCleanup:"));
+ dev = (rdpPtr) arg;
+ dev->xv_timer_schedualed = 0;
+ dev->xv_data_bytes = 0;
+ g_free(dev->xv_data);
+ dev->xv_data = 0;
+ return 0;
+}
+
+/*****************************************************************************/
+/* see hw/xfree86/common/xf86xv.c for info */
+static int
+xrdpVidPutImage(ScrnInfoPtr pScrn,
+ short src_x, short src_y, short drw_x, short drw_y,
+ short src_w, short src_h, short drw_w, short drw_h,
+ int format, unsigned char* buf,
+ short width, short height,
+ Bool sync, RegionPtr clipBoxes,
+ pointer data, DrawablePtr dst)
+{
+ rdpPtr dev;
+ int *rgborg32;
+ int *rgbend32;
+ int index;
+ int error;
+ GCPtr tempGC;
+
+ LLOGLN(10, ("xrdpVidPutImage: format 0x%8.8x", format));
+ LLOGLN(10, ("xrdpVidPutImage: src_x %d srcy_y %d", src_x, src_y));
+ dev = XRDPPTR(pScrn);
+
+ if (dev->xv_timer_schedualed)
+ {
+ TimerCancel(dev->xv_timer);
+ dev->xv_timer = TimerSet(dev->xv_timer, 0, 2000,
+ rdpDeferredXvCleanup, dev);
+ }
+ else
+ {
+ dev->xv_timer_schedualed = 1;
+ dev->xv_timer = TimerSet(dev->xv_timer, 0, 2000,
+ rdpDeferredXvCleanup, dev);
+ }
+
+ index = width * height * 4 + drw_w * drw_h * 4 + 64;
+ if (index > dev->xv_data_bytes)
+ {
+ g_free(dev->xv_data);
+ dev->xv_data = g_malloc(index, 0);
+ if (dev->xv_data == NULL)
+ {
+ LLOGLN(0, ("xrdpVidPutImage: memory alloc error"));
+ dev->xv_data_bytes = 0;
+ return Success;
+ }
+ dev->xv_data_bytes = index;
+ }
+ rgborg32 = (int *) RDPALIGN(dev->xv_data, 16);
+ rgbend32 = rgborg32 + width * height;
+ rgbend32 = (int *) RDPALIGN(rgbend32, 16);
+ error = 0;
+ switch (format)
+ {
+ case FOURCC_YV12:
+ LLOGLN(10, ("xrdpVidPutImage: FOURCC_YV12"));
+ error = dev->yv12_to_rgb32(buf, width, height, rgborg32);
+ break;
+ case FOURCC_I420:
+ LLOGLN(10, ("xrdpVidPutImage: FOURCC_I420"));
+ error = dev->i420_to_rgb32(buf, width, height, rgborg32);
+ break;
+ case FOURCC_YUY2:
+ LLOGLN(10, ("xrdpVidPutImage: FOURCC_YUY2"));
+ error = dev->yuy2_to_rgb32(buf, width, height, rgborg32);
+ break;
+ case FOURCC_UYVY:
+ LLOGLN(10, ("xrdpVidPutImage: FOURCC_UYVY"));
+ error = dev->uyvy_to_rgb32(buf, width, height, rgborg32);
+ break;
+ default:
+ LLOGLN(0, ("xrdpVidPutImage: unknown format 0x%8.8x", format));
+ return Success;
+ }
+ if (error != 0)
+ {
+ return Success;
+ }
+ error = stretch_RGB32_RGB32(rgborg32, width, height,
+ src_x, src_y, src_w, src_h,
+ rgbend32, drw_w, drw_h);
+ if (error != 0)
+ {
+ return Success;
+ }
+
+ tempGC = GetScratchGC(dst->depth, pScrn->pScreen);
+ if (tempGC != NULL)
+ {
+ ValidateGC(dst, tempGC);
+ (*tempGC->ops->PutImage)(dst, tempGC, 24,
+ drw_x - dst->x, drw_y - dst->y,
+ drw_w, drw_h, 0, ZPixmap, (char*)rgbend32);
+ FreeScratchGC(tempGC);
+ }
+
+ return Success;
+}
+
+/*****************************************************************************/
+static int
+xrdpVidQueryImageAttributes(ScrnInfoPtr pScrn, int id,
+ unsigned short *w, unsigned short *h,
+ int *pitches, int *offsets)
+{
+ int size, tmp;
+
+ LLOGLN(10, ("xrdpVidQueryImageAttributes:"));
+ /* this is same code as all drivers currently have */
+ if (*w > 2046)
+ {
+ *w = 2046;
+ }
+ if (*h > 2046)
+ {
+ *h = 2046;
+ }
+ /* make w multiple of 4 so that resizing works properly */
+ *w = (*w + 3) & ~3;
+ if (offsets != NULL)
+ {
+ offsets[0] = 0;
+ }
+ switch (id)
+ {
+ case FOURCC_YV12:
+ case FOURCC_I420:
+ /* make h be even */
+ *h = (*h + 1) & ~1;
+ /* make w be multiple of 4 (ie. pad it) */
+ size = (*w + 3) & ~3;
+ /* width of a Y row => width of image */
+ if (pitches != NULL)
+ {
+ pitches[0] = size;
+ }
+ /* offset of U plane => w * h */
+ size *= *h;
+ if (offsets != NULL)
+ {
+ offsets[1] = size;
+ }
+ /* width of U, V row => width / 2 */
+ tmp = ((*w >> 1) + 3) & ~3;
+ if (pitches != NULL)
+ {
+ pitches[1] = pitches[2] = tmp;
+ }
+ /* offset of V => Y plane + U plane (w * h + w / 2 * h / 2) */
+ tmp *= (*h >> 1);
+ size += tmp;
+ if (offsets != NULL)
+ {
+ offsets[2] = size;
+ }
+ size += tmp;
+ break;
+ case FOURCC_YUY2:
+ case FOURCC_UYVY:
+ size = (*w) * 2;
+ if (pitches != NULL)
+ {
+ pitches[0] = size;
+ }
+ size *= *h;
+ break;
+ default:
+ LLOGLN(0, ("xrdpVidQueryImageAttributes: Unsupported image"));
+ return 0;
+ }
+ LLOGLN(10, ("xrdpVidQueryImageAttributes: finished size %d id 0x%x", size, id));
+ return size;
+}
+
+/*****************************************************************************/
+Bool
+rdpXvInit(ScreenPtr pScreen, ScrnInfoPtr pScrn)
+{
+ XF86VideoAdaptorPtr adaptor;
+ DevUnion* pDevUnion;
+ int bytes;
+
+ adaptor = xf86XVAllocateVideoAdaptorRec(pScrn);
+ if (adaptor == 0)
+ {
+ LLOGLN(0, ("rdpXvInit: xf86XVAllocateVideoAdaptorRec failed"));
+ return 0;
+ }
+ adaptor->type = XvInputMask | XvImageMask | XvVideoMask | XvStillMask | XvWindowMask | XvPixmapMask;
+ //adaptor->flags = VIDEO_NO_CLIPPING;
+ //adaptor->flags = VIDEO_CLIP_TO_VIEWPORT;
+ adaptor->flags = 0;
+ adaptor->name = XRDP_MODULE_NAME " XVideo Adaptor";
+ adaptor->nEncodings = T_NUM_ENCODINGS;
+ adaptor->pEncodings = &(g_xrdpVidEncodings[0]);
+ adaptor->nFormats = T_NUM_FORMATS;
+ adaptor->pFormats = &(g_xrdpVidFormats[0]);
+ adaptor->pFormats[0].depth = pScrn->depth;
+ LLOGLN(0, ("rdpXvInit: depth %d", pScrn->depth));
+ adaptor->nImages = sizeof(g_xrdpVidImages) / sizeof(XF86ImageRec);
+ adaptor->pImages = g_xrdpVidImages;
+ adaptor->nAttributes = 0;
+ adaptor->pAttributes = 0;
+ adaptor->nPorts = T_MAX_PORTS;
+ bytes = sizeof(DevUnion) * T_MAX_PORTS;
+ pDevUnion = (DevUnion*) g_malloc(bytes, 1);
+ adaptor->pPortPrivates = pDevUnion;
+ adaptor->PutVideo = xrdpVidPutVideo;
+ adaptor->PutStill = xrdpVidPutStill;
+ adaptor->GetVideo = xrdpVidGetVideo;
+ adaptor->GetStill = xrdpVidGetStill;
+ adaptor->StopVideo = xrdpVidStopVideo;
+ adaptor->SetPortAttribute = xrdpVidSetPortAttribute;
+ adaptor->GetPortAttribute = xrdpVidGetPortAttribute;
+ adaptor->QueryBestSize = xrdpVidQueryBestSize;
+ adaptor->PutImage = xrdpVidPutImage;
+ adaptor->QueryImageAttributes = xrdpVidQueryImageAttributes;
+ if (!xf86XVScreenInit(pScreen, &adaptor, 1))
+ {
+ LLOGLN(0, ("rdpXvInit: xf86XVScreenInit failed"));
+ return 0;
+ }
+ xf86XVFreeVideoAdaptorRec(adaptor);
+ return 1;
+}
+