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