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 55static 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 105static 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 132int 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