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)                                  \
53if (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
61static  void *win_display;
62static  VADisplay va_dpy;
63static  VAImageFormat *va_image_formats;
64static  int va_num_image_formats = -1;
65static  VAConfigID vpp_config_id = VA_INVALID_ID;
66static  VASurfaceAttrib *va_surface_attribs;
67static  int va_num_surface_attribs = -1;
68static  VASurfaceID surface_id[SURFACE_NUM];
69static  pthread_mutex_t surface_mutex[SURFACE_NUM];
70
71static  void *drawable_thread0, *drawable_thread1;
72static  int surface_width = 352, surface_height = 288;
73static  int win_x = 0, win_y = 0;
74static  int win_width = 352, win_height = 288;
75static  int frame_rate = 0;
76static  unsigned long long frame_num_total = ~0;
77static  int check_event = 1;
78static  int put_pixmap = 0;
79static  int test_clip = 0;
80static  int display_field = VA_FRAME_PICTURE;
81static  pthread_mutex_t gmutex;
82static  int box_width = 32;
83static  int multi_thread = 0;
84static  int verbose = 0;
85static  int test_color_conversion = 0;
86static  unsigned int csc_src_fourcc = 0, csc_dst_fourcc = 0;
87static  VAImage csc_dst_fourcc_image;
88static  VASurfaceID csc_render_surface;
89
90
91typedef struct {
92    const char * fmt_str;
93    unsigned int fourcc;
94} fourcc_map;
95fourcc_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};
105unsigned 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}
117const 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
131static int
132va_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
150static int
151ensure_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
176static const VAImageFormat *
177lookup_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
192static int
193ensure_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
236static const VASurfaceAttrib *
237lookup_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
256int csc_preparation ()
257{
258    VAStatus va_status;
259    VASurfaceAttrib surface_attribs[1], * const s_attrib = &surface_attribs[0];
260
261    // 1. make sure dst fourcc is supported for vaImage
262    if (!lookup_image_format(csc_dst_fourcc)) {
263        test_color_conversion = 0;
264        printf("VA driver doesn't support %s image, skip additional color conversion\n",  map_vafourcc_to_str(csc_dst_fourcc));
265        goto cleanup;
266    }
267
268    // 2. make sure src_fourcc is supported for vaSurface
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
311cleanup:
312    return test_color_conversion;
313}
314
315static 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
351static 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 */
375static 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
383static 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
404static 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}
513int 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