Home | History | Annotate | Download | only in tests
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 Younes Manton.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 /* Force assertions, even on release builds. */
     29 #undef NDEBUG
     30 #include <assert.h>
     31 #include <stdio.h>
     32 #include <string.h>
     33 #include <stdlib.h>
     34 #include "testlib.h"
     35 
     36 #define BLOCK_WIDTH			8
     37 #define BLOCK_HEIGHT			8
     38 #define BLOCK_SIZE			(BLOCK_WIDTH * BLOCK_HEIGHT)
     39 #define MACROBLOCK_WIDTH		16
     40 #define MACROBLOCK_HEIGHT		16
     41 #define MACROBLOCK_WIDTH_IN_BLOCKS	(MACROBLOCK_WIDTH / BLOCK_WIDTH)
     42 #define MACROBLOCK_HEIGHT_IN_BLOCKS	(MACROBLOCK_HEIGHT / BLOCK_HEIGHT)
     43 #define BLOCKS_PER_MACROBLOCK		6
     44 
     45 #define INPUT_WIDTH			64
     46 #define INPUT_HEIGHT			64
     47 #define INPUT_WIDTH_IN_MACROBLOCKS	(INPUT_WIDTH / MACROBLOCK_WIDTH)
     48 #define INPUT_HEIGHT_IN_MACROBLOCKS	(INPUT_HEIGHT / MACROBLOCK_HEIGHT)
     49 #define NUM_MACROBLOCKS			(INPUT_WIDTH_IN_MACROBLOCKS * INPUT_HEIGHT_IN_MACROBLOCKS)
     50 
     51 #define DEFAULT_OUTPUT_WIDTH		INPUT_WIDTH
     52 #define DEFAULT_OUTPUT_HEIGHT		INPUT_HEIGHT
     53 #define DEFAULT_ACCEPTABLE_ERR		0.01
     54 
     55 static void ParseArgs(int argc, char **argv, unsigned int *output_width, unsigned int *output_height, double *acceptable_error, int *prompt)
     56 {
     57 	int fail = 0;
     58 	int i;
     59 
     60 	*output_width = DEFAULT_OUTPUT_WIDTH;
     61 	*output_height = DEFAULT_OUTPUT_HEIGHT;
     62 	*acceptable_error = DEFAULT_ACCEPTABLE_ERR;
     63 	*prompt = 0;
     64 
     65 	for (i = 1; i < argc && !fail; ++i)
     66 	{
     67 		if (!strcmp(argv[i], "-w"))
     68 		{
     69 			if (sscanf(argv[++i], "%u", output_width) != 1)
     70 				fail = 1;
     71 		}
     72 		else if (!strcmp(argv[i], "-h"))
     73 		{
     74 			if (sscanf(argv[++i], "%u", output_height) != 1)
     75 				fail = 1;
     76 		}
     77 		else if (!strcmp(argv[i], "-e"))
     78 		{
     79 			if (sscanf(argv[++i], "%lf", acceptable_error) != 1)
     80 				fail = 1;
     81 		}
     82 		else if (!strcmp(argv[i], "-p"))
     83 			*prompt = 1;
     84 		else
     85 			fail = 1;
     86 	}
     87 
     88 	if (fail)
     89 	{
     90 		fprintf(
     91 			stderr,
     92 			"Bad argument.\n"
     93 			"\n"
     94 			"Usage: %s [options]\n"
     95 			"\t-w <width>\tOutput width\n"
     96 			"\t-h <height>\tOutput height\n"
     97 			"\t-e <error>\tAcceptable margin of error per pixel, from 0 to 1\n"
     98 			"\t-p\tPrompt for quit\n",
     99 			argv[0]
    100 		);
    101 		exit(1);
    102 	}
    103 }
    104 
    105 static void Gradient(short *block, unsigned int start, unsigned int stop, int horizontal, unsigned int intra_unsigned)
    106 {
    107 	unsigned int x, y;
    108 	unsigned int range = stop - start;
    109 
    110 	if (horizontal)
    111 	{
    112 		for (y = 0; y < BLOCK_HEIGHT; ++y)
    113 			for (x = 0; x < BLOCK_WIDTH; ++x) {
    114 				*block = (short)(start + range * (x / (float)(BLOCK_WIDTH - 1)));
    115 				if (intra_unsigned)
    116 					*block += 1 << 10;
    117 				block++;
    118 			}
    119 	}
    120 	else
    121 	{
    122 		for (y = 0; y < BLOCK_HEIGHT; ++y)
    123 			for (x = 0; x < BLOCK_WIDTH; ++x) {
    124 				*block = (short)(start + range * (y / (float)(BLOCK_WIDTH - 1)));
    125 				if (intra_unsigned)
    126 					*block += 1 << 10;
    127 				block++;
    128 			}
    129 	}
    130 }
    131 
    132 int main(int argc, char **argv)
    133 {
    134 	unsigned int		output_width;
    135 	unsigned int		output_height;
    136 	double			acceptable_error;
    137 	int			prompt;
    138 	Display			*display;
    139 	Window			root, window;
    140 	const unsigned int	mc_types[] = {XVMC_MOCOMP | XVMC_MPEG_2};
    141 	XvPortID		port_num;
    142 	int			surface_type_id;
    143 	unsigned int		is_overlay, intra_unsigned;
    144 	int			colorkey;
    145 	XvMCContext		context;
    146 	XvMCSurface		surface;
    147 	XvMCBlockArray		block_array;
    148 	XvMCMacroBlockArray	mb_array;
    149 	int			mbx, mby, bx, by;
    150 	XvMCMacroBlock		*mb;
    151 	short			*blocks;
    152 	int			quit = 0;
    153 
    154 	ParseArgs(argc, argv, &output_width, &output_height, &acceptable_error, &prompt);
    155 
    156 	display = XOpenDisplay(NULL);
    157 
    158 	if (!GetPort
    159 	(
    160 		display,
    161 		INPUT_WIDTH,
    162 		INPUT_HEIGHT,
    163 		XVMC_CHROMA_FORMAT_420,
    164 		mc_types,
    165 		sizeof(mc_types)/sizeof(*mc_types),
    166 		&port_num,
    167 		&surface_type_id,
    168 		&is_overlay,
    169 		&intra_unsigned
    170 	))
    171 	{
    172 		XCloseDisplay(display);
    173 		fprintf(stderr, "Error, unable to find a good port.\n");
    174 		exit(1);
    175 	}
    176 
    177 	if (is_overlay)
    178 	{
    179 		Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
    180 		XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
    181 	}
    182 
    183 	root = XDefaultRootWindow(display);
    184 	window = XCreateSimpleWindow(display, root, 0, 0, output_width, output_height, 0, 0, colorkey);
    185 
    186 	assert(XvMCCreateContext(display, port_num, surface_type_id, INPUT_WIDTH, INPUT_HEIGHT, XVMC_DIRECT, &context) == Success);
    187 	assert(XvMCCreateSurface(display, &context, &surface) == Success);
    188 	assert(XvMCCreateBlocks(display, &context, NUM_MACROBLOCKS * BLOCKS_PER_MACROBLOCK, &block_array) == Success);
    189 	assert(XvMCCreateMacroBlocks(display, &context, NUM_MACROBLOCKS, &mb_array) == Success);
    190 
    191 	mb = mb_array.macro_blocks;
    192 	blocks = block_array.blocks;
    193 
    194 	for (mby = 0; mby < INPUT_HEIGHT_IN_MACROBLOCKS; ++mby)
    195 		for (mbx = 0; mbx < INPUT_WIDTH_IN_MACROBLOCKS; ++mbx)
    196 		{
    197 			mb->x = mbx;
    198 			mb->y = mby;
    199 			mb->macroblock_type = XVMC_MB_TYPE_INTRA;
    200 			/*mb->motion_type = ;*/
    201 			/*mb->motion_vertical_field_select = ;*/
    202 			mb->dct_type = XVMC_DCT_TYPE_FRAME;
    203 			/*mb->PMV[0][0][0] = ;
    204 			mb->PMV[0][0][1] = ;
    205 			mb->PMV[0][1][0] = ;
    206 			mb->PMV[0][1][1] = ;
    207 			mb->PMV[1][0][0] = ;
    208 			mb->PMV[1][0][1] = ;
    209 			mb->PMV[1][1][0] = ;
    210 			mb->PMV[1][1][1] = ;*/
    211 			mb->index = (mby * INPUT_WIDTH_IN_MACROBLOCKS + mbx) * BLOCKS_PER_MACROBLOCK;
    212 			mb->coded_block_pattern = 0x3F;
    213 
    214 			mb++;
    215 
    216 			for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS; ++by)
    217 				for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS; ++bx)
    218 				{
    219 					const int start = 16, stop = 235, range = stop - start;
    220 
    221 					Gradient
    222 					(
    223 						blocks,
    224 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))),
    225 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))),
    226 						1,
    227 						intra_unsigned
    228 					);
    229 
    230 					blocks += BLOCK_SIZE;
    231 				}
    232 
    233 			for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS / 2; ++by)
    234 				for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS / 2; ++bx)
    235 				{
    236 					const int start = 16, stop = 240, range = stop - start;
    237 
    238 					Gradient
    239 					(
    240 						blocks,
    241 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))),
    242 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))),
    243 						1,
    244 						intra_unsigned
    245 					);
    246 
    247 					blocks += BLOCK_SIZE;
    248 
    249 					Gradient
    250 					(
    251 						blocks,
    252 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))),
    253 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))),
    254 						1,
    255 						intra_unsigned
    256 					);
    257 
    258 					blocks += BLOCK_SIZE;
    259 				}
    260 		}
    261 
    262 	XSelectInput(display, window, ExposureMask | KeyPressMask);
    263 	XMapWindow(display, window);
    264 	XSync(display, 0);
    265 
    266 	/* Test NULL context */
    267 	assert(XvMCRenderSurface(display, NULL, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadContext);
    268 	/* Test NULL surface */
    269 	assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, NULL, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadSurface);
    270 	/* Test bad picture structure */
    271 	assert(XvMCRenderSurface(display, &context, 0, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == BadValue);
    272 	/* Test valid params */
    273 	assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == Success);
    274 
    275 	/* Test NULL surface */
    276 	assert(XvMCPutSurface(display, NULL, window, 0, 0, INPUT_WIDTH, INPUT_HEIGHT, 0, 0, output_width, output_height, XVMC_FRAME_PICTURE) == XvMCBadSurface);
    277 	/* Test bad window */
    278 	/* XXX: X halts with a bad drawable for some reason, doesn't return BadDrawable as expected */
    279 	/*assert(XvMCPutSurface(display, &surface, 0, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == BadDrawable);*/
    280 
    281 	if (prompt)
    282 	{
    283 		puts("Press any button to quit...");
    284 
    285 		while (!quit)
    286 		{
    287 			if (XPending(display) > 0)
    288 			{
    289 				XEvent event;
    290 
    291 				XNextEvent(display, &event);
    292 
    293 				switch (event.type)
    294 				{
    295 					case Expose:
    296 					{
    297 						/* Test valid params */
    298 						assert
    299 						(
    300 							XvMCPutSurface
    301 							(
    302 								display, &surface, window,
    303 								0, 0, INPUT_WIDTH, INPUT_HEIGHT,
    304 								0, 0, output_width, output_height,
    305 								XVMC_FRAME_PICTURE
    306 							) == Success
    307 						);
    308 						break;
    309 					}
    310 					case KeyPress:
    311 					{
    312 						quit = 1;
    313 						break;
    314 					}
    315 				}
    316 			}
    317 		}
    318 	}
    319 
    320 	assert(XvMCDestroyBlocks(display, &block_array) == Success);
    321 	assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success);
    322 	assert(XvMCDestroySurface(display, &surface) == Success);
    323 	assert(XvMCDestroyContext(display, &context) == Success);
    324 
    325 	XvUngrabPort(display, port_num, CurrentTime);
    326 	XDestroyWindow(display, window);
    327 	XCloseDisplay(display);
    328 
    329 	return 0;
    330 }
    331