summaryrefslogtreecommitdiff
path: root/src/libXvMC
diff options
context:
space:
mode:
authorYounes Manton <younes.m@gmail.com>2008-06-08 03:04:14 -0400
committerYounes Manton <younes.m@gmail.com>2008-06-08 03:04:14 -0400
commitc11a7ec821d41b91a3825c5abfb4687c98b5bf98 (patch)
treecca76bb6d30d3da0b6bd49a9dd1c61ea6feb3cf2 /src/libXvMC
parent996b549fdbfe772ee56a51858e81e93bccaae5c5 (diff)
Initial commit for g3dvl.
Initial commit for g3dvl, contains support for basic XvMC features. - Context, surface, block, macroblock creation and deletion - Surface rendering - Frame pictures - Frame based motion compensation - Intra-coded macroblocks - Predicted macroblocks - Bi-directionally predicted macroblocks - Surface display - Color conversion - Scaling
Diffstat (limited to 'src/libXvMC')
-rw-r--r--src/libXvMC/Makefile33
-rw-r--r--src/libXvMC/attributes.c20
-rw-r--r--src/libXvMC/block.c85
-rw-r--r--src/libXvMC/context.c154
-rw-r--r--src/libXvMC/subpicture.c110
-rw-r--r--src/libXvMC/surface.c373
-rw-r--r--src/libXvMC/tests/.gitignore5
-rw-r--r--src/libXvMC/tests/Makefile25
-rw-r--r--src/libXvMC/tests/test_blocks.c95
-rw-r--r--src/libXvMC/tests/test_context.c94
-rw-r--r--src/libXvMC/tests/test_rendering.c153
-rw-r--r--src/libXvMC/tests/test_surface.c72
-rw-r--r--src/libXvMC/tests/testlib.c87
-rw-r--r--src/libXvMC/tests/testlib.h38
14 files changed, 1344 insertions, 0 deletions
diff --git a/src/libXvMC/Makefile b/src/libXvMC/Makefile
new file mode 100644
index 0000000000..b2f41e176d
--- /dev/null
+++ b/src/libXvMC/Makefile
@@ -0,0 +1,33 @@
+TARGET = libXvMCg3dvl.so
+SONAME = libXvMCg3dvl.so.1
+GALLIUMDIR = ../gallium
+OBJECTS = block.o surface.o context.o subpicture.o attributes.o ${GALLIUMDIR}/winsys/g3dvl/xsp_winsys.o
+
+CFLAGS += -g -fPIC -Wall -Werror \
+ -I${GALLIUMDIR}/state_trackers/g3dvl \
+ -I${GALLIUMDIR}/winsys/g3dvl \
+ -I${GALLIUMDIR}/include \
+ -I${GALLIUMDIR}/auxiliary \
+ -I${GALLIUMDIR}/drivers
+LDFLAGS += -L${GALLIUMDIR}/state_trackers/g3dvl \
+ -L${GALLIUMDIR}/drivers/softpipe \
+ -L${GALLIUMDIR}/auxiliary/tgsi \
+ -L${GALLIUMDIR}/auxiliary/draw \
+ -L${GALLIUMDIR}/auxiliary/translate \
+ -L${GALLIUMDIR}/auxiliary/cso_cache \
+ -L${GALLIUMDIR}/auxiliary/util \
+ -L${GALLIUMDIR}/auxiliary/rtasm
+LIBS += -lg3dvl -lsoftpipe -ldraw -ltgsi -ltranslate -lrtasm -lcso_cache -lutil
+
+#############################################
+
+.PHONY = all clean
+
+all: ${TARGET}
+
+${TARGET}: ${OBJECTS}
+ $(CC) ${LDFLAGS} -shared -Wl,-soname,${SONAME} -o $@ $^ ${LIBS}
+
+clean:
+ rm -rf ${OBJECTS} ${TARGET}
+
diff --git a/src/libXvMC/attributes.c b/src/libXvMC/attributes.c
new file mode 100644
index 0000000000..674524b8b8
--- /dev/null
+++ b/src/libXvMC/attributes.c
@@ -0,0 +1,20 @@
+#include <assert.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xvlib.h>
+#include <X11/extensions/XvMC.h>
+
+XvAttribute* XvMCQueryAttributes(Display *display, XvMCContext *context, int *number)
+{
+ return NULL;
+}
+
+Status XvMCSetAttribute(Display *display, XvMCContext *context, Atom attribute, int value)
+{
+ return BadImplementation;
+}
+
+Status XvMCGetAttribute(Display *display, XvMCContext *context, Atom attribute, int *value)
+{
+ return BadImplementation;
+}
+
diff --git a/src/libXvMC/block.c b/src/libXvMC/block.c
new file mode 100644
index 0000000000..b56348d464
--- /dev/null
+++ b/src/libXvMC/block.c
@@ -0,0 +1,85 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XvMC.h>
+#include <vl_context.h>
+
+/*
+ * XvMC defines 64 element blocks (8x8 elements).
+ * Elements are 8 bits when they represent color values,
+ * 9 bits when they reprecent DCT coefficients, we
+ * store them in 2 bytes in either case. DCT coefficients
+ * can be signed or unsigned, at our option.
+ */
+#define BLOCK_SIZE (64 * 2)
+
+Status XvMCCreateBlocks(Display *display, XvMCContext *context, unsigned int num_blocks, XvMCBlockArray *blocks)
+{
+ struct vl_context *vl_ctx;
+
+ assert(display);
+
+ if (!context)
+ return XvMCBadContext;
+ if (num_blocks == 0)
+ return BadValue;
+
+ assert(blocks);
+
+ vl_ctx = context->privData;
+ assert(display == vl_ctx->display);
+
+ blocks->context_id = context->context_id;
+ blocks->num_blocks = num_blocks;
+ blocks->blocks = malloc(BLOCK_SIZE * num_blocks);
+ /* Since we don't have a VL type for blocks, set privData to the display so we can catch mismatches */
+ blocks->privData = display;
+
+ return Success;
+}
+
+Status XvMCDestroyBlocks(Display *display, XvMCBlockArray *blocks)
+{
+ assert(display);
+ assert(blocks);
+ assert(display == blocks->privData);
+ free(blocks->blocks);
+
+ return Success;
+}
+
+Status XvMCCreateMacroBlocks(Display *display, XvMCContext *context, unsigned int num_blocks, XvMCMacroBlockArray *blocks)
+{
+ struct vl_context *vl_ctx;
+
+ assert(display);
+
+ if (!context)
+ return XvMCBadContext;
+ if (num_blocks == 0)
+ return BadValue;
+
+ assert(blocks);
+
+ vl_ctx = context->privData;
+ assert(display == vl_ctx->display);
+
+ blocks->context_id = context->context_id;
+ blocks->num_blocks = num_blocks;
+ blocks->macro_blocks = malloc(sizeof(XvMCMacroBlock) * num_blocks);
+ /* Since we don't have a VL type for blocks, set privData to the display so we can catch mismatches */
+ blocks->privData = display;
+
+ return Success;
+}
+
+Status XvMCDestroyMacroBlocks(Display *display, XvMCMacroBlockArray *blocks)
+{
+ assert(display);
+ assert(blocks);
+ assert(display == blocks->privData);
+ free(blocks->macro_blocks);
+
+ return Success;
+}
+
diff --git a/src/libXvMC/context.c b/src/libXvMC/context.c
new file mode 100644
index 0000000000..c835a6acf7
--- /dev/null
+++ b/src/libXvMC/context.c
@@ -0,0 +1,154 @@
+#include <assert.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XvMClib.h>
+#include <vl_context.h>
+#include <xsp_winsys.h>
+
+static Status Validate(Display *display, XvPortID port, int surface_type_id, unsigned int width, unsigned int height, int flags, int *chroma_format)
+{
+ unsigned int found_port = 0;
+ unsigned int found_surface = 0;
+ XvAdaptorInfo *adaptor_info;
+ unsigned int num_adaptors;
+ int num_types;
+ unsigned int max_width, max_height;
+ Status ret;
+ unsigned int i, j, k;
+
+ assert(display && chroma_format);
+
+ ret = XvQueryAdaptors(display, XDefaultRootWindow(display), &num_adaptors, &adaptor_info);
+ if (ret != Success)
+ return ret;
+
+ /* Scan through all adaptors looking for this port and surface */
+ for (i = 0; i < num_adaptors && !found_port; ++i)
+ {
+ /* Scan through all ports of this adaptor looking for our port */
+ for (j = 0; j < adaptor_info[i].num_ports && !found_port; ++j)
+ {
+ /* If this is our port, scan through all its surfaces looking for our surface */
+ if (adaptor_info[i].base_id + j == port)
+ {
+ XvMCSurfaceInfo *surface_info;
+
+ found_port = 1;
+ surface_info = XvMCListSurfaceTypes(display, adaptor_info[i].base_id, &num_types);
+
+ if (surface_info)
+ {
+ for (k = 0; k < num_types && !found_surface; ++k)
+ {
+ if (surface_info[k].surface_type_id == surface_type_id)
+ {
+ found_surface = 1;
+ max_width = surface_info[k].max_width;
+ max_height = surface_info[k].max_height;
+ *chroma_format = surface_info[k].chroma_format;
+ }
+ }
+
+ XFree(surface_info);
+ }
+ else
+ {
+ XvFreeAdaptorInfo(adaptor_info);
+ return BadAlloc;
+ }
+ }
+ }
+ }
+
+ XvFreeAdaptorInfo(adaptor_info);
+
+ if (!found_port)
+ return XvBadPort;
+ if (!found_surface)
+ return BadMatch;
+ if (width > max_width || height > max_height)
+ return BadValue;
+ if (flags != XVMC_DIRECT && flags != 0)
+ return BadValue;
+
+ return Success;
+}
+
+static enum VL_FORMAT FormatToVL(int xvmc_format)
+{
+ enum VL_FORMAT vl_format;
+
+ switch (xvmc_format)
+ {
+ case XVMC_CHROMA_FORMAT_420:
+ {
+ vl_format = VL_FORMAT_YCBCR_420;
+ break;
+ }
+ case XVMC_CHROMA_FORMAT_422:
+ {
+ vl_format = VL_FORMAT_YCBCR_422;
+ break;
+ }
+ case XVMC_CHROMA_FORMAT_444:
+ {
+ vl_format = VL_FORMAT_YCBCR_444;
+ break;
+ }
+ default:
+ assert(0);
+ }
+
+ return vl_format;
+}
+
+Status XvMCCreateContext(Display *display, XvPortID port, int surface_type_id, int width, int height, int flags, XvMCContext *context)
+{
+ int chroma_format;
+ Status ret;
+ struct VL_CONTEXT *vl_ctx;
+ struct pipe_context *pipe;
+
+ assert(display);
+
+ if (!context)
+ return XvMCBadContext;
+
+ ret = Validate(display, port, surface_type_id, width, height, flags, &chroma_format);
+ if (ret != Success)
+ return ret;
+
+ pipe = create_pipe_context(display);
+
+ assert(pipe);
+
+ vlCreateContext(display, pipe, width, height, FormatToVL(chroma_format), &vl_ctx);
+
+ context->context_id = XAllocID(display);
+ context->surface_type_id = surface_type_id;
+ context->width = width;
+ context->height = height;
+ context->flags = flags;
+ context->port = port;
+ context->privData = vl_ctx;
+
+ return Success;
+}
+
+Status XvMCDestroyContext(Display *display, XvMCContext *context)
+{
+ struct VL_CONTEXT *vl_ctx;
+
+ assert(display);
+
+ if (!context)
+ return XvMCBadContext;
+
+ vl_ctx = context->privData;
+
+ assert(display == vl_ctx->display);
+
+ vlDestroyContext(vl_ctx);
+
+ return Success;
+}
+
diff --git a/src/libXvMC/subpicture.c b/src/libXvMC/subpicture.c
new file mode 100644
index 0000000000..38d9343833
--- /dev/null
+++ b/src/libXvMC/subpicture.c
@@ -0,0 +1,110 @@
+#include <assert.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/Xvlib.h>
+#include <X11/extensions/XvMC.h>
+
+Status XvMCCreateSubpicture
+(
+ Display *display,
+ XvMCContext *context,
+ XvMCSubpicture *subpicture,
+ unsigned short width,
+ unsigned short height,
+ int xvimage_id
+)
+{
+ return BadImplementation;
+}
+
+Status XvMCClearSubpicture
+(
+ Display *display,
+ XvMCSubpicture *subpicture,
+ short x,
+ short y,
+ unsigned short width,
+ unsigned short height,
+ unsigned int color
+)
+{
+ return BadImplementation;
+}
+
+Status XvMCCompositeSubpicture
+(
+ Display *display,
+ XvMCSubpicture *subpicture,
+ XvImage *image,
+ short srcx,
+ short srcy,
+ unsigned short width,
+ unsigned short height,
+ short dstx,
+ short dsty
+)
+{
+ return BadImplementation;
+}
+
+Status XvMCDestroySubpicture(Display *display, XvMCSubpicture *subpicture)
+{
+ return BadImplementation;
+}
+
+Status XvMCSetSubpicturePalette(Display *display, XvMCSubpicture *subpicture, unsigned char *palette)
+{
+ return BadImplementation;
+}
+
+Status XvMCBlendSubpicture
+(
+ Display *display,
+ XvMCSurface *target_surface,
+ XvMCSubpicture *subpicture,
+ short subx,
+ short suby,
+ unsigned short subw,
+ unsigned short subh,
+ short surfx,
+ short surfy,
+ unsigned short surfw,
+ unsigned short surfh
+)
+{
+ return BadImplementation;
+}
+
+Status XvMCBlendSubpicture2
+(
+ Display *display,
+ XvMCSurface *source_surface,
+ XvMCSurface *target_surface,
+ XvMCSubpicture *subpicture,
+ short subx,
+ short suby,
+ unsigned short subw,
+ unsigned short subh,
+ short surfx,
+ short surfy,
+ unsigned short surfw,
+ unsigned short surfh
+)
+{
+ return BadImplementation;
+}
+
+Status XvMCSyncSubpicture(Display *display, XvMCSubpicture *subpicture)
+{
+ return BadImplementation;
+}
+
+Status XvMCFlushSubpicture(Display *display, XvMCSubpicture *subpicture)
+{
+ return BadImplementation;
+}
+
+Status XvMCGetSubpictureStatus(Display *display, XvMCSubpicture *subpicture, int *status)
+{
+ return BadImplementation;
+}
+
diff --git a/src/libXvMC/surface.c b/src/libXvMC/surface.c
new file mode 100644
index 0000000000..e4602d8204
--- /dev/null
+++ b/src/libXvMC/surface.c
@@ -0,0 +1,373 @@
+#include <assert.h>
+#include <X11/Xlib.h>
+#include <X11/extensions/XvMC.h>
+#include <vl_context.h>
+#include <vl_surface.h>
+
+static enum VL_PICTURE PictureToVL(int xvmc_pic)
+{
+ enum VL_PICTURE vl_pic;
+
+ switch (xvmc_pic)
+ {
+ case XVMC_TOP_FIELD:
+ {
+ vl_pic = VL_TOP_FIELD;
+ break;
+ }
+ case XVMC_BOTTOM_FIELD:
+ {
+ vl_pic = VL_BOTTOM_FIELD;
+ break;
+ }
+ case XVMC_FRAME_PICTURE:
+ {
+ vl_pic = VL_FRAME_PICTURE;
+ break;
+ }
+ default:
+ assert(0);
+ }
+
+ return vl_pic;
+}
+
+Status XvMCCreateSurface(Display *display, XvMCContext *context, XvMCSurface *surface)
+{
+ struct VL_CONTEXT *vl_ctx;
+ struct VL_SURFACE *vl_sfc;
+
+ assert(display);
+
+ if (!context)
+ return XvMCBadContext;
+ if (!surface)
+ return XvMCBadSurface;
+
+ vl_ctx = context->privData;
+
+ assert(display == vl_ctx->display);
+
+ vlCreateSurface(vl_ctx, &vl_sfc);
+
+ surface->surface_id = XAllocID(display);
+ surface->context_id = context->context_id;
+ surface->surface_type_id = context->surface_type_id;
+ surface->width = context->width;
+ surface->height = context->height;
+ surface->privData = vl_sfc;
+
+ return Success;
+}
+
+Status XvMCRenderSurface
+(
+ Display *display,
+ XvMCContext *context,
+ unsigned int picture_structure,
+ XvMCSurface *target_surface,
+ XvMCSurface *past_surface,
+ XvMCSurface *future_surface,
+ unsigned int flags,
+ unsigned int num_macroblocks,
+ unsigned int first_macroblock,
+ XvMCMacroBlockArray *macroblocks,
+ XvMCBlockArray *blocks
+)
+{
+ struct VL_CONTEXT *vl_ctx;
+ struct VL_SURFACE *target_vl_surface;
+ struct VL_SURFACE *past_vl_surface;
+ struct VL_SURFACE *future_vl_surface;
+ unsigned int i;
+
+ assert(display);
+
+ if (!context)
+ return XvMCBadContext;
+ if (!target_surface)
+ return XvMCBadSurface;
+
+ if
+ (
+ picture_structure != XVMC_TOP_FIELD &&
+ picture_structure != XVMC_BOTTOM_FIELD &&
+ picture_structure != XVMC_FRAME_PICTURE
+ )
+ return BadValue;
+ if (future_surface && !past_surface)
+ return BadMatch;
+
+ vl_ctx = context->privData;
+
+ assert(display == vl_ctx->display);
+
+ target_vl_surface = target_surface->privData;
+ past_vl_surface = past_surface ? past_surface->privData : NULL;
+ future_vl_surface = future_surface ? future_surface->privData : NULL;
+
+ assert(vl_ctx == target_vl_surface->context);
+ assert(!past_vl_surface || vl_ctx == past_vl_surface->context);
+ assert(!future_vl_surface || vl_ctx == future_vl_surface->context);
+
+ assert(macroblocks);
+ assert(blocks);
+
+ assert(macroblocks->context_id == context->context_id);
+ assert(blocks->context_id == context->context_id);
+
+ assert(flags == 0 || flags == XVMC_SECOND_FIELD);
+
+ for (i = first_macroblock; i < first_macroblock + num_macroblocks; ++i)
+ if (macroblocks->macro_blocks[i].macroblock_type & XVMC_MB_TYPE_INTRA)
+ vlRenderIMacroBlock
+ (
+ PictureToVL(picture_structure),
+ flags == XVMC_SECOND_FIELD ? VL_FIELD_SECOND : VL_FIELD_FIRST,
+ macroblocks->macro_blocks[i].x,
+ macroblocks->macro_blocks[i].y,
+ macroblocks->macro_blocks[i].coded_block_pattern,
+ macroblocks->macro_blocks[i].dct_type == XVMC_DCT_TYPE_FIELD ? VL_DCT_FIELD_CODED : VL_DCT_FRAME_CODED,
+ blocks->blocks + (macroblocks->macro_blocks[i].index * 64),
+ target_vl_surface
+ );
+ else if
+ (
+ (macroblocks->macro_blocks[i].macroblock_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD))
+ == XVMC_MB_TYPE_MOTION_FORWARD
+ )
+ {
+ struct VL_MOTION_VECTOR motion_vector =
+ {
+ {
+ macroblocks->macro_blocks[i].PMV[0][0][0],
+ macroblocks->macro_blocks[i].PMV[0][0][1],
+ },
+ {
+ macroblocks->macro_blocks[i].PMV[1][0][0],
+ macroblocks->macro_blocks[i].PMV[1][0][1],
+ }
+ };
+
+ vlRenderPMacroBlock
+ (
+ PictureToVL(picture_structure),
+ flags == XVMC_SECOND_FIELD ? VL_FIELD_SECOND : VL_FIELD_FIRST,
+ macroblocks->macro_blocks[i].x,
+ macroblocks->macro_blocks[i].y,
+ macroblocks->macro_blocks[i].motion_type == XVMC_PREDICTION_FRAME ? VL_FIELD_MC : VL_FRAME_MC,
+ &motion_vector,
+ macroblocks->macro_blocks[i].coded_block_pattern,
+ macroblocks->macro_blocks[i].dct_type == XVMC_DCT_TYPE_FIELD ? VL_DCT_FIELD_CODED : VL_DCT_FRAME_CODED,
+ blocks->blocks + (macroblocks->macro_blocks[i].index * 64),
+ past_vl_surface,
+ target_vl_surface
+ );
+ }
+ else if
+ (
+ (macroblocks->macro_blocks[i].macroblock_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD))
+ == XVMC_MB_TYPE_MOTION_BACKWARD
+ )
+ {
+ struct VL_MOTION_VECTOR motion_vector =
+ {
+ {
+ macroblocks->macro_blocks[i].PMV[0][1][0],
+ macroblocks->macro_blocks[i].PMV[0][1][1],
+ },
+ {
+ macroblocks->macro_blocks[i].PMV[1][1][0],
+ macroblocks->macro_blocks[i].PMV[1][1][1],
+ }
+ };
+
+ vlRenderPMacroBlock
+ (
+ PictureToVL(picture_structure),
+ flags == XVMC_SECOND_FIELD ? VL_FIELD_SECOND : VL_FIELD_FIRST,
+ macroblocks->macro_blocks[i].x,
+ macroblocks->macro_blocks[i].y,
+ macroblocks->macro_blocks[i].motion_type == XVMC_PREDICTION_FRAME ? VL_FIELD_MC : VL_FRAME_MC,
+ &motion_vector,
+ macroblocks->macro_blocks[i].coded_block_pattern,
+ macroblocks->macro_blocks[i].dct_type == XVMC_DCT_TYPE_FIELD ? VL_DCT_FIELD_CODED : VL_DCT_FRAME_CODED,
+ blocks->blocks + (macroblocks->macro_blocks[i].index * 64),
+ future_vl_surface,
+ target_vl_surface
+ );
+ }
+ else if
+ (
+ (macroblocks->macro_blocks[i].macroblock_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD))
+ == (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)
+ )
+ {
+ struct VL_MOTION_VECTOR motion_vector[2] =
+ {
+ {
+ {
+ macroblocks->macro_blocks[i].PMV[0][0][0],
+ macroblocks->macro_blocks[i].PMV[0][0][1],
+ },
+ {
+ macroblocks->macro_blocks[i].PMV[1][0][0],
+ macroblocks->macro_blocks[i].PMV[1][0][1],
+ }
+ },
+ {
+ {
+ macroblocks->macro_blocks[i].PMV[0][1][0],
+ macroblocks->macro_blocks[i].PMV[0][1][1],
+ },
+ {
+ macroblocks->macro_blocks[i].PMV[1][1][0],
+ macroblocks->macro_blocks[i].PMV[1][1][1],
+ }
+ }
+ };
+
+ vlRenderBMacroBlock
+ (
+ PictureToVL(picture_structure),
+ flags == XVMC_SECOND_FIELD ? VL_FIELD_SECOND : VL_FIELD_FIRST,
+ macroblocks->macro_blocks[i].x,
+ macroblocks->macro_blocks[i].y,
+ macroblocks->macro_blocks[i].motion_type == XVMC_PREDICTION_FRAME ? VL_FIELD_MC : VL_FRAME_MC,
+ motion_vector,
+ macroblocks->macro_blocks[i].coded_block_pattern,
+ macroblocks->macro_blocks[i].dct_type == XVMC_DCT_TYPE_FIELD ? VL_DCT_FIELD_CODED : VL_DCT_FRAME_CODED,
+ blocks->blocks + (macroblocks->macro_blocks[i].index * 64),
+ past_vl_surface,
+ future_vl_surface,
+ target_vl_surface
+ );
+ }
+ else
+ fprintf(stderr, "Unrecognized macroblock\n");
+
+ return Success;
+}
+
+Status XvMCFlushSurface(Display *display, XvMCSurface *surface)
+{
+ /* TODO: Check display & surface match */
+ return BadImplementation;
+}
+
+Status XvMCSyncSurface(Display *display, XvMCSurface *surface)
+{
+ /* TODO: Check display & surface match */
+ return BadImplementation;
+}
+
+Status XvMCPutSurface
+(
+ Display *display,
+ XvMCSurface *surface,
+ Drawable drawable,
+ short srcx,
+ short srcy,
+ unsigned short srcw,
+ unsigned short srch,
+ short destx,
+ short desty,
+ unsigned short destw,
+ unsigned short desth,
+ int flags
+)
+{
+ Window root;
+ int x, y;
+ unsigned int width, height;
+ unsigned int border_width;
+ unsigned int depth;
+ struct VL_SURFACE *vl_sfc;
+
+ assert(display);
+
+ if (!surface)
+ return XvMCBadSurface;
+
+ if (XGetGeometry(display, drawable, &root, &x, &y, &width, &height, &border_width, &depth) == BadDrawable)
+ return BadDrawable;
+
+ assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE);
+
+ /* TODO: Correct for negative srcx,srcy & destx,desty by clipping */
+
+ assert(srcx + srcw - 1 < surface->width);
+ assert(srcy + srch - 1 < surface->height);
+ assert(destx + destw - 1 < width);
+ assert(desty + desth - 1 < height);
+
+ vl_sfc = surface->privData;
+
+ vlPutSurface(vl_sfc, drawable, srcx, srcy, srcw, srch, destx, desty, destw, desth, PictureToVL(flags));
+
+ return Success;
+}
+
+Status XvMCGetSurfaceStatus(Display *display, XvMCSurface *surface, int *status)
+{
+ struct VL_CONTEXT *vl_ctx;
+ struct VL_SURFACE *vl_sfc;
+
+ assert(display);
+
+ if (!surface)
+ return XvMCBadSurface;
+
+ assert(status);
+
+ vl_sfc = surface->privData;
+ vl_ctx = vl_sfc->context;
+
+ assert(display == vl_ctx->display);
+
+ /* TODO */
+ *status = 0;
+
+ return BadImplementation;
+}
+
+Status XvMCDestroySurface(Display *display, XvMCSurface *surface)
+{
+ struct VL_CONTEXT *vl_ctx;
+ struct VL_SURFACE *vl_sfc;
+
+ assert(display);
+
+ if (!surface)
+ return XvMCBadSurface;
+
+ vl_sfc = surface->privData;
+ vl_ctx = vl_sfc->context;
+
+ assert(display == vl_ctx->display);
+
+ vlDestroySurface(vl_sfc);
+
+ return Success;
+}
+
+Status XvMCHideSurface(Display *display, XvMCSurface *surface)
+{
+ struct VL_CONTEXT *vl_ctx;
+ struct VL_SURFACE *vl_sfc;
+
+ assert(display);
+
+ if (!surface)
+ return XvMCBadSurface;
+
+ vl_sfc = surface->privData;
+ vl_ctx = vl_sfc->context;
+
+ assert(display == vl_ctx->display);
+
+ /* No op, only for overlaid rendering */
+
+ return Success;
+}
+
diff --git a/src/libXvMC/tests/.gitignore b/src/libXvMC/tests/.gitignore
new file mode 100644
index 0000000000..eb1ef8a076
--- /dev/null
+++ b/src/libXvMC/tests/.gitignore
@@ -0,0 +1,5 @@
+test_context
+test_surface
+test_blocks
+test_rendering
+
diff --git a/src/libXvMC/tests/Makefile b/src/libXvMC/tests/Makefile
new file mode 100644
index 0000000000..2cbc97e88b
--- /dev/null
+++ b/src/libXvMC/tests/Makefile
@@ -0,0 +1,25 @@
+CFLAGS += -g -Wall -Werror
+LDFLAGS +=
+LIBS += -lXvMCW -lXvMC -lXv
+
+#############################################
+
+.PHONY = all clean
+
+all: test_context test_surface test_blocks test_rendering
+
+test_context: test_context.o testlib.o
+ $(CC) ${LDFLAGS} -o $@ $^ ${LIBS}
+
+test_surface: test_surface.o testlib.o
+ $(CC) ${LDFLAGS} -o $@ $^ ${LIBS}
+
+test_blocks: test_blocks.o testlib.o
+ $(CC) ${LDFLAGS} -o $@ $^ ${LIBS}
+
+test_rendering: test_rendering.o testlib.o
+ $(CC) ${LDFLAGS} -o $@ $^ ${LIBS}
+
+clean:
+ rm -rf *.o test_context test_surface test_blocks test_rendering
+
diff --git a/src/libXvMC/tests/test_blocks.c b/src/libXvMC/tests/test_blocks.c
new file mode 100644
index 0000000000..0b895ee773
--- /dev/null
+++ b/src/libXvMC/tests/test_blocks.c
@@ -0,0 +1,95 @@
+#include <assert.h>
+#include <error.h>
+#include "testlib.h"
+
+int main(int argc, char **argv)
+{
+ const unsigned int width = 16, height = 16;
+ const unsigned int min_required_blocks = 1, min_required_macroblocks = 1;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+
+ Display *display;
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context;
+ XvMCSurface surface;
+ XvMCBlockArray blocks = {0};
+ XvMCMacroBlockArray macroblocks = {0};
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ width,
+ height,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success);
+ assert(XvMCCreateSurface(display, &context, &surface) == Success);
+
+ /* Test NULL context */
+ assert(XvMCCreateBlocks(display, NULL, 1, &blocks) == XvMCBadContext);
+ /* Test 0 blocks */
+ assert(XvMCCreateBlocks(display, &context, 0, &blocks) == BadValue);
+ /* Test too many blocks */
+ /*assert(XvMCCreateBlocks(display, &context, 16384, &blocks) == BadAlloc);*/
+
+ /* Note: No XvMCBadBlock(s) error in spec */
+
+ /* Test valid params */
+ assert(XvMCCreateBlocks(display, &context, min_required_blocks, &blocks) == Success);
+ /* Test context id assigned and correct */
+ assert(blocks.context_id == context.context_id);
+ /* Test number of blocks assigned and correct */
+ assert(blocks.num_blocks == min_required_blocks);
+ /* Test block pointer valid */
+ assert(blocks.blocks != NULL);
+ /* Test NULL context */
+ assert(XvMCCreateMacroBlocks(display, NULL, 1, &macroblocks) == XvMCBadContext);
+ /* Test 0 macroblocks */
+ assert(XvMCCreateMacroBlocks(display, &context, 0, &macroblocks) == BadValue);
+ /* Test too many macroblocks */
+ /*assert(XvMCCreateMacroBlocks(display, &context, 16384, &macroblocks) == BadAlloc);*/
+
+ /* Note: No XvMCBadMacroBlock(s) error in spec */
+
+ /* Test valid params */
+ assert(XvMCCreateMacroBlocks(display, &context, min_required_macroblocks, &macroblocks) == Success);
+ /* Test context id assigned and correct */
+ assert(macroblocks.context_id == context.context_id);
+ /* Test macroblock pointer valid */
+ assert(macroblocks.macro_blocks != NULL);
+ /* Test valid params */
+ assert(XvMCDestroyMacroBlocks(display, &macroblocks) == Success);
+ /* Test valid params */
+ assert(XvMCDestroyBlocks(display, &blocks) == Success);
+
+ assert(XvMCDestroySurface(display, &surface) == Success);
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XvUngrabPort(display, port_num, CurrentTime);
+ XCloseDisplay(display);
+
+ return 0;
+}
+
diff --git a/src/libXvMC/tests/test_context.c b/src/libXvMC/tests/test_context.c
new file mode 100644
index 0000000000..22afb7ada4
--- /dev/null
+++ b/src/libXvMC/tests/test_context.c
@@ -0,0 +1,94 @@
+#include <assert.h>
+#include <error.h>
+#include "testlib.h"
+
+int main(int argc, char **argv)
+{
+ const unsigned int width = 16, height = 16;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+
+ Display *display;
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context = {0};
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ width,
+ height,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ /* Note: XvMCBadContext not a valid return for XvMCCreateContext in the XvMC API, but openChrome driver returns it */
+ /* Note: Nvidia binary driver segfaults on NULL context, halts with debug output on bad port */
+
+ /* Test NULL context */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, NULL) == XvMCBadContext);
+ /* Test invalid port */
+ assert(XvMCCreateContext(display, port_num + 1, surface_type_id, width, height, XVMC_DIRECT, &context) == XvBadPort);
+ /* Test invalid surface */
+ assert(XvMCCreateContext(display, port_num, surface_type_id + 1, width, height, XVMC_DIRECT, &context) == BadMatch);
+ /* Test invalid flags */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, -1, &context) == BadValue);
+ /* Test huge width */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, 16384, height, XVMC_DIRECT, &context) == BadValue);
+ /* Test huge height */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, 16384, XVMC_DIRECT, &context) == BadValue);
+ /* Test huge width & height */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, 16384, 16384, XVMC_DIRECT, &context) == BadValue);
+ /* Test valid params */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success);
+ /* Test context id assigned */
+ assert(context.context_id != 0);
+ /* Test surface type id assigned and correct */
+ assert(context.surface_type_id == surface_type_id);
+ /* Test width & height assigned and correct */
+ assert(context.width == width && context.height == height);
+ /* Test port assigned and correct */
+ assert(context.port == port_num);
+ /* Test flags assigned and correct */
+ assert(context.flags == XVMC_DIRECT);
+ /* Test NULL context */
+ assert(XvMCDestroyContext(display, NULL) == XvMCBadContext);
+ /* Test valid params */
+ assert(XvMCDestroyContext(display, &context) == Success);
+ /* Test awkward but valid width */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width + 1, height, XVMC_DIRECT, &context) == Success);
+ assert(context.width >= width + 1);
+ assert(XvMCDestroyContext(display, &context) == Success);
+ /* Test awkward but valid height */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height + 1, XVMC_DIRECT, &context) == Success);
+ assert(context.height >= height + 1);
+ assert(XvMCDestroyContext(display, &context) == Success);
+ /* Test awkward but valid width & height */
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width + 1, height + 1, XVMC_DIRECT, &context) == Success);
+ assert(context.width >= width + 1 && context.height >= height + 1);
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XvUngrabPort(display, port_num, CurrentTime);
+ XCloseDisplay(display);
+
+ return 0;
+}
+
diff --git a/src/libXvMC/tests/test_rendering.c b/src/libXvMC/tests/test_rendering.c
new file mode 100644
index 0000000000..1914b1fb62
--- /dev/null
+++ b/src/libXvMC/tests/test_rendering.c
@@ -0,0 +1,153 @@
+#include <assert.h>
+#include <stdio.h>
+#include <error.h>
+#include "testlib.h"
+
+int main(int argc, char **argv)
+{
+ const unsigned int width = 32, height = 32;
+ const unsigned int mwidth = width / 16, mheight = height / 16;
+ const unsigned int num_macroblocks = mwidth * mheight;
+ const unsigned int num_blocks = num_macroblocks * 6;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+
+ int quit = 0;
+ Display *display;
+ Window root, window;
+ Pixmap framebuffer;
+ XEvent event;
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context;
+ XvMCSurface surface;
+ XvMCBlockArray blocks;
+ XvMCMacroBlockArray macroblocks;
+ unsigned int b, x, y;
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ width,
+ height,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ root = XDefaultRootWindow(display);
+ window = XCreateSimpleWindow(display, root, 0, 0, width, height, 0, 0, colorkey);
+ framebuffer = XCreatePixmap(display, root, width, height, 24);
+
+ XSelectInput(display, window, ExposureMask | KeyPressMask);
+ XMapWindow(display, window);
+ XSync(display, 0);
+
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success);
+ assert(XvMCCreateSurface(display, &context, &surface) == Success);
+ assert(XvMCCreateBlocks(display, &context, num_blocks, &blocks) == Success);
+ assert(XvMCCreateMacroBlocks(display, &context, num_macroblocks, &macroblocks) == Success);
+
+ for (b = 0; b < 6; ++b)
+ {
+ for (y = 0; y < 8; ++y)
+ {
+ for (x = 0; x < 8; ++x)
+ {
+ blocks.blocks[b * 64 + y * 8 + x] = 0xFFFF;
+ }
+ }
+ }
+
+ for (y = 0; y < mheight; ++y)
+ {
+ for (x = 0; x < mwidth; ++x)
+ {
+ macroblocks.macro_blocks[y * mwidth + x].x = x;
+ macroblocks.macro_blocks[y * mwidth + x].y = y;
+ macroblocks.macro_blocks[y * mwidth + x].index = (y * mwidth + x) * 6;
+ macroblocks.macro_blocks[y * mwidth + x].macroblock_type = XVMC_MB_TYPE_INTRA;
+ macroblocks.macro_blocks[y * mwidth + x].coded_block_pattern = 0x3F;
+ macroblocks.macro_blocks[y * mwidth + x].dct_type = XVMC_DCT_TYPE_FRAME;
+ }
+ }
+
+ /* Test NULL context */
+ assert(XvMCRenderSurface(display, NULL, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, 1, 0, &macroblocks, &blocks) == XvMCBadContext);
+ /* Test NULL surface */
+ assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, NULL, NULL, NULL, 0, 1, 0, &macroblocks, &blocks) == XvMCBadSurface);
+ /* Test bad picture structure */
+ assert(XvMCRenderSurface(display, &context, 0, &surface, NULL, NULL, 0, 1, 0, &macroblocks, &blocks) == BadValue);
+ /* Test valid params */
+ assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, num_macroblocks, 0, &macroblocks, &blocks) == Success);
+
+ /* Test NULL surface */
+ assert(XvMCPutSurface(display, NULL, window, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == XvMCBadSurface);
+ /* Test bad window */
+ /* X halts with a bad drawable for some reason, doesn't return BadDrawable as expected */
+ /*assert(XvMCPutSurface(display, &surface, 0, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == BadDrawable);*/
+ /* Test valid params */
+ assert(XvMCPutSurface(display, &surface, framebuffer, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == Success);
+
+ puts("Press any key to continue...");
+
+ while (!quit)
+ {
+ XNextEvent(display, &event);
+ switch (event.type)
+ {
+ case Expose:
+ {
+ XCopyArea
+ (
+ display,
+ framebuffer,
+ window,
+ XDefaultGC(display, XDefaultScreen(display)),
+ 0,
+ 0,
+ width,
+ height,
+ 0,
+ 0
+ );
+ break;
+ }
+ case KeyPress:
+ {
+ quit = 1;
+ break;
+ }
+ }
+ }
+
+ assert(XvMCDestroyBlocks(display, &blocks) == Success);
+ assert(XvMCDestroyMacroBlocks(display, &macroblocks) == Success);
+ assert(XvMCDestroySurface(display, &surface) == Success);
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XFreePixmap(display, framebuffer);
+ XvUngrabPort(display, port_num, CurrentTime);
+ XDestroyWindow(display, window);
+ XCloseDisplay(display);
+
+ return 0;
+}
+
diff --git a/src/libXvMC/tests/test_surface.c b/src/libXvMC/tests/test_surface.c
new file mode 100644
index 0000000000..25ebdcc4fc
--- /dev/null
+++ b/src/libXvMC/tests/test_surface.c
@@ -0,0 +1,72 @@
+#include <assert.h>
+#include <error.h>
+#include "testlib.h"
+
+int main(int argc, char **argv)
+{
+ const unsigned int width = 16, height = 16;
+ const unsigned int mc_types[2] = {XVMC_MOCOMP | XVMC_MPEG_2, XVMC_IDCT | XVMC_MPEG_2};
+
+ Display *display;
+ XvPortID port_num;
+ int surface_type_id;
+ unsigned int is_overlay, intra_unsigned;
+ int colorkey;
+ XvMCContext context;
+ XvMCSurface surface = {0};
+
+ display = XOpenDisplay(NULL);
+
+ if (!GetPort
+ (
+ display,
+ width,
+ height,
+ XVMC_CHROMA_FORMAT_420,
+ mc_types,
+ 2,
+ &port_num,
+ &surface_type_id,
+ &is_overlay,
+ &intra_unsigned
+ ))
+ {
+ XCloseDisplay(display);
+ error(1, 0, "Error, unable to find a good port.\n");
+ }
+
+ if (is_overlay)
+ {
+ Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
+ XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
+ }
+
+ assert(XvMCCreateContext(display, port_num, surface_type_id, width, height, XVMC_DIRECT, &context) == Success);
+
+ /* Test NULL context */
+ assert(XvMCCreateSurface(display, NULL, &surface) == XvMCBadContext);
+ /* Test NULL surface */
+ assert(XvMCCreateSurface(display, &context, NULL) == XvMCBadSurface);
+ /* Test valid params */
+ assert(XvMCCreateSurface(display, &context, &surface) == Success);
+ /* Test surface id assigned */
+ assert(surface.surface_id != 0);
+ /* Test context id assigned and correct */
+ assert(surface.context_id == context.context_id);
+ /* Test surface type id assigned and correct */
+ assert(surface.surface_type_id == surface_type_id);
+ /* Test width & height assigned and correct */
+ assert(surface.width == width && surface.height == height);
+ /* Test valid params */
+ assert(XvMCDestroySurface(display, &surface) == Success);
+ /* Test NULL surface */
+ assert(XvMCDestroySurface(display, NULL) == XvMCBadSurface);
+
+ assert(XvMCDestroyContext(display, &context) == Success);
+
+ XvUngrabPort(display, port_num, CurrentTime);
+ XCloseDisplay(display);
+
+ return 0;
+}
+
diff --git a/src/libXvMC/tests/testlib.c b/src/libXvMC/tests/testlib.c
new file mode 100644
index 0000000000..8672aa9999
--- /dev/null
+++ b/src/libXvMC/tests/testlib.c
@@ -0,0 +1,87 @@
+#include "testlib.h"
+#include <stdio.h>
+
+/*
+void test(int pred, const char *pred_string, const char *doc_string, const char *file, unsigned int line)
+{
+ fputs(doc_string, stderr);
+ if (!pred)
+ fprintf(stderr, " FAIL!\n\t\"%s\" at %s:%u\n", pred_string, file, line);
+ else
+ fputs(" PASS!\n", stderr);
+}
+*/
+
+int GetPort
+(
+ Display *display,
+ unsigned int width,
+ unsigned int height,
+ unsigned int chroma_format,
+ const unsigned int *mc_types,
+ unsigned int num_mc_types,
+ XvPortID *port_id,
+ int *surface_type_id,
+ unsigned int *is_overlay,
+ unsigned int *intra_unsigned
+)
+{
+ unsigned int found_port = 0;
+ XvAdaptorInfo *adaptor_info;
+ unsigned int num_adaptors;
+ int num_types;
+ int ev_base, err_base;
+ unsigned int i, j, k, l;
+
+ if (!XvMCQueryExtension(display, &ev_base, &err_base))
+ return 0;
+ if (XvQueryAdaptors(display, XDefaultRootWindow(display), &num_adaptors, &adaptor_info) != Success)
+ return 0;
+
+ for (i = 0; i < num_adaptors && !found_port; ++i)
+ {
+ if (adaptor_info[i].type & XvImageMask)
+ {
+ XvMCSurfaceInfo *surface_info = XvMCListSurfaceTypes(display, adaptor_info[i].base_id, &num_types);
+
+ if (surface_info)
+ {
+ for (j = 0; j < num_types && !found_port; ++j)
+ {
+ if
+ (
+ surface_info[j].chroma_format == chroma_format &&
+ surface_info[j].max_width >= width &&
+ surface_info[j].max_height >= height
+ )
+ {
+ for (k = 0; k < num_mc_types && !found_port; ++k)
+ {
+ if (surface_info[j].mc_type == mc_types[k])
+ {
+ for (l = 0; l < adaptor_info[i].num_ports && !found_port; ++l)
+ {
+ if (XvGrabPort(display, adaptor_info[i].base_id + l, CurrentTime) == Success)
+ {
+ *port_id = adaptor_info[i].base_id + l;
+ *surface_type_id = surface_info[j].surface_type_id;
+ *is_overlay = surface_info[j].flags & XVMC_OVERLAID_SURFACE;
+ *intra_unsigned = surface_info[j].flags & XVMC_INTRA_UNSIGNED;
+ found_port = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ XFree(surface_info);
+ }
+ }
+ }
+
+ XvFreeAdaptorInfo(adaptor_info);
+
+ return found_port;
+}
+
diff --git a/src/libXvMC/tests/testlib.h b/src/libXvMC/tests/testlib.h
new file mode 100644
index 0000000000..c73845807e
--- /dev/null
+++ b/src/libXvMC/tests/testlib.h
@@ -0,0 +1,38 @@
+#ifndef testlib_h
+#define testlib_h
+
+/*
+#define TEST(pred, doc) test(pred, #pred, doc, __FILE__, __LINE__)
+
+void test(int pred, const char *pred_string, const char *doc_string, const char *file, unsigned int line);
+*/
+
+#include <X11/Xlib.h>
+#include <X11/extensions/XvMClib.h>
+
+/*
+ * display: IN A valid X display
+ * width, height: IN Surface size that the port must display
+ * chroma_format: IN Chroma format that the port must display
+ * mc_types, num_mc_types: IN List of MC types that the port must support, first port that matches the first mc_type will be returned
+ * port_id: OUT Your port's ID
+ * surface_type_id: OUT Your port's surface ID
+ * is_overlay: OUT If 1, port uses overlay surfaces, you need to set a colorkey
+ * intra_unsigned: OUT If 1, port uses unsigned values for intra-coded blocks
+ */
+int GetPort
+(
+ Display *display,
+ unsigned int width,
+ unsigned int height,
+ unsigned int chroma_format,
+ const unsigned int *mc_types,
+ unsigned int num_mc_types,
+ XvPortID *port_id,
+ int *surface_type_id,
+ unsigned int *is_overlay,
+ unsigned int *intra_unsigned
+);
+
+#endif
+