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