Implement prototype of test application for xv. 50/28950/2
authorAndrii Sokolenko <a.sokolenko@samsung.com>
Fri, 17 Oct 2014 11:42:28 +0000 (14:42 +0300)
committerAndrii Sokolenko <a.sokolenko@samsung.com>
Fri, 17 Oct 2014 11:45:45 +0000 (14:45 +0300)
Change-Id: I36c82c85cf7cf0d01210ab0d53a543ef0e8a8c43

12 files changed:
Makefile.am
configure.ac
tests/functional/Makefile.am [new file with mode: 0644]
tests/functional/xv_test/Makefile.am [new file with mode: 0644]
tests/functional/xv_test/data.c [new file with mode: 0644]
tests/functional/xv_test/data.h [new file with mode: 0644]
tests/functional/xv_test/test_xv_resize.c [new file with mode: 0644]
tests/functional/xv_test/test_xv_resize.h [new file with mode: 0644]
tests/functional/xv_test/xcb_api.c [new file with mode: 0644]
tests/functional/xv_test/xcb_api.h [new file with mode: 0644]
tests/functional/xv_test/xv_test.c [new file with mode: 0644]
tests/functional/xv_test/xv_test.h [new file with mode: 0644]

index 7052905..9c09818 100644 (file)
@@ -20,3 +20,6 @@
 
 AUTOMAKE_OPTIONS = foreign
 SUBDIRS = src man
+if HAVE_FT
+SUBDIRS += tests/functional
+endif
index 848b1cf..d850d73 100644 (file)
@@ -16,7 +16,9 @@ AM_MAINTAINER_MODE
 AC_DISABLE_STATIC
 AC_PROG_LIBTOOL
 AC_PROG_CC
+AC_PROG_CC_STDC
 AM_PROG_AS
+AM_PROG_CC_C_O
 
 AH_TOP([#include "xorg-server.h"])
 
@@ -31,39 +33,60 @@ AC_ARG_ENABLE(pciaccess,
                              [Enable use of libpciaccess (default: disabled)]),
                             [PCIACCESS=$enableval], [PCIACCESS=no])
 
+AC_ARG_ENABLE(ftests,
+AS_HELP_STRING([--enable-ftests], [Enable functional tests (default: no)]),
+                [FT="$enableval"], [FT="no"])
 # Checks for extensions
+PKG_CHECK_MODULES(XORG, xorg-server)
 XORG_DRIVER_CHECK_EXT(RANDR, randrproto)
 XORG_DRIVER_CHECK_EXT(RENDER, renderproto)
 XORG_DRIVER_CHECK_EXT(XV, videoproto)
 
 # Checks for pkg-config packages
 PKG_CHECK_MODULES(PROTO, [xproto fontsproto])
-PKG_CHECK_MODULES(XORG, xorg-server >= 1.15.0,
-                  [AC_DEFINE(LATEST_XORG, [1], ["temp define for backward compatibility with old xorg-server"])],
-                  [PKG_CHECK_MODULES(XORG, xorg-server >= 1.0.0)])
+
+if pkg-config --exists 'xorg-server >= 1.15.0'; then
+       AC_DEFINE([LATEST_XORG], 1, [define for backward compatibility with old xorg-server])
+fi
 
 sdkdir=$(pkg-config --variable=sdkdir xorg-server)
 
-# check the conditions
-EXYNOS_CFALGS=""
+
+ftests=no
+FT_CFLAGS=""
+FT_LIBS=""
+EXYNOS_CFLAGS=""
 EXYNOS_LIBS=""
+if test "x$FT" != "xno"; then
+    PKG_CHECK_MODULES(XCB, [xcb xcb-atom xcb-shm xcb-xv xcb-util xcb-dri2], [ftests=yes],
+    [ftests=no])
+    if test "x$FT" = "xyes" -a "x$ftests" != "xyes"; then
+        AC_MSG_ERROR([Not find xcb library for functional tests])
+    fi
+    FT_CFLAGS="$XCB_CFLAGS "
+    FT_LIBS="$XCB_LIBS "
+fi
+
+AM_CONDITIONAL(HAVE_FT, test "x$ftests" = "xyes")
 
-PKG_CHECK_MODULES(XDBG, xdbg)
+# check the conditions
+PKG_CHECK_MODULES(XDBG, [xdbg], [xdbg=yes], [xdbg=no])
 PKG_CHECK_MODULES(DRM, libdrm)
 PKG_CHECK_MODULES(LIBTBM, libtbm)
 PKG_CHECK_MODULES(UDEV, [libudev], [udev=yes], [udev=no])
+
+if test x"$xdbg" = xno; then
+    AC_MSG_ERROR([Not find xdbg lib])
+fi
+
 if test x"$udev" = xyes; then
        AC_DEFINE(HAVE_UDEV,1,[Enable udev-based monitor hotplug detection])
 fi
 
-EXYNOS_CFLAGS="$EXYNOS_CFLAGS $PROTO_CFLAGS $XDBG_CFLAGS"
-EXYNOS_LIBS="$EXYNOS_LIBS $PROTO_CFLAGS $XDBG_LIBS"
-
-EXYNOS_CFLAGS="$EXYNOS_CFLAGS $DRM_CFLAGS $LIBTBM_CFLAGS "
-EXYNOS_LIBS="$EXYNOS_LIBS $DRM_LIBS $LIBTBM_LIBS "
-
-EXYNOS_CFLAGS="$EXYNOS_CFLAGS $UDEV_CFALGS "
-EXYNOS_LIBS="$EXYNOS_LIBS $UDEV_LIBS "
+EXYNOS_CFLAGS="$EXYNOS_CFLAGS $PROTO_CFLAGS $XDBG_CFLAGS $DRM_CFLAGS $LIBTBM_CFLAGS $UDEV_CFALGS"
+EXYNOS_LIBS="$EXYNOS_LIBS $XDBG_LIBS $DRM_LIBS $LIBTBM_LIBS $UDEV_LIBS $XDBG_LIBS"
+FT_CFLAGS="$FT_CFLAGS $EXYNOS_CFLAGS"
+FT_LIBS="$FT_LIBS $EXYNOS_LIBS"
 
 AM_CONDITIONAL(PCIACCESS, [test "x$PCIACCESS" = xyes])
 if test "x$PCIACCESS" = xyes; then
@@ -85,6 +108,8 @@ fi
 
 AC_SUBST([EXYNOS_CFLAGS])
 AC_SUBST([EXYNOS_LIBS])
+AC_SUBST([FT_CFLAGS])
+AC_SUBST([FT_LIBS])
 
 AC_SUBST([XORG_CFLAGS])
 AC_SUBST([moduledir])
@@ -95,8 +120,11 @@ AC_SUBST([DRIVER_NAME])
 XORG_MANPAGE_SECTIONS
 XORG_RELEASE_VERSION
 
-AC_OUTPUT([
+AC_CONFIG_FILES([
        Makefile
        src/Makefile
        man/Makefile
+    tests/functional/Makefile
+    tests/functional/xv_test/Makefile
 ])
+AC_OUTPUT
diff --git a/tests/functional/Makefile.am b/tests/functional/Makefile.am
new file mode 100644 (file)
index 0000000..cdbf2b6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = xv_test
diff --git a/tests/functional/xv_test/Makefile.am b/tests/functional/xv_test/Makefile.am
new file mode 100644 (file)
index 0000000..b1aebbc
--- /dev/null
@@ -0,0 +1,12 @@
+if HAVE_FT
+bin_PROGRAMS = test_xv
+test_xv_CFLAGS = @FT_CFLAGS@ \
+-I@top_srcdir@/tests/functional/xv_test \
+-I@top_srcdir@/src/xv
+test_xv_LDADD = @FT_LIBS@
+test_xv_SOURCES = \
+@top_srcdir@/tests/functional/xv_test/xv_test.c \
+@top_srcdir@/tests/functional/xv_test/data.c \
+@top_srcdir@/tests/functional/xv_test/xcb_api.c \
+@top_srcdir@/tests/functional/xv_test/test_xv_resize.c
+endif
diff --git a/tests/functional/xv_test/data.c b/tests/functional/xv_test/data.c
new file mode 100644 (file)
index 0000000..08ca1d4
--- /dev/null
@@ -0,0 +1,242 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "data.h"
+#include <xcb/shm.h>
+#include <xcb/dri2.h>
+#include <tbm_bufmgr.h>
+#include <xf86drm.h>
+#include <assert.h>
+#include <sys/shm.h>
+#include <fcntl.h>
+#include "xv_types.h"
+#include <string.h>
+
+static tbm_bufmgr bufmgr_p = NULL;
+typedef struct
+{
+    int fd;
+    error_s error;
+} dri_fd_s;
+
+static dri_fd_s
+open_dri2 (xcb_connection_t *c, xcb_screen_t *screen)
+{
+    xcb_dri2_connect_cookie_t dri2_conn_ck;
+    xcb_dri2_connect_reply_t *dri2_conn_reply_p = NULL;
+    xcb_dri2_authenticate_cookie_t dri2_auth_ck;
+    xcb_dri2_authenticate_reply_t *dri2_auth_reply_p = NULL;
+    xcb_generic_error_t  *error_p = NULL;
+    int error = -1;
+    dri_fd_s ret = {};
+    char *device_name_p = NULL;
+    drm_magic_t drm_magic;
+    xcb_window_t window_id = screen->root;
+
+    dri2_conn_ck = xcb_dri2_connect(c, window_id, XCB_DRI2_DRIVER_TYPE_DRI);
+    dri2_conn_reply_p = xcb_dri2_connect_reply(c, dri2_conn_ck, &error_p);
+    if (error_p)
+    {
+      ret.error.error_str = "Can't connect to DRI2 driver";
+      ret.error.error_code = error_p->error_code;
+      goto close;
+    }
+
+    device_name_p = strndup(xcb_dri2_connect_device_name (dri2_conn_reply_p),
+             xcb_dri2_connect_device_name_length (dri2_conn_reply_p));
+
+    ret.fd = open(device_name_p, O_RDWR);
+
+    if (ret.fd < 0)
+    {
+        ret.error.error_str = "Can't open DRI2 file descriptor";
+        ret.error.error_code = ret.fd;
+        goto close;
+    }
+
+    error = drmGetMagic(ret.fd, &drm_magic);
+    if (error < 0)
+    {
+        ret.error.error_str = "Can't get drm magic";
+        ret.error.error_code = error;
+        goto close;
+    }
+
+    dri2_auth_ck = xcb_dri2_authenticate(c, window_id, drm_magic);
+    dri2_auth_reply_p = xcb_dri2_authenticate_reply(c, dri2_auth_ck, &error_p);
+    if (error_p)
+    {
+        ret.error.error_str = "Can't auth DRI2";
+        ret.error.error_code = error_p->error_code;
+        goto close;
+    }
+
+close:
+    if (error_p)
+        free(error_p);
+    if (dri2_conn_reply_p)
+        free(dri2_conn_reply_p);
+    if (dri2_auth_reply_p)
+        free(dri2_auth_reply_p);
+    if (device_name_p)
+        free(device_name_p);
+    return ret;
+}
+
+static shm_data_s
+open_shm(xcb_connection_t *c, size_t data_size)
+{
+    xcb_generic_error_t *error_p = NULL;
+    shm_data_s ret_shm = {};
+
+    ret_shm.shm_seg_id = xcb_generate_id (c);
+
+    int shm_id = shmget (IPC_PRIVATE, data_size, IPC_CREAT | 0777);
+    if (shm_id == -1)
+    {
+        ret_shm.error.error_str = "shm alloc error";
+        ret_shm.error.error_code = shm_id;
+        goto close;
+    }
+
+    ret_shm.shm_seg_addr = shmat (shm_id, NULL, 0);
+    if (!ret_shm.shm_seg_addr)
+    {
+        ret_shm.error.error_str = "shm attach error";
+        goto close;
+    }
+    xcb_void_cookie_t xcb_shm_c =
+            xcb_shm_attach_checked (c, ret_shm.shm_seg_id, shm_id, 0);
+    error_p = xcb_request_check (c, xcb_shm_c);
+    if (error_p)
+    {
+        ret_shm.error.error_str = "xcb_shm attach error";
+        goto close;
+    }
+close:
+    shmctl (shm_id, IPC_RMID, NULL);
+    if (error_p)
+        free(error_p);
+    return ret_shm;
+}
+
+static tbm_bo
+get_data_random (size_t size, tbm_bufmgr bufmgr)
+{
+    FILE *fp = fopen ("/dev/urandom", "r");
+    if (fp == NULL)
+    {
+        return NULL;
+    }
+
+    tbm_bo tbo = tbm_bo_alloc (bufmgr, size, TBM_BO_DEFAULT);
+    if (tbo == NULL)
+    {
+        return NULL;
+    }
+
+    /* copy raw data to tizen buffer object */
+    tbm_bo_handle bo_handle = tbm_bo_map (tbo, TBM_DEVICE_CPU, TBM_OPTION_WRITE);
+    size_t error = fread (bo_handle.ptr, 1, size , fp);
+    tbm_bo_unmap (tbo);
+    fclose (fp);
+    if (error == 0)
+    {
+        tbm_bo_unref(tbo);
+        tbo = NULL;
+    }
+    return tbo;
+}
+
+shm_data_s
+get_image_random (xcb_connection_t *p_xcb_conn, xcb_screen_t *screen,
+                  size_t *sizes, int num_planes)
+{
+    shm_data_s ret = {0,};
+    XV_DATA_PTR xv_data = NULL;
+    if (bufmgr_p == NULL)
+    {
+        dri_fd_s dri2 = open_dri2 (p_xcb_conn, screen);
+        if (dri2.error.error_str)
+        {
+            ret.error = dri2.error;
+            goto close_l;
+        }
+        bufmgr_p = tbm_bufmgr_init (dri2.fd);
+        if (!bufmgr_p)
+        {
+            ret.error.error_str = "Can't open TBM connection\n";
+            ret.error.error_code = 0;
+            goto close_l;
+        }
+    }
+
+    if (sizes == NULL)
+    {
+        ret.error.error_str = "Sizes argument is NULL";
+        goto close_l;
+    }
+
+    if (num_planes > 3 || num_planes < 1)
+    {
+        ret.error.error_str = "Wrong num_planes argument";
+        goto close_l;
+    }
+    size_t full_size = 0;
+    int i;
+    for (i = 0; i < num_planes; i++)
+    {
+        full_size += sizes[i];
+    }
+    ret = open_shm(p_xcb_conn, full_size);
+    if (ret.error.error_str)
+        goto close_l;
+
+    xv_data = ret.shm_seg_addr;
+    XV_INIT_DATA (xv_data);
+    tbm_bo temp_bo = NULL;
+    switch (num_planes)
+    {
+    case 3:
+        temp_bo = get_data_random (sizes[2], bufmgr_p);
+        if (temp_bo == NULL)
+        {
+            ret.error.error_str = "Can't alloc tbm object";
+            goto close_l;
+        }
+        xv_data->CrBuf = tbm_bo_export(temp_bo);
+    case 2:
+        temp_bo = get_data_random (sizes[1], bufmgr_p);
+        if (temp_bo == NULL)
+        {
+            ret.error.error_str = "Can't alloc tbm object";
+            goto close_l;
+        }
+        xv_data->CbBuf = tbm_bo_export(temp_bo);
+    case 1:
+        temp_bo = get_data_random (sizes[0], bufmgr_p);
+        if (temp_bo == NULL)
+        {
+            ret.error.error_str = "Can't alloc tbm object\n";
+            goto close_l;
+        }
+        xv_data->YBuf = tbm_bo_export(temp_bo);
+        break;
+    }
+
+    return ret;
+close_l:
+    // TODO: Close DRI
+    // TODO: Close tbm
+    if (xv_data)
+    {
+        if (xv_data->YBuf != 0)
+            tbm_bo_unref(tbm_bo_import(bufmgr_p, xv_data->YBuf));
+        if (xv_data->CbBuf != 0)
+            tbm_bo_unref(tbm_bo_import(bufmgr_p, xv_data->CbBuf));
+        if (xv_data->CrBuf != 0)
+            tbm_bo_unref(tbm_bo_import(bufmgr_p, xv_data->CrBuf));
+    }
+
+    return ret;
+}
+
diff --git a/tests/functional/xv_test/data.h b/tests/functional/xv_test/data.h
new file mode 100644 (file)
index 0000000..81329c0
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef DATA_H
+#define DATA_H
+#include <xcb/xcb.h>
+#include <xcb/shm.h>
+#include <xcb/xv.h>
+#include "xv_test.h"
+
+typedef struct
+{
+    xcb_shm_seg_t shm_seg_id;
+    void          *shm_seg_addr;
+    error_s error;
+} shm_data_s;
+
+shm_data_s get_image_random (xcb_connection_t *xcb_conn_p, xcb_screen_t *screen,
+                             size_t * sizes, int num_planes);
+
+#endif // DATA_H
diff --git a/tests/functional/xv_test/test_xv_resize.c b/tests/functional/xv_test/test_xv_resize.c
new file mode 100644 (file)
index 0000000..0c77dd7
--- /dev/null
@@ -0,0 +1,520 @@
+#include <xcb/xcb.h>
+#include <xcb/xv.h>
+#include <xcb/shm.h>
+#include <xcb/dri2.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <xf86drm.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <tbm_bufmgr.h>
+#include <assert.h>
+#include "xv_test.h"
+#include "data.h"
+#include "xcb_api.h"
+
+typedef struct
+{
+    xcb_atom_t atom_hflip;
+    xcb_atom_t atom_vflip;
+    xcb_atom_t atom_rotate;
+    xcb_atom_t atom_buffer;
+    error_s error;
+} test_atom_s;
+
+typedef struct
+{
+    size_t steps;
+    rectangle_s *src_crop_p;
+    rectangle_s *dst_crop_p;
+} route_map_s;
+
+typedef struct
+{
+    error_s error;
+    route_map_s route_map;
+} get_route_map_s;
+
+typedef struct
+{
+    xcb_xv_port_t xv_open_port;
+    test_atom_s atoms;
+    xcb_connection_t *xcb_conn_p;
+    xcb_screen_t *screen_p;
+    xcb_window_t window_id;
+    xcb_gcontext_t gc_id;
+    route_map_s route_map;
+} test_data_s;
+
+static test_data_s *st_test_data_p = NULL;
+
+static error_s test_xv_resize_prepare(xcb_connection_t *xcb_conn_p,
+                                      xcb_screen_t * screen_p, rule_s rule);
+
+static error_s test_xv_resize_run(xcb_connection_t *xcb_conn_p,
+                                  xcb_screen_t * screen_p, rule_s rule);
+
+static error_s test_xv_resize_close(xcb_connection_t *xcb_conn_p,
+                                    xcb_screen_t * screen_p, rule_s rule);
+
+test_atom_s
+create_atoms (xcb_connection_t *xcb_conn_p)
+{
+    char const *atom_name_a[4] = {
+        "_USER_WM_PORT_ATTRIBUTE_HFLIP",
+        "_USER_WM_PORT_ATTRIBUTE_VFLIP",
+        "_USER_WM_PORT_ATTRIBUTE_ROTATION",
+        "XV_RETURN_BUFFER"};
+    xcb_intern_atom_cookie_t atom_ck_a[4] = {};
+    xcb_intern_atom_reply_t *atom_reply_p = NULL;
+    test_atom_s ret = {};
+    xcb_generic_error_t *error_p = NULL;
+    int i;
+    for (i = 0; i < 4; i++)
+    {
+        atom_ck_a[i] =
+                xcb_intern_atom (xcb_conn_p, 0, (uint16_t) strlen(atom_name_a[i]),
+                                 atom_name_a[i]);
+    }
+    for (i = 0; i < 4; i++)
+    {
+        atom_reply_p =
+                xcb_intern_atom_reply (xcb_conn_p , atom_ck_a[i], &error_p);
+
+        if (error_p)
+        {
+            ret.error.error_str = "Can't register atom";
+            ret.error.error_code = error_p->error_code;
+            goto close_l;
+        }
+        if (atom_reply_p == NULL)
+        {
+            ret.error.error_str = "Can't register atom";
+            goto close_l;
+        }
+        switch (i)
+        {
+        case 0:
+            ret.atom_hflip = atom_reply_p->atom;
+            break;
+        case 1:
+            ret.atom_vflip = atom_reply_p->atom;
+            break;
+        case 2:
+            ret.atom_rotate = atom_reply_p->atom;
+            break;
+        case 3:
+            ret.atom_buffer = atom_reply_p->atom;
+            break;
+        }
+        free(atom_reply_p);
+        atom_reply_p = NULL;
+    }
+
+close_l:
+
+    if (error_p)
+        free(error_p);
+    if (atom_reply_p)
+        free(atom_reply_p);
+    return ret;
+}
+
+get_route_map_s
+create_route_map (rule_s *rules)
+{
+    get_route_map_s ret = {};
+    rectangle_s *src_crop_p = NULL;
+    rectangle_s *dst_crop_p = NULL;
+    if (rules == NULL)
+    {
+        ret.error.error_str = "Wrong input arguments";
+        goto close_l;
+    }
+    size_t steps_width = (rules->max_width - rules->min_width)/10;
+    size_t steps_height = (rules->max_height - rules->max_height)/10;
+    size_t steps = (max(steps_width, steps_height))*2;
+
+    src_crop_p = calloc(steps, sizeof(rectangle_s));
+    if (!src_crop_p)
+    {
+        ret.error.error_str = "Can't alloc memory";
+        goto close_l;
+    }
+    dst_crop_p = calloc(steps, sizeof(rectangle_s));
+    if (!dst_crop_p)
+    {
+        ret.error.error_str = "Can't alloc memory";
+        goto close_l;
+    }
+//    pace_dst_crop.height = (uint32_t)
+//            ((double)(rules->max_size.height - rules->min_size.height)/
+//             (rules->steps * 2));
+//    pace_dst_crop.width = (uint32_t)
+//            ((double)(rules->max_size.width - rules->min_size.width)/
+//             (rules->steps * 2));
+//    pace_src_crop.height = (uint32_t)
+//            ((double)(rules->image_height - rules->min_size.height)/
+//             (rules->steps * 2));
+//    pace_src_crop.width = (uint32_t)
+//            ((double)(rules->image_width - rules->min_size.width)/
+//             (rules->steps * 2));
+    if (!rules->src_change)
+    {
+        src_crop_p[0].x = 0;
+        src_crop_p[0].y = 0;
+        src_crop_p[0].width = rules->image_width;
+        src_crop_p[0].height = rules->image_height;
+    }
+    else
+    {
+        src_crop_p[0].x = 0;
+        src_crop_p[0].y = 0;
+        src_crop_p[0].width = rules->min_width;
+        src_crop_p[0].height = rules->min_height;
+    }
+
+    if (!rules->dst_change)
+    {
+        dst_crop_p[0].x = 0;
+        dst_crop_p[0].y = 0;
+        dst_crop_p[0].width = rules->image_width;
+        dst_crop_p[0].height = rules->image_height;
+    }
+    else
+    {
+        dst_crop_p[0].x = 0;
+        dst_crop_p[0].y = 0;
+        dst_crop_p[0].width = rules->min_width;
+        dst_crop_p[0].height = rules->min_height;
+    }
+    int i;
+    for (i = 1; i < (steps/2); i++)
+    {
+        if (!rules->src_change)
+        {
+            src_crop_p[i].x = 0;
+            src_crop_p[i].y = 0;
+            src_crop_p[i].width = rules->image_width;
+            src_crop_p[i].height = rules->image_height;
+        }
+        else
+        {
+            src_crop_p[i].x = 0;
+            src_crop_p[i].y = 0;
+            src_crop_p[i].width =
+                    ((src_crop_p[i-1].width + 10) <= rules->image_width) ?
+                        (src_crop_p[i-1].width + 10) : src_crop_p[i-1].width;
+            src_crop_p[i].height =
+                    ((src_crop_p[i-1].height + 10) <= rules->image_height) ?
+                        (src_crop_p[i-1].height + 10) : src_crop_p[i-1].height;
+        }
+        if (!rules->dst_change)
+        {
+            dst_crop_p[i].x = 0;
+            dst_crop_p[i].y = 0;
+            dst_crop_p[i].width = rules->image_width;
+            dst_crop_p[i].height = rules->image_height;
+        }
+        else
+        {
+            dst_crop_p[i].x = 0;
+            dst_crop_p[i].y = 0;
+            dst_crop_p[i].width =
+                    ((dst_crop_p[i-1].width + 10) <= rules->max_width) ?
+                    (dst_crop_p[i-1].width + 10) : dst_crop_p[i-1].width;
+            dst_crop_p[i].height =
+                    ((dst_crop_p[i-1].height + 10) <= rules->max_height) ?
+                    (dst_crop_p[i-1].height + 10) : dst_crop_p[i-1].height;
+        }
+    }
+    for (i = (steps/2); i < steps; i++)
+    {
+        if (!rules->src_change)
+        {
+            src_crop_p[i].x = 0;
+            src_crop_p[i].y = 0;
+            src_crop_p[i].width = rules->image_width;
+            src_crop_p[i].height = rules->image_height;
+        }
+        else
+        {
+            src_crop_p[i].x = 0;
+            src_crop_p[i].y = 0;
+            src_crop_p[i].width =
+                    ((src_crop_p[i-1].width - 10) >= rules->min_width) ?
+                        (src_crop_p[i-1].width - 10) : src_crop_p[i-1].width;
+            src_crop_p[i].height =
+                    ((src_crop_p[i-1].height - 10) >= rules->min_height) ?
+                        (src_crop_p[i-1].height - 10) : src_crop_p[i-1].height;
+        }
+        if (!rules->dst_change)
+        {
+            dst_crop_p[i].x = 0;
+            dst_crop_p[i].y = 0;
+            dst_crop_p[i].width = rules->image_width;
+            dst_crop_p[i].height = rules->image_height;
+        }
+        else
+        {
+            dst_crop_p[i].x = 0;
+            dst_crop_p[i].y = 0;
+            dst_crop_p[i].width =
+                    ((dst_crop_p[i-1].width - 10) >= rules->min_width) ?
+                    (dst_crop_p[i-1].width - 10) : dst_crop_p[i-1].width;
+            dst_crop_p[i].height =
+                    ((dst_crop_p[i-1].height - 10) >= rules->min_height) ?
+                    (dst_crop_p[i-1].height - 10) : dst_crop_p[i-1].height;
+        }
+    }
+
+    ret.route_map.src_crop_p = src_crop_p;
+    ret.route_map.dst_crop_p = dst_crop_p;
+    ret.route_map.steps = steps;
+    return ret;
+close_l:
+    if (src_crop_p)
+        free(src_crop_p);
+    if (dst_crop_p)
+        free(dst_crop_p);
+    return ret;
+}
+test_case_s
+test_xv_resize_init (void)
+{
+    test_case_s ret = {};
+    ret.prepare_test = test_xv_resize_prepare;
+    ret.run_test = test_xv_resize_run;
+    ret.close_test = test_xv_resize_close;
+    return ret;
+}
+
+
+static error_s
+test_xv_resize_prepare(xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p, rule_s rule)
+{
+    error_s ret = {};
+    st_test_data_p = malloc(sizeof(test_data_s));
+    DBG;
+    if (!st_test_data_p)
+    {
+        ret.error_str = "Can't alloc memory for test_data_s";
+        ret.error_code = 0;
+        goto close_l;
+    }
+    st_test_data_p->xcb_conn_p = xcb_conn_p;
+    st_test_data_p->screen_p = screen_p;
+    DBG;
+    get_xv_port_s xv_port = open_adaptor (xcb_conn_p, screen_p->root);
+    if (xv_port.error.error_str)
+    {
+        ret = xv_port.error;
+        goto close_l;
+    }
+    DBG;
+    st_test_data_p->xv_open_port = xv_port.xv_port_id;
+    st_test_data_p->atoms = create_atoms (xcb_conn_p);
+    if(st_test_data_p->atoms.error.error_str)
+    {
+        ret = st_test_data_p->atoms.error;
+        goto close_l;
+    }
+    DBG;
+
+    get_window_s window = create_window(xcb_conn_p, screen_p);
+    if (window.error.error_str)
+    {
+        ret = window.error;
+        goto close_l;
+    }
+    st_test_data_p->window_id = window.window_id;
+    get_gc_s gc = create_gc (xcb_conn_p, st_test_data_p->window_id, screen_p);
+    if (gc.error.error_str)
+    {
+        ret = gc.error;
+        goto close_l;
+    }
+    st_test_data_p->gc_id = gc.gc_id;
+
+    get_route_map_s route = create_route_map (&rule);
+
+    if (route.error.error_str)
+    {
+        ret = route.error;
+        goto close_l;
+    }
+
+    st_test_data_p->route_map = route.route_map;
+    return ret;
+
+close_l:
+    DBG;
+    if (st_test_data_p)
+        free(st_test_data_p);
+/* TODO: close port */
+    st_test_data_p = NULL;
+    return ret;
+}
+static
+error_s
+test_xv_resize_run(xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p, rule_s rule)
+{
+
+    DBG;
+    xcb_generic_error_t  *error_p = NULL;
+    error_s ret = {};
+    shm_data_s shm;
+    if (st_test_data_p == NULL)
+    {
+        ret.error_str = "Wrong argument";
+        return ret;
+    }
+    frame_attr_s frame[st_test_data_p->route_map.steps];
+
+    DBG;
+    get_image_attr_s image_attr =
+            get_image_attr (xcb_conn_p, st_test_data_p->xv_open_port,
+                            rule.image_fourcc, rule.image_width, rule.image_height);
+    DBG;
+    if (image_attr.error.error_str)
+    {
+        ret = image_attr.error;
+        goto close_l;
+    }
+    /* get raw data */
+
+    size_t max_j = rule.count_uniqes_frames;
+    DBG;
+    int i,j = 0;
+    for (i = 0; i < st_test_data_p->route_map.steps; i++)
+    {
+
+        if (i == 0)
+            printf("Generate data:\n");
+        if (i < max_j)
+        {
+            shm = get_image_random (xcb_conn_p, screen_p,
+                                    image_attr.image.sizes,
+                                    image_attr.image.num_planes);
+            if (shm.error.error_str)
+            {
+                ret = shm.error;
+                goto close_l;
+            }
+            frame[i].segment = shm.shm_seg_id;
+            printf("%f%%\n", ((double)i/max_j));
+        }
+        else
+        {
+            if (j == max_j)
+            {
+                j = 0;
+            }
+            frame[i].segment = frame[j].segment;
+            j++;
+        }
+
+        frame[i].image_p = &image_attr.image;
+        frame[i].src_crop_p = &st_test_data_p->route_map.src_crop_p[i];
+        frame[i].dst_crop_p = &st_test_data_p->route_map.dst_crop_p[i];
+
+    }
+    DBG;
+    xcb_void_cookie_t map_window_ck =
+            xcb_map_window_checked (xcb_conn_p, st_test_data_p->window_id);
+    xcb_void_cookie_t put_image_ck =
+    put_image (xcb_conn_p, st_test_data_p->xv_open_port,
+               st_test_data_p->window_id, st_test_data_p->gc_id, &frame[0]);
+    j = 1;
+
+    error_p = xcb_request_check (xcb_conn_p, map_window_ck);
+    if (error_p)
+    {
+        ret.error_str = "Can't make transparent window";
+        ret.error_code = error_p->error_code;
+        goto close_l;
+    }
+
+    xcb_generic_event_t  *e;
+    xcb_client_message_event_t* msg;
+    DBG;
+    while (1)
+    {
+        e = xcb_poll_for_event(xcb_conn_p);
+        while (e)
+        {
+            switch (e->response_type)
+            {
+            case XCB_CLIENT_MESSAGE:
+                msg = (xcb_client_message_event_t *)e;
+                if (msg->type == st_test_data_p->atoms.atom_buffer)
+                {
+                    unsigned int keys[3] = {0, };
+                    keys[0] = msg->data.data32[0];
+                    keys[1] = msg->data.data32[1];
+                    keys[2] = msg->data.data32[2];
+                    printf ("receive: %d, %d, %d (<= Xorg)\n",
+                            keys[0], keys[1], keys[2]);
+                }
+
+                break;
+            case XCB_EXPOSE: 
+                break;
+            default:
+                break;
+            }
+            free(e);
+            e = xcb_poll_for_event(xcb_conn_p);
+        }
+
+        error_p = xcb_request_check (xcb_conn_p, put_image_ck);
+        if (error_p)
+        {
+            ret.error_str = "Can't draw image frame";
+            ret.error_code = error_p->error_code;
+            goto close_l;
+        }
+        if (j >= st_test_data_p->route_map.steps)
+            j = 0;
+        put_image_ck = put_image (xcb_conn_p, st_test_data_p->xv_open_port,
+                                  st_test_data_p->window_id, st_test_data_p->gc_id,
+                                  &frame[j]);
+        printf("src:(%dwx%dh) dst: (%dwx%dh)\n",
+               frame[j].src_crop_p->width, frame[j].src_crop_p->height,
+               frame[j].dst_crop_p->width, frame[j].dst_crop_p->height);
+        j++;
+       usleep(1000000/rule.frame_per_second);
+    }
+
+close_l:
+    if (error_p)
+        free(error_p);
+    return ret;
+}
+
+static error_s
+test_xv_resize_close(xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p, rule_s rule)
+{
+    error_s ret = {};
+    return ret;
+}
+
+#if 0
+xcb_xv_list_image_formats_reply_t *list =
+    xcb_xv_list_image_formats_reply (conn,
+        xcb_xv_list_image_formats (conn, a->base_id), NULL);
+if (list == NULL)
+    return NULL;
+
+/* Check available XVideo chromas */
+xcb_xv_query_image_attributes_reply_t *attr = NULL;
+unsigned rank = UINT_MAX;
+
+for (const xcb_xv_image_format_info_t *f =
+         xcb_xv_list_image_formats_format (list),
+                                      *f_end =
+         f + xcb_xv_list_image_formats_format_length (list);
+     f < f_end;
+     f++)
+#endif
diff --git a/tests/functional/xv_test/test_xv_resize.h b/tests/functional/xv_test/test_xv_resize.h
new file mode 100644 (file)
index 0000000..fdff351
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef TEST_XV_RESIZE_H
+#define TEST_XV_RESIZE_H
+#include "xv_test.h"
+test_case_s test_xv_resize_init (void);
+
+#endif // TEST_XV_RESIZE_H
diff --git a/tests/functional/xv_test/xcb_api.c b/tests/functional/xv_test/xcb_api.c
new file mode 100644 (file)
index 0000000..4f5b013
--- /dev/null
@@ -0,0 +1,258 @@
+#include "xcb_api.h"
+get_image_attr_s
+get_image_attr(xcb_connection_t * xcb_conn_p, xcb_xv_port_t xv_port,
+               uint32_t fourcc_id, uint16_t width, uint16_t height)
+{
+    get_image_attr_s ret = {};
+    xcb_generic_error_t  *error_p = NULL;
+    xcb_xv_query_image_attributes_reply_t * xv_attr_reply_p = NULL;
+
+    if (!xcb_conn_p || xv_port == XCB_XV_BAD_PORT)
+    {
+        ret.error.error_str = "Wrong arguments";
+        ret.error.error_code = 0;
+        goto close;
+    }
+
+    xcb_xv_query_image_attributes_cookie_t xv_attr_ck =
+    xcb_xv_query_image_attributes (xcb_conn_p  /**< */,
+                                   xv_port  /**< */,
+                                   fourcc_id  /**< */,
+                                   width  /**< */,
+                                   height  /**< */);
+    xv_attr_reply_p =
+    xcb_xv_query_image_attributes_reply (xcb_conn_p  /**< */,
+                                         xv_attr_ck  /**< */,
+                                         &error_p  /**< */);
+    if (error_p)
+    {
+        ret.error.error_str = "Can't query image attr";
+        ret.error.error_code = error_p->error_code;
+        goto close;
+    }
+
+    if (xv_attr_reply_p->data_size == 0)
+    {
+        ret.error.error_str = "Wrong input data format";
+        ret.error.error_code = 0;
+        goto close;
+    }
+
+    const uint32_t *offsets=
+            xcb_xv_query_image_attributes_offsets (xv_attr_reply_p);
+    const uint32_t *pitches=
+            xcb_xv_query_image_attributes_pitches (xv_attr_reply_p);
+    ret.image.num_planes = xv_attr_reply_p->num_planes;
+    ret.image.full_size =  xv_attr_reply_p->data_size;
+    ret.image.fourcc_id = fourcc_id;
+    ret.image.width = xv_attr_reply_p->width;
+    ret.image.height = xv_attr_reply_p->height;
+    switch (ret.image.num_planes)
+    {
+    case 3:
+        ret.image.sizes[0] = offsets[1];
+        ret.image.sizes[1] = offsets[2] - offsets[1];
+        ret.image.sizes[2] = ret.image.full_size - offsets[2];
+        break;
+    case 2:
+        ret.image.sizes[1] = ret.image.full_size - offsets[1];
+        ret.image.sizes[0] = offsets[1];
+        break;
+    case 1:
+        ret.image.sizes[0] = ret.image.full_size;
+        break;
+    default:
+        ret.error.error_str = "Wrong input data format";
+        goto close;
+        break;
+    }
+    int i;
+    for (i = 0; i < ret.image.num_planes; ++i)
+    {
+        ret.image.offsets[i] = offsets[i];
+        ret.image.pitches[i] = pitches[i];
+    }
+
+close:
+
+    if (error_p)
+        free(error_p);
+    if (xv_attr_reply_p)
+        free(xv_attr_reply_p);
+
+    return ret;
+}
+
+xcb_void_cookie_t
+put_image (xcb_connection_t * xcb_conn_p, xcb_xv_port_t xv_port,
+           xcb_window_t window_id, xcb_gcontext_t gc_id, frame_attr_s *frame_p)
+{
+    xcb_void_cookie_t ret = {};
+    ret = xcb_xv_shm_put_image_checked (
+                xcb_conn_p, xv_port, window_id, gc_id,
+                frame_p->segment, frame_p->image_p->fourcc_id, 0,
+                frame_p->src_crop_p->x, frame_p->src_crop_p->y,
+                frame_p->src_crop_p->width, frame_p->src_crop_p->height,
+                frame_p->dst_crop_p->x, frame_p->dst_crop_p->y,
+                frame_p->dst_crop_p->width, frame_p->dst_crop_p->height,
+                frame_p->image_p->width, frame_p->image_p->height, 0);
+    return ret;
+}
+
+get_xv_port_s
+open_adaptor (xcb_connection_t *xcb_conn_p, xcb_window_t window_id)
+{
+    xcb_generic_error_t  *error_p = NULL;
+    get_xv_port_s ret = {};
+    xcb_xv_adaptor_info_iterator_t xv_adaptor_iter;
+    xcb_xv_grab_port_reply_t *xv_grab_port_p = NULL;
+    xcb_xv_query_adaptors_cookie_t xv_adaptor_ck =
+            xcb_xv_query_adaptors (xcb_conn_p, window_id);
+    xcb_xv_query_adaptors_reply_t *xv_adaptors_list_p =
+            xcb_xv_query_adaptors_reply (xcb_conn_p, xv_adaptor_ck, &error_p);
+    if (error_p)
+    {
+        ret.error.error_str = "Can't query xv adaptor";
+        ret.error.error_code = error_p->error_code;
+        goto close;
+    }
+
+    for (xv_adaptor_iter = xcb_xv_query_adaptors_info_iterator (xv_adaptors_list_p);
+         xv_adaptor_iter.rem > 0;
+         xcb_xv_adaptor_info_next (&xv_adaptor_iter))
+    {
+        if (!(xv_adaptor_iter.data->type & XCB_XV_TYPE_IMAGE_MASK))
+            continue;
+        int i;
+        for (i = 0; i < xv_adaptor_iter.data->num_ports; i++)
+        {
+            xcb_xv_port_t xv_port = xv_adaptor_iter.data->base_id + i;
+            xcb_xv_grab_port_cookie_t xv_grab_port_c =
+                    xcb_xv_grab_port (xcb_conn_p, xv_port, XCB_CURRENT_TIME);
+            xv_grab_port_p =
+                    xcb_xv_grab_port_reply (xcb_conn_p, xv_grab_port_c, &error_p);
+            if (error_p)
+            {
+                ret.error.error_str = "Can't query xv adaptor";
+                ret.error.error_code = error_p->error_code;
+                goto close;
+            }
+
+            if (xv_grab_port_p && xv_grab_port_p->result == 0)
+            {
+                ret.xv_port_id = xv_port;
+                break;
+            }
+        }
+        if (ret.xv_port_id != 0)
+        {
+            break;
+        }
+    }
+    
+close:
+    if (xv_adaptors_list_p)
+        free(xv_adaptors_list_p);
+    if (xv_grab_port_p)
+        free(xv_grab_port_p);
+    if (error_p)
+        free(error_p);
+
+    return ret;
+}
+
+get_gc_s
+create_gc (xcb_connection_t *xcb_conn_p, xcb_drawable_t drawable_id, xcb_screen_t * screen_p)
+{
+    get_gc_s ret = {};
+    xcb_void_cookie_t gc_ck;
+    xcb_generic_error_t  *error_p = NULL;
+    uint32_t values[2];
+    ret.gc_id = xcb_generate_id (xcb_conn_p);
+    uint32_t mask = XCB_GC_GRAPHICS_EXPOSURES;
+    values[0] = 0;
+//    values[0] = screen_p->white_pixel;
+    gc_ck = xcb_create_gc_checked (xcb_conn_p, ret.gc_id, drawable_id, mask, values);
+
+    error_p = xcb_request_check (xcb_conn_p, gc_ck);
+    if (error_p)
+    {
+      ret.error.error_str = "Can't create graphic context";
+      ret.error.error_code = error_p->error_code;
+      goto close;
+    }
+close:
+    if (error_p)
+        free(error_p);
+    return ret;
+}
+
+get_window_s
+create_window (xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p)
+{
+    get_window_s ret = {};
+    ret.window_id = xcb_generate_id (xcb_conn_p);
+    uint32_t              mask;
+    uint32_t              values[3];
+    xcb_generic_error_t *error_p = NULL;
+    mask = XCB_CW_EVENT_MASK;
+//    values[0] = screen_p->black_pixel;
+    values[0] = XCB_EVENT_MASK_EXPOSURE;
+    xcb_void_cookie_t window_ck =
+            xcb_create_window_checked (xcb_conn_p,
+                                       screen_p->root_depth,
+                                       ret.window_id, screen_p->root,
+                                       0, 0, screen_p->width_in_pixels,
+                                       screen_p->height_in_pixels,
+                                       0, XCB_WINDOW_CLASS_INPUT_OUTPUT,
+                                       screen_p->root_visual,
+                                       mask, values);
+
+    error_p = xcb_request_check (xcb_conn_p, window_ck);
+    if (error_p)
+    {
+        ret.error.error_str = "Can't create window";
+        ret.error.error_code = error_p->error_code;
+        goto close;
+    }
+
+close:
+    if (error_p)
+        free(error_p);
+    return ret;
+}
+
+static xcb_format_t *
+find_format_by_depth (const xcb_setup_t *setup, uint8_t depth)
+{
+  xcb_format_t *fmt = xcb_setup_pixmap_formats(setup);
+  xcb_format_t *fmtend = fmt + xcb_setup_pixmap_formats_length(setup);
+  for(; fmt != fmtend; ++fmt)
+      if(fmt->depth == depth)
+      return fmt;
+  return 0;
+}
+
+#if 1
+xcb_void_cookie_t
+make_transparent (xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p,
+                  xcb_drawable_t drawable_id, xcb_gcontext_t gc_id)
+{
+    xcb_format_t *fmt = find_format_by_depth(xcb_get_setup (xcb_conn_p), 32);
+
+    uint32_t base = 1920 * fmt->bits_per_pixel;
+    uint32_t pad = fmt->scanline_pad >> 3;
+    uint32_t b = base + pad - 1;
+        /* faster if pad is a power of two */
+        if (((pad - 1) & pad) == 0)
+          b = b & -pad;
+        else
+          b = b - b % pad;
+    uint32_t size = 1080 * b;
+    uint8_t *data = (uint8_t *)calloc (1, size);
+    return
+            xcb_put_image_checked (xcb_conn_p, XCB_IMAGE_FORMAT_Z_PIXMAP, drawable_id, gc_id,
+                  screen_p->width_in_pixels, screen_p->height_in_pixels, 0, 0,
+                  0, 32, size, data);
+}
+#endif
diff --git a/tests/functional/xv_test/xcb_api.h b/tests/functional/xv_test/xcb_api.h
new file mode 100644 (file)
index 0000000..5eaf9e5
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef XV_API_H
+#define XV_API_H
+#include <xcb/xcb.h>
+#include <xcb/xv.h>
+#include <xcb/xfixes.h>
+
+#include <xcb/xcb_util.h>
+#include "xv_test.h"
+
+typedef struct
+{
+    uint32_t width;
+    uint32_t height;
+} size_s;
+
+typedef struct
+{
+    int32_t x;
+    int32_t y;
+    uint32_t width;
+    uint32_t height;
+} rectangle_s;
+
+typedef struct
+{
+    uint32_t fourcc_id;
+    uint16_t num_planes;
+    size_t full_size;
+    size_t sizes[3];
+    uint32_t offsets[3];
+    uint32_t pitches[3];
+    uint32_t width;
+    uint32_t height;
+} image_attr_s;
+
+typedef struct
+{
+    rectangle_s *src_crop_p;
+    rectangle_s *dst_crop_p;
+    image_attr_s *image_p;
+    xcb_shm_seg_t segment;
+} frame_attr_s;
+
+typedef struct
+{
+    xcb_xv_port_t xv_port_id;
+    error_s error;
+} get_xv_port_s;
+
+typedef struct
+{
+    error_s error;
+    image_attr_s image;
+} get_image_attr_s;
+
+typedef struct
+{
+    xcb_window_t window_id;
+    error_s error;
+} get_window_s;
+
+typedef struct
+{
+    xcb_gcontext_t gc_id;
+    error_s error;
+} get_gc_s;
+
+get_gc_s create_gc (xcb_connection_t *xcb_conn_p, xcb_drawable_t drawable_id, xcb_screen_t * screen_p);
+get_window_s create_window (xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p);
+
+
+get_image_attr_s get_image_attr(xcb_connection_t * xcb_conn_p, xcb_xv_port_t xv_port,
+                            uint32_t fourcc_id, uint16_t width, uint16_t height);
+get_xv_port_s    open_adaptor (xcb_connection_t *xcb_conn_p, xcb_window_t window_id);
+xcb_void_cookie_t put_image (xcb_connection_t * xcb_conn_p, xcb_xv_port_t xv_port,
+           xcb_window_t window_id, xcb_gcontext_t gc_id, frame_attr_s *frame_p);
+
+xcb_void_cookie_t make_transparent (xcb_connection_t *xcb_conn_p, xcb_screen_t * screen_p,
+                                    xcb_drawable_t drawable_id, xcb_gcontext_t gc_id);
+#endif // XV_API_H
diff --git a/tests/functional/xv_test/xv_test.c b/tests/functional/xv_test/xv_test.c
new file mode 100644 (file)
index 0000000..e6929c6
--- /dev/null
@@ -0,0 +1,219 @@
+#include "xv_test.h"
+#include <xcb/xcb.h>
+#include <xcb/xv.h>
+#include <xcb/shm.h>
+#include <xcb/dri2.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <xcb/dri2.h>
+#include <xf86drm.h>
+#include <fcntl.h>
+#include "xv_types.h"
+#include <tbm_bufmgr.h>
+#include "data.h"
+#include <sys/time.h>
+#include "test_xv_resize.h"
+
+typedef struct
+{
+    size_t num_tests;
+    test_case_s * test_case_array;
+    error_s * error_array;
+} test_map_s;
+
+error_s
+check_xv (xcb_connection_t *xcb_conn_p)
+{
+    xcb_xv_query_extension_cookie_t xv_cookie;
+    xcb_xv_query_extension_reply_t *xv_reply = NULL;
+    xcb_generic_error_t * error_p = NULL;
+    error_s ret = {};
+    xv_cookie = xcb_xv_query_extension (xcb_conn_p);
+    xv_reply = xcb_xv_query_extension_reply (xcb_conn_p, xv_cookie, &error_p);
+    if (error_p)
+    {
+        ret.error_str = "Can't find xv extension";
+        ret.error_code = error_p->error_code;
+    }
+
+    if (xv_reply)
+        free(xv_reply);
+    if (error_p)
+        free(error_p);
+    return ret;
+}
+
+error_s
+check_shm (xcb_connection_t *xcb_conn_p)
+{
+    xcb_shm_query_version_cookie_t shm_cookie;
+    xcb_shm_query_version_reply_t *shm_reply_p = NULL;
+    xcb_generic_error_t * error_p = NULL;
+    error_s ret = {};
+    shm_cookie = xcb_shm_query_version (xcb_conn_p);
+    shm_reply_p = xcb_shm_query_version_reply (xcb_conn_p, shm_cookie, &error_p);
+    if (error_p)
+    {
+        ret.error_str = "Can't find shm extension";
+        ret.error_code = error_p->error_code;
+    }
+
+    if (shm_reply_p)
+        free(shm_reply_p);
+    if (error_p)
+        free(error_p);
+    return ret;
+}
+
+error_s
+check_dri2 (xcb_connection_t *xcb_conn_p)
+{
+    error_s ret = {};
+    xcb_generic_error_t *error_p = NULL;
+    xcb_dri2_query_version_cookie_t xcb_dri2_ck =
+            xcb_dri2_query_version (xcb_conn_p,
+                                    XCB_DRI2_MAJOR_VERSION,
+                                    XCB_DRI2_MINOR_VERSION);
+    xcb_dri2_query_version_reply_t * xcb_dri2_reply_p =
+            xcb_dri2_query_version_reply (xcb_conn_p,
+                                          xcb_dri2_ck,
+                                          &error_p);
+    if (error_p)
+    {
+        ret.error_str = "Can't find dri2 extension";
+        ret.error_code = error_p->error_code;
+    }
+
+    if (xcb_dri2_reply_p)
+        free(xcb_dri2_reply_p);
+    if (error_p)
+        free(error_p);
+    return ret;
+}
+
+rule_s
+make_rule (xcb_connection_t *xcb_conn_p, xcb_screen_t *screen_p)
+{
+    rule_s ret = {};
+    ret.count_frame_per_change = 2;
+    ret.count_uniqes_frames = 10;
+    ret.frame_per_second = 30;
+    ret.max_width = screen_p->width_in_pixels;
+    ret.max_height = screen_p->height_in_pixels;
+    ret.dst_change = 1;
+    ret.src_change = 0;
+    ret.min_height = 100;
+    ret.min_width = 100;
+    ret.image_width = 640;
+    ret.image_height = 480;
+    ret.image_fourcc = FOURCC_SR32;
+    return ret;
+}
+
+test_map_s
+init_tests (void)
+{
+    test_map_s ret = {};
+    ret.num_tests = 1;
+    ret.test_case_array = calloc(ret.num_tests, sizeof(test_case_s));
+    if (ret.test_case_array == NULL)
+    {
+        fprintf(stderr, "Can't alloc memory for test");
+        ret.num_tests = 0;
+        goto error_close;
+    }
+
+    ret.error_array = calloc(ret.num_tests, sizeof(error_s));
+    if (ret.error_array == NULL)
+    {
+        fprintf(stderr, "Can't alloc memory for test");
+        ret.num_tests = 0;
+        goto error_close;
+    }
+    ret.test_case_array[0] = test_xv_resize_init();
+    return ret;
+error_close:
+    if (ret.test_case_array)
+        free(ret.test_case_array);
+    if (ret.error_array)
+        free(ret.error_array);
+
+    return ret;
+}
+
+int main ()
+{
+    xcb_screen_iterator_t screen_iter;
+    xcb_connection_t     *xcb_conn_p;
+    const xcb_setup_t    *setup;
+    xcb_screen_t         *screen_p;
+    int                   screen_number;
+    test_map_s tests = {};
+    rule_s rule_p = {};
+    error_s ret;
+    /* getting the connection */
+    xcb_conn_p = xcb_connect (NULL, &screen_number);
+    if (!xcb_conn_p)
+    {
+        fprintf(stderr, "ERROR: can't connect to an X server\n");
+    }
+    ret = check_xv (xcb_conn_p);
+    exit_if_fail (ret);
+    ret = check_shm (xcb_conn_p);
+    exit_if_fail (ret);
+    ret = check_dri2 (xcb_conn_p);
+    exit_if_fail (ret);
+    DBG;
+    /* getting the current screen */
+    setup = xcb_get_setup (xcb_conn_p);
+    screen_p = NULL;
+    screen_iter = xcb_setup_roots_iterator (setup);
+    for (; screen_iter.rem != 0; --screen_number, xcb_screen_next (&screen_iter))
+        if (screen_number == 0)
+        {
+            screen_p = screen_iter.data;
+            break;
+        }
+    if (!screen_p) {
+        fprintf (stderr, "ERROR: can't get the current screen\n");
+        xcb_disconnect (xcb_conn_p);
+        return -1;
+    }
+    rule_p = make_rule (xcb_conn_p, screen_p);
+    tests = init_tests();
+    if (tests.num_tests == 0)
+    {
+        fprintf (stderr, "Nothing to test. num_tests = 0\n");
+        return 0;
+    }
+    int i;
+    DBG;
+    for (i = 0; i < tests.num_tests; i++)
+    {
+        ret = tests.test_case_array[i].prepare_test(xcb_conn_p, screen_p, rule_p);
+        if (ret.error_str)
+        {
+            tests.error_array[i] = ret;
+            continue;
+        }
+        ret = tests.test_case_array[i].run_test(xcb_conn_p, screen_p, rule_p);
+        if (ret.error_str)
+        {
+            tests.error_array[i] = ret;
+            continue;
+        }
+        ret = tests.test_case_array[i].close_test(xcb_conn_p, screen_p, rule_p);
+        if (ret.error_str)
+        {
+            tests.error_array[i] = ret;
+            continue;
+        }
+    }
+    for (i = 0; i < tests.num_tests; i++)
+    {
+        fprintf(stderr, "%s %d\n", tests.error_array[i].error_str,
+                tests.error_array[i].error_code);
+    }
+    return 0;
+}
diff --git a/tests/functional/xv_test/xv_test.h b/tests/functional/xv_test/xv_test.h
new file mode 100644 (file)
index 0000000..3c33e27
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/shm.h>
+#include <xcb/xcb.h>
+
+#include <xf86drm.h>
+#include <tbm_bufmgr.h>
+
+#include "xv_types.h"
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define max(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a > _b ? _a : _b; })
+#define min(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a < _b ? _a : _b; })
+
+#define exit_if_fail(error_s) \
+    {if (error_s.error_str) {\
+        fprintf (stderr, "Error: '%s' code: '%d'\n", \
+                 error_s.error_str, error_s.error_code); \
+     exit(-1);}}
+
+#define C(b,m)              (((b) >> (m)) & 0xFF)
+#define B(c,s)              ((((unsigned int)(c)) & 0xff) << (s))
+#define FOURCC(a,b,c,d)     (B(d,24) | B(c,16) | B(b,8) | B(a,0))
+#define FOURCC_STR(id)      C(id,0), C(id,8), C(id,16), C(id,24)
+#define FOURCC_RGB565   FOURCC('R','G','B','P')
+#define FOURCC_RGB32    FOURCC('R','G','B','4')
+#define FOURCC_I420     FOURCC('I','4','2','0')
+#define FOURCC_SR16     FOURCC('S','R','1','6')
+#define FOURCC_SR32     FOURCC('S','R','3','2')
+#define FOURCC_S420     FOURCC('S','4','2','0')
+
+#define FOURCC_SN12     FOURCC('S','N','1','2')
+#define XVIMAGE_SN12 \
+   { \
+    FOURCC_SN12, \
+    XvYUV, \
+    LSBFirst, \
+    {'S','N','1','2', \
+      0x00,0x00,0x00,0x10,0x80,0x00,0x00,0xAA,0x00,0x38,0x9B,0x71}, \
+    12, \
+    XvPlanar, \
+    2, \
+    0, 0, 0, 0, \
+    8, 8, 8, \
+    1, 2, 2, \
+    1, 2, 2, \
+    {'Y','U','V', \
+      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, \
+    XvTopToBottom \
+   }
+
+#define DBG \
+{printf("%s %d\n", __FUNCTION__, __LINE__);}
+
+typedef struct
+{
+    uint32_t  min_width;
+    uint32_t  min_height;
+    uint32_t  max_width;
+    uint32_t  max_height;
+    int src_change;
+    int dst_change;
+    uint32_t image_width;
+    uint32_t image_height;
+    uint32_t image_fourcc;
+    size_t count_frame_per_change;
+    size_t frame_per_second;
+    size_t count_uniqes_frames;
+    /* TODO: More rules */
+} rule_s;
+
+typedef struct
+{
+    uint8_t error_code;
+    char const * error_str;
+} error_s;
+
+typedef error_s (*prepare_test_case) (xcb_connection_t *, xcb_screen_t *, rule_s);
+typedef error_s (*run_test_case) (xcb_connection_t *, xcb_screen_t *, rule_s);
+typedef error_s (*close_test_case)(xcb_connection_t *, xcb_screen_t *, rule_s);
+
+typedef struct _test_case_s
+{
+    prepare_test_case prepare_test;
+    run_test_case run_test;
+    close_test_case close_test;
+} test_case_s;
+#endif