mixer.c revision 1448e829e86981e6144410ba6a3d0f16357fb2b3
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 TUNGSTEN GRAPHICS 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_width, max_height, i; 53 enum pipe_video_profile prof = PIPE_VIDEO_PROFILE_UNKNOWN; 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 vmixer->device = dev; 65 vl_compositor_init(&vmixer->compositor, dev->context); 66 67 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, vmixer->csc); 68 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 69 vl_compositor_set_csc_matrix(&vmixer->compositor, vmixer->csc); 70 71 *mixer = vlAddDataHTAB(vmixer); 72 if (*mixer == 0) { 73 ret = VDP_STATUS_ERROR; 74 goto no_handle; 75 } 76 77 ret = VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 78 for (i = 0; i < feature_count; ++i) { 79 switch (features[i]) { 80 /* they are valid, but we doesn't support them */ 81 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 82 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 83 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 84 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 85 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 86 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 87 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 88 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 89 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 90 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 91 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 92 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 93 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 94 break; 95 96 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 97 vmixer->sharpness.supported = true; 98 break; 99 100 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 101 vmixer->noise_reduction.supported = true; 102 break; 103 104 default: goto no_params; 105 } 106 } 107 108 vmixer->chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; 109 ret = VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER; 110 for (i = 0; i < parameter_count; ++i) { 111 switch (parameters[i]) { 112 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 113 vmixer->video_width = *(uint32_t*)parameter_values[i]; 114 break; 115 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 116 vmixer->video_height = *(uint32_t*)parameter_values[i]; 117 break; 118 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE: 119 vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]); 120 break; 121 case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 122 vmixer->max_layers = *(uint32_t*)parameter_values[i]; 123 break; 124 default: goto no_params; 125 } 126 } 127 ret = VDP_STATUS_INVALID_VALUE; 128 if (vmixer->max_layers > 4) { 129 VDPAU_MSG(VDPAU_WARN, "[VDPAU] Max layers > 4 not supported\n", vmixer->max_layers); 130 goto no_params; 131 } 132 max_width = screen->get_video_param(screen, prof, PIPE_VIDEO_CAP_MAX_WIDTH); 133 max_height = screen->get_video_param(screen, prof, PIPE_VIDEO_CAP_MAX_HEIGHT); 134 if (vmixer->video_width < 48 || 135 vmixer->video_width > max_width) { 136 VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for width\n", vmixer->video_width, max_width); 137 goto no_params; 138 } 139 if (vmixer->video_height < 48 || 140 vmixer->video_height > max_height) { 141 VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for height\n", vmixer->video_height, max_height); 142 goto no_params; 143 } 144 vmixer->luma_key_min = 0.f; 145 vmixer->luma_key_max = 1.f; 146 147 return VDP_STATUS_OK; 148 149no_params: 150 vlRemoveDataHTAB(*mixer); 151no_handle: 152 vl_compositor_cleanup(&vmixer->compositor); 153 FREE(vmixer); 154 return ret; 155} 156 157/** 158 * Destroy a VdpVideoMixer. 159 */ 160VdpStatus 161vlVdpVideoMixerDestroy(VdpVideoMixer mixer) 162{ 163 vlVdpVideoMixer *vmixer; 164 165 vmixer = vlGetDataHTAB(mixer); 166 if (!vmixer) 167 return VDP_STATUS_INVALID_HANDLE; 168 vlRemoveDataHTAB(mixer); 169 170 vl_compositor_cleanup(&vmixer->compositor); 171 172 if (vmixer->noise_reduction.filter) { 173 vl_median_filter_cleanup(vmixer->noise_reduction.filter); 174 FREE(vmixer->noise_reduction.filter); 175 } 176 177 if (vmixer->sharpness.filter) { 178 vl_matrix_filter_cleanup(vmixer->sharpness.filter); 179 FREE(vmixer->sharpness.filter); 180 } 181 182 FREE(vmixer); 183 184 return VDP_STATUS_OK; 185} 186 187/** 188 * Perform a video post-processing and compositing operation. 189 */ 190VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer, 191 VdpOutputSurface background_surface, 192 VdpRect const *background_source_rect, 193 VdpVideoMixerPictureStructure current_picture_structure, 194 uint32_t video_surface_past_count, 195 VdpVideoSurface const *video_surface_past, 196 VdpVideoSurface video_surface_current, 197 uint32_t video_surface_future_count, 198 VdpVideoSurface const *video_surface_future, 199 VdpRect const *video_source_rect, 200 VdpOutputSurface destination_surface, 201 VdpRect const *destination_rect, 202 VdpRect const *destination_video_rect, 203 uint32_t layer_count, 204 VdpLayer const *layers) 205{ 206 struct pipe_video_rect src_rect, dst_rect, dst_clip; 207 enum vl_compositor_deinterlace deinterlace; 208 unsigned layer = 0; 209 210 vlVdpVideoMixer *vmixer; 211 vlVdpSurface *surf; 212 vlVdpOutputSurface *dst; 213 214 vmixer = vlGetDataHTAB(mixer); 215 if (!vmixer) 216 return VDP_STATUS_INVALID_HANDLE; 217 218 surf = vlGetDataHTAB(video_surface_current); 219 if (!surf) 220 return VDP_STATUS_INVALID_HANDLE; 221 222 if (surf->device != vmixer->device) 223 return VDP_STATUS_HANDLE_DEVICE_MISMATCH; 224 225 if (vmixer->video_width > surf->video_buffer->width || 226 vmixer->video_height > surf->video_buffer->height || 227 vmixer->chroma_format != surf->video_buffer->chroma_format) 228 return VDP_STATUS_INVALID_SIZE; 229 230 if (layer_count > vmixer->max_layers) 231 return VDP_STATUS_INVALID_VALUE; 232 233 dst = vlGetDataHTAB(destination_surface); 234 if (!dst) 235 return VDP_STATUS_INVALID_HANDLE; 236 237 if (background_surface != VDP_INVALID_HANDLE) { 238 vlVdpOutputSurface *bg = vlGetDataHTAB(background_surface); 239 if (!bg) 240 return VDP_STATUS_INVALID_HANDLE; 241 vl_compositor_set_rgba_layer(&vmixer->compositor, layer++, bg->sampler_view, 242 RectToPipe(background_source_rect, &src_rect), NULL); 243 } 244 245 vl_compositor_clear_layers(&vmixer->compositor); 246 247 switch (current_picture_structure) { 248 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD: 249 deinterlace = VL_COMPOSITOR_BOB_TOP; 250 break; 251 252 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: 253 deinterlace = VL_COMPOSITOR_BOB_BOTTOM; 254 break; 255 256 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME: 257 deinterlace = VL_COMPOSITOR_WEAVE; 258 break; 259 260 default: 261 return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE; 262 }; 263 vl_compositor_set_buffer_layer(&vmixer->compositor, layer++, surf->video_buffer, 264 RectToPipe(video_source_rect, &src_rect), NULL, 265 deinterlace); 266 vl_compositor_render(&vmixer->compositor, dst->surface, 267 RectToPipe(destination_video_rect, &dst_rect), 268 RectToPipe(destination_rect, &dst_clip), 269 &dst->dirty_area); 270 271 /* applying the noise reduction after scaling is actually not very 272 clever, but currently we should avoid to copy around the image 273 data once more. */ 274 if (vmixer->noise_reduction.filter) 275 vl_median_filter_render(vmixer->noise_reduction.filter, 276 dst->sampler_view, dst->surface); 277 278 if (vmixer->sharpness.filter) 279 vl_matrix_filter_render(vmixer->sharpness.filter, 280 dst->sampler_view, dst->surface); 281 282 return VDP_STATUS_OK; 283} 284 285/** 286 * Update the noise reduction setting 287 */ 288static void 289vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer) 290{ 291 assert(vmixer); 292 293 /* if present remove the old filter first */ 294 if (vmixer->noise_reduction.filter) { 295 vl_median_filter_cleanup(vmixer->noise_reduction.filter); 296 FREE(vmixer->noise_reduction.filter); 297 vmixer->noise_reduction.filter = NULL; 298 } 299 300 /* and create a new filter as needed */ 301 if (vmixer->noise_reduction. enabled && vmixer->noise_reduction.level > 0) { 302 vmixer->noise_reduction.filter = MALLOC(sizeof(struct vl_median_filter)); 303 vl_median_filter_init(vmixer->noise_reduction.filter, vmixer->device->context, 304 vmixer->video_width, vmixer->video_height, 305 vmixer->noise_reduction.level + 1, 306 VL_MEDIAN_FILTER_CROSS); 307 } 308} 309 310static void 311vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer) 312{ 313 assert(vmixer); 314 315 /* if present remove the old filter first */ 316 if (vmixer->sharpness.filter) { 317 vl_matrix_filter_cleanup(vmixer->sharpness.filter); 318 FREE(vmixer->sharpness.filter); 319 vmixer->sharpness.filter = NULL; 320 } 321 322 /* and create a new filter as needed */ 323 if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) { 324 float matrix[9]; 325 unsigned i; 326 327 if (vmixer->sharpness.value > 0.0f) { 328 matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f; 329 matrix[3] = -1.0f; matrix[4] = 8.0f; matrix[5] = -1.0f; 330 matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f; 331 332 for (i = 0; i < 9; ++i) 333 matrix[i] *= vmixer->sharpness.value; 334 335 matrix[4] += 1.0f; 336 337 } else { 338 matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f; 339 matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f; 340 matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f; 341 342 for (i = 0; i < 9; ++i) 343 matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f; 344 345 matrix[4] += 1.0f - fabsf(vmixer->sharpness.value); 346 } 347 348 vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter)); 349 vl_matrix_filter_init(vmixer->sharpness.filter, vmixer->device->context, 350 vmixer->video_width, vmixer->video_height, 351 3, 3, matrix); 352 } 353} 354 355/** 356 * Retrieve whether features were requested at creation time. 357 */ 358VdpStatus 359vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer, 360 uint32_t feature_count, 361 VdpVideoMixerFeature const *features, 362 VdpBool *feature_supports) 363{ 364 vlVdpVideoMixer *vmixer; 365 unsigned i; 366 367 if (!(features && feature_supports)) 368 return VDP_STATUS_INVALID_POINTER; 369 370 vmixer = vlGetDataHTAB(mixer); 371 if (!vmixer) 372 return VDP_STATUS_INVALID_HANDLE; 373 374 for (i = 0; i < feature_count; ++i) { 375 switch (features[i]) { 376 /* they are valid, but we doesn't support them */ 377 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 378 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 379 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 380 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 381 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 382 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 383 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 384 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 385 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 386 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 387 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 388 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 389 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 390 feature_supports[i] = false; 391 break; 392 393 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 394 feature_supports[i] = vmixer->sharpness.supported; 395 break; 396 397 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 398 feature_supports[i] = vmixer->noise_reduction.supported; 399 break; 400 401 default: 402 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 403 } 404 } 405 406 return VDP_STATUS_OK; 407} 408 409/** 410 * Enable or disable features. 411 */ 412VdpStatus 413vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer, 414 uint32_t feature_count, 415 VdpVideoMixerFeature const *features, 416 VdpBool const *feature_enables) 417{ 418 vlVdpVideoMixer *vmixer; 419 unsigned i; 420 421 if (!(features && feature_enables)) 422 return VDP_STATUS_INVALID_POINTER; 423 424 vmixer = vlGetDataHTAB(mixer); 425 if (!vmixer) 426 return VDP_STATUS_INVALID_HANDLE; 427 428 for (i = 0; i < feature_count; ++i) { 429 switch (features[i]) { 430 /* they are valid, but we doesn't support them */ 431 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 432 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 433 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 434 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 435 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 436 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 437 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 438 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 439 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 440 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 441 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 442 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 443 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 444 break; 445 446 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 447 vmixer->sharpness.enabled = feature_enables[i]; 448 vlVdpVideoMixerUpdateSharpnessFilter(vmixer); 449 break; 450 451 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 452 vmixer->noise_reduction.enabled = feature_enables[i]; 453 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer); 454 break; 455 456 default: 457 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 458 } 459 } 460 461 return VDP_STATUS_OK; 462} 463 464/** 465 * Retrieve whether features are enabled. 466 */ 467VdpStatus 468vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer, 469 uint32_t feature_count, 470 VdpVideoMixerFeature const *features, 471 VdpBool *feature_enables) 472{ 473 vlVdpVideoMixer *vmixer; 474 unsigned i; 475 476 if (!(features && feature_enables)) 477 return VDP_STATUS_INVALID_POINTER; 478 479 vmixer = vlGetDataHTAB(mixer); 480 if (!vmixer) 481 return VDP_STATUS_INVALID_HANDLE; 482 483 for (i = 0; i < feature_count; ++i) { 484 switch (features[i]) { 485 /* they are valid, but we doesn't support them */ 486 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL: 487 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL: 488 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1: 489 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2: 490 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3: 491 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4: 492 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5: 493 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6: 494 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7: 495 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8: 496 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9: 497 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE: 498 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY: 499 break; 500 501 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS: 502 feature_enables[i] = vmixer->sharpness.enabled; 503 break; 504 505 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION: 506 feature_enables[i] = vmixer->noise_reduction.enabled; 507 break; 508 509 default: 510 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE; 511 } 512 } 513 514 return VDP_STATUS_OK; 515} 516 517/** 518 * Set attribute values. 519 */ 520VdpStatus 521vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer, 522 uint32_t attribute_count, 523 VdpVideoMixerAttribute const *attributes, 524 void const *const *attribute_values) 525{ 526 const VdpColor *background_color; 527 union pipe_color_union color; 528 const float *vdp_csc; 529 float val; 530 unsigned i; 531 532 if (!(attributes && attribute_values)) 533 return VDP_STATUS_INVALID_POINTER; 534 535 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 536 if (!vmixer) 537 return VDP_STATUS_INVALID_HANDLE; 538 539 for (i = 0; i < attribute_count; ++i) { 540 switch (attributes[i]) { 541 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR: 542 background_color = attribute_values[i]; 543 color.f[0] = background_color->red; 544 color.f[1] = background_color->green; 545 color.f[2] = background_color->blue; 546 color.f[3] = background_color->alpha; 547 vl_compositor_set_clear_color(&vmixer->compositor, &color); 548 break; 549 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX: 550 vdp_csc = attribute_values[i]; 551 vmixer->custom_csc = !!vdp_csc; 552 if (!vdp_csc) 553 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, vmixer->csc); 554 else 555 memcpy(vmixer->csc, vdp_csc, sizeof(float)*12); 556 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) 557 vl_compositor_set_csc_matrix(&vmixer->compositor, vmixer->csc); 558 break; 559 560 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL: 561 562 val = *(float*)attribute_values[i]; 563 if (val < 0.f || val > 1.f) 564 return VDP_STATUS_INVALID_VALUE; 565 566 vmixer->noise_reduction.level = val * 10; 567 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer); 568 break; 569 570 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA: 571 val = *(float*)attribute_values[i]; 572 if (val < 0.f || val > 1.f) 573 return VDP_STATUS_INVALID_VALUE; 574 vmixer->luma_key_min = val; 575 break; 576 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA: 577 val = *(float*)attribute_values[i]; 578 if (val < 0.f || val > 1.f) 579 return VDP_STATUS_INVALID_VALUE; 580 vmixer->luma_key_max = val; 581 break; 582 583 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL: 584 585 val = *(float*)attribute_values[i]; 586 if (val < -1.f || val > 1.f) 587 return VDP_STATUS_INVALID_VALUE; 588 589 vmixer->sharpness.value = val; 590 vlVdpVideoMixerUpdateSharpnessFilter(vmixer); 591 break; 592 593 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE: 594 if (*(uint8_t*)attribute_values[i] > 1) 595 return VDP_STATUS_INVALID_VALUE; 596 vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i]; 597 break; 598 default: 599 return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE; 600 } 601 } 602 603 return VDP_STATUS_OK; 604} 605 606/** 607 * Retrieve parameter values given at creation time. 608 */ 609VdpStatus 610vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer, 611 uint32_t parameter_count, 612 VdpVideoMixerParameter const *parameters, 613 void *const *parameter_values) 614{ 615 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 616 unsigned i; 617 if (!vmixer) 618 return VDP_STATUS_INVALID_HANDLE; 619 620 if (!parameter_count) 621 return VDP_STATUS_OK; 622 if (!(parameters && parameter_values)) 623 return VDP_STATUS_INVALID_POINTER; 624 for (i = 0; i < parameter_count; ++i) { 625 switch (parameters[i]) { 626 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH: 627 *(uint32_t*)parameter_values[i] = vmixer->video_width; 628 break; 629 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT: 630 *(uint32_t*)parameter_values[i] = vmixer->video_height; 631 break; 632 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE: 633 *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format); 634 break; 635 case VDP_VIDEO_MIXER_PARAMETER_LAYERS: 636 *(uint32_t*)parameter_values[i] = vmixer->max_layers; 637 break; 638 default: 639 return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER; 640 } 641 } 642 return VDP_STATUS_OK; 643} 644 645/** 646 * Retrieve current attribute values. 647 */ 648VdpStatus 649vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer, 650 uint32_t attribute_count, 651 VdpVideoMixerAttribute const *attributes, 652 void *const *attribute_values) 653{ 654 unsigned i; 655 VdpCSCMatrix **vdp_csc; 656 657 if (!(attributes && attribute_values)) 658 return VDP_STATUS_INVALID_POINTER; 659 660 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer); 661 if (!vmixer) 662 return VDP_STATUS_INVALID_HANDLE; 663 664 for (i = 0; i < attribute_count; ++i) { 665 switch (attributes[i]) { 666 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR: 667 vl_compositor_get_clear_color(&vmixer->compositor, attribute_values[i]); 668 break; 669 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX: 670 vdp_csc = attribute_values[i]; 671 if (!vmixer->custom_csc) { 672 *vdp_csc = NULL; 673 break; 674 } 675 memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12); 676 break; 677 678 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL: 679 *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f; 680 break; 681 682 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA: 683 *(float*)attribute_values[i] = vmixer->luma_key_min; 684 break; 685 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA: 686 *(float*)attribute_values[i] = vmixer->luma_key_max; 687 break; 688 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL: 689 *(float*)attribute_values[i] = vmixer->sharpness.value; 690 break; 691 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE: 692 *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint; 693 break; 694 default: 695 return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE; 696 } 697 } 698 return VDP_STATUS_OK; 699} 700 701/** 702 * Generate a color space conversion matrix. 703 */ 704VdpStatus 705vlVdpGenerateCSCMatrix(VdpProcamp *procamp, 706 VdpColorStandard standard, 707 VdpCSCMatrix *csc_matrix) 708{ 709 float matrix[16]; 710 enum VL_CSC_COLOR_STANDARD vl_std; 711 struct vl_procamp camp; 712 713 if (!(csc_matrix && procamp)) 714 return VDP_STATUS_INVALID_POINTER; 715 716 if (procamp->struct_version > VDP_PROCAMP_VERSION) 717 return VDP_STATUS_INVALID_STRUCT_VERSION; 718 719 switch (standard) { 720 case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break; 721 case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break; 722 case VDP_COLOR_STANDARD_SMPTE_240M: vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break; 723 default: return VDP_STATUS_INVALID_COLOR_STANDARD; 724 } 725 camp.brightness = procamp->brightness; 726 camp.contrast = procamp->contrast; 727 camp.saturation = procamp->saturation; 728 camp.hue = procamp->hue; 729 vl_csc_get_matrix(vl_std, &camp, 1, matrix); 730 memcpy(csc_matrix, matrix, sizeof(float)*12); 731 return VDP_STATUS_OK; 732} 733