• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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