Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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