1 /* 2 * Copyright (c) 2008-2009 Intel Corporation. All Rights Reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the 6 * "Software"), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sub license, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the 13 * next paragraph) shall be included in all copies or substantial portions 14 * of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 19 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR 20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <stdio.h> 26 #include <string.h> 27 #include <stdlib.h> 28 #include <stdint.h> 29 #include <getopt.h> 30 31 #include <sys/time.h> 32 33 #include <unistd.h> 34 35 #include <sys/types.h> 36 #include <sys/stat.h> 37 #include <fcntl.h> 38 #include <assert.h> 39 #include <pthread.h> 40 41 /*currently, if XCheckWindowEvent was called in more than one thread, it would cause 42 * XIO: fatal IO error 11 (Resource temporarily unavailable) on X server ":0.0" 43 * after 87 requests (83 known processed) with 0 events remaining. 44 * 45 * X Error of failed request: BadGC (invalid GC parameter) 46 * Major opcode of failed request: 60 (X_FreeGC) 47 * Resource id in failed request: 0x600034 48 * Serial number of failed request: 398 49 * Current serial number in output stream: 399 50 * The root cause is unknown. */ 51 52 #define CHECK_VASTATUS(va_status,func) \ 53 if (va_status != VA_STATUS_SUCCESS) { \ 54 fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \ 55 exit(1); \ 56 } 57 #include "../loadsurface.h" 58 59 #define SURFACE_NUM 16 60 61 static void *win_display; 62 static VADisplay va_dpy; 63 static VAImageFormat *va_image_formats; 64 static int va_num_image_formats = -1; 65 static VAConfigID vpp_config_id = VA_INVALID_ID; 66 static VASurfaceAttrib *va_surface_attribs; 67 static int va_num_surface_attribs = -1; 68 static VASurfaceID surface_id[SURFACE_NUM]; 69 static pthread_mutex_t surface_mutex[SURFACE_NUM]; 70 71 static void *drawable_thread0, *drawable_thread1; 72 static int surface_width = 352, surface_height = 288; 73 static int win_x = 0, win_y = 0; 74 static int win_width = 352, win_height = 288; 75 static int frame_rate = 0; 76 static unsigned long long frame_num_total = ~0; 77 static int check_event = 1; 78 static int put_pixmap = 0; 79 static int test_clip = 0; 80 static int display_field = VA_FRAME_PICTURE; 81 static pthread_mutex_t gmutex; 82 static int box_width = 32; 83 static int multi_thread = 0; 84 static int verbose = 0; 85 static int test_color_conversion = 0; 86 static unsigned int csc_src_fourcc = 0, csc_dst_fourcc = 0; 87 static VAImage csc_dst_fourcc_image; 88 static VASurfaceID csc_render_surface; 89 90 91 typedef struct { 92 char * fmt_str; 93 unsigned int fourcc; 94 } fourcc_map; 95 fourcc_map va_fourcc_map[] = { 96 {"YUYV", VA_FOURCC_YUY2}, 97 {"YUY2", VA_FOURCC_YUY2}, 98 {"NV12", VA_FOURCC_NV12}, 99 {"YV12", VA_FOURCC_YV12}, 100 {"BGRA", VA_FOURCC_BGRA}, 101 {"RGBA", VA_FOURCC_RGBA}, 102 {"BGRX", VA_FOURCC_BGRX}, 103 {"RGBX", VA_FOURCC_RGBX}, 104 }; 105 unsigned int map_str_to_vafourcc (char * str) 106 { 107 unsigned int i; 108 for (i=0; i< sizeof(va_fourcc_map)/sizeof(fourcc_map); i++) { 109 if (!strcmp(va_fourcc_map[i].fmt_str, str)) { 110 return va_fourcc_map[i].fourcc; 111 } 112 } 113 114 return 0; 115 116 } 117 char* map_vafourcc_to_str (unsigned int format) 118 { 119 static char unknown_format[] = "unknown-format"; 120 unsigned int i; 121 for (i=0; i< sizeof(va_fourcc_map)/sizeof(fourcc_map); i++) { 122 if (va_fourcc_map[i].fourcc == format) { 123 return va_fourcc_map[i].fmt_str; 124 } 125 } 126 127 return unknown_format; 128 129 } 130 131 static int 132 va_value_equals(const VAGenericValue *v1, const VAGenericValue *v2) 133 { 134 if (v1->type != v2->type) 135 return 0; 136 137 switch (v1->type) { 138 case VAGenericValueTypeInteger: 139 return v1->value.i == v2->value.i; 140 case VAGenericValueTypeFloat: 141 return v1->value.f == v2->value.f; 142 case VAGenericValueTypePointer: 143 return v1->value.p == v2->value.p; 144 case VAGenericValueTypeFunc: 145 return v1->value.fn == v2->value.fn; 146 } 147 return 0; 148 } 149 150 static int 151 ensure_image_formats(void) 152 { 153 VAStatus va_status; 154 VAImageFormat *image_formats; 155 int num_image_formats; 156 157 if (va_num_image_formats >= 0) 158 return va_num_image_formats; 159 160 num_image_formats = vaMaxNumImageFormats(va_dpy); 161 if (num_image_formats == 0) 162 return 0; 163 164 image_formats = malloc(num_image_formats * sizeof(*image_formats)); 165 if (!image_formats) 166 return 0; 167 168 va_status = vaQueryImageFormats(va_dpy, image_formats, &num_image_formats); 169 CHECK_VASTATUS(va_status, "vaQuerySurfaceAttributes()"); 170 171 va_image_formats = image_formats; 172 va_num_image_formats = num_image_formats; 173 return num_image_formats; 174 } 175 176 static const VAImageFormat * 177 lookup_image_format(uint32_t fourcc) 178 { 179 int i; 180 181 if (!ensure_image_formats()) 182 return NULL; 183 184 for (i = 0; i < va_num_image_formats; i++) { 185 const VAImageFormat * const image_format = &va_image_formats[i]; 186 if (image_format->fourcc == fourcc) 187 return image_format; 188 } 189 return NULL; 190 } 191 192 static int 193 ensure_surface_attribs(void) 194 { 195 VAStatus va_status; 196 VASurfaceAttrib *surface_attribs; 197 unsigned int num_image_formats, num_surface_attribs; 198 199 if (va_num_surface_attribs >= 0) 200 return va_num_surface_attribs; 201 202 num_image_formats = vaMaxNumImageFormats(va_dpy); 203 if (num_image_formats == 0) 204 return 0; 205 206 va_status = vaCreateConfig(va_dpy, VAProfileNone, VAEntrypointVideoProc, 207 NULL, 0, &vpp_config_id); 208 CHECK_VASTATUS(va_status, "vaCreateConfig()"); 209 210 /* Guess the number of surface attributes, thus including any 211 pixel-format supported by the VA driver */ 212 num_surface_attribs = VASurfaceAttribCount + num_image_formats; 213 surface_attribs = malloc(num_surface_attribs * sizeof(*surface_attribs)); 214 if (!surface_attribs) 215 return 0; 216 217 va_status = vaQuerySurfaceAttributes(va_dpy, vpp_config_id, 218 surface_attribs, &num_surface_attribs); 219 if (va_status == VA_STATUS_SUCCESS) 220 va_surface_attribs = surface_attribs; 221 else if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) { 222 va_surface_attribs = realloc(surface_attribs, 223 num_surface_attribs * sizeof(*va_surface_attribs)); 224 if (!va_surface_attribs) { 225 free(surface_attribs); 226 return 0; 227 } 228 va_status = vaQuerySurfaceAttributes(va_dpy, vpp_config_id, 229 va_surface_attribs, &num_surface_attribs); 230 } 231 CHECK_VASTATUS(va_status, "vaQuerySurfaceAttributes()"); 232 va_num_surface_attribs = num_surface_attribs; 233 return num_surface_attribs; 234 } 235 236 static const VASurfaceAttrib * 237 lookup_surface_attrib(VASurfaceAttribType type, const VAGenericValue *value) 238 { 239 int i; 240 241 if (!ensure_surface_attribs()) 242 return NULL; 243 244 for (i = 0; i < va_num_surface_attribs; i++) { 245 const VASurfaceAttrib * const surface_attrib = &va_surface_attribs[i]; 246 if (surface_attrib->type != type) 247 continue; 248 if (!(surface_attrib->flags & VA_SURFACE_ATTRIB_SETTABLE)) 249 continue; 250 if (va_value_equals(&surface_attrib->value, value)) 251 return surface_attrib; 252 } 253 return NULL; 254 } 255 256 int csc_preparation () 257 { 258 VAStatus va_status; 259 260 // 1. make sure dst fourcc is supported for vaImage 261 if (!lookup_image_format(csc_dst_fourcc)) { 262 test_color_conversion = 0; 263 printf("VA driver doesn't support %s image, skip additional color conversion\n", map_vafourcc_to_str(csc_dst_fourcc)); 264 goto cleanup; 265 } 266 267 // 2. make sure src_fourcc is supported for vaSurface 268 VASurfaceAttrib surface_attribs[1], * const s_attrib = &surface_attribs[0]; 269 s_attrib->type = VASurfaceAttribPixelFormat; 270 s_attrib->flags = VA_SURFACE_ATTRIB_SETTABLE; 271 s_attrib->value.type = VAGenericValueTypeInteger; 272 s_attrib->value.value.i = csc_src_fourcc; 273 274 if (!lookup_surface_attrib(VASurfaceAttribPixelFormat, &s_attrib->value)) { 275 printf("VA driver doesn't support %s surface, skip additional color conversion\n", map_vafourcc_to_str(csc_src_fourcc)); 276 test_color_conversion = 0; 277 goto cleanup; 278 } 279 280 // 3 create all objs required by csc 281 // 3.1 vaSurface with src fourcc 282 va_status = vaCreateSurfaces( 283 va_dpy, 284 VA_RT_FORMAT_YUV420, surface_width, surface_height, 285 &surface_id[0], SURFACE_NUM, 286 surface_attribs, 1 287 ); 288 CHECK_VASTATUS(va_status,"vaCreateSurfaces"); 289 290 // 3.2 vaImage with dst fourcc 291 VAImageFormat image_format; 292 image_format.fourcc = csc_dst_fourcc; 293 image_format.byte_order = VA_LSB_FIRST; 294 image_format.bits_per_pixel = 16; 295 296 va_status = vaCreateImage(va_dpy, &image_format, 297 surface_width, surface_height, 298 &csc_dst_fourcc_image); 299 CHECK_VASTATUS(va_status,"vaCreateImage"); 300 301 302 // 3.3 create a temp VASurface for final rendering(vaPutSurface) 303 s_attrib->value.value.i = VA_FOURCC_NV12; 304 va_status = vaCreateSurfaces(va_dpy, VA_RT_FORMAT_YUV420, 305 surface_width, surface_height, 306 &csc_render_surface, 1, 307 surface_attribs, 1); 308 CHECK_VASTATUS(va_status,"vaCreateSurfaces"); 309 310 311 cleanup: 312 return test_color_conversion; 313 } 314 315 static VASurfaceID get_next_free_surface(int *index) 316 { 317 VASurfaceStatus surface_status; 318 int i; 319 320 assert(index); 321 322 if (multi_thread == 0) { 323 i = *index; 324 i++; 325 if (i == SURFACE_NUM) 326 i = 0; 327 *index = i; 328 329 return surface_id[i]; 330 } 331 332 for (i=0; i<SURFACE_NUM; i++) { 333 surface_status = (VASurfaceStatus)0; 334 vaQuerySurfaceStatus(va_dpy, surface_id[i], &surface_status); 335 if (surface_status == VASurfaceReady) 336 { 337 if (0 == pthread_mutex_trylock(&surface_mutex[i])) 338 { 339 *index = i; 340 break; 341 } 342 } 343 } 344 345 if (i==SURFACE_NUM) 346 return VA_INVALID_SURFACE; 347 else 348 return surface_id[i]; 349 } 350 351 static int upload_source_YUV_once_for_all() 352 { 353 VAImage surface_image; 354 void *surface_p=NULL, *U_start,*V_start; 355 VAStatus va_status; 356 int box_width_loc=8; 357 int row_shift_loc=0; 358 int i; 359 360 for (i=0; i<SURFACE_NUM; i++) { 361 printf("\rLoading data into surface %d.....", i); 362 upload_surface(va_dpy, surface_id[i], box_width_loc, row_shift_loc, 0); 363 364 row_shift_loc++; 365 if (row_shift_loc==(2*box_width_loc)) row_shift_loc= 0; 366 } 367 printf("\n"); 368 369 return 0; 370 } 371 372 /* 373 * Helper function for profiling purposes 374 */ 375 static unsigned long get_tick_count(void) 376 { 377 struct timeval tv; 378 if (gettimeofday(&tv, NULL)) 379 return 0; 380 return tv.tv_usec/1000+tv.tv_sec*1000; 381 } 382 383 static void update_clipbox(VARectangle *cliprects, int width, int height) 384 { 385 if (test_clip == 0) 386 return; 387 388 srand((unsigned)time(NULL)); 389 390 cliprects[0].x = (rand() % width); 391 cliprects[0].y = (rand() % height); 392 cliprects[0].width = (rand() % (width - cliprects[0].x)); 393 cliprects[0].height = (rand() % (height - cliprects[0].y)); 394 395 cliprects[1].x = (rand() % width); 396 cliprects[1].y = (rand() % height); 397 cliprects[1].width = (rand() % (width - cliprects[1].x)); 398 cliprects[1].height = (rand() % (height - cliprects[1].y)); 399 printf("\nTest clip (%d,%d, %d x %d) and (%d,%d, %d x %d) \n", 400 cliprects[0].x, cliprects[0].y, cliprects[0].width, cliprects[0].height, 401 cliprects[1].x, cliprects[1].y, cliprects[1].width, cliprects[1].height); 402 } 403 404 static void* putsurface_thread(void *data) 405 { 406 int width=win_width, height=win_height; 407 void *drawable = data; 408 int quit = 0; 409 VAStatus vaStatus; 410 int row_shift = 0; 411 int index = 0; 412 unsigned int frame_num=0, start_time, putsurface_time; 413 VARectangle cliprects[2]; /* client supplied clip list */ 414 int continue_display = 0; 415 416 if (drawable == drawable_thread0) 417 printf("Enter into thread0\n\n"); 418 if (drawable == drawable_thread1) 419 printf("Enter into thread1\n\n"); 420 421 putsurface_time = 0; 422 while (!quit) { 423 VASurfaceID surface_id = VA_INVALID_SURFACE; 424 425 while (surface_id == VA_INVALID_SURFACE) 426 surface_id = get_next_free_surface(&index); 427 428 if (verbose) printf("Thread: %p Display surface 0x%x,\n", drawable, surface_id); 429 430 if (multi_thread) 431 upload_surface(va_dpy, surface_id, box_width, row_shift, display_field); 432 433 if (check_event) 434 pthread_mutex_lock(&gmutex); 435 436 start_time = get_tick_count(); 437 if ((continue_display == 0) && getenv("FRAME_STOP")) { 438 char c; 439 printf("Press any key to display frame %d...(c/C to continue)\n", frame_num); 440 c = getchar(); 441 if (c == 'c' || c == 'C') 442 continue_display = 1; 443 } 444 if (test_color_conversion) { 445 static int _put_surface_count = 0; 446 if (_put_surface_count++ %50 == 0) { 447 printf("do additional colorcoversion from %s to %s\n", map_vafourcc_to_str(csc_src_fourcc), map_vafourcc_to_str(csc_dst_fourcc)); 448 } 449 // get image from surface, csc_src_fourcc to csc_dst_fourcc conversion happens 450 vaStatus = vaGetImage(va_dpy, surface_id, 0, 0, 451 surface_width, surface_height, csc_dst_fourcc_image.image_id); 452 CHECK_VASTATUS(vaStatus,"vaGetImage"); 453 454 // render csc_dst_fourcc image to temp surface 455 vaStatus = vaPutImage(va_dpy, csc_render_surface, csc_dst_fourcc_image.image_id, 456 0, 0, surface_width, surface_height, 457 0, 0, surface_width, surface_height); 458 CHECK_VASTATUS(vaStatus,"vaPutImage"); 459 460 // render the temp surface, it should be same with original surface without color conversion test 461 vaStatus = vaPutSurface(va_dpy, csc_render_surface, CAST_DRAWABLE(drawable), 462 0,0,surface_width,surface_height, 463 0,0,width,height, 464 (test_clip==0)?NULL:&cliprects[0], 465 (test_clip==0)?0:2, 466 display_field); 467 CHECK_VASTATUS(vaStatus,"vaPutSurface"); 468 } 469 else { 470 vaStatus = vaPutSurface(va_dpy, surface_id, CAST_DRAWABLE(drawable), 471 0,0,surface_width,surface_height, 472 0,0,width,height, 473 (test_clip==0)?NULL:&cliprects[0], 474 (test_clip==0)?0:2, 475 display_field); 476 CHECK_VASTATUS(vaStatus,"vaPutSurface"); 477 } 478 479 putsurface_time += (get_tick_count() - start_time); 480 481 if (check_event) 482 pthread_mutex_unlock(&gmutex); 483 484 pthread_mutex_unlock(&surface_mutex[index]); /* locked in get_next_free_surface */ 485 486 if ((frame_num % 0xff) == 0) { 487 fprintf(stderr, "%.2f FPS \r", 256000.0 / (float)putsurface_time); 488 putsurface_time = 0; 489 update_clipbox(cliprects, width, height); 490 } 491 492 if (check_event) 493 check_window_event(win_display, drawable, &width, &height, &quit); 494 495 if (multi_thread) { /* reload surface content */ 496 row_shift++; 497 if (row_shift==(2*box_width)) row_shift= 0; 498 } 499 500 if (frame_rate != 0) /* rough framerate control */ 501 usleep(1000/frame_rate*1000); 502 503 frame_num++; 504 if (frame_num >= frame_num_total) 505 quit = 1; 506 } 507 508 if (drawable == drawable_thread1) 509 pthread_exit(NULL); 510 511 return 0; 512 } 513 int main(int argc,char **argv) 514 { 515 int major_ver, minor_ver; 516 VAStatus va_status; 517 pthread_t thread1; 518 int ret; 519 char c; 520 int i; 521 char str_src_fmt[5], str_dst_fmt[5]; 522 523 static struct option long_options[] = 524 { 525 {"fmt1", required_argument, NULL, '1'}, 526 {"fmt2", required_argument, NULL, '2'}, 527 {0, 0, 0, 0} 528 }; 529 530 while ((c =getopt_long(argc,argv,"w:h:g:r:d:f:tcep?n:1:2:v", long_options, NULL)) != EOF) { 531 switch (c) { 532 case '?': 533 printf("putsurface <options>\n"); 534 printf(" -g <widthxheight+x_location+y_location> window geometry\n"); 535 printf(" -w/-h resolution of surface\n"); 536 printf(" -r <framerate>\n"); 537 printf(" -d the dimension of black/write square box, default is 32\n"); 538 printf(" -t multi-threads\n"); 539 printf(" -c test clipbox\n"); 540 printf(" -f <1/2> top field, or bottom field\n"); 541 printf(" -1 source format (fourcc) for color conversion test\n"); 542 printf(" -2 dest format (fourcc) for color conversion test\n"); 543 printf(" --fmt1 same to -1\n"); 544 printf(" --fmt2 same to -2\n"); 545 printf(" -v verbose output\n"); 546 exit(0); 547 break; 548 case 'g': 549 ret = sscanf(optarg, "%dx%d+%d+%d", &win_width, &win_height, &win_x, &win_y); 550 if (ret != 4) { 551 printf("invalid window geometry, must be widthxheight+x_location+y_location\n"); 552 exit(0); 553 } else 554 printf("Create window at (%d, %d), width = %d, height = %d\n", 555 win_x, win_y, win_width, win_height); 556 break; 557 case 'r': 558 frame_rate = atoi(optarg); 559 break; 560 case 'w': 561 surface_width = atoi(optarg); 562 break; 563 case 'h': 564 surface_height = atoi(optarg); 565 break; 566 case 'n': 567 frame_num_total = atoi(optarg); 568 break; 569 case 'd': 570 box_width = atoi(optarg); 571 break; 572 case 't': 573 multi_thread = 1; 574 printf("Two threads to do vaPutSurface\n"); 575 break; 576 case 'e': 577 check_event = 0; 578 break; 579 case 'p': 580 put_pixmap = 1; 581 break; 582 case 'c': 583 test_clip = 1; 584 break; 585 case 'f': 586 if (atoi(optarg) == 1) { 587 printf("Display TOP field\n"); 588 display_field = VA_TOP_FIELD; 589 } else if (atoi(optarg) == 2) { 590 printf("Display BOTTOM field\n"); 591 display_field = VA_BOTTOM_FIELD; 592 } else 593 printf("The validate input for -f is: 1(top field)/2(bottom field)\n"); 594 break; 595 case '1': 596 sscanf(optarg, "%s", str_src_fmt); 597 csc_src_fourcc = map_str_to_vafourcc (str_src_fmt); 598 599 if (!csc_src_fourcc) { 600 printf("invalid fmt1: %s\n", str_src_fmt ); 601 exit(0); 602 } 603 break; 604 case '2': 605 sscanf(optarg, "%s", str_dst_fmt); 606 csc_dst_fourcc = map_str_to_vafourcc (str_dst_fmt); 607 608 if (!csc_dst_fourcc) { 609 printf("invalid fmt1: %s\n", str_dst_fmt ); 610 exit(0); 611 } 612 break; 613 case 'v': 614 verbose = 1; 615 printf("Enable verbose output\n"); 616 break; 617 } 618 } 619 620 if (csc_src_fourcc && csc_dst_fourcc) { 621 test_color_conversion = 1; 622 } 623 624 win_display = (void *)open_display(); 625 if (win_display == NULL) { 626 fprintf(stderr, "Can't open the connection of display!\n"); 627 exit(-1); 628 } 629 create_window(win_display, win_x, win_y, win_width, win_height); 630 631 va_dpy = vaGetDisplay(win_display); 632 va_status = vaInitialize(va_dpy, &major_ver, &minor_ver); 633 CHECK_VASTATUS(va_status, "vaInitialize"); 634 635 if (test_color_conversion) { 636 ret = csc_preparation(); 637 } 638 if (!test_color_conversion || !ret ) { 639 va_status = vaCreateSurfaces( 640 va_dpy, 641 VA_RT_FORMAT_YUV420, surface_width, surface_height, 642 &surface_id[0], SURFACE_NUM, 643 NULL, 0 644 ); 645 } 646 CHECK_VASTATUS(va_status, "vaCreateSurfaces"); 647 if (multi_thread == 0) /* upload the content for all surfaces */ 648 upload_source_YUV_once_for_all(); 649 650 if (check_event) 651 pthread_mutex_init(&gmutex, NULL); 652 653 for(i = 0; i< SURFACE_NUM; i++) 654 pthread_mutex_init(&surface_mutex[i], NULL); 655 656 if (multi_thread == 1) 657 ret = pthread_create(&thread1, NULL, putsurface_thread, (void*)drawable_thread1); 658 659 putsurface_thread((void *)drawable_thread0); 660 661 if (multi_thread == 1) 662 pthread_join(thread1, (void **)&ret); 663 printf("thread1 is free\n"); 664 665 if (test_color_conversion) { 666 // destroy temp surface/image 667 va_status = vaDestroySurfaces(va_dpy, &csc_render_surface, 1); 668 CHECK_VASTATUS(va_status,"vaDestroySurfaces"); 669 670 va_status = vaDestroyImage(va_dpy, csc_dst_fourcc_image.image_id); 671 CHECK_VASTATUS(va_status,"vaDestroyImage"); 672 } 673 674 if (vpp_config_id != VA_INVALID_ID) { 675 vaDestroyConfig (va_dpy, vpp_config_id); 676 vpp_config_id = VA_INVALID_ID; 677 } 678 679 vaDestroySurfaces(va_dpy,&surface_id[0],SURFACE_NUM); 680 vaTerminate(va_dpy); 681 682 free(va_image_formats); 683 free(va_surface_attribs); 684 close_display(win_display); 685 686 return 0; 687 } 688