vl: add support for bob deinterlacing
[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 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->pipe);
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
149 no_params:
150 vlRemoveDataHTAB(*mixer);
151 no_handle:
152 vl_compositor_cleanup(&vmixer->compositor);
153 FREE(vmixer);
154 return ret;
155 }
156
157 /**
158 * Destroy a VdpVideoMixer.
159 */
160 VdpStatus
161 vlVdpVideoMixerDestroy(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 */
190 VdpStatus 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 */
288 static void
289 vlVdpVideoMixerUpdateNoiseReductionFilter(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,
304 vmixer->device->context->pipe,
305 vmixer->video_width, vmixer->video_height,
306 vmixer->noise_reduction.level + 1,
307 VL_MEDIAN_FILTER_CROSS);
308 }
309 }
310
311 static void
312 vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer)
313 {
314 assert(vmixer);
315
316 /* if present remove the old filter first */
317 if (vmixer->sharpness.filter) {
318 vl_matrix_filter_cleanup(vmixer->sharpness.filter);
319 FREE(vmixer->sharpness.filter);
320 vmixer->sharpness.filter = NULL;
321 }
322
323 /* and create a new filter as needed */
324 if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) {
325 float matrix[9];
326 unsigned i;
327
328 if (vmixer->sharpness.value > 0.0f) {
329 matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f;
330 matrix[3] = -1.0f; matrix[4] = 8.0f; matrix[5] = -1.0f;
331 matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f;
332
333 for (i = 0; i < 9; ++i)
334 matrix[i] *= vmixer->sharpness.value;
335
336 matrix[4] += 1.0f;
337
338 } else {
339 matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f;
340 matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f;
341 matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f;
342
343 for (i = 0; i < 9; ++i)
344 matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f;
345
346 matrix[4] += 1.0f - fabsf(vmixer->sharpness.value);
347 }
348
349 vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter));
350 vl_matrix_filter_init(vmixer->sharpness.filter,
351 vmixer->device->context->pipe,
352 vmixer->video_width, vmixer->video_height,
353 3, 3, matrix);
354 }
355 }
356
357 /**
358 * Retrieve whether features were requested at creation time.
359 */
360 VdpStatus
361 vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,
362 uint32_t feature_count,
363 VdpVideoMixerFeature const *features,
364 VdpBool *feature_supports)
365 {
366 vlVdpVideoMixer *vmixer;
367 unsigned i;
368
369 if (!(features && feature_supports))
370 return VDP_STATUS_INVALID_POINTER;
371
372 vmixer = vlGetDataHTAB(mixer);
373 if (!vmixer)
374 return VDP_STATUS_INVALID_HANDLE;
375
376 for (i = 0; i < feature_count; ++i) {
377 switch (features[i]) {
378 /* they are valid, but we doesn't support them */
379 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
380 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
381 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
382 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
383 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
384 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
385 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
386 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
387 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
388 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
389 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
390 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
391 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
392 feature_supports[i] = false;
393 break;
394
395 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
396 feature_supports[i] = vmixer->sharpness.supported;
397 break;
398
399 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
400 feature_supports[i] = vmixer->noise_reduction.supported;
401 break;
402
403 default:
404 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
405 }
406 }
407
408 return VDP_STATUS_OK;
409 }
410
411 /**
412 * Enable or disable features.
413 */
414 VdpStatus
415 vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,
416 uint32_t feature_count,
417 VdpVideoMixerFeature const *features,
418 VdpBool const *feature_enables)
419 {
420 vlVdpVideoMixer *vmixer;
421 unsigned i;
422
423 if (!(features && feature_enables))
424 return VDP_STATUS_INVALID_POINTER;
425
426 vmixer = vlGetDataHTAB(mixer);
427 if (!vmixer)
428 return VDP_STATUS_INVALID_HANDLE;
429
430 for (i = 0; i < feature_count; ++i) {
431 switch (features[i]) {
432 /* they are valid, but we doesn't support them */
433 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
434 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
435 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
436 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
437 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
438 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
439 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
440 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
441 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
442 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
443 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
444 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
445 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
446 break;
447
448 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
449 vmixer->sharpness.enabled = feature_enables[i];
450 vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
451 break;
452
453 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
454 vmixer->noise_reduction.enabled = feature_enables[i];
455 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
456 break;
457
458 default:
459 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
460 }
461 }
462
463 return VDP_STATUS_OK;
464 }
465
466 /**
467 * Retrieve whether features are enabled.
468 */
469 VdpStatus
470 vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,
471 uint32_t feature_count,
472 VdpVideoMixerFeature const *features,
473 VdpBool *feature_enables)
474 {
475 vlVdpVideoMixer *vmixer;
476 unsigned i;
477
478 if (!(features && feature_enables))
479 return VDP_STATUS_INVALID_POINTER;
480
481 vmixer = vlGetDataHTAB(mixer);
482 if (!vmixer)
483 return VDP_STATUS_INVALID_HANDLE;
484
485 for (i = 0; i < feature_count; ++i) {
486 switch (features[i]) {
487 /* they are valid, but we doesn't support them */
488 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
489 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
490 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
491 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
492 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
493 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
494 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
495 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
496 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
497 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
498 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
499 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
500 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
501 break;
502
503 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
504 feature_enables[i] = vmixer->sharpness.enabled;
505 break;
506
507 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
508 feature_enables[i] = vmixer->noise_reduction.enabled;
509 break;
510
511 default:
512 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
513 }
514 }
515
516 return VDP_STATUS_OK;
517 }
518
519 /**
520 * Set attribute values.
521 */
522 VdpStatus
523 vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer,
524 uint32_t attribute_count,
525 VdpVideoMixerAttribute const *attributes,
526 void const *const *attribute_values)
527 {
528 const VdpColor *background_color;
529 union pipe_color_union color;
530 const float *vdp_csc;
531 float val;
532 unsigned i;
533
534 if (!(attributes && attribute_values))
535 return VDP_STATUS_INVALID_POINTER;
536
537 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
538 if (!vmixer)
539 return VDP_STATUS_INVALID_HANDLE;
540
541 for (i = 0; i < attribute_count; ++i) {
542 switch (attributes[i]) {
543 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
544 background_color = attribute_values[i];
545 color.f[0] = background_color->red;
546 color.f[1] = background_color->green;
547 color.f[2] = background_color->blue;
548 color.f[3] = background_color->alpha;
549 vl_compositor_set_clear_color(&vmixer->compositor, &color);
550 break;
551 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
552 vdp_csc = attribute_values[i];
553 vmixer->custom_csc = !!vdp_csc;
554 if (!vdp_csc)
555 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, vmixer->csc);
556 else
557 memcpy(vmixer->csc, vdp_csc, sizeof(float)*12);
558 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
559 vl_compositor_set_csc_matrix(&vmixer->compositor, vmixer->csc);
560 break;
561
562 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
563
564 val = *(float*)attribute_values[i];
565 if (val < 0.f || val > 1.f)
566 return VDP_STATUS_INVALID_VALUE;
567
568 vmixer->noise_reduction.level = val * 10;
569 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
570 break;
571
572 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
573 val = *(float*)attribute_values[i];
574 if (val < 0.f || val > 1.f)
575 return VDP_STATUS_INVALID_VALUE;
576 vmixer->luma_key_min = val;
577 break;
578 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
579 val = *(float*)attribute_values[i];
580 if (val < 0.f || val > 1.f)
581 return VDP_STATUS_INVALID_VALUE;
582 vmixer->luma_key_max = val;
583 break;
584
585 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
586
587 val = *(float*)attribute_values[i];
588 if (val < -1.f || val > 1.f)
589 return VDP_STATUS_INVALID_VALUE;
590
591 vmixer->sharpness.value = val;
592 vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
593 break;
594
595 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
596 if (*(uint8_t*)attribute_values[i] > 1)
597 return VDP_STATUS_INVALID_VALUE;
598 vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i];
599 break;
600 default:
601 return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
602 }
603 }
604
605 return VDP_STATUS_OK;
606 }
607
608 /**
609 * Retrieve parameter values given at creation time.
610 */
611 VdpStatus
612 vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer,
613 uint32_t parameter_count,
614 VdpVideoMixerParameter const *parameters,
615 void *const *parameter_values)
616 {
617 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
618 unsigned i;
619 if (!vmixer)
620 return VDP_STATUS_INVALID_HANDLE;
621
622 if (!parameter_count)
623 return VDP_STATUS_OK;
624 if (!(parameters && parameter_values))
625 return VDP_STATUS_INVALID_POINTER;
626 for (i = 0; i < parameter_count; ++i) {
627 switch (parameters[i]) {
628 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
629 *(uint32_t*)parameter_values[i] = vmixer->video_width;
630 break;
631 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
632 *(uint32_t*)parameter_values[i] = vmixer->video_height;
633 break;
634 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
635 *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format);
636 break;
637 case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
638 *(uint32_t*)parameter_values[i] = vmixer->max_layers;
639 break;
640 default:
641 return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
642 }
643 }
644 return VDP_STATUS_OK;
645 }
646
647 /**
648 * Retrieve current attribute values.
649 */
650 VdpStatus
651 vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer,
652 uint32_t attribute_count,
653 VdpVideoMixerAttribute const *attributes,
654 void *const *attribute_values)
655 {
656 unsigned i;
657 VdpCSCMatrix **vdp_csc;
658
659 if (!(attributes && attribute_values))
660 return VDP_STATUS_INVALID_POINTER;
661
662 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
663 if (!vmixer)
664 return VDP_STATUS_INVALID_HANDLE;
665
666 for (i = 0; i < attribute_count; ++i) {
667 switch (attributes[i]) {
668 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
669 vl_compositor_get_clear_color(&vmixer->compositor, attribute_values[i]);
670 break;
671 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
672 vdp_csc = attribute_values[i];
673 if (!vmixer->custom_csc) {
674 *vdp_csc = NULL;
675 break;
676 }
677 memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12);
678 break;
679
680 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
681 *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f;
682 break;
683
684 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
685 *(float*)attribute_values[i] = vmixer->luma_key_min;
686 break;
687 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
688 *(float*)attribute_values[i] = vmixer->luma_key_max;
689 break;
690 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
691 *(float*)attribute_values[i] = vmixer->sharpness.value;
692 break;
693 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
694 *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint;
695 break;
696 default:
697 return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
698 }
699 }
700 return VDP_STATUS_OK;
701 }
702
703 /**
704 * Generate a color space conversion matrix.
705 */
706 VdpStatus
707 vlVdpGenerateCSCMatrix(VdpProcamp *procamp,
708 VdpColorStandard standard,
709 VdpCSCMatrix *csc_matrix)
710 {
711 float matrix[16];
712 enum VL_CSC_COLOR_STANDARD vl_std;
713 struct vl_procamp camp;
714
715 if (!(csc_matrix && procamp))
716 return VDP_STATUS_INVALID_POINTER;
717
718 if (procamp->struct_version > VDP_PROCAMP_VERSION)
719 return VDP_STATUS_INVALID_STRUCT_VERSION;
720
721 switch (standard) {
722 case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break;
723 case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break;
724 case VDP_COLOR_STANDARD_SMPTE_240M: vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break;
725 default: return VDP_STATUS_INVALID_COLOR_STANDARD;
726 }
727 camp.brightness = procamp->brightness;
728 camp.contrast = procamp->contrast;
729 camp.saturation = procamp->saturation;
730 camp.hue = procamp->hue;
731 vl_csc_get_matrix(vl_std, &camp, 1, matrix);
732 memcpy(csc_matrix, matrix, sizeof(float)*12);
733 return VDP_STATUS_OK;
734 }