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 vl_compositor_init_state(&vmixer
->cstate
, dev
->context
);
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
);
74 *mixer
= vlAddDataHTAB(vmixer
);
76 ret
= VDP_STATUS_ERROR
;
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_L2
:
86 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3
:
87 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4
:
88 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5
:
89 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6
:
90 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7
:
91 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8
:
92 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9
:
93 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
:
96 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
97 vmixer
->deint
.supported
= true;
100 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS
:
101 vmixer
->sharpness
.supported
= true;
104 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
:
105 vmixer
->noise_reduction
.supported
= true;
108 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY
:
109 vmixer
->luma_key
.supported
= true;
112 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
:
113 vmixer
->bicubic
.supported
= true;
115 default: goto no_params
;
119 vmixer
->chroma_format
= PIPE_VIDEO_CHROMA_FORMAT_420
;
120 ret
= VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER
;
121 for (i
= 0; i
< parameter_count
; ++i
) {
122 switch (parameters
[i
]) {
123 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
:
124 vmixer
->video_width
= *(uint32_t*)parameter_values
[i
];
126 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
:
127 vmixer
->video_height
= *(uint32_t*)parameter_values
[i
];
129 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
:
130 vmixer
->chroma_format
= ChromaToPipe(*(VdpChromaType
*)parameter_values
[i
]);
132 case VDP_VIDEO_MIXER_PARAMETER_LAYERS
:
133 vmixer
->max_layers
= *(uint32_t*)parameter_values
[i
];
135 default: goto no_params
;
138 ret
= VDP_STATUS_INVALID_VALUE
;
139 if (vmixer
->max_layers
> 4) {
140 VDPAU_MSG(VDPAU_WARN
, "[VDPAU] Max layers > 4 not supported\n", vmixer
->max_layers
);
144 max_2d_texture_level
= screen
->get_param(screen
, PIPE_CAP_MAX_TEXTURE_2D_LEVELS
);
145 max_size
= pow(2, max_2d_texture_level
-1);
146 if (vmixer
->video_width
< 48 || vmixer
->video_width
> max_size
) {
147 VDPAU_MSG(VDPAU_WARN
, "[VDPAU] 48 < %u < %u not valid for width\n",
148 vmixer
->video_width
, max_size
);
151 if (vmixer
->video_height
< 48 || vmixer
->video_height
> max_size
) {
152 VDPAU_MSG(VDPAU_WARN
, "[VDPAU] 48 < %u < %u not valid for height\n",
153 vmixer
->video_height
, max_size
);
156 vmixer
->luma_key
.luma_min
= 1.0f
;
157 vmixer
->luma_key
.luma_max
= 0.0f
;
158 pipe_mutex_unlock(dev
->mutex
);
160 return VDP_STATUS_OK
;
163 vlRemoveDataHTAB(*mixer
);
166 vl_compositor_cleanup_state(&vmixer
->cstate
);
167 pipe_mutex_unlock(dev
->mutex
);
168 DeviceReference(&vmixer
->device
, NULL
);
174 * Destroy a VdpVideoMixer.
177 vlVdpVideoMixerDestroy(VdpVideoMixer mixer
)
179 vlVdpVideoMixer
*vmixer
;
181 vmixer
= vlGetDataHTAB(mixer
);
183 return VDP_STATUS_INVALID_HANDLE
;
185 pipe_mutex_lock(vmixer
->device
->mutex
);
187 vlVdpResolveDelayedRendering(vmixer
->device
, NULL
, NULL
);
189 vlRemoveDataHTAB(mixer
);
191 vl_compositor_cleanup_state(&vmixer
->cstate
);
193 if (vmixer
->deint
.filter
) {
194 vl_deint_filter_cleanup(vmixer
->deint
.filter
);
195 FREE(vmixer
->deint
.filter
);
198 if (vmixer
->noise_reduction
.filter
) {
199 vl_median_filter_cleanup(vmixer
->noise_reduction
.filter
);
200 FREE(vmixer
->noise_reduction
.filter
);
203 if (vmixer
->sharpness
.filter
) {
204 vl_matrix_filter_cleanup(vmixer
->sharpness
.filter
);
205 FREE(vmixer
->sharpness
.filter
);
208 if (vmixer
->bicubic
.filter
) {
209 vl_bicubic_filter_cleanup(vmixer
->bicubic
.filter
);
210 FREE(vmixer
->bicubic
.filter
);
212 pipe_mutex_unlock(vmixer
->device
->mutex
);
213 DeviceReference(&vmixer
->device
, NULL
);
217 return VDP_STATUS_OK
;
221 * Perform a video post-processing and compositing operation.
223 VdpStatus
vlVdpVideoMixerRender(VdpVideoMixer mixer
,
224 VdpOutputSurface background_surface
,
225 VdpRect
const *background_source_rect
,
226 VdpVideoMixerPictureStructure current_picture_structure
,
227 uint32_t video_surface_past_count
,
228 VdpVideoSurface
const *video_surface_past
,
229 VdpVideoSurface video_surface_current
,
230 uint32_t video_surface_future_count
,
231 VdpVideoSurface
const *video_surface_future
,
232 VdpRect
const *video_source_rect
,
233 VdpOutputSurface destination_surface
,
234 VdpRect
const *destination_rect
,
235 VdpRect
const *destination_video_rect
,
236 uint32_t layer_count
,
237 VdpLayer
const *layers
)
239 enum vl_compositor_deinterlace deinterlace
;
240 struct u_rect rect
, clip
, *prect
, dirty_area
;
241 unsigned i
, layer
= 0;
242 struct pipe_video_buffer
*video_buffer
;
243 struct pipe_sampler_view
*sampler_view
, sv_templ
;
244 struct pipe_surface
*surface
, surf_templ
;
245 struct pipe_context
*pipe
= NULL
;
246 struct pipe_resource res_tmpl
, *res
;
248 vlVdpVideoMixer
*vmixer
;
250 vlVdpOutputSurface
*dst
, *bg
= NULL
;
252 struct vl_compositor
*compositor
;
254 vmixer
= vlGetDataHTAB(mixer
);
256 return VDP_STATUS_INVALID_HANDLE
;
258 compositor
= &vmixer
->device
->compositor
;
260 surf
= vlGetDataHTAB(video_surface_current
);
262 return VDP_STATUS_INVALID_HANDLE
;
263 video_buffer
= surf
->video_buffer
;
265 if (surf
->device
!= vmixer
->device
)
266 return VDP_STATUS_HANDLE_DEVICE_MISMATCH
;
268 if (vmixer
->video_width
> video_buffer
->width
||
269 vmixer
->video_height
> video_buffer
->height
||
270 vmixer
->chroma_format
!= video_buffer
->chroma_format
)
271 return VDP_STATUS_INVALID_SIZE
;
273 if (layer_count
> vmixer
->max_layers
)
274 return VDP_STATUS_INVALID_VALUE
;
276 dst
= vlGetDataHTAB(destination_surface
);
278 return VDP_STATUS_INVALID_HANDLE
;
280 if (background_surface
!= VDP_INVALID_HANDLE
) {
281 bg
= vlGetDataHTAB(background_surface
);
283 return VDP_STATUS_INVALID_HANDLE
;
286 pipe_mutex_lock(vmixer
->device
->mutex
);
287 vlVdpResolveDelayedRendering(vmixer
->device
, NULL
, NULL
);
289 vl_compositor_clear_layers(&vmixer
->cstate
);
292 vl_compositor_set_rgba_layer(&vmixer
->cstate
, compositor
, layer
++, bg
->sampler_view
,
293 RectToPipe(background_source_rect
, &rect
), NULL
, NULL
);
295 switch (current_picture_structure
) {
296 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD
:
297 deinterlace
= VL_COMPOSITOR_BOB_TOP
;
300 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD
:
301 deinterlace
= VL_COMPOSITOR_BOB_BOTTOM
;
304 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME
:
305 deinterlace
= VL_COMPOSITOR_WEAVE
;
309 pipe_mutex_unlock(vmixer
->device
->mutex
);
310 return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE
;
313 if (deinterlace
!= VL_COMPOSITOR_WEAVE
&& vmixer
->deint
.enabled
&&
314 video_surface_past_count
> 1 && video_surface_future_count
> 0) {
315 vlVdpSurface
*prevprev
= vlGetDataHTAB(video_surface_past
[1]);
316 vlVdpSurface
*prev
= vlGetDataHTAB(video_surface_past
[0]);
317 vlVdpSurface
*next
= vlGetDataHTAB(video_surface_future
[0]);
318 if (prevprev
&& prev
&& next
&&
319 vl_deint_filter_check_buffers(vmixer
->deint
.filter
,
320 prevprev
->video_buffer
, prev
->video_buffer
, surf
->video_buffer
, next
->video_buffer
)) {
321 vl_deint_filter_render(vmixer
->deint
.filter
, prevprev
->video_buffer
,
322 prev
->video_buffer
, surf
->video_buffer
,
324 deinterlace
== VL_COMPOSITOR_BOB_BOTTOM
);
325 deinterlace
= VL_COMPOSITOR_WEAVE
;
326 video_buffer
= vmixer
->deint
.filter
->video_buffer
;
330 prect
= RectToPipe(video_source_rect
, &rect
);
334 rect
.x1
= surf
->templat
.width
;
335 rect
.y1
= surf
->templat
.height
;
338 vl_compositor_set_buffer_layer(&vmixer
->cstate
, compositor
, layer
, video_buffer
, prect
, NULL
, deinterlace
);
340 if (vmixer
->bicubic
.filter
|| vmixer
->sharpness
.filter
|| vmixer
->noise_reduction
.filter
) {
341 pipe
= vmixer
->device
->context
;
342 memset(&res_tmpl
, 0, sizeof(res_tmpl
));
344 res_tmpl
.target
= PIPE_TEXTURE_2D
;
345 res_tmpl
.format
= dst
->sampler_view
->format
;
347 res_tmpl
.array_size
= 1;
348 res_tmpl
.bind
= PIPE_BIND_SAMPLER_VIEW
| PIPE_BIND_RENDER_TARGET
;
349 res_tmpl
.usage
= PIPE_USAGE_DEFAULT
;
351 if (!vmixer
->bicubic
.filter
) {
352 res_tmpl
.width0
= dst
->surface
->width
;
353 res_tmpl
.height0
= dst
->surface
->height
;
355 res_tmpl
.width0
= surf
->templat
.width
;
356 res_tmpl
.height0
= surf
->templat
.height
;
359 res
= pipe
->screen
->resource_create(pipe
->screen
, &res_tmpl
);
361 vlVdpDefaultSamplerViewTemplate(&sv_templ
, res
);
362 sampler_view
= pipe
->create_sampler_view(pipe
, res
, &sv_templ
);
364 memset(&surf_templ
, 0, sizeof(surf_templ
));
365 surf_templ
.format
= res
->format
;
366 surface
= pipe
->create_surface(pipe
, res
, &surf_templ
);
368 vl_compositor_reset_dirty_area(&dirty_area
);
369 pipe_resource_reference(&res
, NULL
);
371 surface
= dst
->surface
;
372 sampler_view
= dst
->sampler_view
;
373 dirty_area
= dst
->dirty_area
;
376 if (!vmixer
->bicubic
.filter
) {
377 vl_compositor_set_layer_dst_area(&vmixer
->cstate
, layer
++, RectToPipe(destination_video_rect
, &rect
));
378 vl_compositor_set_dst_clip(&vmixer
->cstate
, RectToPipe(destination_rect
, &clip
));
381 for (i
= 0; i
< layer_count
; ++i
) {
382 vlVdpOutputSurface
*src
= vlGetDataHTAB(layers
->source_surface
);
384 pipe_mutex_unlock(vmixer
->device
->mutex
);
385 return VDP_STATUS_INVALID_HANDLE
;
388 assert(layers
->struct_version
== VDP_LAYER_VERSION
);
390 vl_compositor_set_rgba_layer(&vmixer
->cstate
, compositor
, layer
, src
->sampler_view
,
391 RectToPipe(layers
->source_rect
, &rect
), NULL
, NULL
);
392 vl_compositor_set_layer_dst_area(&vmixer
->cstate
, layer
++, RectToPipe(layers
->destination_rect
, &rect
));
397 if (!vmixer
->noise_reduction
.filter
&& !vmixer
->sharpness
.filter
&& !vmixer
->bicubic
.filter
)
398 vlVdpSave4DelayedRendering(vmixer
->device
, destination_surface
, &vmixer
->cstate
);
400 vl_compositor_render(&vmixer
->cstate
, compositor
, surface
, &dirty_area
, true);
402 if (vmixer
->noise_reduction
.filter
) {
403 if (!vmixer
->sharpness
.filter
&& !vmixer
->bicubic
.filter
) {
404 vl_median_filter_render(vmixer
->noise_reduction
.filter
,
405 sampler_view
, dst
->surface
);
407 res
= pipe
->screen
->resource_create(pipe
->screen
, &res_tmpl
);
408 struct pipe_sampler_view
*sampler_view_temp
= pipe
->create_sampler_view(pipe
, res
, &sv_templ
);
409 struct pipe_surface
*surface_temp
= pipe
->create_surface(pipe
, res
, &surf_templ
);
410 pipe_resource_reference(&res
, NULL
);
412 vl_median_filter_render(vmixer
->noise_reduction
.filter
,
413 sampler_view
, surface_temp
);
415 pipe_sampler_view_reference(&sampler_view
, NULL
);
416 pipe_surface_reference(&surface
, NULL
);
418 sampler_view
= sampler_view_temp
;
419 surface
= surface_temp
;
423 if (vmixer
->sharpness
.filter
) {
424 if (!vmixer
->bicubic
.filter
) {
425 vl_matrix_filter_render(vmixer
->sharpness
.filter
,
426 sampler_view
, dst
->surface
);
428 res
= pipe
->screen
->resource_create(pipe
->screen
, &res_tmpl
);
429 struct pipe_sampler_view
*sampler_view_temp
= pipe
->create_sampler_view(pipe
, res
, &sv_templ
);
430 struct pipe_surface
*surface_temp
= pipe
->create_surface(pipe
, res
, &surf_templ
);
431 pipe_resource_reference(&res
, NULL
);
433 vl_matrix_filter_render(vmixer
->sharpness
.filter
,
434 sampler_view
, surface_temp
);
436 pipe_sampler_view_reference(&sampler_view
, NULL
);
437 pipe_surface_reference(&surface
, NULL
);
439 sampler_view
= sampler_view_temp
;
440 surface
= surface_temp
;
444 if (vmixer
->bicubic
.filter
)
445 vl_bicubic_filter_render(vmixer
->bicubic
.filter
,
446 sampler_view
, dst
->surface
,
447 RectToPipe(destination_video_rect
, &rect
),
448 RectToPipe(destination_rect
, &clip
));
450 if(surface
!= dst
->surface
) {
451 pipe_sampler_view_reference(&sampler_view
, NULL
);
452 pipe_surface_reference(&surface
, NULL
);
455 pipe_mutex_unlock(vmixer
->device
->mutex
);
457 return VDP_STATUS_OK
;
461 vlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer
*vmixer
)
463 struct pipe_context
*pipe
= vmixer
->device
->context
;
466 /* remove existing filter */
467 if (vmixer
->deint
.filter
) {
468 vl_deint_filter_cleanup(vmixer
->deint
.filter
);
469 FREE(vmixer
->deint
.filter
);
470 vmixer
->deint
.filter
= NULL
;
473 /* create a new filter if requested */
474 if (vmixer
->deint
.enabled
&& vmixer
->chroma_format
== PIPE_VIDEO_CHROMA_FORMAT_420
) {
475 vmixer
->deint
.filter
= MALLOC(sizeof(struct vl_deint_filter
));
476 vmixer
->deint
.enabled
= vl_deint_filter_init(vmixer
->deint
.filter
, pipe
,
477 vmixer
->video_width
, vmixer
->video_height
,
478 vmixer
->skip_chroma_deint
, vmixer
->deint
.spatial
);
479 if (!vmixer
->deint
.enabled
) {
480 FREE(vmixer
->deint
.filter
);
486 * Update the noise reduction setting
489 vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer
*vmixer
)
493 /* if present remove the old filter first */
494 if (vmixer
->noise_reduction
.filter
) {
495 vl_median_filter_cleanup(vmixer
->noise_reduction
.filter
);
496 FREE(vmixer
->noise_reduction
.filter
);
497 vmixer
->noise_reduction
.filter
= NULL
;
500 /* and create a new filter as needed */
501 if (vmixer
->noise_reduction
. enabled
&& vmixer
->noise_reduction
.level
> 0) {
502 vmixer
->noise_reduction
.filter
= MALLOC(sizeof(struct vl_median_filter
));
503 vl_median_filter_init(vmixer
->noise_reduction
.filter
, vmixer
->device
->context
,
504 vmixer
->video_width
, vmixer
->video_height
,
505 vmixer
->noise_reduction
.level
+ 1,
506 VL_MEDIAN_FILTER_CROSS
);
511 vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer
*vmixer
)
515 /* if present remove the old filter first */
516 if (vmixer
->sharpness
.filter
) {
517 vl_matrix_filter_cleanup(vmixer
->sharpness
.filter
);
518 FREE(vmixer
->sharpness
.filter
);
519 vmixer
->sharpness
.filter
= NULL
;
522 /* and create a new filter as needed */
523 if (vmixer
->sharpness
.enabled
&& vmixer
->sharpness
.value
!= 0.0f
) {
527 if (vmixer
->sharpness
.value
> 0.0f
) {
528 matrix
[0] = -1.0f
; matrix
[1] = -1.0f
; matrix
[2] = -1.0f
;
529 matrix
[3] = -1.0f
; matrix
[4] = 8.0f
; matrix
[5] = -1.0f
;
530 matrix
[6] = -1.0f
; matrix
[7] = -1.0f
; matrix
[8] = -1.0f
;
532 for (i
= 0; i
< 9; ++i
)
533 matrix
[i
] *= vmixer
->sharpness
.value
;
538 matrix
[0] = 1.0f
; matrix
[1] = 2.0f
; matrix
[2] = 1.0f
;
539 matrix
[3] = 2.0f
; matrix
[4] = 4.0f
; matrix
[5] = 2.0f
;
540 matrix
[6] = 1.0f
; matrix
[7] = 2.0f
; matrix
[8] = 1.0f
;
542 for (i
= 0; i
< 9; ++i
)
543 matrix
[i
] *= fabsf(vmixer
->sharpness
.value
) / 16.0f
;
545 matrix
[4] += 1.0f
- fabsf(vmixer
->sharpness
.value
);
548 vmixer
->sharpness
.filter
= MALLOC(sizeof(struct vl_matrix_filter
));
549 vl_matrix_filter_init(vmixer
->sharpness
.filter
, vmixer
->device
->context
,
550 vmixer
->video_width
, vmixer
->video_height
,
556 * Update the bicubic filter
559 vlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer
*vmixer
)
563 /* if present remove the old filter first */
564 if (vmixer
->bicubic
.filter
) {
565 vl_bicubic_filter_cleanup(vmixer
->bicubic
.filter
);
566 FREE(vmixer
->bicubic
.filter
);
567 vmixer
->bicubic
.filter
= NULL
;
569 /* and create a new filter as needed */
570 if (vmixer
->bicubic
.enabled
) {
571 vmixer
->bicubic
.filter
= MALLOC(sizeof(struct vl_bicubic_filter
));
572 vl_bicubic_filter_init(vmixer
->bicubic
.filter
, vmixer
->device
->context
,
573 vmixer
->video_width
, vmixer
->video_height
);
578 * Retrieve whether features were requested at creation time.
581 vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer
,
582 uint32_t feature_count
,
583 VdpVideoMixerFeature
const *features
,
584 VdpBool
*feature_supports
)
586 vlVdpVideoMixer
*vmixer
;
589 if (!(features
&& feature_supports
))
590 return VDP_STATUS_INVALID_POINTER
;
592 vmixer
= vlGetDataHTAB(mixer
);
594 return VDP_STATUS_INVALID_HANDLE
;
596 for (i
= 0; i
< feature_count
; ++i
) {
597 switch (features
[i
]) {
598 /* they are valid, but we doesn't support them */
599 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
:
600 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2
:
601 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3
:
602 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4
:
603 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5
:
604 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6
:
605 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7
:
606 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8
:
607 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9
:
608 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
:
609 feature_supports
[i
] = false;
612 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
613 feature_supports
[i
] = vmixer
->deint
.supported
;
616 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS
:
617 feature_supports
[i
] = vmixer
->sharpness
.supported
;
620 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
:
621 feature_supports
[i
] = vmixer
->noise_reduction
.supported
;
624 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY
:
625 feature_supports
[i
] = vmixer
->luma_key
.supported
;
628 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
:
629 feature_supports
[i
] = vmixer
->bicubic
.supported
;
633 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE
;
637 return VDP_STATUS_OK
;
641 * Enable or disable features.
644 vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer
,
645 uint32_t feature_count
,
646 VdpVideoMixerFeature
const *features
,
647 VdpBool
const *feature_enables
)
649 vlVdpVideoMixer
*vmixer
;
652 if (!(features
&& feature_enables
))
653 return VDP_STATUS_INVALID_POINTER
;
655 vmixer
= vlGetDataHTAB(mixer
);
657 return VDP_STATUS_INVALID_HANDLE
;
659 pipe_mutex_lock(vmixer
->device
->mutex
);
660 for (i
= 0; i
< feature_count
; ++i
) {
661 switch (features
[i
]) {
662 /* they are valid, but we doesn't support them */
663 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
:
664 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2
:
665 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3
:
666 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4
:
667 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5
:
668 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6
:
669 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7
:
670 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8
:
671 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9
:
672 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
:
675 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
676 vmixer
->deint
.enabled
= feature_enables
[i
];
677 vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer
);
680 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS
:
681 vmixer
->sharpness
.enabled
= feature_enables
[i
];
682 vlVdpVideoMixerUpdateSharpnessFilter(vmixer
);
685 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
:
686 vmixer
->noise_reduction
.enabled
= feature_enables
[i
];
687 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer
);
690 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY
:
691 vmixer
->luma_key
.enabled
= feature_enables
[i
];
692 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE
))
693 vl_compositor_set_csc_matrix(&vmixer
->cstate
, (const vl_csc_matrix
*)&vmixer
->csc
,
694 vmixer
->luma_key
.luma_min
, vmixer
->luma_key
.luma_max
);
697 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
:
698 vmixer
->bicubic
.enabled
= feature_enables
[i
];
699 vlVdpVideoMixerUpdateBicubicFilter(vmixer
);
703 pipe_mutex_unlock(vmixer
->device
->mutex
);
704 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE
;
707 pipe_mutex_unlock(vmixer
->device
->mutex
);
709 return VDP_STATUS_OK
;
713 * Retrieve whether features are enabled.
716 vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer
,
717 uint32_t feature_count
,
718 VdpVideoMixerFeature
const *features
,
719 VdpBool
*feature_enables
)
721 vlVdpVideoMixer
*vmixer
;
724 if (!(features
&& feature_enables
))
725 return VDP_STATUS_INVALID_POINTER
;
727 vmixer
= vlGetDataHTAB(mixer
);
729 return VDP_STATUS_INVALID_HANDLE
;
731 for (i
= 0; i
< feature_count
; ++i
) {
732 switch (features
[i
]) {
733 /* they are valid, but we doesn't support them */
734 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
735 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
:
736 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2
:
737 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3
:
738 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4
:
739 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5
:
740 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6
:
741 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7
:
742 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8
:
743 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9
:
744 case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
:
747 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS
:
748 feature_enables
[i
] = vmixer
->sharpness
.enabled
;
751 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
:
752 feature_enables
[i
] = vmixer
->noise_reduction
.enabled
;
755 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY
:
756 feature_enables
[i
] = vmixer
->luma_key
.enabled
;
759 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
:
760 feature_enables
[i
] = vmixer
->bicubic
.enabled
;
764 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE
;
768 return VDP_STATUS_OK
;
772 * Set attribute values.
775 vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer
,
776 uint32_t attribute_count
,
777 VdpVideoMixerAttribute
const *attributes
,
778 void const *const *attribute_values
)
780 const VdpColor
*background_color
;
781 union pipe_color_union color
;
782 const float *vdp_csc
;
787 if (!(attributes
&& attribute_values
))
788 return VDP_STATUS_INVALID_POINTER
;
790 vlVdpVideoMixer
*vmixer
= vlGetDataHTAB(mixer
);
792 return VDP_STATUS_INVALID_HANDLE
;
794 pipe_mutex_lock(vmixer
->device
->mutex
);
795 for (i
= 0; i
< attribute_count
; ++i
) {
796 switch (attributes
[i
]) {
797 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR
:
798 background_color
= attribute_values
[i
];
799 color
.f
[0] = background_color
->red
;
800 color
.f
[1] = background_color
->green
;
801 color
.f
[2] = background_color
->blue
;
802 color
.f
[3] = background_color
->alpha
;
803 vl_compositor_set_clear_color(&vmixer
->cstate
, &color
);
805 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX
:
806 vdp_csc
= attribute_values
[i
];
807 vmixer
->custom_csc
= !!vdp_csc
;
809 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601
, NULL
, 1, &vmixer
->csc
);
811 memcpy(vmixer
->csc
, vdp_csc
, sizeof(vl_csc_matrix
));
812 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE
))
813 vl_compositor_set_csc_matrix(&vmixer
->cstate
, (const vl_csc_matrix
*)&vmixer
->csc
,
814 vmixer
->luma_key
.luma_min
, vmixer
->luma_key
.luma_max
);
817 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL
:
819 val
= *(float*)attribute_values
[i
];
820 if (val
< 0.0f
|| val
> 1.0f
) {
821 ret
= VDP_STATUS_INVALID_VALUE
;
825 vmixer
->noise_reduction
.level
= val
* 10;
826 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer
);
829 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA
:
830 val
= *(float*)attribute_values
[i
];
831 if (val
< 0.0f
|| val
> 1.0f
) {
832 ret
= VDP_STATUS_INVALID_VALUE
;
835 vmixer
->luma_key
.luma_min
= val
;
836 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE
))
837 vl_compositor_set_csc_matrix(&vmixer
->cstate
, (const vl_csc_matrix
*)&vmixer
->csc
,
838 vmixer
->luma_key
.luma_min
, vmixer
->luma_key
.luma_max
);
841 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA
:
842 val
= *(float*)attribute_values
[i
];
843 if (val
< 0.0f
|| val
> 1.0f
) {
844 ret
= VDP_STATUS_INVALID_VALUE
;
847 vmixer
->luma_key
.luma_max
= val
;
848 if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE
))
849 vl_compositor_set_csc_matrix(&vmixer
->cstate
, (const vl_csc_matrix
*)&vmixer
->csc
,
850 vmixer
->luma_key
.luma_min
, vmixer
->luma_key
.luma_max
);
853 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL
:
855 val
= *(float*)attribute_values
[i
];
856 if (val
< -1.0f
|| val
> 1.0f
) {
857 ret
= VDP_STATUS_INVALID_VALUE
;
861 vmixer
->sharpness
.value
= val
;
862 vlVdpVideoMixerUpdateSharpnessFilter(vmixer
);
865 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE
:
866 if (*(uint8_t*)attribute_values
[i
] > 1) {
867 ret
= VDP_STATUS_INVALID_VALUE
;
870 vmixer
->skip_chroma_deint
= *(uint8_t*)attribute_values
[i
];
871 vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer
);
874 ret
= VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE
;
878 pipe_mutex_unlock(vmixer
->device
->mutex
);
880 return VDP_STATUS_OK
;
882 pipe_mutex_unlock(vmixer
->device
->mutex
);
887 * Retrieve parameter values given at creation time.
890 vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer
,
891 uint32_t parameter_count
,
892 VdpVideoMixerParameter
const *parameters
,
893 void *const *parameter_values
)
895 vlVdpVideoMixer
*vmixer
= vlGetDataHTAB(mixer
);
898 return VDP_STATUS_INVALID_HANDLE
;
900 if (!parameter_count
)
901 return VDP_STATUS_OK
;
902 if (!(parameters
&& parameter_values
))
903 return VDP_STATUS_INVALID_POINTER
;
904 for (i
= 0; i
< parameter_count
; ++i
) {
905 switch (parameters
[i
]) {
906 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
:
907 *(uint32_t*)parameter_values
[i
] = vmixer
->video_width
;
909 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
:
910 *(uint32_t*)parameter_values
[i
] = vmixer
->video_height
;
912 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
:
913 *(VdpChromaType
*)parameter_values
[i
] = PipeToChroma(vmixer
->chroma_format
);
915 case VDP_VIDEO_MIXER_PARAMETER_LAYERS
:
916 *(uint32_t*)parameter_values
[i
] = vmixer
->max_layers
;
919 return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER
;
922 return VDP_STATUS_OK
;
926 * Retrieve current attribute values.
929 vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer
,
930 uint32_t attribute_count
,
931 VdpVideoMixerAttribute
const *attributes
,
932 void *const *attribute_values
)
935 VdpCSCMatrix
**vdp_csc
;
937 if (!(attributes
&& attribute_values
))
938 return VDP_STATUS_INVALID_POINTER
;
940 vlVdpVideoMixer
*vmixer
= vlGetDataHTAB(mixer
);
942 return VDP_STATUS_INVALID_HANDLE
;
944 pipe_mutex_lock(vmixer
->device
->mutex
);
945 for (i
= 0; i
< attribute_count
; ++i
) {
946 switch (attributes
[i
]) {
947 case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR
:
948 vl_compositor_get_clear_color(&vmixer
->cstate
, attribute_values
[i
]);
950 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX
:
951 vdp_csc
= attribute_values
[i
];
952 if (!vmixer
->custom_csc
) {
956 memcpy(*vdp_csc
, vmixer
->csc
, sizeof(float)*12);
959 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL
:
960 *(float*)attribute_values
[i
] = (float)vmixer
->noise_reduction
.level
/ 10.0f
;
963 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA
:
964 *(float*)attribute_values
[i
] = vmixer
->luma_key
.luma_min
;
966 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA
:
967 *(float*)attribute_values
[i
] = vmixer
->luma_key
.luma_max
;
969 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL
:
970 *(float*)attribute_values
[i
] = vmixer
->sharpness
.value
;
972 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE
:
973 *(uint8_t*)attribute_values
[i
] = vmixer
->skip_chroma_deint
;
976 pipe_mutex_unlock(vmixer
->device
->mutex
);
977 return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE
;
980 pipe_mutex_unlock(vmixer
->device
->mutex
);
981 return VDP_STATUS_OK
;
985 * Generate a color space conversion matrix.
988 vlVdpGenerateCSCMatrix(VdpProcamp
*procamp
,
989 VdpColorStandard standard
,
990 VdpCSCMatrix
*csc_matrix
)
992 enum VL_CSC_COLOR_STANDARD vl_std
;
993 struct vl_procamp camp
;
996 return VDP_STATUS_INVALID_POINTER
;
999 case VDP_COLOR_STANDARD_ITUR_BT_601
: vl_std
= VL_CSC_COLOR_STANDARD_BT_601
; break;
1000 case VDP_COLOR_STANDARD_ITUR_BT_709
: vl_std
= VL_CSC_COLOR_STANDARD_BT_709
; break;
1001 case VDP_COLOR_STANDARD_SMPTE_240M
: vl_std
= VL_CSC_COLOR_STANDARD_SMPTE_240M
; break;
1002 default: return VDP_STATUS_INVALID_COLOR_STANDARD
;
1006 if (procamp
->struct_version
> VDP_PROCAMP_VERSION
)
1007 return VDP_STATUS_INVALID_STRUCT_VERSION
;
1008 camp
.brightness
= procamp
->brightness
;
1009 camp
.contrast
= procamp
->contrast
;
1010 camp
.saturation
= procamp
->saturation
;
1011 camp
.hue
= procamp
->hue
;
1014 vl_csc_get_matrix(vl_std
, procamp
? &camp
: NULL
, true, csc_matrix
);
1015 return VDP_STATUS_OK
;