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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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