Subversion Repositories Kolibri OS

Rev

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

  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.  */
  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 = &rect;
  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. }
  789.