1 /**************************************************************************
3 * Copyright 2010 Thomas Balling Sørensen.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
28 #include <vdpau/vdpau.h>
30 #include "util/u_memory.h"
31 #include "util/u_debug.h"
33 #include "vl/vl_csc.h"
35 #include "vdpau_private.h"
38 * Create a VdpVideoMixer.
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
,
49 vlVdpVideoMixer
*vmixer
= NULL
;
51 struct pipe_screen
*screen
;
52 uint32_t max_2d_texture_level
;
55 vlVdpDevice
*dev
= vlGetDataHTAB(device
);
57 return VDP_STATUS_INVALID_HANDLE
;
58 screen
= dev
->vscreen
->pscreen
;
60 vmixer
= CALLOC(1, sizeof(vlVdpVideoMixer
));
62 return VDP_STATUS_RESOURCES
;
64 DeviceReference(&vmixer
->device
, dev
);
66 pipe_mutex_lock(dev
->mutex
);
68 if (!vl_compositor_init_state(&vmixer
->cstate
, dev
->context
)) {
69 ret
= VDP_STATUS_ERROR
;
70 goto no_compositor_state
;
73 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601
, NULL
, true, &vmixer
->csc
);
74 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE
)) {
75 if (!vl_compositor_set_csc_matrix(&vmixer
->cstate
, (const vl_csc_matrix
*)&vmixer
->csc
, 1.0f
, 0.0f
)) {
76 ret
= VDP_STATUS_ERROR
;
81 *mixer
= vlAddDataHTAB(vmixer
);
83 ret
= VDP_STATUS_ERROR
;
87 ret
= VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE
;
88 for (i
= 0; i
< feature_count
; ++i
) {
89 switch (features
[i
]) {
90 /* they are valid, but we doesn't support them */
91 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
:
92 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2
:
93 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3
:
94 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4
:
95 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5
:
96 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6
:
97 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7
:
98 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8
:
99 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9
:
100 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
:
103 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
104 vmixer
->deint
.supported
= true;
107 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS
:
108 vmixer
->sharpness
.supported
= true;
111 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
:
112 vmixer
->noise_reduction
.supported
= true;
115 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY
:
116 vmixer
->luma_key
.supported
= true;
119 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
:
120 vmixer
->bicubic
.supported
= true;
122 default: goto no_params
;
126 vmixer
->chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
127 ret
= VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER
;
128 for (i
= 0; i
< parameter_count
; ++i
) {
129 switch (parameters
[i
]) {
130 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
:
131 vmixer
->video_width
= *(uint32_t*)parameter_values
[i
];
133 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
:
134 vmixer
->video_height
= *(uint32_t*)parameter_values
[i
];
136 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
:
137 vmixer
->chroma_format
= ChromaToPipe(*(VdpChromaType
*)parameter_values
[i
]);
139 case VDP_VIDEO_MIXER_PARAMETER_LAYERS
:
140 vmixer
->max_layers
= *(uint32_t*)parameter_values
[i
];
142 default: goto no_params
;
145 ret
= VDP_STATUS_INVALID_VALUE
;
146 if (vmixer
->max_layers
> 4) {
147 VDPAU_MSG(VDPAU_WARN
, "[VDPAU] Max layers > 4 not supported\n", vmixer
->max_layers
);
151 max_2d_texture_level
= screen
->get_param(screen
, PIPE_CAP_MAX_TEXTURE_2D_LEVELS
);
152 max_size
= pow(2, max_2d_texture_level
-1);
153 if (vmixer
->video_width
< 48 || vmixer
->video_width
> max_size
) {
154 VDPAU_MSG(VDPAU_WARN
, "[VDPAU] 48 < %u < %u not valid for width\n",
155 vmixer
->video_width
, max_size
);
158 if (vmixer
->video_height
< 48 || vmixer
->video_height
> max_size
) {
159 VDPAU_MSG(VDPAU_WARN
, "[VDPAU] 48 < %u < %u not valid for height\n",
160 vmixer
->video_height
, max_size
);
163 vmixer
->luma_key
.luma_min
= 1.0f
;
164 vmixer
->luma_key
.luma_max
= 0.0f
;
165 pipe_mutex_unlock(dev
->mutex
);
167 return VDP_STATUS_OK
;
170 vlRemoveDataHTAB(*mixer
);
174 vl_compositor_cleanup_state(&vmixer
->cstate
);
176 pipe_mutex_unlock(dev
->mutex
);
177 DeviceReference(&vmixer
->device
, NULL
);
183 * Destroy a VdpVideoMixer.
186 vlVdpVideoMixerDestroy(VdpVideoMixer mixer
)
188 vlVdpVideoMixer
*vmixer
;
190 vmixer
= vlGetDataHTAB(mixer
);
192 return VDP_STATUS_INVALID_HANDLE
;
194 pipe_mutex_lock(vmixer
->device
->mutex
);
196 vlRemoveDataHTAB(mixer
);
198 vl_compositor_cleanup_state(&vmixer
->cstate
);
200 if (vmixer
->deint
.filter
) {
201 vl_deint_filter_cleanup(vmixer
->deint
.filter
);
202 FREE(vmixer
->deint
.filter
);
205 if (vmixer
->noise_reduction
.filter
) {
206 vl_median_filter_cleanup(vmixer
->noise_reduction
.filter
);
207 FREE(vmixer
->noise_reduction
.filter
);
210 if (vmixer
->sharpness
.filter
) {
211 vl_matrix_filter_cleanup(vmixer
->sharpness
.filter
);
212 FREE(vmixer
->sharpness
.filter
);
215 if (vmixer
->bicubic
.filter
) {
216 vl_bicubic_filter_cleanup(vmixer
->bicubic
.filter
);
217 FREE(vmixer
->bicubic
.filter
);
219 pipe_mutex_unlock(vmixer
->device
->mutex
);
220 DeviceReference(&vmixer
->device
, NULL
);
224 return VDP_STATUS_OK
;
228 * Perform a video post-processing and compositing operation.
230 VdpStatus
vlVdpVideoMixerRender(VdpVideoMixer mixer
,
231 VdpOutputSurface background_surface
,
232 VdpRect
const *background_source_rect
,
233 VdpVideoMixerPictureStructure current_picture_structure
,
234 uint32_t video_surface_past_count
,
235 VdpVideoSurface
const *video_surface_past
,
236 VdpVideoSurface video_surface_current
,
237 uint32_t video_surface_future_count
,
238 VdpVideoSurface
const *video_surface_future
,
239 VdpRect
const *video_source_rect
,
240 VdpOutputSurface destination_surface
,
241 VdpRect
const *destination_rect
,
242 VdpRect
const *destination_video_rect
,
243 uint32_t layer_count
,
244 VdpLayer
const *layers
)
246 enum vl_compositor_deinterlace deinterlace
;
247 struct u_rect rect
, clip
, *prect
, dirty_area
;
248 unsigned i
, layer
= 0;
249 struct pipe_video_buffer
*video_buffer
;
250 struct pipe_sampler_view
*sampler_view
, sv_templ
;
251 struct pipe_surface
*surface
, surf_templ
;
252 struct pipe_context
*pipe
= NULL
;
253 struct pipe_resource res_tmpl
, *res
;
255 vlVdpVideoMixer
*vmixer
;
257 vlVdpOutputSurface
*dst
, *bg
= NULL
;
259 struct vl_compositor
*compositor
;
261 vmixer
= vlGetDataHTAB(mixer
);
263 return VDP_STATUS_INVALID_HANDLE
;
265 compositor
= &vmixer
->device
->compositor
;
267 surf
= vlGetDataHTAB(video_surface_current
);
269 return VDP_STATUS_INVALID_HANDLE
;
270 video_buffer
= surf
->video_buffer
;
272 if (surf
->device
!= vmixer
->device
)
273 return VDP_STATUS_HANDLE_DEVICE_MISMATCH
;
275 if (vmixer
->video_width
> video_buffer
->width
||
276 vmixer
->video_height
> video_buffer
->height
||
277 vmixer
->chroma_format
!= video_buffer
->chroma_format
)
278 return VDP_STATUS_INVALID_SIZE
;
280 if (layer_count
> vmixer
->max_layers
)
281 return VDP_STATUS_INVALID_VALUE
;
283 dst
= vlGetDataHTAB(destination_surface
);
285 return VDP_STATUS_INVALID_HANDLE
;
287 if (background_surface
!= VDP_INVALID_HANDLE
) {
288 bg
= vlGetDataHTAB(background_surface
);
290 return VDP_STATUS_INVALID_HANDLE
;
293 pipe_mutex_lock(vmixer
->device
->mutex
);
295 vl_compositor_clear_layers(&vmixer
->cstate
);
298 vl_compositor_set_rgba_layer(&vmixer
->cstate
, compositor
, layer
++, bg
->sampler_view
,
299 RectToPipe(background_source_rect
, &rect
), NULL
, NULL
);
301 switch (current_picture_structure
) {
302 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD
:
303 deinterlace
= VL_COMPOSITOR_BOB_TOP
;
306 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD
:
307 deinterlace
= VL_COMPOSITOR_BOB_BOTTOM
;
310 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME
:
311 deinterlace
= VL_COMPOSITOR_WEAVE
;
315 pipe_mutex_unlock(vmixer
->device
->mutex
);
316 return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE
;
319 if (deinterlace
!= VL_COMPOSITOR_WEAVE
&& vmixer
->deint
.enabled
&&
320 video_surface_past_count
> 1 && video_surface_future_count
> 0) {
321 vlVdpSurface
*prevprev
= vlGetDataHTAB(video_surface_past
[1]);
322 vlVdpSurface
*prev
= vlGetDataHTAB(video_surface_past
[0]);
323 vlVdpSurface
*next
= vlGetDataHTAB(video_surface_future
[0]);
324 if (prevprev
&& prev
&& next
&&
325 vl_deint_filter_check_buffers(vmixer
->deint
.filter
,
326 prevprev
->video_buffer
, prev
->video_buffer
, surf
->video_buffer
, next
->video_buffer
)) {
327 vl_deint_filter_render(vmixer
->deint
.filter
, prevprev
->video_buffer
,
328 prev
->video_buffer
, surf
->video_buffer
,
330 deinterlace
== VL_COMPOSITOR_BOB_BOTTOM
);
331 deinterlace
= VL_COMPOSITOR_WEAVE
;
332 video_buffer
= vmixer
->deint
.filter
->video_buffer
;
336 prect
= RectToPipe(video_source_rect
, &rect
);
340 rect
.x1
= surf
->templat
.width
;
341 rect
.y1
= surf
->templat
.height
;
344 vl_compositor_set_buffer_layer(&vmixer
->cstate
, compositor
, layer
, video_buffer
, prect
, NULL
, deinterlace
);
346 if (vmixer
->bicubic
.filter
|| vmixer
->sharpness
.filter
|| vmixer
->noise_reduction
.filter
) {
347 pipe
= vmixer
->device
->context
;
348 memset(&res_tmpl
, 0, sizeof(res_tmpl
));
350 res_tmpl
.target
= PIPE_TEXTURE_2D
;
351 res_tmpl
.format
= dst
->sampler_view
->format
;
353 res_tmpl
.array_size
= 1;
354 res_tmpl
.bind
= PIPE_BIND_SAMPLER_VIEW
| PIPE_BIND_RENDER_TARGET
;
355 res_tmpl
.usage
= PIPE_USAGE_DEFAULT
;
357 if (!vmixer
->bicubic
.filter
) {
358 res_tmpl
.width0
= dst
->surface
->width
;
359 res_tmpl
.height0
= dst
->surface
->height
;
361 res_tmpl
.width0
= surf
->templat
.width
;
362 res_tmpl
.height0
= surf
->templat
.height
;
365 res
= pipe
->screen
->resource_create(pipe
->screen
, &res_tmpl
);
367 vlVdpDefaultSamplerViewTemplate(&sv_templ
, res
);
368 sampler_view
= pipe
->create_sampler_view(pipe
, res
, &sv_templ
);
370 memset(&surf_templ
, 0, sizeof(surf_templ
));
371 surf_templ
.format
= res
->format
;
372 surface
= pipe
->create_surface(pipe
, res
, &surf_templ
);
374 vl_compositor_reset_dirty_area(&dirty_area
);
375 pipe_resource_reference(&res
, NULL
);
377 surface
= dst
->surface
;
378 sampler_view
= dst
->sampler_view
;
379 dirty_area
= dst
->dirty_area
;
382 if (!vmixer
->bicubic
.filter
) {
383 vl_compositor_set_layer_dst_area(&vmixer
->cstate
, layer
++, RectToPipe(destination_video_rect
, &rect
));
384 vl_compositor_set_dst_clip(&vmixer
->cstate
, RectToPipe(destination_rect
, &clip
));
387 for (i
= 0; i
< layer_count
; ++i
) {
388 vlVdpOutputSurface
*src
= vlGetDataHTAB(layers
->source_surface
);
390 pipe_mutex_unlock(vmixer
->device
->mutex
);
391 return VDP_STATUS_INVALID_HANDLE
;
394 assert(layers
->struct_version
== VDP_LAYER_VERSION
);
396 vl_compositor_set_rgba_layer(&vmixer
->cstate
, compositor
, layer
, src
->sampler_view
,
397 RectToPipe(layers
->source_rect
, &rect
), NULL
, NULL
);
398 vl_compositor_set_layer_dst_area(&vmixer
->cstate
, layer
++, RectToPipe(layers
->destination_rect
, &rect
));
403 vl_compositor_render(&vmixer
->cstate
, compositor
, surface
, &dirty_area
, true);
405 if (vmixer
->noise_reduction
.filter
) {
406 if (!vmixer
->sharpness
.filter
&& !vmixer
->bicubic
.filter
) {
407 vl_median_filter_render(vmixer
->noise_reduction
.filter
,
408 sampler_view
, dst
->surface
);
410 res
= pipe
->screen
->resource_create(pipe
->screen
, &res_tmpl
);
411 struct pipe_sampler_view
*sampler_view_temp
= pipe
->create_sampler_view(pipe
, res
, &sv_templ
);
412 struct pipe_surface
*surface_temp
= pipe
->create_surface(pipe
, res
, &surf_templ
);
413 pipe_resource_reference(&res
, NULL
);
415 vl_median_filter_render(vmixer
->noise_reduction
.filter
,
416 sampler_view
, surface_temp
);
418 pipe_sampler_view_reference(&sampler_view
, NULL
);
419 pipe_surface_reference(&surface
, NULL
);
421 sampler_view
= sampler_view_temp
;
422 surface
= surface_temp
;
426 if (vmixer
->sharpness
.filter
) {
427 if (!vmixer
->bicubic
.filter
) {
428 vl_matrix_filter_render(vmixer
->sharpness
.filter
,
429 sampler_view
, dst
->surface
);
431 res
= pipe
->screen
->resource_create(pipe
->screen
, &res_tmpl
);
432 struct pipe_sampler_view
*sampler_view_temp
= pipe
->create_sampler_view(pipe
, res
, &sv_templ
);
433 struct pipe_surface
*surface_temp
= pipe
->create_surface(pipe
, res
, &surf_templ
);
434 pipe_resource_reference(&res
, NULL
);
436 vl_matrix_filter_render(vmixer
->sharpness
.filter
,
437 sampler_view
, surface_temp
);
439 pipe_sampler_view_reference(&sampler_view
, NULL
);
440 pipe_surface_reference(&surface
, NULL
);
442 sampler_view
= sampler_view_temp
;
443 surface
= surface_temp
;
447 if (vmixer
->bicubic
.filter
)
448 vl_bicubic_filter_render(vmixer
->bicubic
.filter
,
449 sampler_view
, dst
->surface
,
450 RectToPipe(destination_video_rect
, &rect
),
451 RectToPipe(destination_rect
, &clip
));
453 if(surface
!= dst
->surface
) {
454 pipe_sampler_view_reference(&sampler_view
, NULL
);
455 pipe_surface_reference(&surface
, NULL
);
457 pipe_mutex_unlock(vmixer
->device
->mutex
);
459 return VDP_STATUS_OK
;
463 vlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer
*vmixer
)
465 struct pipe_context
*pipe
= vmixer
->device
->context
;
468 /* remove existing filter */
469 if (vmixer
->deint
.filter
) {
470 vl_deint_filter_cleanup(vmixer
->deint
.filter
);
471 FREE(vmixer
->deint
.filter
);
472 vmixer
->deint
.filter
= NULL
;
475 /* create a new filter if requested */
476 if (vmixer
->deint
.enabled
&& vmixer
->chroma_format
== PIPE_VIDEO_CHROMA_FORMAT_420
) {
477 vmixer
->deint
.filter
= MALLOC(sizeof(struct vl_deint_filter
));
478 vmixer
->deint
.enabled
= vl_deint_filter_init(vmixer
->deint
.filter
, pipe
,
479 vmixer
->video_width
, vmixer
->video_height
,
480 vmixer
->skip_chroma_deint
, vmixer
->deint
.spatial
);
481 if (!vmixer
->deint
.enabled
) {
482 FREE(vmixer
->deint
.filter
);
488 * Update the noise reduction setting
491 vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer
*vmixer
)
495 /* if present remove the old filter first */
496 if (vmixer
->noise_reduction
.filter
) {
497 vl_median_filter_cleanup(vmixer
->noise_reduction
.filter
);
498 FREE(vmixer
->noise_reduction
.filter
);
499 vmixer
->noise_reduction
.filter
= NULL
;
502 /* and create a new filter as needed */
503 if (vmixer
->noise_reduction
. enabled
&& vmixer
->noise_reduction
.level
> 0) {
504 vmixer
->noise_reduction
.filter
= MALLOC(sizeof(struct vl_median_filter
));
505 vl_median_filter_init(vmixer
->noise_reduction
.filter
, vmixer
->device
->context
,
506 vmixer
->video_width
, vmixer
->video_height
,
507 vmixer
->noise_reduction
.level
+ 1,
508 VL_MEDIAN_FILTER_CROSS
);
513 vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer
*vmixer
)
517 /* if present remove the old filter first */
518 if (vmixer
->sharpness
.filter
) {
519 vl_matrix_filter_cleanup(vmixer
->sharpness
.filter
);
520 FREE(vmixer
->sharpness
.filter
);
521 vmixer
->sharpness
.filter
= NULL
;
524 /* and create a new filter as needed */
525 if (vmixer
->sharpness
.enabled
&& vmixer
->sharpness
.value
!= 0.0f
) {
529 if (vmixer
->sharpness
.value
> 0.0f
) {
530 matrix
[0] = -1.0f
; matrix
[1] = -1.0f
; matrix
[2] = -1.0f
;
531 matrix
[3] = -1.0f
; matrix
[4] = 8.0f
; matrix
[5] = -1.0f
;
532 matrix
[6] = -1.0f
; matrix
[7] = -1.0f
; matrix
[8] = -1.0f
;
534 for (i
= 0; i
< 9; ++i
)
535 matrix
[i
] *= vmixer
->sharpness
.value
;
540 matrix
[0] = 1.0f
; matrix
[1] = 2.0f
; matrix
[2] = 1.0f
;
541 matrix
[3] = 2.0f
; matrix
[4] = 4.0f
; matrix
[5] = 2.0f
;
542 matrix
[6] = 1.0f
; matrix
[7] = 2.0f
; matrix
[8] = 1.0f
;
544 for (i
= 0; i
< 9; ++i
)
545 matrix
[i
] *= fabsf(vmixer
->sharpness
.value
) / 16.0f
;
547 matrix
[4] += 1.0f
- fabsf(vmixer
->sharpness
.value
);
550 vmixer
->sharpness
.filter
= MALLOC(sizeof(struct vl_matrix_filter
));
551 vl_matrix_filter_init(vmixer
->sharpness
.filter
, vmixer
->device
->context
,
552 vmixer
->video_width
, vmixer
->video_height
,
558 * Update the bicubic filter
561 vlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer
*vmixer
)
565 /* if present remove the old filter first */
566 if (vmixer
->bicubic
.filter
) {
567 vl_bicubic_filter_cleanup(vmixer
->bicubic
.filter
);
568 FREE(vmixer
->bicubic
.filter
);
569 vmixer
->bicubic
.filter
= NULL
;
571 /* and create a new filter as needed */
572 if (vmixer
->bicubic
.enabled
) {
573 vmixer
->bicubic
.filter
= MALLOC(sizeof(struct vl_bicubic_filter
));
574 vl_bicubic_filter_init(vmixer
->bicubic
.filter
, vmixer
->device
->context
,
575 vmixer
->video_width
, vmixer
->video_height
);
580 * Retrieve whether features were requested at creation time.
583 vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer
,
584 uint32_t feature_count
,
585 VdpVideoMixerFeature
const *features
,
586 VdpBool
*feature_supports
)
588 vlVdpVideoMixer
*vmixer
;
591 if (!(features
&& feature_supports
))
592 return VDP_STATUS_INVALID_POINTER
;
594 vmixer
= vlGetDataHTAB(mixer
);
596 return VDP_STATUS_INVALID_HANDLE
;
598 for (i
= 0; i
< feature_count
; ++i
) {
599 switch (features
[i
]) {
600 /* they are valid, but we doesn't support them */
601 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
:
602 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2
:
603 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3
:
604 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4
:
605 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5
:
606 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6
:
607 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7
:
608 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8
:
609 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9
:
610 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
:
611 feature_supports
[i
] = false;
614 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
615 feature_supports
[i
] = vmixer
->deint
.supported
;
618 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS
:
619 feature_supports
[i
] = vmixer
->sharpness
.supported
;
622 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
:
623 feature_supports
[i
] = vmixer
->noise_reduction
.supported
;
626 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY
:
627 feature_supports
[i
] = vmixer
->luma_key
.supported
;
630 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
:
631 feature_supports
[i
] = vmixer
->bicubic
.supported
;
635 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE
;
639 return VDP_STATUS_OK
;
643 * Enable or disable features.
646 vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer
,
647 uint32_t feature_count
,
648 VdpVideoMixerFeature
const *features
,
649 VdpBool
const *feature_enables
)
651 vlVdpVideoMixer
*vmixer
;
654 if (!(features
&& feature_enables
))
655 return VDP_STATUS_INVALID_POINTER
;
657 vmixer
= vlGetDataHTAB(mixer
);
659 return VDP_STATUS_INVALID_HANDLE
;
661 pipe_mutex_lock(vmixer
->device
->mutex
);
662 for (i
= 0; i
< feature_count
; ++i
) {
663 switch (features
[i
]) {
664 /* they are valid, but we doesn't support them */
665 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
:
666 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2
:
667 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3
:
668 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4
:
669 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5
:
670 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6
:
671 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7
:
672 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8
:
673 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9
:
674 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
:
677 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
678 vmixer
->deint
.enabled
= feature_enables
[i
];
679 vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer
);
682 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS
:
683 vmixer
->sharpness
.enabled
= feature_enables
[i
];
684 vlVdpVideoMixerUpdateSharpnessFilter(vmixer
);
687 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
:
688 vmixer
->noise_reduction
.enabled
= feature_enables
[i
];
689 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer
);
692 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY
:
693 vmixer
->luma_key
.enabled
= feature_enables
[i
];
694 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE
))
695 if (!vl_compositor_set_csc_matrix(&vmixer
->cstate
, (const vl_csc_matrix
*)&vmixer
->csc
,
696 vmixer
->luma_key
.luma_min
, vmixer
->luma_key
.luma_max
)) {
697 pipe_mutex_unlock(vmixer
->device
->mutex
);
698 return VDP_STATUS_ERROR
;
702 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
:
703 vmixer
->bicubic
.enabled
= feature_enables
[i
];
704 vlVdpVideoMixerUpdateBicubicFilter(vmixer
);
708 pipe_mutex_unlock(vmixer
->device
->mutex
);
709 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE
;
712 pipe_mutex_unlock(vmixer
->device
->mutex
);
714 return VDP_STATUS_OK
;
718 * Retrieve whether features are enabled.
721 vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer
,
722 uint32_t feature_count
,
723 VdpVideoMixerFeature
const *features
,
724 VdpBool
*feature_enables
)
726 vlVdpVideoMixer
*vmixer
;
729 if (!(features
&& feature_enables
))
730 return VDP_STATUS_INVALID_POINTER
;
732 vmixer
= vlGetDataHTAB(mixer
);
734 return VDP_STATUS_INVALID_HANDLE
;
736 for (i
= 0; i
< feature_count
; ++i
) {
737 switch (features
[i
]) {
738 /* they are valid, but we doesn't support them */
739 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
740 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
:
741 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2
:
742 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3
:
743 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4
:
744 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5
:
745 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6
:
746 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7
:
747 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8
:
748 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9
:
749 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
:
752 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS
:
753 feature_enables
[i
] = vmixer
->sharpness
.enabled
;
756 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
:
757 feature_enables
[i
] = vmixer
->noise_reduction
.enabled
;
760 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY
:
761 feature_enables
[i
] = vmixer
->luma_key
.enabled
;
764 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
:
765 feature_enables
[i
] = vmixer
->bicubic
.enabled
;
769 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE
;
773 return VDP_STATUS_OK
;
777 * Set attribute values.
780 vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer
,
781 uint32_t attribute_count
,
782 VdpVideoMixerAttribute
const *attributes
,
783 void const *const *attribute_values
)
785 const VdpColor
*background_color
;
786 union pipe_color_union color
;
787 const float *vdp_csc
;
792 if (!(attributes
&& attribute_values
))
793 return VDP_STATUS_INVALID_POINTER
;
795 vlVdpVideoMixer
*vmixer
= vlGetDataHTAB(mixer
);
797 return VDP_STATUS_INVALID_HANDLE
;
799 pipe_mutex_lock(vmixer
->device
->mutex
);
800 for (i
= 0; i
< attribute_count
; ++i
) {
801 switch (attributes
[i
]) {
802 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR
:
803 background_color
= attribute_values
[i
];
804 color
.f
[0] = background_color
->red
;
805 color
.f
[1] = background_color
->green
;
806 color
.f
[2] = background_color
->blue
;
807 color
.f
[3] = background_color
->alpha
;
808 vl_compositor_set_clear_color(&vmixer
->cstate
, &color
);
810 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX
:
811 vdp_csc
= attribute_values
[i
];
812 vmixer
->custom_csc
= !!vdp_csc
;
814 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601
, NULL
, 1, &vmixer
->csc
);
816 memcpy(vmixer
->csc
, vdp_csc
, sizeof(vl_csc_matrix
));
817 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE
))
818 if (!vl_compositor_set_csc_matrix(&vmixer
->cstate
, (const vl_csc_matrix
*)&vmixer
->csc
,
819 vmixer
->luma_key
.luma_min
, vmixer
->luma_key
.luma_max
)) {
820 ret
= VDP_STATUS_ERROR
;
825 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL
:
827 val
= *(float*)attribute_values
[i
];
828 if (val
< 0.0f
|| val
> 1.0f
) {
829 ret
= VDP_STATUS_INVALID_VALUE
;
833 vmixer
->noise_reduction
.level
= val
* 10;
834 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer
);
837 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA
:
838 val
= *(float*)attribute_values
[i
];
839 if (val
< 0.0f
|| val
> 1.0f
) {
840 ret
= VDP_STATUS_INVALID_VALUE
;
843 vmixer
->luma_key
.luma_min
= val
;
844 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE
))
845 if (!vl_compositor_set_csc_matrix(&vmixer
->cstate
, (const vl_csc_matrix
*)&vmixer
->csc
,
846 vmixer
->luma_key
.luma_min
, vmixer
->luma_key
.luma_max
)) {
847 ret
= VDP_STATUS_ERROR
;
852 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA
:
853 val
= *(float*)attribute_values
[i
];
854 if (val
< 0.0f
|| val
> 1.0f
) {
855 ret
= VDP_STATUS_INVALID_VALUE
;
858 vmixer
->luma_key
.luma_max
= val
;
859 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE
))
860 if (!vl_compositor_set_csc_matrix(&vmixer
->cstate
, (const vl_csc_matrix
*)&vmixer
->csc
,
861 vmixer
->luma_key
.luma_min
, vmixer
->luma_key
.luma_max
)) {
862 ret
= VDP_STATUS_ERROR
;
867 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL
:
869 val
= *(float*)attribute_values
[i
];
870 if (val
< -1.0f
|| val
> 1.0f
) {
871 ret
= VDP_STATUS_INVALID_VALUE
;
875 vmixer
->sharpness
.value
= val
;
876 vlVdpVideoMixerUpdateSharpnessFilter(vmixer
);
879 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE
:
880 if (*(uint8_t*)attribute_values
[i
] > 1) {
881 ret
= VDP_STATUS_INVALID_VALUE
;
884 vmixer
->skip_chroma_deint
= *(uint8_t*)attribute_values
[i
];
885 vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer
);
888 ret
= VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE
;
892 pipe_mutex_unlock(vmixer
->device
->mutex
);
894 return VDP_STATUS_OK
;
896 pipe_mutex_unlock(vmixer
->device
->mutex
);
901 * Retrieve parameter values given at creation time.
904 vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer
,
905 uint32_t parameter_count
,
906 VdpVideoMixerParameter
const *parameters
,
907 void *const *parameter_values
)
909 vlVdpVideoMixer
*vmixer
= vlGetDataHTAB(mixer
);
912 return VDP_STATUS_INVALID_HANDLE
;
914 if (!parameter_count
)
915 return VDP_STATUS_OK
;
916 if (!(parameters
&& parameter_values
))
917 return VDP_STATUS_INVALID_POINTER
;
918 for (i
= 0; i
< parameter_count
; ++i
) {
919 switch (parameters
[i
]) {
920 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
:
921 *(uint32_t*)parameter_values
[i
] = vmixer
->video_width
;
923 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
:
924 *(uint32_t*)parameter_values
[i
] = vmixer
->video_height
;
926 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
:
927 *(VdpChromaType
*)parameter_values
[i
] = PipeToChroma(vmixer
->chroma_format
);
929 case VDP_VIDEO_MIXER_PARAMETER_LAYERS
:
930 *(uint32_t*)parameter_values
[i
] = vmixer
->max_layers
;
933 return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER
;
936 return VDP_STATUS_OK
;
940 * Retrieve current attribute values.
943 vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer
,
944 uint32_t attribute_count
,
945 VdpVideoMixerAttribute
const *attributes
,
946 void *const *attribute_values
)
949 VdpCSCMatrix
**vdp_csc
;
951 if (!(attributes
&& attribute_values
))
952 return VDP_STATUS_INVALID_POINTER
;
954 vlVdpVideoMixer
*vmixer
= vlGetDataHTAB(mixer
);
956 return VDP_STATUS_INVALID_HANDLE
;
958 pipe_mutex_lock(vmixer
->device
->mutex
);
959 for (i
= 0; i
< attribute_count
; ++i
) {
960 switch (attributes
[i
]) {
961 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR
:
962 vl_compositor_get_clear_color(&vmixer
->cstate
, attribute_values
[i
]);
964 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX
:
965 vdp_csc
= attribute_values
[i
];
966 if (!vmixer
->custom_csc
) {
970 memcpy(*vdp_csc
, vmixer
->csc
, sizeof(float)*12);
973 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL
:
974 *(float*)attribute_values
[i
] = (float)vmixer
->noise_reduction
.level
/ 10.0f
;
977 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA
:
978 *(float*)attribute_values
[i
] = vmixer
->luma_key
.luma_min
;
980 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA
:
981 *(float*)attribute_values
[i
] = vmixer
->luma_key
.luma_max
;
983 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL
:
984 *(float*)attribute_values
[i
] = vmixer
->sharpness
.value
;
986 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE
:
987 *(uint8_t*)attribute_values
[i
] = vmixer
->skip_chroma_deint
;
990 pipe_mutex_unlock(vmixer
->device
->mutex
);
991 return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE
;
994 pipe_mutex_unlock(vmixer
->device
->mutex
);
995 return VDP_STATUS_OK
;
999 * Generate a color space conversion matrix.
1002 vlVdpGenerateCSCMatrix(VdpProcamp
*procamp
,
1003 VdpColorStandard standard
,
1004 VdpCSCMatrix
*csc_matrix
)
1006 enum VL_CSC_COLOR_STANDARD vl_std
;
1007 struct vl_procamp camp
;
1010 return VDP_STATUS_INVALID_POINTER
;
1013 case VDP_COLOR_STANDARD_ITUR_BT_601
: vl_std
= VL_CSC_COLOR_STANDARD_BT_601
; break;
1014 case VDP_COLOR_STANDARD_ITUR_BT_709
: vl_std
= VL_CSC_COLOR_STANDARD_BT_709
; break;
1015 case VDP_COLOR_STANDARD_SMPTE_240M
: vl_std
= VL_CSC_COLOR_STANDARD_SMPTE_240M
; break;
1016 default: return VDP_STATUS_INVALID_COLOR_STANDARD
;
1020 if (procamp
->struct_version
> VDP_PROCAMP_VERSION
)
1021 return VDP_STATUS_INVALID_STRUCT_VERSION
;
1022 camp
.brightness
= procamp
->brightness
;
1023 camp
.contrast
= procamp
->contrast
;
1024 camp
.saturation
= procamp
->saturation
;
1025 camp
.hue
= procamp
->hue
;
1028 vl_csc_get_matrix(vl_std
, procamp
? &camp
: NULL
, true, csc_matrix
);
1029 return VDP_STATUS_OK
;