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