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
ParseArgs(int argc,char ** argv,unsigned int * output_width,unsigned int * output_height,double * acceptable_error,int * prompt)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
Gradient(short * block,unsigned int start,unsigned int stop,int horizontal,unsigned int intra_unsigned)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
main(int argc,char ** argv)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