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 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 };
map_str_to_vafourcc(char * str)105 unsigned int map_str_to_vafourcc(char * str)
106 {
107 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 }
map_vafourcc_to_str(unsigned int format)117 char* map_vafourcc_to_str(unsigned int format)
118 {
119 static char unknown_format[] = "unknown-format";
120 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
va_value_equals(const VAGenericValue * v1,const VAGenericValue * v2)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
ensure_image_formats(void)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 = (VAImageFormat *)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 *
lookup_image_format(uint32_t fourcc)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
ensure_surface_attribs(void)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 = (VASurfaceAttrib *)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 = (VASurfaceAttrib *)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 *
lookup_surface_attrib(VASurfaceAttribType type,const VAGenericValue * value)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
csc_preparation()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 return test_color_conversion;
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
get_next_free_surface(int * index)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 if (0 == pthread_mutex_trylock(&surface_mutex[i])) {
337 *index = i;
338 break;
339 }
340 }
341 }
342
343 if (i == SURFACE_NUM)
344 return VA_INVALID_SURFACE;
345 else
346 return surface_id[i];
347 }
348
upload_source_YUV_once_for_all()349 static int upload_source_YUV_once_for_all()
350 {
351 int box_width_loc = 8;
352 int row_shift_loc = 0;
353 int i;
354
355 for (i = 0; i < SURFACE_NUM; i++) {
356 printf("\rLoading data into surface %d.....", i);
357 upload_surface(va_dpy, surface_id[i], box_width_loc, row_shift_loc, 0);
358
359 row_shift_loc++;
360 if (row_shift_loc == (2 * box_width_loc)) row_shift_loc = 0;
361 }
362 printf("\n");
363
364 return 0;
365 }
366
367 /*
368 * Helper function for profiling purposes
369 */
get_tick_count(void)370 static unsigned long get_tick_count(void)
371 {
372 struct timeval tv;
373 if (gettimeofday(&tv, NULL))
374 return 0;
375 return tv.tv_usec / 1000 + tv.tv_sec * 1000;
376 }
377
update_clipbox(VARectangle * cliprects,int width,int height)378 static void update_clipbox(VARectangle *cliprects, int width, int height)
379 {
380 if (test_clip == 0)
381 return;
382
383 srand((unsigned)time(NULL));
384
385 cliprects[0].x = (rand() % width);
386 cliprects[0].y = (rand() % height);
387 cliprects[0].width = (rand() % (width - cliprects[0].x));
388 cliprects[0].height = (rand() % (height - cliprects[0].y));
389
390 cliprects[1].x = (rand() % width);
391 cliprects[1].y = (rand() % height);
392 cliprects[1].width = (rand() % (width - cliprects[1].x));
393 cliprects[1].height = (rand() % (height - cliprects[1].y));
394 printf("\nTest clip (%d,%d, %d x %d) and (%d,%d, %d x %d) \n",
395 cliprects[0].x, cliprects[0].y, cliprects[0].width, cliprects[0].height,
396 cliprects[1].x, cliprects[1].y, cliprects[1].width, cliprects[1].height);
397 }
398
putsurface_thread(void * data)399 static void* putsurface_thread(void *data)
400 {
401 int width = win_width, height = win_height;
402 void *drawable = data;
403 int quit = 0;
404 VAStatus vaStatus;
405 int row_shift = 0;
406 int index = 0;
407 unsigned int frame_num = 0, start_time, putsurface_time;
408 VARectangle cliprects[2]; /* client supplied clip list */
409 int continue_display = 0;
410
411 if (drawable == drawable_thread0)
412 printf("Enter into thread0\n\n");
413 if (drawable == drawable_thread1)
414 printf("Enter into thread1\n\n");
415
416 putsurface_time = 0;
417 while (!quit) {
418 VASurfaceID surface_id = VA_INVALID_SURFACE;
419
420 while (surface_id == VA_INVALID_SURFACE)
421 surface_id = get_next_free_surface(&index);
422
423 if (verbose) printf("Thread: %p Display surface 0x%x,\n", drawable, surface_id);
424
425 if (multi_thread)
426 upload_surface(va_dpy, surface_id, box_width, row_shift, display_field);
427
428 if (check_event)
429 pthread_mutex_lock(&gmutex);
430
431 start_time = get_tick_count();
432 if ((continue_display == 0) && getenv("FRAME_STOP")) {
433 char c;
434 printf("Press any key to display frame %d...(c/C to continue)\n", frame_num);
435 c = getchar();
436 if (c == 'c' || c == 'C')
437 continue_display = 1;
438 }
439 if (test_color_conversion) {
440 static int _put_surface_count = 0;
441 if (_put_surface_count++ % 50 == 0) {
442 printf("do additional colorcoversion from %s to %s\n", map_vafourcc_to_str(csc_src_fourcc), map_vafourcc_to_str(csc_dst_fourcc));
443 }
444 // get image from surface, csc_src_fourcc to csc_dst_fourcc conversion happens
445 vaStatus = vaGetImage(va_dpy, surface_id, 0, 0,
446 surface_width, surface_height, csc_dst_fourcc_image.image_id);
447 CHECK_VASTATUS(vaStatus, "vaGetImage");
448
449 // render csc_dst_fourcc image to temp surface
450 vaStatus = vaPutImage(va_dpy, csc_render_surface, csc_dst_fourcc_image.image_id,
451 0, 0, surface_width, surface_height,
452 0, 0, surface_width, surface_height);
453 CHECK_VASTATUS(vaStatus, "vaPutImage");
454
455 // render the temp surface, it should be same with original surface without color conversion test
456 vaStatus = vaPutSurface(va_dpy, csc_render_surface, CAST_DRAWABLE(drawable),
457 0, 0, surface_width, surface_height,
458 0, 0, width, height,
459 (test_clip == 0) ? NULL : &cliprects[0],
460 (test_clip == 0) ? 0 : 2,
461 display_field);
462 CHECK_VASTATUS(vaStatus, "vaPutSurface");
463
464 } else {
465 vaStatus = vaPutSurface(va_dpy, surface_id, CAST_DRAWABLE(drawable),
466 0, 0, surface_width, surface_height,
467 0, 0, width, height,
468 (test_clip == 0) ? NULL : &cliprects[0],
469 (test_clip == 0) ? 0 : 2,
470 display_field);
471 CHECK_VASTATUS(vaStatus, "vaPutSurface");
472 }
473
474 putsurface_time += (get_tick_count() - start_time);
475
476 if (check_event)
477 pthread_mutex_unlock(&gmutex);
478
479 pthread_mutex_unlock(&surface_mutex[index]); /* locked in get_next_free_surface */
480
481 if ((frame_num % 0xff) == 0) {
482 fprintf(stderr, "%.2f FPS \r", 256000.0 / (float)putsurface_time);
483 putsurface_time = 0;
484 update_clipbox(cliprects, width, height);
485 }
486
487 if (check_event)
488 check_window_event(win_display, drawable, &width, &height, &quit);
489
490 if (multi_thread) { /* reload surface content */
491 row_shift++;
492 if (row_shift == (2 * box_width)) row_shift = 0;
493 }
494
495 if (frame_rate != 0) /* rough framerate control */
496 usleep(1000 / frame_rate * 1000);
497
498 frame_num++;
499 if (frame_num >= frame_num_total)
500 quit = 1;
501 }
502
503 if (drawable == drawable_thread1)
504 pthread_exit(NULL);
505
506 return 0;
507 }
main(int argc,char ** argv)508 int main(int argc, char **argv)
509 {
510 int major_ver, minor_ver;
511 VAStatus va_status;
512 pthread_t thread1;
513 int ret;
514 int c;
515 int i;
516 char str_src_fmt[5], str_dst_fmt[5];
517
518 static struct option long_options[] = {
519 {"fmt1", required_argument, NULL, '1'},
520 {"fmt2", required_argument, NULL, '2'},
521 {0, 0, 0, 0}
522 };
523
524 while ((c = getopt_long(argc, argv, "w:h:g:r:d:f:tcep?n:1:2:v", long_options, NULL)) != EOF) {
525 switch (c) {
526 case '?':
527 printf("putsurface <options>\n");
528 printf(" -g <widthxheight+x_location+y_location> window geometry\n");
529 printf(" -w/-h resolution of surface\n");
530 printf(" -r <framerate>\n");
531 printf(" -d the dimension of black/write square box, default is 32\n");
532 printf(" -t multi-threads\n");
533 printf(" -c test clipbox\n");
534 printf(" -f <1/2> top field, or bottom field\n");
535 printf(" -1 source format (fourcc) for color conversion test\n");
536 printf(" -2 dest format (fourcc) for color conversion test\n");
537 printf(" --fmt1 same to -1\n");
538 printf(" --fmt2 same to -2\n");
539 printf(" -v verbose output\n");
540 exit(0);
541 break;
542 case 'g':
543 ret = sscanf(optarg, "%dx%d+%d+%d", &win_width, &win_height, &win_x, &win_y);
544 if (ret != 4) {
545 printf("invalid window geometry, must be widthxheight+x_location+y_location\n");
546 exit(0);
547 } else
548 printf("Create window at (%d, %d), width = %d, height = %d\n",
549 win_x, win_y, win_width, win_height);
550 break;
551 case 'r':
552 frame_rate = atoi(optarg);
553 break;
554 case 'w':
555 surface_width = atoi(optarg);
556 break;
557 case 'h':
558 surface_height = atoi(optarg);
559 break;
560 case 'n':
561 frame_num_total = atoi(optarg);
562 break;
563 case 'd':
564 box_width = atoi(optarg);
565 break;
566 case 't':
567 multi_thread = 1;
568 printf("Two threads to do vaPutSurface\n");
569 break;
570 case 'e':
571 check_event = 0;
572 break;
573 case 'p':
574 put_pixmap = 1;
575 break;
576 case 'c':
577 test_clip = 1;
578 break;
579 case 'f':
580 if (atoi(optarg) == 1) {
581 printf("Display TOP field\n");
582 display_field = VA_TOP_FIELD;
583 } else if (atoi(optarg) == 2) {
584 printf("Display BOTTOM field\n");
585 display_field = VA_BOTTOM_FIELD;
586 } else
587 printf("The validate input for -f is: 1(top field)/2(bottom field)\n");
588 break;
589 case '1':
590 sscanf(optarg, "%5s", str_src_fmt);
591 csc_src_fourcc = map_str_to_vafourcc(str_src_fmt);
592
593 if (!csc_src_fourcc) {
594 printf("invalid fmt1: %s\n", str_src_fmt);
595 exit(0);
596 }
597 break;
598 case '2':
599 sscanf(optarg, "%5s", str_dst_fmt);
600 csc_dst_fourcc = map_str_to_vafourcc(str_dst_fmt);
601
602 if (!csc_dst_fourcc) {
603 printf("invalid fmt1: %s\n", str_dst_fmt);
604 exit(0);
605 }
606 break;
607 case 'v':
608 verbose = 1;
609 printf("Enable verbose output\n");
610 break;
611 }
612 }
613
614 if (csc_src_fourcc && csc_dst_fourcc) {
615 test_color_conversion = 1;
616 }
617
618 win_display = (void *)open_display();
619 if (win_display == NULL) {
620 fprintf(stderr, "Can't open the connection of display!\n");
621 exit(-1);
622 }
623 create_window(win_display, win_x, win_y, win_width, win_height);
624
625 va_dpy = vaGetDisplay(win_display);
626 va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
627 CHECK_VASTATUS(va_status, "vaInitialize");
628
629 if (test_color_conversion) {
630 ret = csc_preparation();
631 }
632 if (!test_color_conversion || !ret) {
633 va_status = vaCreateSurfaces(
634 va_dpy,
635 VA_RT_FORMAT_YUV420, surface_width, surface_height,
636 &surface_id[0], SURFACE_NUM,
637 NULL, 0
638 );
639 }
640 CHECK_VASTATUS(va_status, "vaCreateSurfaces");
641 if (multi_thread == 0) /* upload the content for all surfaces */
642 upload_source_YUV_once_for_all();
643
644 if (check_event)
645 pthread_mutex_init(&gmutex, NULL);
646
647 for (i = 0; i < SURFACE_NUM; i++)
648 pthread_mutex_init(&surface_mutex[i], NULL);
649
650 if (multi_thread == 1)
651 ret = pthread_create(&thread1, NULL, putsurface_thread, (void*)drawable_thread1);
652
653 putsurface_thread((void *)drawable_thread0);
654
655 if (multi_thread == 1)
656 pthread_join(thread1, (void **)&ret);
657 printf("thread1 is free\n");
658
659 if (test_color_conversion) {
660 // destroy temp surface/image
661 va_status = vaDestroySurfaces(va_dpy, &csc_render_surface, 1);
662 CHECK_VASTATUS(va_status, "vaDestroySurfaces");
663
664 va_status = vaDestroyImage(va_dpy, csc_dst_fourcc_image.image_id);
665 CHECK_VASTATUS(va_status, "vaDestroyImage");
666 }
667
668 if (vpp_config_id != VA_INVALID_ID) {
669 vaDestroyConfig(va_dpy, vpp_config_id);
670 vpp_config_id = VA_INVALID_ID;
671 }
672
673 vaDestroySurfaces(va_dpy, &surface_id[0], SURFACE_NUM);
674 vaTerminate(va_dpy);
675
676 free(va_image_formats);
677 free(va_surface_attribs);
678 close_display(win_display);
679
680 return 0;
681 }
682