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 
53 static VADisplay va_dpy = NULL;
54 static VAContextID context_id = 0;
55 static VAConfigID  config_id = 0;
56 static VAProcFilterType g_filter_type = VAProcFilterNone;
57 static VASurfaceID g_in_surface_id = VA_INVALID_ID;
58 static VASurfaceID g_out_surface_id = VA_INVALID_ID;
59 
60 static FILE* g_config_file_fd = NULL;
61 static FILE* g_src_file_fd = NULL;
62 static FILE* g_dst_file_fd = NULL;
63 
64 static char g_config_file_name[MAX_LEN];
65 static char g_src_file_name[MAX_LEN];
66 static char g_dst_file_name[MAX_LEN];
67 static char g_filter_type_name[MAX_LEN];
68 
69 static uint32_t g_in_pic_width = 352;
70 static uint32_t g_in_pic_height = 288;
71 static uint32_t g_out_pic_width = 352;
72 static uint32_t g_out_pic_height = 288;
73 
74 static uint32_t g_in_fourcc  = VA_FOURCC('N', 'V', '1', '2');
75 static uint32_t g_in_format  = VA_RT_FORMAT_YUV420;
76 static uint32_t g_out_fourcc = VA_FOURCC('N', 'V', '1', '2');
77 static uint32_t g_out_format = VA_RT_FORMAT_YUV420;
78 
79 static uint8_t g_blending_enabled = 0;
80 static uint8_t g_blending_min_luma = 1;
81 static uint8_t g_blending_max_luma = 254;
82 
83 static uint32_t g_frame_count = 0;
84 
85 static int8_t
read_value_string(FILE * fp,const char * field_name,char * value)86 read_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 
130 static int8_t
read_value_uint8(FILE * fp,const char * field_name,uint8_t * value)131 read_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 
144 static int8_t
read_value_uint32(FILE * fp,const char * field_name,uint32_t * value)145 read_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 
158 static int8_t
read_value_float(FILE * fp,const char * field_name,float * value)159 read_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 
171 static float
adjust_to_range(VAProcFilterValueRange * range,float value)172 adjust_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 
183 static VAStatus
create_surface(VASurfaceID * p_surface_id,uint32_t width,uint32_t height,uint32_t fourCC,uint32_t format)184 create_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 
206 static VAStatus
construct_nv12_mask_surface(VASurfaceID surface_id,uint8_t min_luma,uint8_t max_luma)207 construct_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*/
255 static VAStatus
upload_yv12_frame_to_yuv_surface(FILE * fp,VASurfaceID surface_id)256 upload_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*/
356 static VAStatus
store_yuv_surface_to_yv12_frame(FILE * fp,VASurfaceID surface_id)357 store_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 
462 static VAStatus
denoise_filter_init(VABufferID * filter_param_buf_id)463 denoise_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 
498 static VAStatus
deinterlace_filter_init(VABufferID * filter_param_buf_id)499 deinterlace_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 
567 static VAStatus
sharpening_filter_init(VABufferID * filter_param_buf_id)568 sharpening_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 
603 static VAStatus
color_balance_filter_init(VABufferID * filter_param_buf_id)604 color_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 
665 static VAStatus
blending_state_init(VABlendState * state)666 blending_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 
720 static VAStatus
video_frame_process(VAProcFilterType filter_type,uint32_t frame_idx,VASurfaceID in_surface_id,VASurfaceID out_surface_id)721 video_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 
810 static VAStatus
vpp_context_create()811 vpp_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 
946 static void
vpp_context_destroy()947 vpp_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 
959 static int8_t
parse_fourcc_and_format(char * str,uint32_t * fourcc,uint32_t * format)960 parse_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 
979 static int8_t
parse_basic_parameters()980 parse_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 
main(int32_t argc,char * argv[])1041 int32_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