• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ParseArgs(int argc,char ** argv,unsigned int * output_width,unsigned int * output_height,double * acceptable_error,int * prompt)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 
Gradient(short * block,unsigned int start,unsigned int stop,int horizontal,unsigned int intra_unsigned)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 
main(int argc,char ** argv)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