1 /**************************************************************************
2 *
3 * Copyright 2010 Thomas Balling Sørensen.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include <vdpau/vdpau.h>
29
30 #include "util/u_memory.h"
31 #include "util/u_debug.h"
32
33 #include "vl/vl_csc.h"
34
35 #include "vdpau_private.h"
36
37 /**
38 * Create a VdpVideoMixer.
39 */
40 VdpStatus
vlVdpVideoMixerCreate(VdpDevice device,uint32_t feature_count,VdpVideoMixerFeature const * features,uint32_t parameter_count,VdpVideoMixerParameter const * parameters,void const * const * parameter_values,VdpVideoMixer * mixer)41 vlVdpVideoMixerCreate(VdpDevice device,
42 uint32_t feature_count,
43 VdpVideoMixerFeature const *features,
44 uint32_t parameter_count,
45 VdpVideoMixerParameter const *parameters,
46 void const *const *parameter_values,
47 VdpVideoMixer *mixer)
48 {
49 vlVdpVideoMixer *vmixer = NULL;
50 VdpStatus ret;
51 struct pipe_screen *screen;
52 uint32_t max_2d_texture_level;
53 unsigned max_size, i;
54
55 vlVdpDevice *dev = vlGetDataHTAB(device);
56 if (!dev)
57 return VDP_STATUS_INVALID_HANDLE;
58 screen = dev->vscreen->pscreen;
59
60 vmixer = CALLOC(1, sizeof(vlVdpVideoMixer));
61 if (!vmixer)
62 return VDP_STATUS_RESOURCES;
63
64 DeviceReference(&vmixer->device, dev);
65
66 pipe_mutex_lock(dev->mutex);
67
68 if (!vl_compositor_init_state(&vmixer->cstate, dev->context)) {
69 ret = VDP_STATUS_ERROR;
70 goto no_compositor_state;
71 }
72
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;
77 goto err_csc_matrix;
78 }
79 }
80
81 *mixer = vlAddDataHTAB(vmixer);
82 if (*mixer == 0) {
83 ret = VDP_STATUS_ERROR;
84 goto no_handle;
85 }
86
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:
101 break;
102
103 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
104 vmixer->deint.supported = true;
105 break;
106
107 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
108 vmixer->sharpness.supported = true;
109 break;
110
111 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
112 vmixer->noise_reduction.supported = true;
113 break;
114
115 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
116 vmixer->luma_key.supported = true;
117 break;
118
119 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
120 vmixer->bicubic.supported = true;
121 break;
122 default: goto no_params;
123 }
124 }
125
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];
132 break;
133 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
134 vmixer->video_height = *(uint32_t*)parameter_values[i];
135 break;
136 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
137 vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]);
138 break;
139 case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
140 vmixer->max_layers = *(uint32_t*)parameter_values[i];
141 break;
142 default: goto no_params;
143 }
144 }
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);
148 goto no_params;
149 }
150
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);
156 goto no_params;
157 }
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);
161 goto no_params;
162 }
163 vmixer->luma_key.luma_min = 1.0f;
164 vmixer->luma_key.luma_max = 0.0f;
165 pipe_mutex_unlock(dev->mutex);
166
167 return VDP_STATUS_OK;
168
169 no_params:
170 vlRemoveDataHTAB(*mixer);
171
172 no_handle:
173 err_csc_matrix:
174 vl_compositor_cleanup_state(&vmixer->cstate);
175 no_compositor_state:
176 pipe_mutex_unlock(dev->mutex);
177 DeviceReference(&vmixer->device, NULL);
178 FREE(vmixer);
179 return ret;
180 }
181
182 /**
183 * Destroy a VdpVideoMixer.
184 */
185 VdpStatus
vlVdpVideoMixerDestroy(VdpVideoMixer mixer)186 vlVdpVideoMixerDestroy(VdpVideoMixer mixer)
187 {
188 vlVdpVideoMixer *vmixer;
189
190 vmixer = vlGetDataHTAB(mixer);
191 if (!vmixer)
192 return VDP_STATUS_INVALID_HANDLE;
193
194 pipe_mutex_lock(vmixer->device->mutex);
195
196 vlRemoveDataHTAB(mixer);
197
198 vl_compositor_cleanup_state(&vmixer->cstate);
199
200 if (vmixer->deint.filter) {
201 vl_deint_filter_cleanup(vmixer->deint.filter);
202 FREE(vmixer->deint.filter);
203 }
204
205 if (vmixer->noise_reduction.filter) {
206 vl_median_filter_cleanup(vmixer->noise_reduction.filter);
207 FREE(vmixer->noise_reduction.filter);
208 }
209
210 if (vmixer->sharpness.filter) {
211 vl_matrix_filter_cleanup(vmixer->sharpness.filter);
212 FREE(vmixer->sharpness.filter);
213 }
214
215 if (vmixer->bicubic.filter) {
216 vl_bicubic_filter_cleanup(vmixer->bicubic.filter);
217 FREE(vmixer->bicubic.filter);
218 }
219 pipe_mutex_unlock(vmixer->device->mutex);
220 DeviceReference(&vmixer->device, NULL);
221
222 FREE(vmixer);
223
224 return VDP_STATUS_OK;
225 }
226
227 /**
228 * Perform a video post-processing and compositing operation.
229 */
vlVdpVideoMixerRender(VdpVideoMixer mixer,VdpOutputSurface background_surface,VdpRect const * background_source_rect,VdpVideoMixerPictureStructure current_picture_structure,uint32_t video_surface_past_count,VdpVideoSurface const * video_surface_past,VdpVideoSurface video_surface_current,uint32_t video_surface_future_count,VdpVideoSurface const * video_surface_future,VdpRect const * video_source_rect,VdpOutputSurface destination_surface,VdpRect const * destination_rect,VdpRect const * destination_video_rect,uint32_t layer_count,VdpLayer const * layers)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)
245 {
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;
254
255 vlVdpVideoMixer *vmixer;
256 vlVdpSurface *surf;
257 vlVdpOutputSurface *dst, *bg = NULL;
258
259 struct vl_compositor *compositor;
260
261 vmixer = vlGetDataHTAB(mixer);
262 if (!vmixer)
263 return VDP_STATUS_INVALID_HANDLE;
264
265 compositor = &vmixer->device->compositor;
266
267 surf = vlGetDataHTAB(video_surface_current);
268 if (!surf)
269 return VDP_STATUS_INVALID_HANDLE;
270 video_buffer = surf->video_buffer;
271
272 if (surf->device != vmixer->device)
273 return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
274
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;
279
280 if (layer_count > vmixer->max_layers)
281 return VDP_STATUS_INVALID_VALUE;
282
283 dst = vlGetDataHTAB(destination_surface);
284 if (!dst)
285 return VDP_STATUS_INVALID_HANDLE;
286
287 if (background_surface != VDP_INVALID_HANDLE) {
288 bg = vlGetDataHTAB(background_surface);
289 if (!bg)
290 return VDP_STATUS_INVALID_HANDLE;
291 }
292
293 pipe_mutex_lock(vmixer->device->mutex);
294
295 vl_compositor_clear_layers(&vmixer->cstate);
296
297 if (bg)
298 vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view,
299 RectToPipe(background_source_rect, &rect), NULL, NULL);
300
301 switch (current_picture_structure) {
302 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD:
303 deinterlace = VL_COMPOSITOR_BOB_TOP;
304 break;
305
306 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:
307 deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
308 break;
309
310 case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME:
311 deinterlace = VL_COMPOSITOR_WEAVE;
312 break;
313
314 default:
315 pipe_mutex_unlock(vmixer->device->mutex);
316 return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE;
317 }
318
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,
329 next->video_buffer,
330 deinterlace == VL_COMPOSITOR_BOB_BOTTOM);
331 deinterlace = VL_COMPOSITOR_WEAVE;
332 video_buffer = vmixer->deint.filter->video_buffer;
333 }
334 }
335
336 prect = RectToPipe(video_source_rect, &rect);
337 if (!prect) {
338 rect.x0 = 0;
339 rect.y0 = 0;
340 rect.x1 = surf->templat.width;
341 rect.y1 = surf->templat.height;
342 prect = ▭
343 }
344 vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace);
345
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));
349
350 res_tmpl.target = PIPE_TEXTURE_2D;
351 res_tmpl.format = dst->sampler_view->format;
352 res_tmpl.depth0 = 1;
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;
356
357 if (!vmixer->bicubic.filter) {
358 res_tmpl.width0 = dst->surface->width;
359 res_tmpl.height0 = dst->surface->height;
360 } else {
361 res_tmpl.width0 = surf->templat.width;
362 res_tmpl.height0 = surf->templat.height;
363 }
364
365 res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
366
367 vlVdpDefaultSamplerViewTemplate(&sv_templ, res);
368 sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);
369
370 memset(&surf_templ, 0, sizeof(surf_templ));
371 surf_templ.format = res->format;
372 surface = pipe->create_surface(pipe, res, &surf_templ);
373
374 vl_compositor_reset_dirty_area(&dirty_area);
375 pipe_resource_reference(&res, NULL);
376 } else {
377 surface = dst->surface;
378 sampler_view = dst->sampler_view;
379 dirty_area = dst->dirty_area;
380 }
381
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));
385 }
386
387 for (i = 0; i < layer_count; ++i) {
388 vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface);
389 if (!src) {
390 pipe_mutex_unlock(vmixer->device->mutex);
391 return VDP_STATUS_INVALID_HANDLE;
392 }
393
394 assert(layers->struct_version == VDP_LAYER_VERSION);
395
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));
399
400 ++layers;
401 }
402
403 vl_compositor_render(&vmixer->cstate, compositor, surface, &dirty_area, true);
404
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);
409 } else {
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);
414
415 vl_median_filter_render(vmixer->noise_reduction.filter,
416 sampler_view, surface_temp);
417
418 pipe_sampler_view_reference(&sampler_view, NULL);
419 pipe_surface_reference(&surface, NULL);
420
421 sampler_view = sampler_view_temp;
422 surface = surface_temp;
423 }
424 }
425
426 if (vmixer->sharpness.filter) {
427 if (!vmixer->bicubic.filter) {
428 vl_matrix_filter_render(vmixer->sharpness.filter,
429 sampler_view, dst->surface);
430 } else {
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);
435
436 vl_matrix_filter_render(vmixer->sharpness.filter,
437 sampler_view, surface_temp);
438
439 pipe_sampler_view_reference(&sampler_view, NULL);
440 pipe_surface_reference(&surface, NULL);
441
442 sampler_view = sampler_view_temp;
443 surface = surface_temp;
444 }
445 }
446
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));
452
453 if(surface != dst->surface) {
454 pipe_sampler_view_reference(&sampler_view, NULL);
455 pipe_surface_reference(&surface, NULL);
456 }
457 pipe_mutex_unlock(vmixer->device->mutex);
458
459 return VDP_STATUS_OK;
460 }
461
462 static void
vlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer * vmixer)463 vlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer *vmixer)
464 {
465 struct pipe_context *pipe = vmixer->device->context;
466 assert(vmixer);
467
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;
473 }
474
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);
483 }
484 }
485 }
486
487 /**
488 * Update the noise reduction setting
489 */
490 static void
vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer * vmixer)491 vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer)
492 {
493 assert(vmixer);
494
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;
500 }
501
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);
509 }
510 }
511
512 static void
vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer * vmixer)513 vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer)
514 {
515 assert(vmixer);
516
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;
522 }
523
524 /* and create a new filter as needed */
525 if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) {
526 float matrix[9];
527 unsigned i;
528
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;
533
534 for (i = 0; i < 9; ++i)
535 matrix[i] *= vmixer->sharpness.value;
536
537 matrix[4] += 1.0f;
538
539 } else {
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;
543
544 for (i = 0; i < 9; ++i)
545 matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f;
546
547 matrix[4] += 1.0f - fabsf(vmixer->sharpness.value);
548 }
549
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,
553 3, 3, matrix);
554 }
555 }
556
557 /**
558 * Update the bicubic filter
559 */
560 static void
vlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer * vmixer)561 vlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer *vmixer)
562 {
563 assert(vmixer);
564
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;
570 }
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);
576 }
577 }
578
579 /**
580 * Retrieve whether features were requested at creation time.
581 */
582 VdpStatus
vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,uint32_t feature_count,VdpVideoMixerFeature const * features,VdpBool * feature_supports)583 vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,
584 uint32_t feature_count,
585 VdpVideoMixerFeature const *features,
586 VdpBool *feature_supports)
587 {
588 vlVdpVideoMixer *vmixer;
589 unsigned i;
590
591 if (!(features && feature_supports))
592 return VDP_STATUS_INVALID_POINTER;
593
594 vmixer = vlGetDataHTAB(mixer);
595 if (!vmixer)
596 return VDP_STATUS_INVALID_HANDLE;
597
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;
612 break;
613
614 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
615 feature_supports[i] = vmixer->deint.supported;
616 break;
617
618 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
619 feature_supports[i] = vmixer->sharpness.supported;
620 break;
621
622 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
623 feature_supports[i] = vmixer->noise_reduction.supported;
624 break;
625
626 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
627 feature_supports[i] = vmixer->luma_key.supported;
628 break;
629
630 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
631 feature_supports[i] = vmixer->bicubic.supported;
632 break;
633
634 default:
635 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
636 }
637 }
638
639 return VDP_STATUS_OK;
640 }
641
642 /**
643 * Enable or disable features.
644 */
645 VdpStatus
vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,uint32_t feature_count,VdpVideoMixerFeature const * features,VdpBool const * feature_enables)646 vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,
647 uint32_t feature_count,
648 VdpVideoMixerFeature const *features,
649 VdpBool const *feature_enables)
650 {
651 vlVdpVideoMixer *vmixer;
652 unsigned i;
653
654 if (!(features && feature_enables))
655 return VDP_STATUS_INVALID_POINTER;
656
657 vmixer = vlGetDataHTAB(mixer);
658 if (!vmixer)
659 return VDP_STATUS_INVALID_HANDLE;
660
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:
675 break;
676
677 case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
678 vmixer->deint.enabled = feature_enables[i];
679 vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);
680 break;
681
682 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
683 vmixer->sharpness.enabled = feature_enables[i];
684 vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
685 break;
686
687 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
688 vmixer->noise_reduction.enabled = feature_enables[i];
689 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
690 break;
691
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;
699 }
700 break;
701
702 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
703 vmixer->bicubic.enabled = feature_enables[i];
704 vlVdpVideoMixerUpdateBicubicFilter(vmixer);
705 break;
706
707 default:
708 pipe_mutex_unlock(vmixer->device->mutex);
709 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
710 }
711 }
712 pipe_mutex_unlock(vmixer->device->mutex);
713
714 return VDP_STATUS_OK;
715 }
716
717 /**
718 * Retrieve whether features are enabled.
719 */
720 VdpStatus
vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,uint32_t feature_count,VdpVideoMixerFeature const * features,VdpBool * feature_enables)721 vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,
722 uint32_t feature_count,
723 VdpVideoMixerFeature const *features,
724 VdpBool *feature_enables)
725 {
726 vlVdpVideoMixer *vmixer;
727 unsigned i;
728
729 if (!(features && feature_enables))
730 return VDP_STATUS_INVALID_POINTER;
731
732 vmixer = vlGetDataHTAB(mixer);
733 if (!vmixer)
734 return VDP_STATUS_INVALID_HANDLE;
735
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:
750 break;
751
752 case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
753 feature_enables[i] = vmixer->sharpness.enabled;
754 break;
755
756 case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
757 feature_enables[i] = vmixer->noise_reduction.enabled;
758 break;
759
760 case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
761 feature_enables[i] = vmixer->luma_key.enabled;
762 break;
763
764 case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
765 feature_enables[i] = vmixer->bicubic.enabled;
766 break;
767
768 default:
769 return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
770 }
771 }
772
773 return VDP_STATUS_OK;
774 }
775
776 /**
777 * Set attribute values.
778 */
779 VdpStatus
vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer,uint32_t attribute_count,VdpVideoMixerAttribute const * attributes,void const * const * attribute_values)780 vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer,
781 uint32_t attribute_count,
782 VdpVideoMixerAttribute const *attributes,
783 void const *const *attribute_values)
784 {
785 const VdpColor *background_color;
786 union pipe_color_union color;
787 const float *vdp_csc;
788 float val;
789 unsigned i;
790 VdpStatus ret;
791
792 if (!(attributes && attribute_values))
793 return VDP_STATUS_INVALID_POINTER;
794
795 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
796 if (!vmixer)
797 return VDP_STATUS_INVALID_HANDLE;
798
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);
809 break;
810 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
811 vdp_csc = attribute_values[i];
812 vmixer->custom_csc = !!vdp_csc;
813 if (!vdp_csc)
814 vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &vmixer->csc);
815 else
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;
821 goto fail;
822 }
823 break;
824
825 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
826
827 val = *(float*)attribute_values[i];
828 if (val < 0.0f || val > 1.0f) {
829 ret = VDP_STATUS_INVALID_VALUE;
830 goto fail;
831 }
832
833 vmixer->noise_reduction.level = val * 10;
834 vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
835 break;
836
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;
841 goto fail;
842 }
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;
848 goto fail;
849 }
850 break;
851
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;
856 goto fail;
857 }
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;
863 goto fail;
864 }
865 break;
866
867 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
868
869 val = *(float*)attribute_values[i];
870 if (val < -1.0f || val > 1.0f) {
871 ret = VDP_STATUS_INVALID_VALUE;
872 goto fail;
873 }
874
875 vmixer->sharpness.value = val;
876 vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
877 break;
878
879 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
880 if (*(uint8_t*)attribute_values[i] > 1) {
881 ret = VDP_STATUS_INVALID_VALUE;
882 goto fail;
883 }
884 vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i];
885 vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);
886 break;
887 default:
888 ret = VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
889 goto fail;
890 }
891 }
892 pipe_mutex_unlock(vmixer->device->mutex);
893
894 return VDP_STATUS_OK;
895 fail:
896 pipe_mutex_unlock(vmixer->device->mutex);
897 return ret;
898 }
899
900 /**
901 * Retrieve parameter values given at creation time.
902 */
903 VdpStatus
vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer,uint32_t parameter_count,VdpVideoMixerParameter const * parameters,void * const * parameter_values)904 vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer,
905 uint32_t parameter_count,
906 VdpVideoMixerParameter const *parameters,
907 void *const *parameter_values)
908 {
909 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
910 unsigned i;
911 if (!vmixer)
912 return VDP_STATUS_INVALID_HANDLE;
913
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;
922 break;
923 case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
924 *(uint32_t*)parameter_values[i] = vmixer->video_height;
925 break;
926 case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
927 *(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format);
928 break;
929 case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
930 *(uint32_t*)parameter_values[i] = vmixer->max_layers;
931 break;
932 default:
933 return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
934 }
935 }
936 return VDP_STATUS_OK;
937 }
938
939 /**
940 * Retrieve current attribute values.
941 */
942 VdpStatus
vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer,uint32_t attribute_count,VdpVideoMixerAttribute const * attributes,void * const * attribute_values)943 vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer,
944 uint32_t attribute_count,
945 VdpVideoMixerAttribute const *attributes,
946 void *const *attribute_values)
947 {
948 unsigned i;
949 VdpCSCMatrix **vdp_csc;
950
951 if (!(attributes && attribute_values))
952 return VDP_STATUS_INVALID_POINTER;
953
954 vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
955 if (!vmixer)
956 return VDP_STATUS_INVALID_HANDLE;
957
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]);
963 break;
964 case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
965 vdp_csc = attribute_values[i];
966 if (!vmixer->custom_csc) {
967 *vdp_csc = NULL;
968 break;
969 }
970 memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12);
971 break;
972
973 case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
974 *(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f;
975 break;
976
977 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
978 *(float*)attribute_values[i] = vmixer->luma_key.luma_min;
979 break;
980 case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
981 *(float*)attribute_values[i] = vmixer->luma_key.luma_max;
982 break;
983 case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
984 *(float*)attribute_values[i] = vmixer->sharpness.value;
985 break;
986 case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
987 *(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint;
988 break;
989 default:
990 pipe_mutex_unlock(vmixer->device->mutex);
991 return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
992 }
993 }
994 pipe_mutex_unlock(vmixer->device->mutex);
995 return VDP_STATUS_OK;
996 }
997
998 /**
999 * Generate a color space conversion matrix.
1000 */
1001 VdpStatus
vlVdpGenerateCSCMatrix(VdpProcamp * procamp,VdpColorStandard standard,VdpCSCMatrix * csc_matrix)1002 vlVdpGenerateCSCMatrix(VdpProcamp *procamp,
1003 VdpColorStandard standard,
1004 VdpCSCMatrix *csc_matrix)
1005 {
1006 enum VL_CSC_COLOR_STANDARD vl_std;
1007 struct vl_procamp camp;
1008
1009 if (!csc_matrix)
1010 return VDP_STATUS_INVALID_POINTER;
1011
1012 switch (standard) {
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;
1017 }
1018
1019 if (procamp) {
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;
1026 }
1027
1028 vl_csc_get_matrix(vl_std, procamp ? &camp : NULL, true, csc_matrix);
1029 return VDP_STATUS_OK;
1030 }
1031