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 TUNGSTEN GRAPHICS 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 #include <assert.h>
     29 #include <stdio.h>
     30 #include <string.h>
     31 #include <error.h>
     32 #include "testlib.h"
     33 
     34 #define BLOCK_WIDTH			8
     35 #define BLOCK_HEIGHT			8
     36 #define BLOCK_SIZE			(BLOCK_WIDTH * BLOCK_HEIGHT)
     37 #define MACROBLOCK_WIDTH		16
     38 #define MACROBLOCK_HEIGHT		16
     39 #define MACROBLOCK_WIDTH_IN_BLOCKS	(MACROBLOCK_WIDTH / BLOCK_WIDTH)
     40 #define MACROBLOCK_HEIGHT_IN_BLOCKS	(MACROBLOCK_HEIGHT / BLOCK_HEIGHT)
     41 #define BLOCKS_PER_MACROBLOCK		6
     42 
     43 #define INPUT_WIDTH			64
     44 #define INPUT_HEIGHT			64
     45 #define INPUT_WIDTH_IN_MACROBLOCKS	(INPUT_WIDTH / MACROBLOCK_WIDTH)
     46 #define INPUT_HEIGHT_IN_MACROBLOCKS	(INPUT_HEIGHT / MACROBLOCK_HEIGHT)
     47 #define NUM_MACROBLOCKS			(INPUT_WIDTH_IN_MACROBLOCKS * INPUT_HEIGHT_IN_MACROBLOCKS)
     48 
     49 #define DEFAULT_OUTPUT_WIDTH		INPUT_WIDTH
     50 #define DEFAULT_OUTPUT_HEIGHT		INPUT_HEIGHT
     51 #define DEFAULT_ACCEPTABLE_ERR		0.01
     52 
     53 void ParseArgs(int argc, char **argv, unsigned int *output_width, unsigned int *output_height, double *acceptable_error, int *prompt);
     54 
     55 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 = 1;
     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], "-n"))
     83 			*prompt = 0;
     84 		else
     85 			fail = 1;
     86 	}
     87 
     88 	if (fail)
     89 		error
     90 		(
     91 			1, 0,
     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-n\tDon't prompt for quit\n",
     99 			argv[0]
    100 		);
    101 }
    102 
    103 static void Gradient(short *block, unsigned int start, unsigned int stop, int horizontal, unsigned int intra_unsigned)
    104 {
    105 	unsigned int x, y;
    106 	unsigned int range = stop - start;
    107 
    108 	if (horizontal)
    109 	{
    110 		for (y = 0; y < BLOCK_HEIGHT; ++y)
    111 			for (x = 0; x < BLOCK_WIDTH; ++x) {
    112 				*block = (short)(start + range * (x / (float)(BLOCK_WIDTH - 1)));
    113 				if (intra_unsigned)
    114 					*block += 1 << 10;
    115 				block++;
    116 			}
    117 	}
    118 	else
    119 	{
    120 		for (y = 0; y < BLOCK_HEIGHT; ++y)
    121 			for (x = 0; x < BLOCK_WIDTH; ++x) {
    122 				*block = (short)(start + range * (y / (float)(BLOCK_WIDTH - 1)));
    123 				if (intra_unsigned)
    124 					*block += 1 << 10;
    125 				block++;
    126 			}
    127 	}
    128 }
    129 
    130 int main(int argc, char **argv)
    131 {
    132 	unsigned int		output_width;
    133 	unsigned int		output_height;
    134 	double			acceptable_error;
    135 	int			prompt;
    136 	Display			*display;
    137 	Window			root, window;
    138 	const unsigned int	mc_types[] = {XVMC_MOCOMP | XVMC_MPEG_2};
    139 	XvPortID		port_num;
    140 	int			surface_type_id;
    141 	unsigned int		is_overlay, intra_unsigned;
    142 	int			colorkey;
    143 	XvMCContext		context;
    144 	XvMCSurface		surface;
    145 	XvMCBlockArray		block_array;
    146 	XvMCMacroBlockArray	mb_array;
    147 	int			mbx, mby, bx, by;
    148 	XvMCMacroBlock		*mb;
    149 	short			*blocks;
    150 	int			quit = 0;
    151 
    152 	ParseArgs(argc, argv, &output_width, &output_height, &acceptable_error, &prompt);
    153 
    154 	display = XOpenDisplay(NULL);
    155 
    156 	if (!GetPort
    157 	(
    158 		display,
    159 		INPUT_WIDTH,
    160 		INPUT_HEIGHT,
    161 		XVMC_CHROMA_FORMAT_420,
    162 		mc_types,
    163 		sizeof(mc_types)/sizeof(*mc_types),
    164 		&port_num,
    165 		&surface_type_id,
    166 		&is_overlay,
    167 		&intra_unsigned
    168 	))
    169 	{
    170 		XCloseDisplay(display);
    171 		error(1, 0, "Error, unable to find a good port.\n");
    172 	}
    173 
    174 	if (is_overlay)
    175 	{
    176 		Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0);
    177 		XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey);
    178 	}
    179 
    180 	root = XDefaultRootWindow(display);
    181 	window = XCreateSimpleWindow(display, root, 0, 0, output_width, output_height, 0, 0, colorkey);
    182 
    183 	assert(XvMCCreateContext(display, port_num, surface_type_id, INPUT_WIDTH, INPUT_HEIGHT, XVMC_DIRECT, &context) == Success);
    184 	assert(XvMCCreateSurface(display, &context, &surface) == Success);
    185 	assert(XvMCCreateBlocks(display, &context, NUM_MACROBLOCKS * BLOCKS_PER_MACROBLOCK, &block_array) == Success);
    186 	assert(XvMCCreateMacroBlocks(display, &context, NUM_MACROBLOCKS, &mb_array) == Success);
    187 
    188 	mb = mb_array.macro_blocks;
    189 	blocks = block_array.blocks;
    190 
    191 	for (mby = 0; mby < INPUT_HEIGHT_IN_MACROBLOCKS; ++mby)
    192 		for (mbx = 0; mbx < INPUT_WIDTH_IN_MACROBLOCKS; ++mbx)
    193 		{
    194 			mb->x = mbx;
    195 			mb->y = mby;
    196 			mb->macroblock_type = XVMC_MB_TYPE_INTRA;
    197 			/*mb->motion_type = ;*/
    198 			/*mb->motion_vertical_field_select = ;*/
    199 			mb->dct_type = XVMC_DCT_TYPE_FRAME;
    200 			/*mb->PMV[0][0][0] = ;
    201 			mb->PMV[0][0][1] = ;
    202 			mb->PMV[0][1][0] = ;
    203 			mb->PMV[0][1][1] = ;
    204 			mb->PMV[1][0][0] = ;
    205 			mb->PMV[1][0][1] = ;
    206 			mb->PMV[1][1][0] = ;
    207 			mb->PMV[1][1][1] = ;*/
    208 			mb->index = (mby * INPUT_WIDTH_IN_MACROBLOCKS + mbx) * BLOCKS_PER_MACROBLOCK;
    209 			mb->coded_block_pattern = 0x3F;
    210 
    211 			mb++;
    212 
    213 			for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS; ++by)
    214 				for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS; ++bx)
    215 				{
    216 					const int start = 16, stop = 235, range = stop - start;
    217 
    218 					Gradient
    219 					(
    220 						blocks,
    221 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))),
    222 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))),
    223 						1,
    224 						intra_unsigned
    225 					);
    226 
    227 					blocks += BLOCK_SIZE;
    228 				}
    229 
    230 			for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS / 2; ++by)
    231 				for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS / 2; ++bx)
    232 				{
    233 					const int start = 16, stop = 240, range = stop - start;
    234 
    235 					Gradient
    236 					(
    237 						blocks,
    238 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))),
    239 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))),
    240 						1,
    241 						intra_unsigned
    242 					);
    243 
    244 					blocks += BLOCK_SIZE;
    245 
    246 					Gradient
    247 					(
    248 						blocks,
    249 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))),
    250 						(short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))),
    251 						1,
    252 						intra_unsigned
    253 					);
    254 
    255 					blocks += BLOCK_SIZE;
    256 				}
    257 		}
    258 
    259 	XSelectInput(display, window, ExposureMask | KeyPressMask);
    260 	XMapWindow(display, window);
    261 	XSync(display, 0);
    262 
    263 	/* Test NULL context */
    264 	assert(XvMCRenderSurface(display, NULL, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadContext);
    265 	/* Test NULL surface */
    266 	assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, NULL, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadSurface);
    267 	/* Test bad picture structure */
    268 	assert(XvMCRenderSurface(display, &context, 0, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == BadValue);
    269 	/* Test valid params */
    270 	assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == Success);
    271 
    272 	/* Test NULL surface */
    273 	assert(XvMCPutSurface(display, NULL, window, 0, 0, INPUT_WIDTH, INPUT_HEIGHT, 0, 0, output_width, output_height, XVMC_FRAME_PICTURE) == XvMCBadSurface);
    274 	/* Test bad window */
    275 	/* XXX: X halts with a bad drawable for some reason, doesn't return BadDrawable as expected */
    276 	/*assert(XvMCPutSurface(display, &surface, 0, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == BadDrawable);*/
    277 
    278 	if (prompt)
    279 	{
    280 		puts("Press any button to quit...");
    281 
    282 		while (!quit)
    283 		{
    284 			if (XPending(display) > 0)
    285 			{
    286 				XEvent event;
    287 
    288 				XNextEvent(display, &event);
    289 
    290 				switch (event.type)
    291 				{
    292 					case Expose:
    293 					{
    294 						/* Test valid params */
    295 						assert
    296 						(
    297 							XvMCPutSurface
    298 							(
    299 								display, &surface, window,
    300 								0, 0, INPUT_WIDTH, INPUT_HEIGHT,
    301 								0, 0, output_width, output_height,
    302 								XVMC_FRAME_PICTURE
    303 							) == Success
    304 						);
    305 						break;
    306 					}
    307 					case KeyPress:
    308 					{
    309 						quit = 1;
    310 						break;
    311 					}
    312 				}
    313 			}
    314 		}
    315 	}
    316 
    317 	assert(XvMCDestroyBlocks(display, &block_array) == Success);
    318 	assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success);
    319 	assert(XvMCDestroySurface(display, &surface) == Success);
    320 	assert(XvMCDestroyContext(display, &context) == Success);
    321 
    322 	XvUngrabPort(display, port_num, CurrentTime);
    323 	XDestroyWindow(display, window);
    324 	XCloseDisplay(display);
    325 
    326 	return 0;
    327 }
    328