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