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