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