| /************************************************************************** |
| * |
| * Copyright 2009 Younes Manton. |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| **************************************************************************/ |
| |
| #include <assert.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <error.h> |
| #include "testlib.h" |
| |
| #define BLOCK_WIDTH 8 |
| #define BLOCK_HEIGHT 8 |
| #define BLOCK_SIZE (BLOCK_WIDTH * BLOCK_HEIGHT) |
| #define MACROBLOCK_WIDTH 16 |
| #define MACROBLOCK_HEIGHT 16 |
| #define MACROBLOCK_WIDTH_IN_BLOCKS (MACROBLOCK_WIDTH / BLOCK_WIDTH) |
| #define MACROBLOCK_HEIGHT_IN_BLOCKS (MACROBLOCK_HEIGHT / BLOCK_HEIGHT) |
| #define BLOCKS_PER_MACROBLOCK 6 |
| |
| #define INPUT_WIDTH 64 |
| #define INPUT_HEIGHT 64 |
| #define INPUT_WIDTH_IN_MACROBLOCKS (INPUT_WIDTH / MACROBLOCK_WIDTH) |
| #define INPUT_HEIGHT_IN_MACROBLOCKS (INPUT_HEIGHT / MACROBLOCK_HEIGHT) |
| #define NUM_MACROBLOCKS (INPUT_WIDTH_IN_MACROBLOCKS * INPUT_HEIGHT_IN_MACROBLOCKS) |
| |
| #define DEFAULT_OUTPUT_WIDTH INPUT_WIDTH |
| #define DEFAULT_OUTPUT_HEIGHT INPUT_HEIGHT |
| #define DEFAULT_ACCEPTABLE_ERR 0.01 |
| |
| void ParseArgs(int argc, char **argv, unsigned int *output_width, unsigned int *output_height, double *acceptable_error, int *prompt); |
| |
| void ParseArgs(int argc, char **argv, unsigned int *output_width, unsigned int *output_height, double *acceptable_error, int *prompt) |
| { |
| int fail = 0; |
| int i; |
| |
| *output_width = DEFAULT_OUTPUT_WIDTH; |
| *output_height = DEFAULT_OUTPUT_HEIGHT; |
| *acceptable_error = DEFAULT_ACCEPTABLE_ERR; |
| *prompt = 1; |
| |
| for (i = 1; i < argc && !fail; ++i) |
| { |
| if (!strcmp(argv[i], "-w")) |
| { |
| if (sscanf(argv[++i], "%u", output_width) != 1) |
| fail = 1; |
| } |
| else if (!strcmp(argv[i], "-h")) |
| { |
| if (sscanf(argv[++i], "%u", output_height) != 1) |
| fail = 1; |
| } |
| else if (!strcmp(argv[i], "-e")) |
| { |
| if (sscanf(argv[++i], "%lf", acceptable_error) != 1) |
| fail = 1; |
| } |
| else if (strcmp(argv[i], "-n")) |
| *prompt = 0; |
| else |
| fail = 1; |
| } |
| |
| if (fail) |
| error |
| ( |
| 1, 0, |
| "Bad argument.\n" |
| "\n" |
| "Usage: %s [options]\n" |
| "\t-w <width>\tOutput width\n" |
| "\t-h <height>\tOutput height\n" |
| "\t-e <error>\tAcceptable margin of error per pixel, from 0 to 1\n" |
| "\t-n\tDon't prompt for quit\n", |
| argv[0] |
| ); |
| } |
| |
| static void Gradient(short *block, unsigned int start, unsigned int stop, int horizontal, unsigned int intra_unsigned) |
| { |
| unsigned int x, y; |
| unsigned int range = stop - start; |
| |
| if (horizontal) |
| { |
| for (y = 0; y < BLOCK_HEIGHT; ++y) |
| for (x = 0; x < BLOCK_WIDTH; ++x) { |
| *block = (short)(start + range * (x / (float)(BLOCK_WIDTH - 1))); |
| if (intra_unsigned) |
| *block += 1 << 10; |
| block++; |
| } |
| } |
| else |
| { |
| for (y = 0; y < BLOCK_HEIGHT; ++y) |
| for (x = 0; x < BLOCK_WIDTH; ++x) { |
| *block = (short)(start + range * (y / (float)(BLOCK_WIDTH - 1))); |
| if (intra_unsigned) |
| *block += 1 << 10; |
| block++; |
| } |
| } |
| } |
| |
| int main(int argc, char **argv) |
| { |
| unsigned int output_width; |
| unsigned int output_height; |
| double acceptable_error; |
| int prompt; |
| Display *display; |
| Window root, window; |
| const unsigned int mc_types[] = {XVMC_MOCOMP | XVMC_MPEG_2}; |
| XvPortID port_num; |
| int surface_type_id; |
| unsigned int is_overlay, intra_unsigned; |
| int colorkey; |
| XvMCContext context; |
| XvMCSurface surface; |
| XvMCBlockArray block_array; |
| XvMCMacroBlockArray mb_array; |
| int mbx, mby, bx, by; |
| XvMCMacroBlock *mb; |
| short *blocks; |
| int quit = 0; |
| |
| ParseArgs(argc, argv, &output_width, &output_height, &acceptable_error, &prompt); |
| |
| display = XOpenDisplay(NULL); |
| |
| if (!GetPort |
| ( |
| display, |
| INPUT_WIDTH, |
| INPUT_HEIGHT, |
| XVMC_CHROMA_FORMAT_420, |
| mc_types, |
| sizeof(mc_types)/sizeof(*mc_types), |
| &port_num, |
| &surface_type_id, |
| &is_overlay, |
| &intra_unsigned |
| )) |
| { |
| XCloseDisplay(display); |
| error(1, 0, "Error, unable to find a good port.\n"); |
| } |
| |
| if (is_overlay) |
| { |
| Atom xv_colorkey = XInternAtom(display, "XV_COLORKEY", 0); |
| XvGetPortAttribute(display, port_num, xv_colorkey, &colorkey); |
| } |
| |
| root = XDefaultRootWindow(display); |
| window = XCreateSimpleWindow(display, root, 0, 0, output_width, output_height, 0, 0, colorkey); |
| |
| assert(XvMCCreateContext(display, port_num, surface_type_id, INPUT_WIDTH, INPUT_HEIGHT, XVMC_DIRECT, &context) == Success); |
| assert(XvMCCreateSurface(display, &context, &surface) == Success); |
| assert(XvMCCreateBlocks(display, &context, NUM_MACROBLOCKS * BLOCKS_PER_MACROBLOCK, &block_array) == Success); |
| assert(XvMCCreateMacroBlocks(display, &context, NUM_MACROBLOCKS, &mb_array) == Success); |
| |
| mb = mb_array.macro_blocks; |
| blocks = block_array.blocks; |
| |
| for (mby = 0; mby < INPUT_HEIGHT_IN_MACROBLOCKS; ++mby) |
| for (mbx = 0; mbx < INPUT_WIDTH_IN_MACROBLOCKS; ++mbx) |
| { |
| mb->x = mbx; |
| mb->y = mby; |
| mb->macroblock_type = XVMC_MB_TYPE_INTRA; |
| /*mb->motion_type = ;*/ |
| /*mb->motion_vertical_field_select = ;*/ |
| mb->dct_type = XVMC_DCT_TYPE_FRAME; |
| /*mb->PMV[0][0][0] = ; |
| mb->PMV[0][0][1] = ; |
| mb->PMV[0][1][0] = ; |
| mb->PMV[0][1][1] = ; |
| mb->PMV[1][0][0] = ; |
| mb->PMV[1][0][1] = ; |
| mb->PMV[1][1][0] = ; |
| mb->PMV[1][1][1] = ;*/ |
| mb->index = (mby * INPUT_WIDTH_IN_MACROBLOCKS + mbx) * BLOCKS_PER_MACROBLOCK; |
| mb->coded_block_pattern = 0x3F; |
| |
| mb++; |
| |
| for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS; ++by) |
| for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS; ++bx) |
| { |
| const int start = 16, stop = 235, range = stop - start; |
| |
| Gradient |
| ( |
| blocks, |
| (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))), |
| (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))), |
| 1, |
| intra_unsigned |
| ); |
| |
| blocks += BLOCK_SIZE; |
| } |
| |
| for (by = 0; by < MACROBLOCK_HEIGHT_IN_BLOCKS / 2; ++by) |
| for (bx = 0; bx < MACROBLOCK_WIDTH_IN_BLOCKS / 2; ++bx) |
| { |
| const int start = 16, stop = 240, range = stop - start; |
| |
| Gradient |
| ( |
| blocks, |
| (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))), |
| (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))), |
| 1, |
| intra_unsigned |
| ); |
| |
| blocks += BLOCK_SIZE; |
| |
| Gradient |
| ( |
| blocks, |
| (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH) / (float)(INPUT_WIDTH - 1))), |
| (short)(start + range * ((mbx * MACROBLOCK_WIDTH + bx * BLOCK_WIDTH + BLOCK_WIDTH - 1) / (float)(INPUT_WIDTH - 1))), |
| 1, |
| intra_unsigned |
| ); |
| |
| blocks += BLOCK_SIZE; |
| } |
| } |
| |
| XSelectInput(display, window, ExposureMask | KeyPressMask); |
| XMapWindow(display, window); |
| XSync(display, 0); |
| |
| /* Test NULL context */ |
| assert(XvMCRenderSurface(display, NULL, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadContext); |
| /* Test NULL surface */ |
| assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, NULL, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == XvMCBadSurface); |
| /* Test bad picture structure */ |
| assert(XvMCRenderSurface(display, &context, 0, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == BadValue); |
| /* Test valid params */ |
| assert(XvMCRenderSurface(display, &context, XVMC_FRAME_PICTURE, &surface, NULL, NULL, 0, NUM_MACROBLOCKS, 0, &mb_array, &block_array) == Success); |
| |
| /* Test NULL surface */ |
| assert(XvMCPutSurface(display, NULL, window, 0, 0, INPUT_WIDTH, INPUT_HEIGHT, 0, 0, output_width, output_height, XVMC_FRAME_PICTURE) == XvMCBadSurface); |
| /* Test bad window */ |
| /* XXX: X halts with a bad drawable for some reason, doesn't return BadDrawable as expected */ |
| /*assert(XvMCPutSurface(display, &surface, 0, 0, 0, width, height, 0, 0, width, height, XVMC_FRAME_PICTURE) == BadDrawable);*/ |
| |
| if (prompt) |
| { |
| puts("Press any button to quit..."); |
| |
| while (!quit) |
| { |
| if (XPending(display) > 0) |
| { |
| XEvent event; |
| |
| XNextEvent(display, &event); |
| |
| switch (event.type) |
| { |
| case Expose: |
| { |
| /* Test valid params */ |
| assert |
| ( |
| XvMCPutSurface |
| ( |
| display, &surface, window, |
| 0, 0, INPUT_WIDTH, INPUT_HEIGHT, |
| 0, 0, output_width, output_height, |
| XVMC_FRAME_PICTURE |
| ) == Success |
| ); |
| break; |
| } |
| case KeyPress: |
| { |
| quit = 1; |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| assert(XvMCDestroyBlocks(display, &block_array) == Success); |
| assert(XvMCDestroyMacroBlocks(display, &mb_array) == Success); |
| assert(XvMCDestroySurface(display, &surface) == Success); |
| assert(XvMCDestroyContext(display, &context) == Success); |
| |
| XvUngrabPort(display, port_num, CurrentTime); |
| XDestroyWindow(display, window); |
| XCloseDisplay(display); |
| |
| return 0; |
| } |