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