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