Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/frontends/vdpau/mixer.c
4565 views
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
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_size, i;
53
54
vlVdpDevice *dev = vlGetDataHTAB(device);
55
if (!dev)
56
return VDP_STATUS_INVALID_HANDLE;
57
screen = dev->vscreen->pscreen;
58
59
vmixer = CALLOC(1, sizeof(vlVdpVideoMixer));
60
if (!vmixer)
61
return VDP_STATUS_RESOURCES;
62
63
DeviceReference(&vmixer->device, dev);
64
65
mtx_lock(&dev->mutex);
66
67
if (!vl_compositor_init_state(&vmixer->cstate, dev->context)) {
68
ret = VDP_STATUS_ERROR;
69
goto no_compositor_state;
70
}
71
72
vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, true, &vmixer->csc);
73
if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE)) {
74
if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc, 1.0f, 0.0f)) {
75
ret = VDP_STATUS_ERROR;
76
goto err_csc_matrix;
77
}
78
}
79
80
*mixer = vlAddDataHTAB(vmixer);
81
if (*mixer == 0) {
82
ret = VDP_STATUS_ERROR;
83
goto no_handle;
84
}
85
86
ret = VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
87
for (i = 0; i < feature_count; ++i) {
88
switch (features[i]) {
89
/* they are valid, but we doesn't support them */
90
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
91
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
92
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
93
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
94
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
95
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
96
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
97
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
98
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
99
case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
100
break;
101
102
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
103
vmixer->deint.supported = true;
104
break;
105
106
case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
107
vmixer->sharpness.supported = true;
108
break;
109
110
case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
111
vmixer->noise_reduction.supported = true;
112
break;
113
114
case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
115
vmixer->luma_key.supported = true;
116
break;
117
118
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
119
vmixer->bicubic.supported = true;
120
break;
121
default: goto no_params;
122
}
123
}
124
125
vmixer->chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
126
ret = VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
127
for (i = 0; i < parameter_count; ++i) {
128
switch (parameters[i]) {
129
case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
130
vmixer->video_width = *(uint32_t*)parameter_values[i];
131
break;
132
case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
133
vmixer->video_height = *(uint32_t*)parameter_values[i];
134
break;
135
case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
136
vmixer->chroma_format = ChromaToPipe(*(VdpChromaType*)parameter_values[i]);
137
break;
138
case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
139
vmixer->max_layers = *(uint32_t*)parameter_values[i];
140
break;
141
default: goto no_params;
142
}
143
}
144
ret = VDP_STATUS_INVALID_VALUE;
145
if (vmixer->max_layers > 4) {
146
VDPAU_MSG(VDPAU_WARN, "[VDPAU] Max layers %u > 4 not supported\n", vmixer->max_layers);
147
goto no_params;
148
}
149
150
max_size = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_SIZE);
151
if (vmixer->video_width < 48 || vmixer->video_width > max_size) {
152
VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for width\n",
153
vmixer->video_width, max_size);
154
goto no_params;
155
}
156
if (vmixer->video_height < 48 || vmixer->video_height > max_size) {
157
VDPAU_MSG(VDPAU_WARN, "[VDPAU] 48 < %u < %u not valid for height\n",
158
vmixer->video_height, max_size);
159
goto no_params;
160
}
161
vmixer->luma_key.luma_min = 1.0f;
162
vmixer->luma_key.luma_max = 0.0f;
163
mtx_unlock(&dev->mutex);
164
165
return VDP_STATUS_OK;
166
167
no_params:
168
vlRemoveDataHTAB(*mixer);
169
170
no_handle:
171
err_csc_matrix:
172
vl_compositor_cleanup_state(&vmixer->cstate);
173
no_compositor_state:
174
mtx_unlock(&dev->mutex);
175
DeviceReference(&vmixer->device, NULL);
176
FREE(vmixer);
177
return ret;
178
}
179
180
/**
181
* Destroy a VdpVideoMixer.
182
*/
183
VdpStatus
184
vlVdpVideoMixerDestroy(VdpVideoMixer mixer)
185
{
186
vlVdpVideoMixer *vmixer;
187
188
vmixer = vlGetDataHTAB(mixer);
189
if (!vmixer)
190
return VDP_STATUS_INVALID_HANDLE;
191
192
mtx_lock(&vmixer->device->mutex);
193
194
vlRemoveDataHTAB(mixer);
195
196
vl_compositor_cleanup_state(&vmixer->cstate);
197
198
if (vmixer->deint.filter) {
199
vl_deint_filter_cleanup(vmixer->deint.filter);
200
FREE(vmixer->deint.filter);
201
}
202
203
if (vmixer->noise_reduction.filter) {
204
vl_median_filter_cleanup(vmixer->noise_reduction.filter);
205
FREE(vmixer->noise_reduction.filter);
206
}
207
208
if (vmixer->sharpness.filter) {
209
vl_matrix_filter_cleanup(vmixer->sharpness.filter);
210
FREE(vmixer->sharpness.filter);
211
}
212
213
if (vmixer->bicubic.filter) {
214
vl_bicubic_filter_cleanup(vmixer->bicubic.filter);
215
FREE(vmixer->bicubic.filter);
216
}
217
mtx_unlock(&vmixer->device->mutex);
218
DeviceReference(&vmixer->device, NULL);
219
220
FREE(vmixer);
221
222
return VDP_STATUS_OK;
223
}
224
225
/**
226
* Perform a video post-processing and compositing operation.
227
*/
228
VdpStatus vlVdpVideoMixerRender(VdpVideoMixer mixer,
229
VdpOutputSurface background_surface,
230
VdpRect const *background_source_rect,
231
VdpVideoMixerPictureStructure current_picture_structure,
232
uint32_t video_surface_past_count,
233
VdpVideoSurface const *video_surface_past,
234
VdpVideoSurface video_surface_current,
235
uint32_t video_surface_future_count,
236
VdpVideoSurface const *video_surface_future,
237
VdpRect const *video_source_rect,
238
VdpOutputSurface destination_surface,
239
VdpRect const *destination_rect,
240
VdpRect const *destination_video_rect,
241
uint32_t layer_count,
242
VdpLayer const *layers)
243
{
244
enum vl_compositor_deinterlace deinterlace;
245
struct u_rect rect, clip, *prect, dirty_area;
246
unsigned i, layer = 0;
247
struct pipe_video_buffer *video_buffer;
248
struct pipe_sampler_view *sampler_view, sv_templ;
249
struct pipe_surface *surface, surf_templ;
250
struct pipe_context *pipe = NULL;
251
struct pipe_resource res_tmpl, *res;
252
253
vlVdpVideoMixer *vmixer;
254
vlVdpSurface *surf;
255
vlVdpOutputSurface *dst, *bg = NULL;
256
257
struct vl_compositor *compositor;
258
259
vmixer = vlGetDataHTAB(mixer);
260
if (!vmixer)
261
return VDP_STATUS_INVALID_HANDLE;
262
263
compositor = &vmixer->device->compositor;
264
265
surf = vlGetDataHTAB(video_surface_current);
266
if (!surf)
267
return VDP_STATUS_INVALID_HANDLE;
268
video_buffer = surf->video_buffer;
269
270
if (surf->device != vmixer->device)
271
return VDP_STATUS_HANDLE_DEVICE_MISMATCH;
272
273
if (vmixer->video_width > video_buffer->width ||
274
vmixer->video_height > video_buffer->height ||
275
vmixer->chroma_format != pipe_format_to_chroma_format(video_buffer->buffer_format))
276
return VDP_STATUS_INVALID_SIZE;
277
278
if (layer_count > vmixer->max_layers)
279
return VDP_STATUS_INVALID_VALUE;
280
281
dst = vlGetDataHTAB(destination_surface);
282
if (!dst)
283
return VDP_STATUS_INVALID_HANDLE;
284
285
if (background_surface != VDP_INVALID_HANDLE) {
286
bg = vlGetDataHTAB(background_surface);
287
if (!bg)
288
return VDP_STATUS_INVALID_HANDLE;
289
}
290
291
mtx_lock(&vmixer->device->mutex);
292
293
vl_compositor_clear_layers(&vmixer->cstate);
294
295
if (bg)
296
vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer++, bg->sampler_view,
297
RectToPipe(background_source_rect, &rect), NULL, NULL);
298
299
switch (current_picture_structure) {
300
case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD:
301
deinterlace = VL_COMPOSITOR_BOB_TOP;
302
break;
303
304
case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:
305
deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
306
break;
307
308
case VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME:
309
deinterlace = VL_COMPOSITOR_WEAVE;
310
break;
311
312
default:
313
mtx_unlock(&vmixer->device->mutex);
314
return VDP_STATUS_INVALID_VIDEO_MIXER_PICTURE_STRUCTURE;
315
}
316
317
if (deinterlace != VL_COMPOSITOR_WEAVE && vmixer->deint.enabled &&
318
video_surface_past_count > 1 && video_surface_future_count > 0) {
319
vlVdpSurface *prevprev = vlGetDataHTAB(video_surface_past[1]);
320
vlVdpSurface *prev = vlGetDataHTAB(video_surface_past[0]);
321
vlVdpSurface *next = vlGetDataHTAB(video_surface_future[0]);
322
if (prevprev && prev && next &&
323
vl_deint_filter_check_buffers(vmixer->deint.filter,
324
prevprev->video_buffer, prev->video_buffer, surf->video_buffer, next->video_buffer)) {
325
vl_deint_filter_render(vmixer->deint.filter, prevprev->video_buffer,
326
prev->video_buffer, surf->video_buffer,
327
next->video_buffer,
328
deinterlace == VL_COMPOSITOR_BOB_BOTTOM);
329
deinterlace = VL_COMPOSITOR_WEAVE;
330
video_buffer = vmixer->deint.filter->video_buffer;
331
}
332
}
333
334
if (!destination_video_rect)
335
destination_video_rect = video_source_rect;
336
337
prect = RectToPipe(video_source_rect, &rect);
338
if (!prect) {
339
rect.x0 = 0;
340
rect.y0 = 0;
341
rect.x1 = surf->templat.width;
342
rect.y1 = surf->templat.height;
343
prect = &rect;
344
}
345
vl_compositor_set_buffer_layer(&vmixer->cstate, compositor, layer, video_buffer, prect, NULL, deinterlace);
346
347
if (vmixer->bicubic.filter || vmixer->sharpness.filter || vmixer->noise_reduction.filter) {
348
pipe = vmixer->device->context;
349
memset(&res_tmpl, 0, sizeof(res_tmpl));
350
351
res_tmpl.target = PIPE_TEXTURE_2D;
352
res_tmpl.format = dst->sampler_view->format;
353
res_tmpl.depth0 = 1;
354
res_tmpl.array_size = 1;
355
res_tmpl.bind = PIPE_BIND_SAMPLER_VIEW | PIPE_BIND_RENDER_TARGET;
356
res_tmpl.usage = PIPE_USAGE_DEFAULT;
357
358
if (!vmixer->bicubic.filter) {
359
res_tmpl.width0 = dst->surface->width;
360
res_tmpl.height0 = dst->surface->height;
361
} else {
362
res_tmpl.width0 = surf->templat.width;
363
res_tmpl.height0 = surf->templat.height;
364
}
365
366
res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
367
368
vlVdpDefaultSamplerViewTemplate(&sv_templ, res);
369
sampler_view = pipe->create_sampler_view(pipe, res, &sv_templ);
370
371
memset(&surf_templ, 0, sizeof(surf_templ));
372
surf_templ.format = res->format;
373
surface = pipe->create_surface(pipe, res, &surf_templ);
374
375
vl_compositor_reset_dirty_area(&dirty_area);
376
pipe_resource_reference(&res, NULL);
377
} else {
378
surface = dst->surface;
379
sampler_view = dst->sampler_view;
380
dirty_area = dst->dirty_area;
381
}
382
383
if (!vmixer->bicubic.filter) {
384
vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(destination_video_rect, &rect));
385
vl_compositor_set_dst_clip(&vmixer->cstate, RectToPipe(destination_rect, &clip));
386
}
387
388
for (i = 0; i < layer_count; ++i) {
389
vlVdpOutputSurface *src = vlGetDataHTAB(layers->source_surface);
390
if (!src) {
391
mtx_unlock(&vmixer->device->mutex);
392
return VDP_STATUS_INVALID_HANDLE;
393
}
394
395
assert(layers->struct_version == VDP_LAYER_VERSION);
396
397
vl_compositor_set_rgba_layer(&vmixer->cstate, compositor, layer, src->sampler_view,
398
RectToPipe(layers->source_rect, &rect), NULL, NULL);
399
vl_compositor_set_layer_dst_area(&vmixer->cstate, layer++, RectToPipe(layers->destination_rect, &rect));
400
401
++layers;
402
}
403
404
vl_compositor_render(&vmixer->cstate, compositor, surface, &dirty_area, true);
405
406
if (vmixer->noise_reduction.filter) {
407
if (!vmixer->sharpness.filter && !vmixer->bicubic.filter) {
408
vl_median_filter_render(vmixer->noise_reduction.filter,
409
sampler_view, dst->surface);
410
} else {
411
res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
412
struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ);
413
struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ);
414
pipe_resource_reference(&res, NULL);
415
416
vl_median_filter_render(vmixer->noise_reduction.filter,
417
sampler_view, surface_temp);
418
419
pipe_sampler_view_reference(&sampler_view, NULL);
420
pipe_surface_reference(&surface, NULL);
421
422
sampler_view = sampler_view_temp;
423
surface = surface_temp;
424
}
425
}
426
427
if (vmixer->sharpness.filter) {
428
if (!vmixer->bicubic.filter) {
429
vl_matrix_filter_render(vmixer->sharpness.filter,
430
sampler_view, dst->surface);
431
} else {
432
res = pipe->screen->resource_create(pipe->screen, &res_tmpl);
433
struct pipe_sampler_view *sampler_view_temp = pipe->create_sampler_view(pipe, res, &sv_templ);
434
struct pipe_surface *surface_temp = pipe->create_surface(pipe, res, &surf_templ);
435
pipe_resource_reference(&res, NULL);
436
437
vl_matrix_filter_render(vmixer->sharpness.filter,
438
sampler_view, surface_temp);
439
440
pipe_sampler_view_reference(&sampler_view, NULL);
441
pipe_surface_reference(&surface, NULL);
442
443
sampler_view = sampler_view_temp;
444
surface = surface_temp;
445
}
446
}
447
448
if (vmixer->bicubic.filter)
449
vl_bicubic_filter_render(vmixer->bicubic.filter,
450
sampler_view, dst->surface,
451
RectToPipe(destination_video_rect, &rect),
452
RectToPipe(destination_rect, &clip));
453
454
if(surface != dst->surface) {
455
pipe_sampler_view_reference(&sampler_view, NULL);
456
pipe_surface_reference(&surface, NULL);
457
}
458
mtx_unlock(&vmixer->device->mutex);
459
460
return VDP_STATUS_OK;
461
}
462
463
static void
464
vlVdpVideoMixerUpdateDeinterlaceFilter(vlVdpVideoMixer *vmixer)
465
{
466
struct pipe_context *pipe = vmixer->device->context;
467
assert(vmixer);
468
469
/* remove existing filter */
470
if (vmixer->deint.filter) {
471
vl_deint_filter_cleanup(vmixer->deint.filter);
472
FREE(vmixer->deint.filter);
473
vmixer->deint.filter = NULL;
474
}
475
476
/* create a new filter if requested */
477
if (vmixer->deint.enabled && vmixer->chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) {
478
vmixer->deint.filter = MALLOC(sizeof(struct vl_deint_filter));
479
vmixer->deint.enabled = vl_deint_filter_init(vmixer->deint.filter, pipe,
480
vmixer->video_width, vmixer->video_height,
481
vmixer->skip_chroma_deint, vmixer->deint.spatial);
482
if (!vmixer->deint.enabled) {
483
FREE(vmixer->deint.filter);
484
}
485
}
486
}
487
488
/**
489
* Update the noise reduction setting
490
*/
491
static void
492
vlVdpVideoMixerUpdateNoiseReductionFilter(vlVdpVideoMixer *vmixer)
493
{
494
assert(vmixer);
495
496
/* if present remove the old filter first */
497
if (vmixer->noise_reduction.filter) {
498
vl_median_filter_cleanup(vmixer->noise_reduction.filter);
499
FREE(vmixer->noise_reduction.filter);
500
vmixer->noise_reduction.filter = NULL;
501
}
502
503
/* and create a new filter as needed */
504
if (vmixer->noise_reduction. enabled && vmixer->noise_reduction.level > 0) {
505
vmixer->noise_reduction.filter = MALLOC(sizeof(struct vl_median_filter));
506
vl_median_filter_init(vmixer->noise_reduction.filter, vmixer->device->context,
507
vmixer->video_width, vmixer->video_height,
508
vmixer->noise_reduction.level + 1,
509
VL_MEDIAN_FILTER_CROSS);
510
}
511
}
512
513
static void
514
vlVdpVideoMixerUpdateSharpnessFilter(vlVdpVideoMixer *vmixer)
515
{
516
assert(vmixer);
517
518
/* if present remove the old filter first */
519
if (vmixer->sharpness.filter) {
520
vl_matrix_filter_cleanup(vmixer->sharpness.filter);
521
FREE(vmixer->sharpness.filter);
522
vmixer->sharpness.filter = NULL;
523
}
524
525
/* and create a new filter as needed */
526
if (vmixer->sharpness.enabled && vmixer->sharpness.value != 0.0f) {
527
float matrix[9];
528
unsigned i;
529
530
if (vmixer->sharpness.value > 0.0f) {
531
matrix[0] = -1.0f; matrix[1] = -1.0f; matrix[2] = -1.0f;
532
matrix[3] = -1.0f; matrix[4] = 8.0f; matrix[5] = -1.0f;
533
matrix[6] = -1.0f; matrix[7] = -1.0f; matrix[8] = -1.0f;
534
535
for (i = 0; i < 9; ++i)
536
matrix[i] *= vmixer->sharpness.value;
537
538
matrix[4] += 1.0f;
539
540
} else {
541
matrix[0] = 1.0f; matrix[1] = 2.0f; matrix[2] = 1.0f;
542
matrix[3] = 2.0f; matrix[4] = 4.0f; matrix[5] = 2.0f;
543
matrix[6] = 1.0f; matrix[7] = 2.0f; matrix[8] = 1.0f;
544
545
for (i = 0; i < 9; ++i)
546
matrix[i] *= fabsf(vmixer->sharpness.value) / 16.0f;
547
548
matrix[4] += 1.0f - fabsf(vmixer->sharpness.value);
549
}
550
551
vmixer->sharpness.filter = MALLOC(sizeof(struct vl_matrix_filter));
552
vl_matrix_filter_init(vmixer->sharpness.filter, vmixer->device->context,
553
vmixer->video_width, vmixer->video_height,
554
3, 3, matrix);
555
}
556
}
557
558
/**
559
* Update the bicubic filter
560
*/
561
static void
562
vlVdpVideoMixerUpdateBicubicFilter(vlVdpVideoMixer *vmixer)
563
{
564
assert(vmixer);
565
566
/* if present remove the old filter first */
567
if (vmixer->bicubic.filter) {
568
vl_bicubic_filter_cleanup(vmixer->bicubic.filter);
569
FREE(vmixer->bicubic.filter);
570
vmixer->bicubic.filter = NULL;
571
}
572
/* and create a new filter as needed */
573
if (vmixer->bicubic.enabled) {
574
vmixer->bicubic.filter = MALLOC(sizeof(struct vl_bicubic_filter));
575
vl_bicubic_filter_init(vmixer->bicubic.filter, vmixer->device->context,
576
vmixer->video_width, vmixer->video_height);
577
}
578
}
579
580
/**
581
* Retrieve whether features were requested at creation time.
582
*/
583
VdpStatus
584
vlVdpVideoMixerGetFeatureSupport(VdpVideoMixer mixer,
585
uint32_t feature_count,
586
VdpVideoMixerFeature const *features,
587
VdpBool *feature_supports)
588
{
589
vlVdpVideoMixer *vmixer;
590
unsigned i;
591
592
if (!(features && feature_supports))
593
return VDP_STATUS_INVALID_POINTER;
594
595
vmixer = vlGetDataHTAB(mixer);
596
if (!vmixer)
597
return VDP_STATUS_INVALID_HANDLE;
598
599
for (i = 0; i < feature_count; ++i) {
600
switch (features[i]) {
601
/* they are valid, but we doesn't support them */
602
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
603
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
604
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
605
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
606
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
607
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
608
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
609
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
610
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
611
case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
612
feature_supports[i] = false;
613
break;
614
615
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
616
feature_supports[i] = vmixer->deint.supported;
617
break;
618
619
case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
620
feature_supports[i] = vmixer->sharpness.supported;
621
break;
622
623
case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
624
feature_supports[i] = vmixer->noise_reduction.supported;
625
break;
626
627
case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
628
feature_supports[i] = vmixer->luma_key.supported;
629
break;
630
631
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
632
feature_supports[i] = vmixer->bicubic.supported;
633
break;
634
635
default:
636
return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
637
}
638
}
639
640
return VDP_STATUS_OK;
641
}
642
643
/**
644
* Enable or disable features.
645
*/
646
VdpStatus
647
vlVdpVideoMixerSetFeatureEnables(VdpVideoMixer mixer,
648
uint32_t feature_count,
649
VdpVideoMixerFeature const *features,
650
VdpBool const *feature_enables)
651
{
652
vlVdpVideoMixer *vmixer;
653
unsigned i;
654
655
if (!(features && feature_enables))
656
return VDP_STATUS_INVALID_POINTER;
657
658
vmixer = vlGetDataHTAB(mixer);
659
if (!vmixer)
660
return VDP_STATUS_INVALID_HANDLE;
661
662
mtx_lock(&vmixer->device->mutex);
663
for (i = 0; i < feature_count; ++i) {
664
switch (features[i]) {
665
/* they are valid, but we doesn't support them */
666
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
667
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
668
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
669
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
670
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
671
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
672
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
673
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
674
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
675
case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
676
break;
677
678
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
679
vmixer->deint.enabled = feature_enables[i];
680
vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);
681
break;
682
683
case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
684
vmixer->sharpness.enabled = feature_enables[i];
685
vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
686
break;
687
688
case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
689
vmixer->noise_reduction.enabled = feature_enables[i];
690
vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
691
break;
692
693
case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
694
vmixer->luma_key.enabled = feature_enables[i];
695
if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
696
if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
697
vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
698
mtx_unlock(&vmixer->device->mutex);
699
return VDP_STATUS_ERROR;
700
}
701
break;
702
703
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
704
vmixer->bicubic.enabled = feature_enables[i];
705
vlVdpVideoMixerUpdateBicubicFilter(vmixer);
706
break;
707
708
default:
709
mtx_unlock(&vmixer->device->mutex);
710
return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
711
}
712
}
713
mtx_unlock(&vmixer->device->mutex);
714
715
return VDP_STATUS_OK;
716
}
717
718
/**
719
* Retrieve whether features are enabled.
720
*/
721
VdpStatus
722
vlVdpVideoMixerGetFeatureEnables(VdpVideoMixer mixer,
723
uint32_t feature_count,
724
VdpVideoMixerFeature const *features,
725
VdpBool *feature_enables)
726
{
727
vlVdpVideoMixer *vmixer;
728
unsigned i;
729
730
if (!(features && feature_enables))
731
return VDP_STATUS_INVALID_POINTER;
732
733
vmixer = vlGetDataHTAB(mixer);
734
if (!vmixer)
735
return VDP_STATUS_INVALID_HANDLE;
736
737
for (i = 0; i < feature_count; ++i) {
738
switch (features[i]) {
739
/* they are valid, but we doesn't support them */
740
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL:
741
case VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL:
742
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L2:
743
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L3:
744
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L4:
745
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L5:
746
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L6:
747
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L7:
748
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L8:
749
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L9:
750
case VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE:
751
break;
752
753
case VDP_VIDEO_MIXER_FEATURE_SHARPNESS:
754
feature_enables[i] = vmixer->sharpness.enabled;
755
break;
756
757
case VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION:
758
feature_enables[i] = vmixer->noise_reduction.enabled;
759
break;
760
761
case VDP_VIDEO_MIXER_FEATURE_LUMA_KEY:
762
feature_enables[i] = vmixer->luma_key.enabled;
763
break;
764
765
case VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1:
766
feature_enables[i] = vmixer->bicubic.enabled;
767
break;
768
769
default:
770
return VDP_STATUS_INVALID_VIDEO_MIXER_FEATURE;
771
}
772
}
773
774
return VDP_STATUS_OK;
775
}
776
777
/**
778
* Set attribute values.
779
*/
780
VdpStatus
781
vlVdpVideoMixerSetAttributeValues(VdpVideoMixer mixer,
782
uint32_t attribute_count,
783
VdpVideoMixerAttribute const *attributes,
784
void const *const *attribute_values)
785
{
786
const VdpColor *background_color;
787
union pipe_color_union color;
788
const float *vdp_csc;
789
float val;
790
unsigned i;
791
VdpStatus ret;
792
793
if (!(attributes && attribute_values))
794
return VDP_STATUS_INVALID_POINTER;
795
796
vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
797
if (!vmixer)
798
return VDP_STATUS_INVALID_HANDLE;
799
800
mtx_lock(&vmixer->device->mutex);
801
for (i = 0; i < attribute_count; ++i) {
802
switch (attributes[i]) {
803
case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
804
background_color = attribute_values[i];
805
color.f[0] = background_color->red;
806
color.f[1] = background_color->green;
807
color.f[2] = background_color->blue;
808
color.f[3] = background_color->alpha;
809
vl_compositor_set_clear_color(&vmixer->cstate, &color);
810
break;
811
case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
812
vdp_csc = attribute_values[i];
813
vmixer->custom_csc = !!vdp_csc;
814
if (!vdp_csc)
815
vl_csc_get_matrix(VL_CSC_COLOR_STANDARD_BT_601, NULL, 1, &vmixer->csc);
816
else
817
memcpy(vmixer->csc, vdp_csc, sizeof(vl_csc_matrix));
818
if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
819
if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
820
vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
821
ret = VDP_STATUS_ERROR;
822
goto fail;
823
}
824
break;
825
826
case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
827
828
val = *(float*)attribute_values[i];
829
if (val < 0.0f || val > 1.0f) {
830
ret = VDP_STATUS_INVALID_VALUE;
831
goto fail;
832
}
833
834
vmixer->noise_reduction.level = val * 10;
835
vlVdpVideoMixerUpdateNoiseReductionFilter(vmixer);
836
break;
837
838
case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
839
val = *(float*)attribute_values[i];
840
if (val < 0.0f || val > 1.0f) {
841
ret = VDP_STATUS_INVALID_VALUE;
842
goto fail;
843
}
844
vmixer->luma_key.luma_min = val;
845
if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
846
if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
847
vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
848
ret = VDP_STATUS_ERROR;
849
goto fail;
850
}
851
break;
852
853
case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
854
val = *(float*)attribute_values[i];
855
if (val < 0.0f || val > 1.0f) {
856
ret = VDP_STATUS_INVALID_VALUE;
857
goto fail;
858
}
859
vmixer->luma_key.luma_max = val;
860
if (!debug_get_bool_option("G3DVL_NO_CSC", FALSE))
861
if (!vl_compositor_set_csc_matrix(&vmixer->cstate, (const vl_csc_matrix *)&vmixer->csc,
862
vmixer->luma_key.luma_min, vmixer->luma_key.luma_max)) {
863
ret = VDP_STATUS_ERROR;
864
goto fail;
865
}
866
break;
867
868
case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
869
870
val = *(float*)attribute_values[i];
871
if (val < -1.0f || val > 1.0f) {
872
ret = VDP_STATUS_INVALID_VALUE;
873
goto fail;
874
}
875
876
vmixer->sharpness.value = val;
877
vlVdpVideoMixerUpdateSharpnessFilter(vmixer);
878
break;
879
880
case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
881
if (*(uint8_t*)attribute_values[i] > 1) {
882
ret = VDP_STATUS_INVALID_VALUE;
883
goto fail;
884
}
885
vmixer->skip_chroma_deint = *(uint8_t*)attribute_values[i];
886
vlVdpVideoMixerUpdateDeinterlaceFilter(vmixer);
887
break;
888
default:
889
ret = VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
890
goto fail;
891
}
892
}
893
mtx_unlock(&vmixer->device->mutex);
894
895
return VDP_STATUS_OK;
896
fail:
897
mtx_unlock(&vmixer->device->mutex);
898
return ret;
899
}
900
901
/**
902
* Retrieve parameter values given at creation time.
903
*/
904
VdpStatus
905
vlVdpVideoMixerGetParameterValues(VdpVideoMixer mixer,
906
uint32_t parameter_count,
907
VdpVideoMixerParameter const *parameters,
908
void *const *parameter_values)
909
{
910
vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
911
unsigned i;
912
if (!vmixer)
913
return VDP_STATUS_INVALID_HANDLE;
914
915
if (!parameter_count)
916
return VDP_STATUS_OK;
917
if (!(parameters && parameter_values))
918
return VDP_STATUS_INVALID_POINTER;
919
for (i = 0; i < parameter_count; ++i) {
920
switch (parameters[i]) {
921
case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH:
922
*(uint32_t*)parameter_values[i] = vmixer->video_width;
923
break;
924
case VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT:
925
*(uint32_t*)parameter_values[i] = vmixer->video_height;
926
break;
927
case VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE:
928
*(VdpChromaType*)parameter_values[i] = PipeToChroma(vmixer->chroma_format);
929
break;
930
case VDP_VIDEO_MIXER_PARAMETER_LAYERS:
931
*(uint32_t*)parameter_values[i] = vmixer->max_layers;
932
break;
933
default:
934
return VDP_STATUS_INVALID_VIDEO_MIXER_PARAMETER;
935
}
936
}
937
return VDP_STATUS_OK;
938
}
939
940
/**
941
* Retrieve current attribute values.
942
*/
943
VdpStatus
944
vlVdpVideoMixerGetAttributeValues(VdpVideoMixer mixer,
945
uint32_t attribute_count,
946
VdpVideoMixerAttribute const *attributes,
947
void *const *attribute_values)
948
{
949
unsigned i;
950
VdpCSCMatrix **vdp_csc;
951
952
if (!(attributes && attribute_values))
953
return VDP_STATUS_INVALID_POINTER;
954
955
vlVdpVideoMixer *vmixer = vlGetDataHTAB(mixer);
956
if (!vmixer)
957
return VDP_STATUS_INVALID_HANDLE;
958
959
mtx_lock(&vmixer->device->mutex);
960
for (i = 0; i < attribute_count; ++i) {
961
switch (attributes[i]) {
962
case VDP_VIDEO_MIXER_ATTRIBUTE_BACKGROUND_COLOR:
963
vl_compositor_get_clear_color(&vmixer->cstate, attribute_values[i]);
964
break;
965
case VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX:
966
vdp_csc = attribute_values[i];
967
if (!vmixer->custom_csc) {
968
*vdp_csc = NULL;
969
break;
970
}
971
memcpy(*vdp_csc, vmixer->csc, sizeof(float)*12);
972
break;
973
974
case VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL:
975
*(float*)attribute_values[i] = (float)vmixer->noise_reduction.level / 10.0f;
976
break;
977
978
case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MIN_LUMA:
979
*(float*)attribute_values[i] = vmixer->luma_key.luma_min;
980
break;
981
case VDP_VIDEO_MIXER_ATTRIBUTE_LUMA_KEY_MAX_LUMA:
982
*(float*)attribute_values[i] = vmixer->luma_key.luma_max;
983
break;
984
case VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL:
985
*(float*)attribute_values[i] = vmixer->sharpness.value;
986
break;
987
case VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE:
988
*(uint8_t*)attribute_values[i] = vmixer->skip_chroma_deint;
989
break;
990
default:
991
mtx_unlock(&vmixer->device->mutex);
992
return VDP_STATUS_INVALID_VIDEO_MIXER_ATTRIBUTE;
993
}
994
}
995
mtx_unlock(&vmixer->device->mutex);
996
return VDP_STATUS_OK;
997
}
998
999
/**
1000
* Generate a color space conversion matrix.
1001
*/
1002
VdpStatus
1003
vlVdpGenerateCSCMatrix(VdpProcamp *procamp,
1004
VdpColorStandard standard,
1005
VdpCSCMatrix *csc_matrix)
1006
{
1007
enum VL_CSC_COLOR_STANDARD vl_std;
1008
struct vl_procamp camp;
1009
1010
if (!csc_matrix)
1011
return VDP_STATUS_INVALID_POINTER;
1012
1013
switch (standard) {
1014
case VDP_COLOR_STANDARD_ITUR_BT_601: vl_std = VL_CSC_COLOR_STANDARD_BT_601; break;
1015
case VDP_COLOR_STANDARD_ITUR_BT_709: vl_std = VL_CSC_COLOR_STANDARD_BT_709; break;
1016
case VDP_COLOR_STANDARD_SMPTE_240M: vl_std = VL_CSC_COLOR_STANDARD_SMPTE_240M; break;
1017
default: return VDP_STATUS_INVALID_COLOR_STANDARD;
1018
}
1019
1020
if (procamp) {
1021
if (procamp->struct_version > VDP_PROCAMP_VERSION)
1022
return VDP_STATUS_INVALID_STRUCT_VERSION;
1023
camp.brightness = procamp->brightness;
1024
camp.contrast = procamp->contrast;
1025
camp.saturation = procamp->saturation;
1026
camp.hue = procamp->hue;
1027
}
1028
1029
vl_csc_get_matrix(vl_std, procamp ? &camp : NULL, true, csc_matrix);
1030
return VDP_STATUS_OK;
1031
}
1032
1033