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