1/*
2 * Copyright (c) 2014 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 INTEL 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 * Video process test case based on LibVA.
26 * This test covers deinterlace, denoise, color balance, sharpening,
27 * blending, scaling and several surface format conversion.
28 * Usage: videoprocess process.cfg
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <stdint.h>
35#include <sys/time.h>
36#include <assert.h>
37#include <va/va.h>
38#include <va/va_vpp.h>
39#include "va_display.h"
40
41#ifndef VA_FOURCC_I420
42#define VA_FOURCC_I420 0x30323449
43#endif
44
45#define MAX_LEN   1024
46
47#define CHECK_VASTATUS(va_status,func)                                      \
48  if (va_status != VA_STATUS_SUCCESS) {                                     \
49      fprintf(stderr,"%s:%s (%d) failed,exit\n", __func__, func, __LINE__); \
50      exit(1);                                                              \
51  }
52
53static VADisplay va_dpy = NULL;
54static VAContextID context_id = 0;
55static VAConfigID  config_id = 0;
56static VAProcFilterType g_filter_type = VAProcFilterNone;
57static VASurfaceID g_in_surface_id = VA_INVALID_ID;
58static VASurfaceID g_out_surface_id = VA_INVALID_ID;
59
60static FILE* g_config_file_fd = NULL;
61static FILE* g_src_file_fd = NULL;
62static FILE* g_dst_file_fd = NULL;
63
64static char g_config_file_name[MAX_LEN];
65static char g_src_file_name[MAX_LEN];
66static char g_dst_file_name[MAX_LEN];
67static char g_filter_type_name[MAX_LEN];
68
69static uint32_t g_in_pic_width = 352;
70static uint32_t g_in_pic_height = 288;
71static uint32_t g_out_pic_width = 352;
72static uint32_t g_out_pic_height = 288;
73
74static uint32_t g_in_fourcc  = VA_FOURCC('N', 'V', '1', '2');
75static uint32_t g_in_format  = VA_RT_FORMAT_YUV420;
76static uint32_t g_out_fourcc = VA_FOURCC('N', 'V', '1', '2');
77static uint32_t g_out_format = VA_RT_FORMAT_YUV420;
78
79static uint8_t g_blending_enabled = 0;
80static uint8_t g_blending_min_luma = 1;
81static uint8_t g_blending_max_luma = 254;
82
83static uint32_t g_frame_count = 0;
84
85static int8_t
86read_value_string(FILE *fp, const char* field_name, char* value)
87{
88    char strLine[MAX_LEN];
89    char* field;
90    char* str;
91    uint16_t i;
92
93    if (!fp || !field_name || !value)  {
94        printf("Invalid fuction parameters\n");
95        return -1;
96    }
97
98    rewind(fp);
99
100    while (!feof(fp)) {
101        if (!fgets(strLine, MAX_LEN, fp))
102            continue;
103
104        for (i = 0; strLine[i] && i < MAX_LEN; i++)
105            if (strLine[i] != ' ') break;
106
107        if (strLine[i] == '#' || strLine[i] == '\n' || i == 1024)
108            continue;
109
110        field = strtok(&strLine[i], ":");
111        if (strncmp(field, field_name, strlen(field_name)))
112            continue;
113
114        if (!(str = strtok(NULL, ":")))
115            continue;
116
117        /* skip blank space in string */
118        while (*str == ' ')
119            str++;
120
121        *(str + strlen(str)-1) = '\0';
122        strcpy(value, str);
123
124        return 0;
125    }
126
127    return -1;
128}
129
130static int8_t
131read_value_uint8(FILE* fp, const char* field_name, uint8_t* value)
132{
133    char str[MAX_LEN];
134
135    if (read_value_string(fp, field_name, str)) {
136        printf("Failed to find integer field: %s", field_name);
137        return -1;
138    }
139
140    *value = (uint8_t)atoi(str);
141    return 0;
142}
143
144static int8_t
145read_value_uint32(FILE* fp, const char* field_name, uint32_t* value)
146{
147    char str[MAX_LEN];
148
149    if (read_value_string(fp, field_name, str)) {
150       printf("Failed to find integer field: %s", field_name);
151       return -1;
152    }
153
154    *value = (uint32_t)atoi(str);
155    return 0;
156}
157
158static int8_t
159read_value_float(FILE *fp, const char* field_name, float* value)
160{
161    char str[MAX_LEN];
162    if (read_value_string(fp, field_name, str)) {
163       printf("Failed to find float field: %s \n",field_name);
164       return -1;
165    }
166
167    *value = atof(str);
168    return 0;
169}
170
171static float
172adjust_to_range(VAProcFilterValueRange *range, float value)
173{
174    if (value < range->min_value || value > range->max_value){
175        printf("Value: %f exceed range: (%f ~ %f), force to use default: %f \n",
176                value, range->min_value, range->max_value, range->default_value);
177        return range->default_value;
178    }
179
180    return value;
181}
182
183static VAStatus
184create_surface(VASurfaceID * p_surface_id,
185               uint32_t width, uint32_t height,
186               uint32_t fourCC, uint32_t format)
187{
188    VAStatus va_status;
189    VASurfaceAttrib    surface_attrib;
190    surface_attrib.type =  VASurfaceAttribPixelFormat;
191    surface_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE;
192    surface_attrib.value.type = VAGenericValueTypeInteger;
193    surface_attrib.value.value.i = fourCC;
194
195    va_status = vaCreateSurfaces(va_dpy,
196                                 format,
197                                 width ,
198                                 height,
199                                 p_surface_id,
200                                 1,
201                                 &surface_attrib,
202                                 1);
203   return va_status;
204}
205
206static VAStatus
207construct_nv12_mask_surface(VASurfaceID surface_id,
208                            uint8_t min_luma,
209                            uint8_t max_luma)
210{
211    VAStatus va_status;
212    VAImage surface_image;
213    void *surface_p = NULL;
214    unsigned char *y_dst, *u_dst, *v_dst;
215    uint32_t row, col;
216
217    va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
218    CHECK_VASTATUS(va_status, "vaDeriveImage");
219
220    va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
221    CHECK_VASTATUS(va_status, "vaMapBuffer");
222
223    y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
224    u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
225    v_dst = u_dst;
226
227    /* fill Y plane, the luma values of some pixels is in the range of min_luma~max_luma,
228     * and others are out side of it, in luma key blending case, the pixels with Y value
229     * exceeding the range will be hided*/
230    for (row = 0; row < surface_image.height; row++) {
231        if (row < surface_image.height / 4 || row > surface_image.height * 3 / 4)
232            memset(y_dst, max_luma + 1, surface_image.pitches[0]);
233        else
234            memset(y_dst, (min_luma + max_luma) / 2, surface_image.pitches[0]);
235
236        y_dst += surface_image.pitches[0];
237     }
238
239     /* fill UV plane */
240     for (row = 0; row < surface_image.height / 2; row++) {
241         for (col = 0; col < surface_image.width / 2; col++) {
242             u_dst[col * 2] = 128;
243             u_dst[col * 2 + 1] = 128;
244        }
245        u_dst += surface_image.pitches[1];
246     }
247
248    vaUnmapBuffer(va_dpy, surface_image.buf);
249    vaDestroyImage(va_dpy, surface_image.image_id);
250
251    return VA_STATUS_SUCCESS;
252}
253
254/* Load yv12 frame to NV12/YV12/I420 surface*/
255static VAStatus
256upload_yv12_frame_to_yuv_surface(FILE *fp,
257                                 VASurfaceID surface_id)
258{
259    VAStatus va_status;
260    VAImage surface_image;
261    unsigned char *y_src, *u_src, *v_src;
262    unsigned char *y_dst, *u_dst, *v_dst;
263    void *surface_p = NULL;
264    uint32_t frame_size, i, row, col;
265    size_t n_items;
266    unsigned char * newImageBuffer = NULL;
267
268    va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
269    CHECK_VASTATUS(va_status, "vaDeriveImage");
270
271    va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
272    CHECK_VASTATUS(va_status, "vaMapBuffer");
273
274    if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
275        surface_image.format.fourcc == VA_FOURCC_I420 ||
276        surface_image.format.fourcc == VA_FOURCC_NV12){
277
278        frame_size = surface_image.width * surface_image.height * 3 / 2;
279        newImageBuffer = (unsigned char*)malloc(frame_size);
280        do {
281            n_items = fread(newImageBuffer, frame_size, 1, fp);
282        } while (n_items != 1);
283
284        y_src = newImageBuffer;
285        v_src = newImageBuffer + surface_image.width * surface_image.height;
286        u_src = newImageBuffer + surface_image.width * surface_image.height * 5 / 4;
287
288        y_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
289
290        if(surface_image.format.fourcc == VA_FOURCC_YV12){
291            v_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
292            u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
293        }else if(surface_image.format.fourcc == VA_FOURCC_I420){
294            u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
295            v_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
296        }else {
297            u_dst = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
298            v_dst = u_dst;
299        }
300
301        /* Y plane, directly copy */
302        for (row = 0; row < surface_image.height; row++) {
303            memcpy(y_dst, y_src, surface_image.width);
304            y_dst += surface_image.pitches[0];
305            y_src += surface_image.width;
306        }
307
308        /* UV plane */
309        if (surface_image.format.fourcc == VA_FOURCC_YV12||
310            surface_image.format.fourcc == VA_FOURCC_I420){
311            /* UV plane */
312            for (row = 0; row < surface_image.height /2; row ++){
313                memcpy(v_dst, v_src, surface_image.width/2);
314                memcpy(u_dst, u_src, surface_image.width/2);
315
316                v_src += surface_image.width/2;
317                u_src += surface_image.width/2;
318
319                if (surface_image.format.fourcc == VA_FOURCC_YV12){
320                    v_dst += surface_image.pitches[1];
321                    u_dst += surface_image.pitches[2];
322                } else {
323                    v_dst += surface_image.pitches[2];
324                    u_dst += surface_image.pitches[1];
325                }
326            }
327        } else if (surface_image.format.fourcc == VA_FOURCC_NV12){
328            for (row = 0; row < surface_image.height / 2; row++) {
329                for (col = 0; col < surface_image.width / 2; col++) {
330                    u_dst[col * 2] = u_src[col];
331                    u_dst[col * 2 + 1] = v_src[col];
332                }
333
334                u_dst += surface_image.pitches[1];
335                u_src += (surface_image.width / 2);
336                v_src += (surface_image.width / 2);
337            }
338        }
339     } else {
340         printf("Not supported YUV surface fourcc !!! \n");
341         return VA_STATUS_ERROR_INVALID_SURFACE;
342     }
343
344     if (newImageBuffer){
345         free(newImageBuffer);
346         newImageBuffer = NULL;
347     }
348
349     vaUnmapBuffer(va_dpy, surface_image.buf);
350     vaDestroyImage(va_dpy, surface_image.image_id);
351
352     return VA_STATUS_SUCCESS;
353}
354
355/* Store NV12/YV12/I420 surface to yv12 frame*/
356static VAStatus
357store_yuv_surface_to_yv12_frame(FILE *fp,
358                            VASurfaceID surface_id)
359{
360    VAStatus va_status;
361    VAImageFormat image_format;
362    VAImage surface_image;
363    void *surface_p = NULL;
364    unsigned char *y_src, *u_src, *v_src;
365    unsigned char *y_dst, *u_dst, *v_dst;
366    uint32_t frame_size, row, col;
367    int32_t  ret, n_items;
368    unsigned char * newImageBuffer = NULL;
369
370    va_status = vaDeriveImage(va_dpy, surface_id, &surface_image);
371    CHECK_VASTATUS(va_status, "vaDeriveImage");
372
373    va_status = vaMapBuffer(va_dpy, surface_image.buf, &surface_p);
374    CHECK_VASTATUS(va_status, "vaMapBuffer");
375
376    /* store the surface to one YV12 file or one bmp file*/
377    if (surface_image.format.fourcc == VA_FOURCC_YV12 ||
378        surface_image.format.fourcc == VA_FOURCC_I420 ||
379        surface_image.format.fourcc == VA_FOURCC_NV12){
380
381        uint32_t y_size = surface_image.width * surface_image.height;
382        uint32_t u_size = y_size/4;
383
384        newImageBuffer = (unsigned char*)malloc(y_size * 3 / 2);
385
386        /* stored as YV12 format */
387        y_dst = newImageBuffer;
388        v_dst = newImageBuffer + y_size;
389        u_dst = newImageBuffer + y_size + u_size;
390
391        y_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[0]);
392        if (surface_image.format.fourcc == VA_FOURCC_YV12){
393            v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
394            u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
395        } else if(surface_image.format.fourcc == VA_FOURCC_I420){
396            u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
397            v_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[2]);
398        } else if(surface_image.format.fourcc == VA_FOURCC_NV12){
399            u_src = (unsigned char *)((unsigned char*)surface_p + surface_image.offsets[1]);
400            v_src = u_src;
401        }
402
403        /* Y plane copy */
404        for (row = 0; row < surface_image.height; row++) {
405            memcpy(y_dst, y_src, surface_image.width);
406            y_src += surface_image.pitches[0];
407            y_dst += surface_image.width;
408        }
409
410        /* UV plane copy */
411        if (surface_image.format.fourcc == VA_FOURCC_YV12||
412            surface_image.format.fourcc == VA_FOURCC_I420){
413            for (row = 0; row < surface_image.height /2; row ++){
414                memcpy(v_dst, v_src, surface_image.width/2);
415                memcpy(u_dst, u_src, surface_image.width/2);
416
417                v_dst += surface_image.width/2;
418                u_dst += surface_image.width/2;
419
420                if (surface_image.format.fourcc == VA_FOURCC_YV12){
421                    v_src += surface_image.pitches[1];
422                    u_src += surface_image.pitches[2];
423                 } else {
424                    v_src += surface_image.pitches[2];
425                    u_src += surface_image.pitches[1];
426                 }
427             }
428         } else if (surface_image.format.fourcc == VA_FOURCC_NV12){
429             for (row = 0; row < surface_image.height / 2; row++) {
430                 for (col = 0; col < surface_image.width /2; col++) {
431                     u_dst[col] = u_src[col * 2];
432                     v_dst[col] = u_src[col * 2 + 1];
433                  }
434
435                  u_src += surface_image.pitches[1];
436                  u_dst += (surface_image.width / 2);
437                  v_dst += (surface_image.width / 2);
438             }
439         }
440
441         /* write frame to file */
442         do {
443             n_items = fwrite(newImageBuffer, y_size * 3 / 2, 1, fp);
444         } while (n_items != 1);
445
446     } else {
447         printf("Not supported YUV surface fourcc !!! \n");
448         return VA_STATUS_ERROR_INVALID_SURFACE;
449     }
450
451     if (newImageBuffer){
452         free(newImageBuffer);
453         newImageBuffer = NULL;
454     }
455
456     vaUnmapBuffer(va_dpy, surface_image.buf);
457     vaDestroyImage(va_dpy, surface_image.image_id);
458
459     return VA_STATUS_SUCCESS;
460}
461
462static VAStatus
463denoise_filter_init(VABufferID *filter_param_buf_id)
464{
465    VAStatus va_status = VA_STATUS_SUCCESS;
466    VAProcFilterParameterBuffer denoise_param;
467    VABufferID denoise_param_buf_id;
468    float intensity;
469
470    VAProcFilterCap denoise_caps;
471    uint32_t num_denoise_caps = 1;
472    va_status = vaQueryVideoProcFilterCaps(va_dpy, context_id,
473                                           VAProcFilterNoiseReduction,
474                                           &denoise_caps, &num_denoise_caps);
475    CHECK_VASTATUS(va_status,"vaQueryVideoProcFilterCaps");
476
477    if (read_value_float(g_config_file_fd, "DENOISE_INTENSITY", &intensity)) {
478        printf("Read denoise intensity failed, use default value");
479        intensity = denoise_caps.range.default_value;
480    }
481    intensity = adjust_to_range(&denoise_caps.range, intensity);
482
483    denoise_param.type  = VAProcFilterNoiseReduction;
484    denoise_param.value = intensity;
485
486    printf("Denoise intensity: %f\n", intensity);
487
488    va_status = vaCreateBuffer(va_dpy, context_id,
489                               VAProcFilterParameterBufferType, sizeof(denoise_param), 1,
490                               &denoise_param, &denoise_param_buf_id);
491    CHECK_VASTATUS(va_status,"vaCreateBuffer");
492
493    *filter_param_buf_id = denoise_param_buf_id;
494
495    return va_status;
496}
497
498static VAStatus
499deinterlace_filter_init(VABufferID *filter_param_buf_id)
500{
501    VAStatus va_status = VA_STATUS_SUCCESS;
502    VAProcFilterParameterBufferDeinterlacing deinterlacing_param;
503    VABufferID deinterlacing_param_buf_id;
504    char algorithm_str[MAX_LEN], flags_str[MAX_LEN];
505    uint32_t i;
506
507    /* read and check whether configured deinterlace algorithm is supported */
508    deinterlacing_param.algorithm  = VAProcDeinterlacingBob;
509    if (!read_value_string(g_config_file_fd, "DEINTERLACING_ALGORITHM", algorithm_str)) {
510        printf("Deinterlacing algorithm in config: %s \n", algorithm_str);
511        if (!strcmp(algorithm_str, "VAProcDeinterlacingBob"))
512            deinterlacing_param.algorithm  = VAProcDeinterlacingBob;
513        else if (!strcmp(algorithm_str, "VAProcDeinterlacingWeave"))
514            deinterlacing_param.algorithm  = VAProcDeinterlacingWeave;
515        else if (!strcmp(algorithm_str, "VAProcDeinterlacingMotionAdaptive"))
516            deinterlacing_param.algorithm  = VAProcDeinterlacingMotionAdaptive;
517        else if (!strcmp(algorithm_str, "VAProcDeinterlacingMotionCompensated"))
518            deinterlacing_param.algorithm  = VAProcDeinterlacingMotionCompensated;
519    } else {
520        printf("Read deinterlace algorithm failed, use default algorithm");
521        deinterlacing_param.algorithm  = VAProcDeinterlacingBob;
522    }
523
524    VAProcFilterCapDeinterlacing deinterlacing_caps[VAProcDeinterlacingCount];
525    uint32_t num_deinterlacing_caps = VAProcDeinterlacingCount;
526    va_status = vaQueryVideoProcFilterCaps(va_dpy, context_id,
527                                           VAProcFilterDeinterlacing,
528                                           &deinterlacing_caps, &num_deinterlacing_caps);
529    CHECK_VASTATUS(va_status,"vaQueryVideoProcFilterCaps");
530
531    for (i = 0; i < VAProcDeinterlacingCount; i ++)
532       if (deinterlacing_caps[i].type == deinterlacing_param.algorithm)
533         break;
534
535    if (i == VAProcDeinterlacingCount) {
536        printf("Deinterlacing algorithm: %d is not supported by driver, \
537                use defautl algorithm :%d \n",
538                deinterlacing_param.algorithm,
539                VAProcDeinterlacingBob);
540        deinterlacing_param.algorithm = VAProcDeinterlacingBob;
541    }
542
543    /* read and check the deinterlace flags */
544    deinterlacing_param.flags = 0;
545    if (!read_value_string(g_config_file_fd, "DEINTERLACING_FLAG", flags_str)) {
546        if (strstr(flags_str, "VA_DEINTERLACING_BOTTOM_FIELD_FIRST"))
547            deinterlacing_param.flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
548        if (strstr(flags_str, "VA_DEINTERLACING_BOTTOM_FIELD"))
549            deinterlacing_param.flags |= VA_DEINTERLACING_BOTTOM_FIELD;
550        if (strstr(flags_str, "VA_DEINTERLACING_ONE_FIELD"))
551            deinterlacing_param.flags |= VA_DEINTERLACING_ONE_FIELD;
552    }
553
554    deinterlacing_param.type  = VAProcFilterDeinterlacing;
555
556    /* create deinterlace fitler buffer */
557    va_status = vaCreateBuffer(va_dpy, context_id,
558                               VAProcFilterParameterBufferType, sizeof(deinterlacing_param), 1,
559                               &deinterlacing_param, &deinterlacing_param_buf_id);
560    CHECK_VASTATUS(va_status, "vaCreateBuffer");
561
562    *filter_param_buf_id = deinterlacing_param_buf_id;
563
564    return va_status;
565}
566
567static VAStatus
568sharpening_filter_init(VABufferID *filter_param_buf_id)
569{
570    VAStatus va_status;
571    VAProcFilterParameterBuffer sharpening_param;
572    VABufferID sharpening_param_buf_id;
573    float intensity;
574
575    VAProcFilterCap sharpening_caps;
576    uint32_t num_sharpening_caps = 1;
577    va_status = vaQueryVideoProcFilterCaps(va_dpy, context_id,
578                VAProcFilterSharpening,
579                &sharpening_caps, &num_sharpening_caps);
580    CHECK_VASTATUS(va_status,"vaQueryVideoProcFilterCaps");
581
582    if(read_value_float(g_config_file_fd, "SHARPENING_INTENSITY", &intensity)) {
583        printf("Read sharpening intensity failed, use default value.");
584        intensity = sharpening_caps.range.default_value;
585    }
586
587    intensity = adjust_to_range(&sharpening_caps.range, intensity);
588    printf("Sharpening intensity: %f\n", intensity);
589    sharpening_param.value = intensity;
590
591    sharpening_param.type  = VAProcFilterSharpening;
592
593    /* create sharpening fitler buffer */
594    va_status = vaCreateBuffer(va_dpy, context_id,
595                               VAProcFilterParameterBufferType, sizeof(sharpening_param), 1,
596                               &sharpening_param, &sharpening_param_buf_id);
597
598    *filter_param_buf_id = sharpening_param_buf_id;
599
600    return va_status;
601}
602
603static VAStatus
604color_balance_filter_init(VABufferID *filter_param_buf_id)
605{
606    VAStatus va_status;
607    VAProcFilterParameterBufferColorBalance color_balance_param[4];
608    VABufferID color_balance_param_buf_id;
609    float value;
610    uint32_t i, count;
611    int8_t status;
612
613    VAProcFilterCapColorBalance color_balance_caps[VAProcColorBalanceCount];
614    unsigned int num_color_balance_caps = VAProcColorBalanceCount;
615    va_status = vaQueryVideoProcFilterCaps(va_dpy, context_id,
616                                           VAProcFilterColorBalance,
617                                           &color_balance_caps, &num_color_balance_caps);
618    CHECK_VASTATUS(va_status,"vaQueryVideoProcFilterCaps");
619
620    count = 0;
621    printf("Color balance params: ");
622    for (i = 0; i < num_color_balance_caps; i++) {
623        if (color_balance_caps[i].type == VAProcColorBalanceHue) {
624            color_balance_param[count].attrib  = VAProcColorBalanceHue;
625            status = read_value_float(g_config_file_fd, "COLOR_BALANCE_HUE", &value);
626            printf("Hue: ");
627        } else if (color_balance_caps[i].type == VAProcColorBalanceSaturation) {
628            color_balance_param[count].attrib  = VAProcColorBalanceSaturation;
629            status = read_value_float(g_config_file_fd, "COLOR_BALANCE_SATURATION", &value);
630            printf("Saturation: ");
631        } else if (color_balance_caps[i].type == VAProcColorBalanceBrightness) {
632            color_balance_param[count].attrib  = VAProcColorBalanceBrightness;
633            status = read_value_float(g_config_file_fd, "COLOR_BALANCE_BRIGHTNESS", &value);
634            printf("Brightness: ");
635        } else if (color_balance_caps[i].type == VAProcColorBalanceContrast) {
636            color_balance_param[count].attrib  = VAProcColorBalanceContrast;
637            status = read_value_float(g_config_file_fd, "COLOR_BALANCE_CONTRAST", &value);
638            printf("Contrast: ");
639        } else {
640            continue;
641        }
642
643        if (status)
644            value = color_balance_caps[i].range.default_value;
645        else
646            value = adjust_to_range(&color_balance_caps[i].range, value);
647
648        color_balance_param[count].value = value;
649        color_balance_param[count].type  = VAProcFilterColorBalance;
650        count++;
651
652        printf("%4f,  ", value);
653    }
654    printf("\n");
655
656    va_status = vaCreateBuffer(va_dpy, context_id,
657                               VAProcFilterParameterBufferType, sizeof(color_balance_param), 4,
658                               color_balance_param, &color_balance_param_buf_id);
659
660    *filter_param_buf_id = color_balance_param_buf_id;
661
662    return va_status;
663}
664
665static VAStatus
666blending_state_init(VABlendState *state)
667{
668    VAStatus va_status = VA_STATUS_SUCCESS;
669    char blending_flags_str[MAX_LEN];
670    float global_alpha;
671    uint32_t min_luma, max_luma;
672
673    /* read and check blend state */
674    state->flags = 0;
675    if (!read_value_string(g_config_file_fd, "BLENDING_FLAGS", blending_flags_str)){
676        if (strstr(blending_flags_str, "VA_BLEND_GLOBAL_ALPHA")) {
677           if (read_value_float(g_config_file_fd, "BLENDING_GLOBAL_ALPHA", &global_alpha)) {
678               global_alpha = 1.0  ;
679               printf("Use default global alpha : %4f \n", global_alpha);
680           }
681           state->flags |= VA_BLEND_GLOBAL_ALPHA;
682           state->global_alpha = global_alpha;
683        }
684        if (strstr(blending_flags_str, "VA_BLEND_LUMA_KEY")) {
685            if (read_value_uint8(g_config_file_fd, "BLENDING_MIN_LUMA", &g_blending_min_luma)) {
686                g_blending_min_luma = 1;
687                printf("Use default min luma : %3d \n", g_blending_min_luma);
688            }
689            if (read_value_uint8(g_config_file_fd, "BLENDING_MAX_LUMA", &g_blending_max_luma)) {
690                g_blending_max_luma = 254;
691                printf("Use default max luma : %3d \n", g_blending_max_luma);
692            }
693            state->flags |= VA_BLEND_LUMA_KEY;
694            state->min_luma = g_blending_min_luma * 1.0 / 256;
695            state->max_luma = g_blending_max_luma * 1.0 / 256;
696        }
697
698        printf("Blending type = %s, alpha = %f, min_luma = %3d, max_luma = %3d \n",
699              blending_flags_str, global_alpha, min_luma, max_luma);
700    }
701
702    VAProcPipelineCaps pipeline_caps;
703    va_status = vaQueryVideoProcPipelineCaps(va_dpy, context_id,
704                NULL, 0, &pipeline_caps);
705    CHECK_VASTATUS(va_status,"vaQueryVideoProcPipelineCaps");
706
707    if (!pipeline_caps.blend_flags){
708        printf("Blending is not supported in driver! \n");
709        return VA_STATUS_ERROR_UNIMPLEMENTED;
710    }
711
712    if (! (pipeline_caps.blend_flags & state->flags)) {
713        printf("Driver do not support current blending flags: %d", state->flags);
714        return VA_STATUS_ERROR_UNIMPLEMENTED;
715    }
716
717    return va_status;
718}
719
720static VAStatus
721video_frame_process(VAProcFilterType filter_type,
722                    uint32_t frame_idx,
723                    VASurfaceID in_surface_id,
724                    VASurfaceID out_surface_id)
725{
726    VAStatus va_status;
727    VAProcPipelineParameterBuffer pipeline_param;
728    VARectangle surface_region, output_region;
729    VABufferID pipeline_param_buf_id = VA_INVALID_ID;
730    VABufferID filter_param_buf_id = VA_INVALID_ID;
731    VABlendState state ;
732    uint32_t filter_count = 1;
733
734    /* create denoise_filter buffer id */
735    switch(filter_type){
736      case VAProcFilterNoiseReduction:
737           denoise_filter_init(&filter_param_buf_id);
738           break;
739      case VAProcFilterDeinterlacing:
740           deinterlace_filter_init(&filter_param_buf_id);
741           break;
742      case VAProcFilterSharpening:
743           sharpening_filter_init(&filter_param_buf_id);
744           break;
745      case VAProcFilterColorBalance:
746           color_balance_filter_init(&filter_param_buf_id);
747           break;
748      default :
749           filter_count = 0;
750         break;
751    }
752
753    /* Fill pipeline buffer */
754    surface_region.x = 0;
755    surface_region.y = 0;
756    surface_region.width = g_in_pic_width;
757    surface_region.height = g_in_pic_height;
758    output_region.x = 0;
759    output_region.y = 0;
760    output_region.width = g_out_pic_width;
761    output_region.height = g_out_pic_height;
762
763    memset(&pipeline_param, 0, sizeof(pipeline_param));
764    pipeline_param.surface = in_surface_id;
765    pipeline_param.surface_region = &surface_region;
766    pipeline_param.output_region = &output_region;
767
768    pipeline_param.filter_flags = 0;
769    pipeline_param.filters      = &filter_param_buf_id;
770    pipeline_param.num_filters  = filter_count;
771
772    /* Blending related state */
773    if (g_blending_enabled){
774        blending_state_init(&state);
775        pipeline_param.blend_state = &state;
776    }
777
778    va_status = vaCreateBuffer(va_dpy,
779                               context_id,
780                               VAProcPipelineParameterBufferType,
781                               sizeof(pipeline_param),
782                               1,
783                               &pipeline_param,
784                               &pipeline_param_buf_id);
785    CHECK_VASTATUS(va_status, "vaCreateBuffer");
786
787    va_status = vaBeginPicture(va_dpy,
788                               context_id,
789                               out_surface_id);
790    CHECK_VASTATUS(va_status, "vaBeginPicture");
791
792    va_status = vaRenderPicture(va_dpy,
793                                context_id,
794                                &pipeline_param_buf_id,
795                                1);
796    CHECK_VASTATUS(va_status, "vaRenderPicture");
797
798    va_status = vaEndPicture(va_dpy, context_id);
799    CHECK_VASTATUS(va_status, "vaEndPicture");
800
801    if (filter_param_buf_id != VA_INVALID_ID)
802        vaDestroyBuffer(va_dpy,filter_param_buf_id);
803
804    if (pipeline_param_buf_id != VA_INVALID_ID)
805        vaDestroyBuffer(va_dpy,pipeline_param_buf_id);
806
807    return va_status;
808}
809
810static VAStatus
811vpp_context_create()
812{
813    VAStatus va_status = VA_STATUS_SUCCESS;
814    uint32_t i;
815
816    /* VA driver initialization */
817    va_dpy = va_open_display();
818    int32_t major_ver, minor_ver;
819    va_status = vaInitialize(va_dpy, &major_ver, &minor_ver);
820    assert(va_status == VA_STATUS_SUCCESS);
821
822    /* Check whether VPP is supported by driver */
823    VAEntrypoint entrypoints[5];
824    int32_t num_entrypoints;
825    num_entrypoints = vaMaxNumEntrypoints(va_dpy);
826    va_status = vaQueryConfigEntrypoints(va_dpy,
827                                         VAProfileNone,
828                                         entrypoints,
829                                         &num_entrypoints);
830    CHECK_VASTATUS(va_status, "vaQueryConfigEntrypoints");
831
832    for	(i = 0; i < num_entrypoints; i++) {
833        if (entrypoints[i] == VAEntrypointVideoProc)
834            break;
835    }
836
837    if (i == num_entrypoints) {
838        printf("VPP is not supported by driver\n");
839        assert(0);
840    }
841
842    /* Render target surface format check */
843    VAConfigAttrib attrib;
844    attrib.type = VAConfigAttribRTFormat;
845    va_status = vaGetConfigAttributes(va_dpy,
846                                      VAProfileNone,
847                                      VAEntrypointVideoProc,
848                                      &attrib,
849                                     1);
850    CHECK_VASTATUS(va_status, "vaGetConfigAttributes");
851    if ((attrib.value != g_out_format)) {
852        printf("RT format %d is not supported by VPP !\n",g_out_format);
853        assert(0);
854    }
855
856    /* Create surface/config/context for VPP pipeline */
857    va_status = create_surface(&g_in_surface_id, g_in_pic_width, g_in_pic_height,
858                                g_in_fourcc, g_in_format);
859    CHECK_VASTATUS(va_status, "vaCreateSurfaces for input");
860
861    va_status = create_surface(&g_out_surface_id, g_out_pic_width, g_out_pic_height,
862                                g_out_fourcc, g_out_format);
863    CHECK_VASTATUS(va_status, "vaCreateSurfaces for output");
864
865    va_status = vaCreateConfig(va_dpy,
866                               VAProfileNone,
867                               VAEntrypointVideoProc,
868                               &attrib,
869                               1,
870                               &config_id);
871    CHECK_VASTATUS(va_status, "vaCreateConfig");
872
873    /* Source surface format check */
874    uint32_t num_surf_attribs = VASurfaceAttribCount;
875    VASurfaceAttrib * surf_attribs = (VASurfaceAttrib*)
876              malloc(sizeof(VASurfaceAttrib) * num_surf_attribs);
877    if (!surf_attribs)
878       assert(0);
879
880    va_status = vaQuerySurfaceAttributes(va_dpy,
881                                        config_id,
882                                        surf_attribs,
883                                        &num_surf_attribs);
884
885    if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
886        surf_attribs = (VASurfaceAttrib*)realloc(surf_attribs,
887                        sizeof(VASurfaceAttrib) * num_surf_attribs);
888         if (!surf_attribs)
889             assert(0);
890         va_status = vaQuerySurfaceAttributes(va_dpy,
891                                              config_id,
892                                              surf_attribs,
893                                              &num_surf_attribs);
894    }
895    CHECK_VASTATUS(va_status, "vaQuerySurfaceAttributes");
896
897    for (i = 0; i < num_surf_attribs; i++) {
898        if (surf_attribs[i].type == VASurfaceAttribPixelFormat &&
899            surf_attribs[i].value.value.i == g_in_fourcc)
900            break;
901    }
902    free(surf_attribs);
903
904    if (i == num_surf_attribs) {
905        printf("Input fourCC %d  is not supported by VPP !\n", g_in_fourcc);
906        assert(0);
907    }
908
909    va_status = vaCreateContext(va_dpy,
910                                config_id,
911                                g_out_pic_width,
912                                g_out_pic_height,
913                                VA_PROGRESSIVE,
914                                &g_out_surface_id,
915                                1,
916                                &context_id);
917    CHECK_VASTATUS(va_status, "vaCreateContext");
918
919
920    /* Validate  whether currect filter is supported */
921    if (g_filter_type != VAProcFilterNone) {
922        uint32_t supported_filter_num = VAProcFilterCount;
923        VAProcFilterType supported_filter_types[VAProcFilterCount];
924
925        va_status = vaQueryVideoProcFilters(va_dpy,
926                                            context_id,
927                                            supported_filter_types,
928                                            &supported_filter_num);
929
930        CHECK_VASTATUS(va_status, "vaQueryVideoProcFilters");
931
932        for (i = 0; i < supported_filter_num; i++){
933            if (supported_filter_types[i] == g_filter_type)
934                break;
935        }
936
937        if (i == supported_filter_num) {
938            printf("VPP filter type %s is not supported by driver !\n", g_filter_type_name);
939            assert(0);
940        }
941    }
942
943    return va_status;
944}
945
946static void
947vpp_context_destroy()
948{
949    /* Release resource */
950    vaDestroySurfaces(va_dpy, &g_in_surface_id, 1);
951    vaDestroySurfaces(va_dpy, &g_out_surface_id, 1);
952    vaDestroyContext(va_dpy, context_id);
953    vaDestroyConfig(va_dpy, config_id);
954
955    vaTerminate(va_dpy);
956    va_close_display(va_dpy);
957}
958
959static int8_t
960parse_fourcc_and_format(char *str, uint32_t *fourcc, uint32_t *format)
961{
962    if (!strcmp(str, "YV12")){
963        *fourcc = VA_FOURCC('Y', 'V', '1', '2');
964        *format = VA_RT_FORMAT_YUV420;
965    } else if(!strcmp(str, "I420")){
966        *fourcc = VA_FOURCC('I', '4', '2', '0');
967        *format = VA_RT_FORMAT_YUV420;
968    } else if(!strcmp(str, "NV12")){
969        *fourcc = VA_FOURCC('N', 'V', '1', '2');
970        *format = VA_RT_FORMAT_YUV420;
971    } else{
972        printf("Not supported format: %s! Currently only support following format: %s\n",
973         str, "YV12, I420, NV12");
974        assert(0);
975    }
976    return 0;
977}
978
979static int8_t
980parse_basic_parameters()
981{
982    char str[MAX_LEN];
983
984    /* Read src frame file information */
985    read_value_string(g_config_file_fd, "SRC_FILE_NAME", g_src_file_name);
986    read_value_uint32(g_config_file_fd, "SRC_FRAME_WIDTH", &g_in_pic_width);
987    read_value_uint32(g_config_file_fd, "SRC_FRAME_HEIGHT", &g_in_pic_height);
988    read_value_string(g_config_file_fd, "SRC_FRAME_FORMAT", str);
989    parse_fourcc_and_format(str, &g_in_fourcc, &g_in_format);
990
991    /* Read dst frame file information */
992    read_value_string(g_config_file_fd, "DST_FILE_NAME", g_dst_file_name);
993    read_value_uint32(g_config_file_fd, "DST_FRAME_WIDTH", &g_out_pic_width);
994    read_value_uint32(g_config_file_fd, "DST_FRAME_HEIGHT",&g_out_pic_height);
995    read_value_string(g_config_file_fd, "DST_FRAME_FORMAT", str);
996    parse_fourcc_and_format(str, &g_out_fourcc, &g_out_format);
997
998    read_value_uint32(g_config_file_fd, "FRAME_SUM", &g_frame_count);
999
1000    /* Read filter type */
1001    if (read_value_string(g_config_file_fd, "FILTER_TYPE", g_filter_type_name)){
1002        printf("Read filter type error !\n");
1003        assert(0);
1004    }
1005
1006    if (!strcmp(g_filter_type_name, "VAProcFilterNoiseReduction"))
1007        g_filter_type = VAProcFilterNoiseReduction;
1008    else if (!strcmp(g_filter_type_name, "VAProcFilterDeinterlacing"))
1009        g_filter_type = VAProcFilterDeinterlacing;
1010    else if (!strcmp(g_filter_type_name, "VAProcFilterSharpening"))
1011        g_filter_type = VAProcFilterSharpening;
1012    else if (!strcmp(g_filter_type_name, "VAProcFilterColorBalance"))
1013        g_filter_type = VAProcFilterColorBalance;
1014    else if (!strcmp(g_filter_type_name, "VAProcFilterNone"))
1015        g_filter_type = VAProcFilterNone;
1016    else {
1017        printf("Unsupported filter type :%s \n", g_filter_type_name);
1018        return -1;
1019    }
1020
1021    /* Check whether blending is enabled */
1022    if (read_value_uint8(g_config_file_fd, "BLENDING_ENABLED", &g_blending_enabled))
1023        g_blending_enabled = 0;
1024
1025    if (g_blending_enabled)
1026        printf("Blending will be done \n");
1027
1028    if (g_in_pic_width != g_out_pic_width ||
1029        g_in_pic_height != g_out_pic_height)
1030        printf("Scaling will be done : from %4d x %4d to %4d x %4d \n",
1031                g_in_pic_width, g_in_pic_height,
1032                g_out_pic_width, g_out_pic_height);
1033
1034    if (g_in_fourcc != g_out_fourcc)
1035        printf("Format conversion will be done: from %d to %d \n",
1036               g_in_fourcc, g_out_fourcc);
1037
1038    return 0;
1039}
1040
1041int32_t main(int32_t argc, char *argv[])
1042{
1043    VAStatus va_status;
1044    uint32_t i;
1045
1046    if (argc != 2){
1047        printf("Input error! please specify the configure file \n");
1048        return -1;
1049    }
1050
1051    /* Parse the configure file for video process*/
1052    strcpy(g_config_file_name, argv[1]);
1053    if (NULL == (g_config_file_fd = fopen(g_config_file_name, "r"))){
1054        printf("Open configure file %s failed!\n",g_config_file_name);
1055        assert(0);
1056    }
1057
1058    /* Parse basic parameters */
1059    if (parse_basic_parameters()){
1060        printf("Parse parameters in configure file error\n");
1061        assert(0);
1062    }
1063
1064    va_status = vpp_context_create();
1065    if (va_status != VA_STATUS_SUCCESS) {
1066        printf("vpp context create failed \n");
1067        assert(0);
1068    }
1069
1070    /* Video frame fetch, process and store */
1071    if (NULL == (g_src_file_fd = fopen(g_src_file_name, "r"))){
1072        printf("Open SRC_FILE_NAME: %s failed, please specify it in config file: %s !\n",
1073                g_src_file_name, g_config_file_name);
1074        assert(0);
1075    }
1076
1077    if (NULL == (g_dst_file_fd = fopen(g_dst_file_name, "w"))){
1078        printf("Open DST_FILE_NAME: %s failed, please specify it in config file: %s !\n",
1079               g_dst_file_name, g_config_file_name);
1080        assert(0);
1081    }
1082
1083    printf("\nStart to process, processing type is %s ...\n", g_filter_type_name);
1084    struct timeval start_time, end_time;
1085    gettimeofday(&start_time, NULL);
1086
1087    for (i = 0; i < g_frame_count; i ++){
1088        if (g_blending_enabled) {
1089            construct_nv12_mask_surface(g_in_surface_id, g_blending_min_luma, g_blending_max_luma);
1090            upload_yv12_frame_to_yuv_surface(g_src_file_fd, g_out_surface_id);
1091        } else {
1092            upload_yv12_frame_to_yuv_surface(g_src_file_fd, g_in_surface_id);
1093        }
1094
1095        video_frame_process(g_filter_type, i, g_in_surface_id, g_out_surface_id);
1096        store_yuv_surface_to_yv12_frame(g_dst_file_fd, g_out_surface_id);
1097    }
1098
1099    gettimeofday(&end_time, NULL);
1100    float duration = (end_time.tv_sec - start_time.tv_sec) +
1101                     (end_time.tv_usec - start_time.tv_usec)/1000000.0;
1102    printf("Finish processing, performance: \n" );
1103    printf("%d frames processed in: %f s, ave time = %.6fs \n",g_frame_count, duration, duration/g_frame_count);
1104
1105    if (g_src_file_fd)
1106       fclose(g_src_file_fd);
1107
1108    if (g_dst_file_fd)
1109       fclose(g_dst_file_fd);
1110
1111    if (g_config_file_fd)
1112       fclose(g_config_file_fd);
1113
1114    vpp_context_destroy();
1115
1116    return 0;
1117}
1118
1119