1 /************************************************************************** 2 * 3 * Copyright 2010 Thomas Balling Srensen. 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 * 26 **************************************************************************/ 27 28 #include <vdpau/vdpau.h> 29 30 #include "util/u_memory.h" 31 #include "util/u_debug.h" 32 33 #include "vl/vl_csc.h" 34 35 #include "vdpau_private.h" 36 37 /** 38 * Create a VdpVideoMixer. 39 */ 40 VdpStatus 41 vlVdpVideoMixerCreate(VdpDevice device, 42 uint32_t feature_count, 43 VdpVideoMixerFeature const *features, 44 uint32_t parameter_count, 45 VdpVideoMixerParameter const *parameters, 46 void const *const *parameter_values, 47 VdpVideoMixer *mixer) 48 { 49 vlVdpVideoMixer *vmixer = NULL; 50 VdpStatus ret; 51 struct pipe_screen *screen; 52 uint32_t max_2d_texture_level; 53 unsigned max_size, i; 54 55 vlVdpDevice *dev = vlGetDataHTAB(device); 56 if (!dev) 57 return VDP_STATUS_INVALID_HANDLE; 58 screen = dev->vscreen->pscreen; 59 60 vmixer = CALLOC(1, sizeof(vlVdpVideoMixer)); 61 if (!vmixer) 62 return VDP_STATUS_RESOURCES; 63 64 DeviceReference(&vmixer->device, dev); 65 66 pipe_mutex_lock(dev->mutex); 67 68 if (!vl_compositor_init_state(&vmixer->cstate, dev->context)) { 69 ret = VDP_STATUS_ERROR; 70 goto no_compositor_state; 71 } 72 73 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, &vmixer->csc); 74 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) { 75 if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 1.0f, 0.0f)) { 76 ret = VDP_STATUS_ERROR; 77 goto err_csc_matrix; 78 } 79 } 80 81 *mixer = vlAddDataHTAB(vmixer); 82 if (*mixer == 0) { 83 ret = VDP_STATUS_ERROR; 84 goto no_handle; 85 } 86 87 ret = VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 88 for (i = 0; i < feature_count; ++i) { 89 switch (features[i]) { 90 /* they are valid, but we doesn't support them */ 91 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 92 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 93 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 94 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 95 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 96 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 97 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 98 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 99 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 100 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 101 break; 102 103 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 104 vmixer->deint.supported = true; 105 break; 106 107 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 108 vmixer->sharpness.supported = true; 109 break; 110 111 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 112 vmixer->noise_reduction.supported = true; 113 break; 114 115 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 116 vmixer->luma_key.supported = true; 117 break; 118 119 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 120 vmixer->bicubic.supported = true; 121 break; 122 default: goto no_params; 123 } 124 } 125 126 vmixer->chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; 127 ret = VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER; 128 for (i = 0; i < parameter_count; ++i) { 129 switch (parameters[i]) { 130 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 131 vmixer->video_width = *(uint32_t*)parameter_values[i]; 132 break; 133 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 134 vmixer->video_height = *(uint32_t*)parameter_values[i]; 135 break; 136 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE: 137 vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]); 138 break; 139 case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 140 vmixer->max_layers = *(uint32_t*)parameter_values[i]; 141 break; 142 default: goto no_params; 143 } 144 } 145 ret = VDP_STATUS_INVALID_VALUE; 146 if (vmixer->max_layers > 4) { 147 VDPAU_MSG(VDPAU_WARN, "[VDPAU] Max layers > 4 not supported\n", vmixer->max_layers); 148 goto no_params; 149 } 150 151 max_2d_texture_level = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS); 152 max_size = pow(2, max_2d_texture_level-1); 153 if (vmixer->video_width < 48 || vmixer->video_width > max_size) { 154 VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for width\n", 155 vmixer->video_width, max_size); 156 goto no_params; 157 } 158 if (vmixer->video_height < 48 || vmixer->video_height > max_size) { 159 VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for height\n", 160 vmixer->video_height, max_size); 161 goto no_params; 162 } 163 vmixer->luma_key.luma_min = 1.0f; 164 vmixer->luma_key.luma_max = 0.0f; 165 pipe_mutex_unlock(dev->mutex); 166 167 return VDP_STATUS_OK; 168 169 no_params: 170 vlRemoveDataHTAB(*mixer); 171 172 no_handle: 173 err_csc_matrix: 174 vl_compositor_cleanup_state(&vmixer->cstate); 175 no_compositor_state: 176 pipe_mutex_unlock(dev->mutex); 177 DeviceReference(&vmixer->device, NULL); 178 FREE(vmixer); 179 return ret; 180 } 181 182 /** 183 * Destroy a VdpVideoMixer. 184 */ 185 VdpStatus 186 vlVdpVideoMixerDestroy(VdpVideoMixer mixer) 187 { 188 vlVdpVideoMixer *vmixer; 189 190 vmixer = vlGetDataHTAB(mixer); 191 if (!vmixer) 192 return VDP_STATUS_INVALID_HANDLE; 193 194 pipe_mutex_lock(vmixer->device->mutex); 195 196 vlRemoveDataHTAB(mixer); 197 198 vl_compositor_cleanup_state(&vmixer->cstate); 199 200 if (vmixer->deint.filter) { 201 vl_deint_filter_cleanup(vmixer->deint.filter); 202 FREE(vmixer->deint.filter); 203 } 204 205 if (vmixer->noise_reduction.filter) { 206 vl_median_filter_cleanup(vmixer->noise_reduction.filter); 207 FREE(vmixer->noise_reduction.filter); 208 } 209 210 if (vmixer->sharpness.filter) { 211 vl_matrix_filter_cleanup(vmixer->sharpness.filter); 212 FREE(vmixer->sharpness.filter); 213 } 214 215 if (vmixer->bicubic.filter) { 216 vl_bicubic_filter_cleanup(vmixer->bicubic.filter); 217 FREE(vmixer->bicubic.filter); 218 } 219 pipe_mutex_unlock(vmixer->device->mutex); 220 DeviceReference(&vmixer->device, NULL); 221 222 FREE(vmixer); 223 224 return VDP_STATUS_OK; 225 } 226 227 /** 228 * Perform a video post-processing and compositing operation. 229 */ 230 VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer, 231 VdpOutputSurface background_surface, 232 VdpRect const *background_source_rect, 233 VdpVideoMixerPictureStructure current_picture_structure, 234 uint32_t video_surface_past_count, 235 VdpVideoSurface const *video_surface_past, 236 VdpVideoSurface video_surface_current, 237 uint32_t video_surface_future_count, 238 VdpVideoSurface const *video_surface_future, 239 VdpRect const *video_source_rect, 240 VdpOutputSurface destination_surface, 241 VdpRect const *destination_rect, 242 VdpRect const *destination_video_rect, 243 uint32_t layer_count, 244 VdpLayer const *layers) 245 { 246 enum vl_compositor_deinterlace deinterlace; 247 struct u_rect rect, clip, *prect, dirty_area; 248 unsigned i, layer = 0; 249 struct pipe_video_buffer *video_buffer; 250 struct pipe_sampler_view *sampler_view, sv_templ; 251 struct pipe_surface *surface, surf_templ; 252 struct pipe_context *pipe = NULL; 253 struct pipe_resource res_tmpl, *res; 254 255 vlVdpVideoMixer *vmixer; 256 vlVdpSurface *surf; 257 vlVdpOutputSurface *dst, *bg = NULL; 258 259 struct vl_compositor *compositor; 260 261 vmixer = vlGetDataHTAB(mixer); 262 if (!vmixer) 263 return VDP_STATUS_INVALID_HANDLE; 264 265 compositor = &vmixer->device->compositor; 266 267 surf = vlGetDataHTAB(video_surface_current); 268 if (!surf) 269 return VDP_STATUS_INVALID_HANDLE; 270 video_buffer = surf->video_buffer; 271 272 if (surf->device != vmixer->device) 273 return VDP_STATUS_HANDLE_DEVICE_MISMATCH; 274 275 if (vmixer->video_width > video_buffer->width || 276 vmixer->video_height > video_buffer->height || 277 vmixer->chroma_format != video_buffer->chroma_format) 278 return VDP_STATUS_INVALID_SIZE; 279 280 if (layer_count > vmixer->max_layers) 281 return VDP_STATUS_INVALID_VALUE; 282 283 dst = vlGetDataHTAB(destination_surface); 284 if (!dst) 285 return VDP_STATUS_INVALID_HANDLE; 286 287 if (background_surface != VDP_INVALID_HANDLE) { 288 bg = vlGetDataHTAB(background_surface); 289 if (!bg) 290 return VDP_STATUS_INVALID_HANDLE; 291 } 292 293 pipe_mutex_lock(vmixer->device->mutex); 294 295 vl_compositor_clear_layers(&vmixer->cstate); 296 297 if (bg) 298 vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view, 299 RectToPipe(background_source_rect, &rect), NULL, NULL); 300 301 switch (current_picture_structure) { 302 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD: 303 deinterlace = VL_COMPOSITOR_BOB_TOP; 304 break; 305 306 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: 307 deinterlace = VL_COMPOSITOR_BOB_BOTTOM; 308 break; 309 310 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME: 311 deinterlace = VL_COMPOSITOR_WEAVE; 312 break; 313 314 default: 315 pipe_mutex_unlock(vmixer->device->mutex); 316 return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE; 317 } 318 319 if (deinterlace != VL_COMPOSITOR_WEAVE && vmixer->deint.enabled && 320 video_surface_past_count > 1 && video_surface_future_count > 0) { 321 vlVdpSurface *prevprev = vlGetDataHTAB(video_surface_past[1]); 322 vlVdpSurface *prev = vlGetDataHTAB(video_surface_past[0]); 323 vlVdpSurface *next = vlGetDataHTAB(video_surface_future[0]); 324 if (prevprev && prev && next && 325 vl_deint_filter_check_buffers(vmixer->deint.filter, 326 prevprev->video_buffer, prev->video_buffer, surf->video_buffer, next->video_buffer)) { 327 vl_deint_filter_render(vmixer->deint.filter, prevprev->video_buffer, 328 prev->video_buffer, surf->video_buffer, 329 next->video_buffer, 330 deinterlace == VL_COMPOSITOR_BOB_BOTTOM); 331 deinterlace = VL_COMPOSITOR_WEAVE; 332 video_buffer = vmixer->deint.filter->video_buffer; 333 } 334 } 335 336 prect = RectToPipe(video_source_rect, &rect); 337 if (!prect) { 338 rect.x0 = 0; 339 rect.y0 = 0; 340 rect.x1 = surf->templat.width; 341 rect.y1 = surf->templat.height; 342 prect = ▭ 343 } 344 vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace); 345 346 if (vmixer->bicubic.filter || vmixer->sharpness.filter || vmixer->noise_reduction.filter) { 347 pipe = vmixer->device->context; 348 memset(&res_tmpl, 0, sizeof(res_tmpl)); 349 350 res_tmpl.target = PIPE_TEXTURE_2D; 351 res_tmpl.format = dst->sampler_view->format; 352 res_tmpl.depth0 = 1; 353 res_tmpl.array_size = 1; 354 res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET; 355 res_tmpl.usage = PIPE_USAGE_DEFAULT; 356 357 if (!vmixer->bicubic.filter) { 358 res_tmpl.width0 = dst->surface->width; 359 res_tmpl.height0 = dst->surface->height; 360 } else { 361 res_tmpl.width0 = surf->templat.width; 362 res_tmpl.height0 = surf->templat.height; 363 } 364 365 res = pipe->screen->resource_create(pipe->screen, &res_tmpl); 366 367 vlVdpDefaultSamplerViewTemplate(&sv_templ, res); 368 sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ); 369 370 memset(&surf_templ, 0, sizeof(surf_templ)); 371 surf_templ.format = res->format; 372 surface = pipe->create_surface(pipe, res, &surf_templ); 373 374 vl_compositor_reset_dirty_area(&dirty_area); 375 pipe_resource_reference(&res, NULL); 376 } else { 377 surface = dst->surface; 378 sampler_view = dst->sampler_view; 379 dirty_area = dst->dirty_area; 380 } 381 382 if (!vmixer->bicubic.filter) { 383 vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect)); 384 vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip)); 385 } 386 387 for (i = 0; i < layer_count; ++i) { 388 vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface); 389 if (!src) { 390 pipe_mutex_unlock(vmixer->device->mutex); 391 return VDP_STATUS_INVALID_HANDLE; 392 } 393 394 assert(layers->struct_version == VDP_LAYER_VERSION); 395 396 vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer, src->sampler_view, 397 RectToPipe(layers->source_rect, &rect), NULL, NULL); 398 vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(layers->destination_rect, &rect)); 399 400 ++layers; 401 } 402 403 vl_compositor_render(&vmixer->cstate, compositor, surface, &dirty_area, true); 404 405 if (vmixer->noise_reduction.filter) { 406 if (!vmixer->sharpness.filter && !vmixer->bicubic.filter) { 407 vl_median_filter_render(vmixer->noise_reduction.filter, 408 sampler_view, dst->surface); 409 } else { 410 res = pipe->screen->resource_create(pipe->screen, &res_tmpl); 411 struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ); 412 struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ); 413 pipe_resource_reference(&res, NULL); 414 415 vl_median_filter_render(vmixer->noise_reduction.filter, 416 sampler_view, surface_temp); 417 418 pipe_sampler_view_reference(&sampler_view, NULL); 419 pipe_surface_reference(&surface, NULL); 420 421 sampler_view = sampler_view_temp; 422 surface = surface_temp; 423 } 424 } 425 426 if (vmixer->sharpness.filter) { 427 if (!vmixer->bicubic.filter) { 428 vl_matrix_filter_render(vmixer->sharpness.filter, 429 sampler_view, dst->surface); 430 } else { 431 res = pipe->screen->resource_create(pipe->screen, &res_tmpl); 432 struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ); 433 struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ); 434 pipe_resource_reference(&res, NULL); 435 436 vl_matrix_filter_render(vmixer->sharpness.filter, 437 sampler_view, surface_temp); 438 439 pipe_sampler_view_reference(&sampler_view, NULL); 440 pipe_surface_reference(&surface, NULL); 441 442 sampler_view = sampler_view_temp; 443 surface = surface_temp; 444 } 445 } 446 447 if (vmixer->bicubic.filter) 448 vl_bicubic_filter_render(vmixer->bicubic.filter, 449 sampler_view, dst->surface, 450 RectToPipe(destination_video_rect, &rect), 451 RectToPipe(destination_rect, &clip)); 452 453 if(surface != dst->surface) { 454 pipe_sampler_view_reference(&sampler_view, NULL); 455 pipe_surface_reference(&surface, NULL); 456 } 457 pipe_mutex_unlock(vmixer->device->mutex); 458 459 return VDP_STATUS_OK; 460 } 461 462 static void 463 vlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer *vmixer) 464 { 465 struct pipe_context *pipe = vmixer->device->context; 466 assert(vmixer); 467 468 /* remove existing filter */ 469 if (vmixer->deint.filter) { 470 vl_deint_filter_cleanup(vmixer->deint.filter); 471 FREE(vmixer->deint.filter); 472 vmixer->deint.filter = NULL; 473 } 474 475 /* create a new filter if requested */ 476 if (vmixer->deint.enabled && vmixer->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) { 477 vmixer->deint.filter = MALLOC(sizeof(struct vl_deint_filter)); 478 vmixer->deint.enabled = vl_deint_filter_init(vmixer->deint.filter, pipe, 479 vmixer->video_width, vmixer->video_height, 480 vmixer->skip_chroma_deint, vmixer->deint.spatial); 481 if (!vmixer->deint.enabled) { 482 FREE(vmixer->deint.filter); 483 } 484 } 485 } 486 487 /** 488 * Update the noise reduction setting 489 */ 490 static void 491 vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer) 492 { 493 assert(vmixer); 494 495 /* if present remove the old filter first */ 496 if (vmixer->noise_reduction.filter) { 497 vl_median_filter_cleanup(vmixer->noise_reduction.filter); 498 FREE(vmixer->noise_reduction.filter); 499 vmixer->noise_reduction.filter = NULL; 500 } 501 502 /* and create a new filter as needed */ 503 if (vmixer->noise_reduction. enabled && vmixer->noise_reduction.level > 0) { 504 vmixer->noise_reduction.filter = MALLOC(sizeof(struct vl_median_filter)); 505 vl_median_filter_init(vmixer->noise_reduction.filter, vmixer->device->context, 506 vmixer->video_width, vmixer->video_height, 507 vmixer->noise_reduction.level + 1, 508 VL_MEDIAN_FILTER_CROSS); 509 } 510 } 511 512 static void 513 vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer) 514 { 515 assert(vmixer); 516 517 /* if present remove the old filter first */ 518 if (vmixer->sharpness.filter) { 519 vl_matrix_filter_cleanup(vmixer->sharpness.filter); 520 FREE(vmixer->sharpness.filter); 521 vmixer->sharpness.filter = NULL; 522 } 523 524 /* and create a new filter as needed */ 525 if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) { 526 float matrix[9]; 527 unsigned i; 528 529 if (vmixer->sharpness.value > 0.0f) { 530 matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f; 531 matrix[3] = -1.0f; matrix[4] = 8.0f; matrix[5] = -1.0f; 532 matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f; 533 534 for (i = 0; i < 9; ++i) 535 matrix[i] *= vmixer->sharpness.value; 536 537 matrix[4] += 1.0f; 538 539 } else { 540 matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f; 541 matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f; 542 matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f; 543 544 for (i = 0; i < 9; ++i) 545 matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f; 546 547 matrix[4] += 1.0f - fabsf(vmixer->sharpness.value); 548 } 549 550 vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter)); 551 vl_matrix_filter_init(vmixer->sharpness.filter, vmixer->device->context, 552 vmixer->video_width, vmixer->video_height, 553 3, 3, matrix); 554 } 555 } 556 557 /** 558 * Update the bicubic filter 559 */ 560 static void 561 vlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer *vmixer) 562 { 563 assert(vmixer); 564 565 /* if present remove the old filter first */ 566 if (vmixer->bicubic.filter) { 567 vl_bicubic_filter_cleanup(vmixer->bicubic.filter); 568 FREE(vmixer->bicubic.filter); 569 vmixer->bicubic.filter = NULL; 570 } 571 /* and create a new filter as needed */ 572 if (vmixer->bicubic.enabled) { 573 vmixer->bicubic.filter = MALLOC(sizeof(struct vl_bicubic_filter)); 574 vl_bicubic_filter_init(vmixer->bicubic.filter, vmixer->device->context, 575 vmixer->video_width, vmixer->video_height); 576 } 577 } 578 579 /** 580 * Retrieve whether features were requested at creation time. 581 */ 582 VdpStatus 583 vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer, 584 uint32_t feature_count, 585 VdpVideoMixerFeature const *features, 586 VdpBool *feature_supports) 587 { 588 vlVdpVideoMixer *vmixer; 589 unsigned i; 590 591 if (!(features && feature_supports)) 592 return VDP_STATUS_INVALID_POINTER; 593 594 vmixer = vlGetDataHTAB(mixer); 595 if (!vmixer) 596 return VDP_STATUS_INVALID_HANDLE; 597 598 for (i = 0; i < feature_count; ++i) { 599 switch (features[i]) { 600 /* they are valid, but we doesn't support them */ 601 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 602 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 603 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 604 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 605 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 606 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 607 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 608 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 609 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 610 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 611 feature_supports[i] = false; 612 break; 613 614 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 615 feature_supports[i] = vmixer->deint.supported; 616 break; 617 618 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 619 feature_supports[i] = vmixer->sharpness.supported; 620 break; 621 622 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 623 feature_supports[i] = vmixer->noise_reduction.supported; 624 break; 625 626 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 627 feature_supports[i] = vmixer->luma_key.supported; 628 break; 629 630 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 631 feature_supports[i] = vmixer->bicubic.supported; 632 break; 633 634 default: 635 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 636 } 637 } 638 639 return VDP_STATUS_OK; 640 } 641 642 /** 643 * Enable or disable features. 644 */ 645 VdpStatus 646 vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer, 647 uint32_t feature_count, 648 VdpVideoMixerFeature const *features, 649 VdpBool const *feature_enables) 650 { 651 vlVdpVideoMixer *vmixer; 652 unsigned i; 653 654 if (!(features && feature_enables)) 655 return VDP_STATUS_INVALID_POINTER; 656 657 vmixer = vlGetDataHTAB(mixer); 658 if (!vmixer) 659 return VDP_STATUS_INVALID_HANDLE; 660 661 pipe_mutex_lock(vmixer->device->mutex); 662 for (i = 0; i < feature_count; ++i) { 663 switch (features[i]) { 664 /* they are valid, but we doesn't support them */ 665 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 666 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 667 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 668 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 669 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 670 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 671 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 672 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 673 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 674 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 675 break; 676 677 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 678 vmixer->deint.enabled = feature_enables[i]; 679 vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer); 680 break; 681 682 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 683 vmixer->sharpness.enabled = feature_enables[i]; 684 vlVdpVideoMixerUpdateSharpnessFilter(vmixer); 685 break; 686 687 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 688 vmixer->noise_reduction.enabled = feature_enables[i]; 689 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer); 690 break; 691 692 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 693 vmixer->luma_key.enabled = feature_enables[i]; 694 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 695 if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 696 vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 697 pipe_mutex_unlock(vmixer->device->mutex); 698 return VDP_STATUS_ERROR; 699 } 700 break; 701 702 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 703 vmixer->bicubic.enabled = feature_enables[i]; 704 vlVdpVideoMixerUpdateBicubicFilter(vmixer); 705 break; 706 707 default: 708 pipe_mutex_unlock(vmixer->device->mutex); 709 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 710 } 711 } 712 pipe_mutex_unlock(vmixer->device->mutex); 713 714 return VDP_STATUS_OK; 715 } 716 717 /** 718 * Retrieve whether features are enabled. 719 */ 720 VdpStatus 721 vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer, 722 uint32_t feature_count, 723 VdpVideoMixerFeature const *features, 724 VdpBool *feature_enables) 725 { 726 vlVdpVideoMixer *vmixer; 727 unsigned i; 728 729 if (!(features && feature_enables)) 730 return VDP_STATUS_INVALID_POINTER; 731 732 vmixer = vlGetDataHTAB(mixer); 733 if (!vmixer) 734 return VDP_STATUS_INVALID_HANDLE; 735 736 for (i = 0; i < feature_count; ++i) { 737 switch (features[i]) { 738 /* they are valid, but we doesn't support them */ 739 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 740 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 741 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 742 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 743 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 744 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 745 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 746 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 747 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 748 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 749 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 750 break; 751 752 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 753 feature_enables[i] = vmixer->sharpness.enabled; 754 break; 755 756 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 757 feature_enables[i] = vmixer->noise_reduction.enabled; 758 break; 759 760 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 761 feature_enables[i] = vmixer->luma_key.enabled; 762 break; 763 764 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 765 feature_enables[i] = vmixer->bicubic.enabled; 766 break; 767 768 default: 769 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 770 } 771 } 772 773 return VDP_STATUS_OK; 774 } 775 776 /** 777 * Set attribute values. 778 */ 779 VdpStatus 780 vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer, 781 uint32_t attribute_count, 782 VdpVideoMixerAttribute const *attributes, 783 void const *const *attribute_values) 784 { 785 const VdpColor *background_color; 786 union pipe_color_union color; 787 const float *vdp_csc; 788 float val; 789 unsigned i; 790 VdpStatus ret; 791 792 if (!(attributes && attribute_values)) 793 return VDP_STATUS_INVALID_POINTER; 794 795 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 796 if (!vmixer) 797 return VDP_STATUS_INVALID_HANDLE; 798 799 pipe_mutex_lock(vmixer->device->mutex); 800 for (i = 0; i < attribute_count; ++i) { 801 switch (attributes[i]) { 802 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR: 803 background_color = attribute_values[i]; 804 color.f[0] = background_color->red; 805 color.f[1] = background_color->green; 806 color.f[2] = background_color->blue; 807 color.f[3] = background_color->alpha; 808 vl_compositor_set_clear_color(&vmixer->cstate, &color); 809 break; 810 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX: 811 vdp_csc = attribute_values[i]; 812 vmixer->custom_csc = !!vdp_csc; 813 if (!vdp_csc) 814 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &vmixer->csc); 815 else 816 memcpy(vmixer->csc, vdp_csc, sizeof(vl_csc_matrix)); 817 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 818 if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 819 vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 820 ret = VDP_STATUS_ERROR; 821 goto fail; 822 } 823 break; 824 825 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL: 826 827 val = *(float*)attribute_values[i]; 828 if (val < 0.0f || val > 1.0f) { 829 ret = VDP_STATUS_INVALID_VALUE; 830 goto fail; 831 } 832 833 vmixer->noise_reduction.level = val * 10; 834 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer); 835 break; 836 837 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA: 838 val = *(float*)attribute_values[i]; 839 if (val < 0.0f || val > 1.0f) { 840 ret = VDP_STATUS_INVALID_VALUE; 841 goto fail; 842 } 843 vmixer->luma_key.luma_min = val; 844 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 845 if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 846 vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 847 ret = VDP_STATUS_ERROR; 848 goto fail; 849 } 850 break; 851 852 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA: 853 val = *(float*)attribute_values[i]; 854 if (val < 0.0f || val > 1.0f) { 855 ret = VDP_STATUS_INVALID_VALUE; 856 goto fail; 857 } 858 vmixer->luma_key.luma_max = val; 859 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 860 if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 861 vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) { 862 ret = VDP_STATUS_ERROR; 863 goto fail; 864 } 865 break; 866 867 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL: 868 869 val = *(float*)attribute_values[i]; 870 if (val < -1.0f || val > 1.0f) { 871 ret = VDP_STATUS_INVALID_VALUE; 872 goto fail; 873 } 874 875 vmixer->sharpness.value = val; 876 vlVdpVideoMixerUpdateSharpnessFilter(vmixer); 877 break; 878 879 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE: 880 if (*(uint8_t*)attribute_values[i] > 1) { 881 ret = VDP_STATUS_INVALID_VALUE; 882 goto fail; 883 } 884 vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i]; 885 vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer); 886 break; 887 default: 888 ret = VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE; 889 goto fail; 890 } 891 } 892 pipe_mutex_unlock(vmixer->device->mutex); 893 894 return VDP_STATUS_OK; 895 fail: 896 pipe_mutex_unlock(vmixer->device->mutex); 897 return ret; 898 } 899 900 /** 901 * Retrieve parameter values given at creation time. 902 */ 903 VdpStatus 904 vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer, 905 uint32_t parameter_count, 906 VdpVideoMixerParameter const *parameters, 907 void *const *parameter_values) 908 { 909 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 910 unsigned i; 911 if (!vmixer) 912 return VDP_STATUS_INVALID_HANDLE; 913 914 if (!parameter_count) 915 return VDP_STATUS_OK; 916 if (!(parameters && parameter_values)) 917 return VDP_STATUS_INVALID_POINTER; 918 for (i = 0; i < parameter_count; ++i) { 919 switch (parameters[i]) { 920 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 921 *(uint32_t*)parameter_values[i] = vmixer->video_width; 922 break; 923 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 924 *(uint32_t*)parameter_values[i] = vmixer->video_height; 925 break; 926 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE: 927 *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format); 928 break; 929 case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 930 *(uint32_t*)parameter_values[i] = vmixer->max_layers; 931 break; 932 default: 933 return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER; 934 } 935 } 936 return VDP_STATUS_OK; 937 } 938 939 /** 940 * Retrieve current attribute values. 941 */ 942 VdpStatus 943 vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer, 944 uint32_t attribute_count, 945 VdpVideoMixerAttribute const *attributes, 946 void *const *attribute_values) 947 { 948 unsigned i; 949 VdpCSCMatrix **vdp_csc; 950 951 if (!(attributes && attribute_values)) 952 return VDP_STATUS_INVALID_POINTER; 953 954 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 955 if (!vmixer) 956 return VDP_STATUS_INVALID_HANDLE; 957 958 pipe_mutex_lock(vmixer->device->mutex); 959 for (i = 0; i < attribute_count; ++i) { 960 switch (attributes[i]) { 961 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR: 962 vl_compositor_get_clear_color(&vmixer->cstate, attribute_values[i]); 963 break; 964 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX: 965 vdp_csc = attribute_values[i]; 966 if (!vmixer->custom_csc) { 967 *vdp_csc = NULL; 968 break; 969 } 970 memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12); 971 break; 972 973 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL: 974 *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f; 975 break; 976 977 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA: 978 *(float*)attribute_values[i] = vmixer->luma_key.luma_min; 979 break; 980 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA: 981 *(float*)attribute_values[i] = vmixer->luma_key.luma_max; 982 break; 983 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL: 984 *(float*)attribute_values[i] = vmixer->sharpness.value; 985 break; 986 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE: 987 *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint; 988 break; 989 default: 990 pipe_mutex_unlock(vmixer->device->mutex); 991 return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE; 992 } 993 } 994 pipe_mutex_unlock(vmixer->device->mutex); 995 return VDP_STATUS_OK; 996 } 997 998 /** 999 * Generate a color space conversion matrix. 1000 */ 1001 VdpStatus 1002 vlVdpGenerateCSCMatrix(VdpProcamp *procamp, 1003 VdpColorStandard standard, 1004 VdpCSCMatrix *csc_matrix) 1005 { 1006 enum VL_CSC_COLOR_STANDARD vl_std; 1007 struct vl_procamp camp; 1008 1009 if (!csc_matrix) 1010 return VDP_STATUS_INVALID_POINTER; 1011 1012 switch (standard) { 1013 case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break; 1014 case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break; 1015 case VDP_COLOR_STANDARD_SMPTE_240M: vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break; 1016 default: return VDP_STATUS_INVALID_COLOR_STANDARD; 1017 } 1018 1019 if (procamp) { 1020 if (procamp->struct_version > VDP_PROCAMP_VERSION) 1021 return VDP_STATUS_INVALID_STRUCT_VERSION; 1022 camp.brightness = procamp->brightness; 1023 camp.contrast = procamp->contrast; 1024 camp.saturation = procamp->saturation; 1025 camp.hue = procamp->hue; 1026 } 1027 1028 vl_csc_get_matrix(vl_std, procamp ? &camp : NULL, true, csc_matrix); 1029 return VDP_STATUS_OK; 1030 } 1031