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