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