[Mesa-dev] [PATCH v4 6/9] st/va: add colospace conversion through Video Post Processing

Christian König deathsimple at vodafone.de
Fri Oct 30 04:54:33 PDT 2015


On 29.10.2015 18:40, Julien Isorce wrote:
> Add support for VPP in the following functions:
> vlVaCreateContext
> vlVaDestroyContext
> vlVaBeginPicture
> vlVaRenderPicture
> vlVaEndPicture
>
> Add support for VAProcFilterNone in:
> vlVaQueryVideoProcFilters
> vlVaQueryVideoProcFilterCaps
> vlVaQueryVideoProcPipelineCaps
>
> Add handleVAProcPipelineParameterBufferType helper.
>
> One application is:
> VASurfaceNV12 -> gstvaapipostproc -> VASurfaceRGBA
>
> Signed-off-by: Julien Isorce <j.isorce at samsung.com>

Reviewed-by: Christian König <christian.koenig at amd.com>

Are you planning to implement the different filters as well? Most of the 
shaders for those are already present.

Regards,
Christian.

> ---
>   src/gallium/state_trackers/va/context.c    | 124 +++++++++++++++++------------
>   src/gallium/state_trackers/va/picture.c    |  81 ++++++++++++++++++-
>   src/gallium/state_trackers/va/surface.c    |  98 ++++++++++++++++++++++-
>   src/gallium/state_trackers/va/va_private.h |   8 ++
>   4 files changed, 259 insertions(+), 52 deletions(-)
>
> diff --git a/src/gallium/state_trackers/va/context.c b/src/gallium/state_trackers/va/context.c
> index 9cc402e..a107cc4 100644
> --- a/src/gallium/state_trackers/va/context.c
> +++ b/src/gallium/state_trackers/va/context.c
> @@ -87,6 +87,14 @@ static struct VADriverVTable vtable =
>      &vlVaQuerySurfaceAttributes
>   };
>   
> +static struct VADriverVTableVPP vtable_vpp =
> +{
> +   1,
> +   &vlVaQueryVideoProcFilters,
> +   &vlVaQueryVideoProcFilterCaps,
> +   &vlVaQueryVideoProcPipelineCaps
> +};
> +
>   PUBLIC VAStatus
>   VA_DRIVER_INIT_FUNC(VADriverContextP ctx)
>   {
> @@ -122,6 +130,7 @@ VA_DRIVER_INIT_FUNC(VADriverContextP ctx)
>      ctx->version_major = 0;
>      ctx->version_minor = 1;
>      *ctx->vtable = vtable;
> +   *ctx->vtable_vpp = vtable_vpp;
>      ctx->max_profiles = PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH - PIPE_VIDEO_PROFILE_UNKNOWN;
>      ctx->max_entrypoints = 1;
>      ctx->max_attributes = 1;
> @@ -151,11 +160,15 @@ vlVaCreateContext(VADriverContextP ctx, VAConfigID config_id, int picture_width,
>      struct pipe_video_codec templat = {};
>      vlVaDriver *drv;
>      vlVaContext *context;
> +   int is_vpp;
>   
>      if (!ctx)
>         return VA_STATUS_ERROR_INVALID_CONTEXT;
>   
> -   if (!(picture_width && picture_height))
> +   is_vpp = config_id == PIPE_VIDEO_PROFILE_UNKNOWN && !picture_width &&
> +            !picture_height && !flag && !render_targets && !num_render_targets;
> +
> +   if (!(picture_width && picture_height) && !is_vpp)
>         return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
>   
>      drv = VL_VA_DRIVER(ctx);
> @@ -163,52 +176,60 @@ vlVaCreateContext(VADriverContextP ctx, VAConfigID config_id, int picture_width,
>      if (!context)
>         return VA_STATUS_ERROR_ALLOCATION_FAILED;
>   
> -   templat.profile = config_id;
> -   templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_BITSTREAM;
> -   templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
> -   templat.width = picture_width;
> -   templat.height = picture_height;
> -   templat.max_references = num_render_targets;
> -   templat.expect_chunked_decode = true;
> -
> -   if (u_reduce_video_profile(templat.profile) ==
> -       PIPE_VIDEO_FORMAT_MPEG4_AVC)
> -      templat.level = u_get_h264_level(templat.width, templat.height,
> -                            &templat.max_references);
> -
> -   context->decoder = drv->pipe->create_video_codec(drv->pipe, &templat);
> -   if (!context->decoder) {
> -      FREE(context);
> -      return VA_STATUS_ERROR_ALLOCATION_FAILED;
> -   }
> -
> -   if (u_reduce_video_profile(context->decoder->profile) ==
> -         PIPE_VIDEO_FORMAT_MPEG4_AVC) {
> -      context->desc.h264.pps = CALLOC_STRUCT(pipe_h264_pps);
> -      if (!context->desc.h264.pps) {
> +   if (is_vpp) {
> +      context->decoder = NULL;
> +      if (!drv->compositor.upload) {
>            FREE(context);
> -         return VA_STATUS_ERROR_ALLOCATION_FAILED;
> +         return VA_STATUS_ERROR_INVALID_CONTEXT;
>         }
> -      context->desc.h264.pps->sps = CALLOC_STRUCT(pipe_h264_sps);
> -      if (!context->desc.h264.pps->sps) {
> -         FREE(context->desc.h264.pps);
> +   } else {
> +      templat.profile = config_id;
> +      templat.entrypoint = PIPE_VIDEO_ENTRYPOINT_BITSTREAM;
> +      templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420;
> +      templat.width = picture_width;
> +      templat.height = picture_height;
> +      templat.max_references = num_render_targets;
> +      templat.expect_chunked_decode = true;
> +
> +      if (u_reduce_video_profile(templat.profile) ==
> +        PIPE_VIDEO_FORMAT_MPEG4_AVC)
> +        templat.level = u_get_h264_level(templat.width, templat.height,
> +                             &templat.max_references);
> +
> +      context->decoder = drv->pipe->create_video_codec(drv->pipe, &templat);
> +      if (!context->decoder) {
>            FREE(context);
>            return VA_STATUS_ERROR_ALLOCATION_FAILED;
>         }
> -   }
>   
> -   if (u_reduce_video_profile(context->decoder->profile) ==
> -         PIPE_VIDEO_FORMAT_HEVC) {
> -      context->desc.h265.pps = CALLOC_STRUCT(pipe_h265_pps);
> -      if (!context->desc.h265.pps) {
> -         FREE(context);
> -         return VA_STATUS_ERROR_ALLOCATION_FAILED;
> +      if (u_reduce_video_profile(context->decoder->profile) ==
> +         PIPE_VIDEO_FORMAT_MPEG4_AVC) {
> +         context->desc.h264.pps = CALLOC_STRUCT(pipe_h264_pps);
> +         if (!context->desc.h264.pps) {
> +            FREE(context);
> +            return VA_STATUS_ERROR_ALLOCATION_FAILED;
> +         }
> +         context->desc.h264.pps->sps = CALLOC_STRUCT(pipe_h264_sps);
> +         if (!context->desc.h264.pps->sps) {
> +            FREE(context->desc.h264.pps);
> +            FREE(context);
> +            return VA_STATUS_ERROR_ALLOCATION_FAILED;
> +         }
>         }
> -      context->desc.h265.pps->sps = CALLOC_STRUCT(pipe_h265_sps);
> -      if (!context->desc.h265.pps->sps) {
> -         FREE(context->desc.h265.pps);
> -         FREE(context);
> -         return VA_STATUS_ERROR_ALLOCATION_FAILED;
> +
> +      if (u_reduce_video_profile(context->decoder->profile) ==
> +            PIPE_VIDEO_FORMAT_HEVC) {
> +         context->desc.h265.pps = CALLOC_STRUCT(pipe_h265_pps);
> +         if (!context->desc.h265.pps) {
> +            FREE(context);
> +            return VA_STATUS_ERROR_ALLOCATION_FAILED;
> +         }
> +         context->desc.h265.pps->sps = CALLOC_STRUCT(pipe_h265_sps);
> +         if (!context->desc.h265.pps->sps) {
> +            FREE(context->desc.h265.pps);
> +            FREE(context);
> +            return VA_STATUS_ERROR_ALLOCATION_FAILED;
> +         }
>         }
>      }
>   
> @@ -229,17 +250,20 @@ vlVaDestroyContext(VADriverContextP ctx, VAContextID context_id)
>   
>      drv = VL_VA_DRIVER(ctx);
>      context = handle_table_get(drv->htab, context_id);
> -   if (u_reduce_video_profile(context->decoder->profile) ==
> -         PIPE_VIDEO_FORMAT_MPEG4_AVC) {
> -      FREE(context->desc.h264.pps->sps);
> -      FREE(context->desc.h264.pps);
> -   }
> -   if (u_reduce_video_profile(context->decoder->profile) ==
> -         PIPE_VIDEO_FORMAT_HEVC) {
> -      FREE(context->desc.h265.pps->sps);
> -      FREE(context->desc.h265.pps);
> +
> +   if (context->decoder) {
> +      if (u_reduce_video_profile(context->decoder->profile) ==
> +            PIPE_VIDEO_FORMAT_MPEG4_AVC) {
> +         FREE(context->desc.h264.pps->sps);
> +         FREE(context->desc.h264.pps);
> +      }
> +      if (u_reduce_video_profile(context->decoder->profile) ==
> +            PIPE_VIDEO_FORMAT_HEVC) {
> +         FREE(context->desc.h265.pps->sps);
> +         FREE(context->desc.h265.pps);
> +      }
> +      context->decoder->destroy(context->decoder);
>      }
> -   context->decoder->destroy(context->decoder);
>      FREE(context);
>      handle_table_remove(drv->htab, context_id);
>   
> diff --git a/src/gallium/state_trackers/va/picture.c b/src/gallium/state_trackers/va/picture.c
> index 9cd496f..e850689 100644
> --- a/src/gallium/state_trackers/va/picture.c
> +++ b/src/gallium/state_trackers/va/picture.c
> @@ -32,6 +32,7 @@
>   #include "util/u_video.h"
>   
>   #include "vl/vl_vlc.h"
> +#include "vl/vl_winsys.h"
>   
>   #include "va_private.h"
>   
> @@ -58,6 +59,16 @@ vlVaBeginPicture(VADriverContextP ctx, VAContextID context_id, VASurfaceID rende
>         return VA_STATUS_ERROR_INVALID_SURFACE;
>   
>      context->target = surf->buffer;
> +
> +   if (!context->decoder) {
> +      /* VPP */
> +      if ((context->target->buffer_format != PIPE_FORMAT_B8G8R8A8_UNORM  &&
> +           context->target->buffer_format != PIPE_FORMAT_R8G8B8A8_UNORM) ||
> +           context->target->interlaced)
> +          return VA_STATUS_ERROR_UNIMPLEMENTED;
> +      return VA_STATUS_SUCCESS;
> +   }
> +
>      context->decoder->begin_frame(context->decoder, context->target, &context->desc.base);
>   
>      return VA_STATUS_SUCCESS;
> @@ -703,11 +714,71 @@ handleVASliceDataBufferType(vlVaContext *context, vlVaBuffer *buf)
>         num_buffers, (const void * const*)buffers, sizes);
>   }
>   
> +static VAStatus
> +handleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf)
> +{
> +    struct u_rect src_rect;
> +    struct u_rect dst_rect;
> +    struct u_rect *dirty_area;
> +    vlVaSurface *src_surface;
> +    VAProcPipelineParameterBuffer *pipeline_param;
> +    struct pipe_surface **surfaces;
> +    struct pipe_screen *screen;
> +    struct pipe_surface *psurf;
> +
> +    if (!drv || !context)
> +       return VA_STATUS_ERROR_INVALID_CONTEXT;
> +
> +    if (!buf || !buf->data)
> +       return VA_STATUS_ERROR_INVALID_BUFFER;
> +
> +    if (!context->target)
> +        return VA_STATUS_ERROR_INVALID_SURFACE;
> +
> +    pipeline_param = (VAProcPipelineParameterBuffer *)buf->data;
> +
> +    src_surface = handle_table_get(drv->htab, pipeline_param->surface);
> +    if (!src_surface || !src_surface->buffer)
> +       return VA_STATUS_ERROR_INVALID_SURFACE;
> +
> +    surfaces = context->target->get_surfaces(context->target);
> +
> +    if (!surfaces || !surfaces[0])
> +        return VA_STATUS_ERROR_INVALID_SURFACE;
> +
> +    screen = drv->pipe->screen;
> +
> +    psurf = surfaces[0];
> +
> +    src_rect.x0 = pipeline_param->surface_region->x;
> +    src_rect.y0 = pipeline_param->surface_region->y;
> +    src_rect.x1 = pipeline_param->surface_region->x + pipeline_param->surface_region->width;
> +    src_rect.y1 = pipeline_param->surface_region->y + pipeline_param->surface_region->height;
> +
> +    dst_rect.x0 = pipeline_param->output_region->x;
> +    dst_rect.y0 = pipeline_param->output_region->y;
> +    dst_rect.x1 = pipeline_param->output_region->x + pipeline_param->output_region->width;
> +    dst_rect.y1 = pipeline_param->output_region->y + pipeline_param->output_region->height;
> +
> +    dirty_area = vl_screen_get_dirty_area(drv->vscreen);
> +
> +    vl_compositor_clear_layers(&drv->cstate);
> +    vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, src_surface->buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE);
> +    vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
> +    vl_compositor_render(&drv->cstate, &drv->compositor, psurf, dirty_area, true);
> +
> +    screen->fence_reference(screen, &src_surface->fence, NULL);
> +    drv->pipe->flush(drv->pipe, &src_surface->fence, 0);
> +
> +    return VA_STATUS_SUCCESS;
> +}
> +
>   VAStatus
>   vlVaRenderPicture(VADriverContextP ctx, VAContextID context_id, VABufferID *buffers, int num_buffers)
>   {
>      vlVaDriver *drv;
>      vlVaContext *context;
> +   VAStatus vaStatus = VA_STATUS_SUCCESS;
>   
>      unsigned i;
>   
> @@ -743,13 +814,16 @@ vlVaRenderPicture(VADriverContextP ctx, VAContextID context_id, VABufferID *buff
>         case VASliceDataBufferType:
>            handleVASliceDataBufferType(context, buf);
>            break;
> +      case VAProcPipelineParameterBufferType:
> +         vaStatus = handleVAProcPipelineParameterBufferType(drv, context, buf);
> +         break;
>   
>         default:
>            break;
>         }
>      }
>   
> -   return VA_STATUS_SUCCESS;
> +   return vaStatus;
>   }
>   
>   VAStatus
> @@ -769,6 +843,11 @@ vlVaEndPicture(VADriverContextP ctx, VAContextID context_id)
>      if (!context)
>         return VA_STATUS_ERROR_INVALID_CONTEXT;
>   
> +   if (!context->decoder) {
> +      /* VPP */
> +      return VA_STATUS_SUCCESS;
> +   }
> +
>      context->mpeg4.frame_num++;
>      context->decoder->end_frame(context->decoder, context->target, &context->desc.base);
>   
> diff --git a/src/gallium/state_trackers/va/surface.c b/src/gallium/state_trackers/va/surface.c
> index c1f7182..50c9cf9 100644
> --- a/src/gallium/state_trackers/va/surface.c
> +++ b/src/gallium/state_trackers/va/surface.c
> @@ -348,7 +348,8 @@ vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config,
>       i = 0;
>   
>       if (config == PIPE_VIDEO_PROFILE_UNKNOWN) {
> -       /* Assume VAEntrypointVideoProc for now. */
> +       /* vlVaCreateConfig returns PIPE_VIDEO_PROFILE_UNKNOWN
> +          only for VAEntrypointVideoProc. */
>          attribs[i].type = VASurfaceAttribPixelFormat;
>          attribs[i].value.type = VAGenericValueTypeInteger;
>          attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
> @@ -638,3 +639,98 @@ no_res:
>   
>      return VA_STATUS_ERROR_ALLOCATION_FAILED;
>   }
> +
> +VAStatus
> +vlVaQueryVideoProcFilters(VADriverContextP ctx, VAContextID context,
> +                          VAProcFilterType *filters, unsigned int *num_filters)
> +{
> +   unsigned int num = 0;
> +
> +   if (!ctx)
> +      return VA_STATUS_ERROR_INVALID_CONTEXT;
> +
> +   if (!num_filters || !filters)
> +      return VA_STATUS_ERROR_INVALID_PARAMETER;
> +
> +   filters[num++] = VAProcFilterNone;
> +
> +   *num_filters = num;
> +
> +   return VA_STATUS_SUCCESS;
> +}
> +
> +VAStatus
> +vlVaQueryVideoProcFilterCaps(VADriverContextP ctx, VAContextID context,
> +                             VAProcFilterType type, void *filter_caps,
> +                             unsigned int *num_filter_caps)
> +{
> +   unsigned int i;
> +
> +   if (!ctx)
> +      return VA_STATUS_ERROR_INVALID_CONTEXT;
> +
> +   if (!filter_caps || !num_filter_caps)
> +      return VA_STATUS_ERROR_INVALID_PARAMETER;
> +
> +   i = 0;
> +
> +   switch (type) {
> +   case VAProcFilterNone:
> +      break;
> +   case VAProcFilterNoiseReduction:
> +   case VAProcFilterDeinterlacing:
> +   case VAProcFilterSharpening:
> +   case VAProcFilterColorBalance:
> +   case VAProcFilterSkinToneEnhancement:
> +      return VA_STATUS_ERROR_UNIMPLEMENTED;
> +   default:
> +      assert(0);
> +   }
> +
> +   *num_filter_caps = i;
> +
> +   return VA_STATUS_SUCCESS;
> +}
> +
> +static VAProcColorStandardType vpp_input_color_standards[VAProcColorStandardCount] = {
> +   VAProcColorStandardBT601
> +};
> +
> +static VAProcColorStandardType vpp_output_color_standards[VAProcColorStandardCount] = {
> +   VAProcColorStandardBT601
> +};
> +
> +VAStatus
> +vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context,
> +                               VABufferID *filters, unsigned int num_filters,
> +                               VAProcPipelineCaps *pipeline_cap)
> +{
> +   unsigned int i = 0;
> +
> +   if (!ctx)
> +      return VA_STATUS_ERROR_INVALID_CONTEXT;
> +
> +   if (!pipeline_cap)
> +   return VA_STATUS_ERROR_INVALID_PARAMETER;
> +
> +   if (num_filters && !filters)
> +      return VA_STATUS_ERROR_INVALID_PARAMETER;
> +
> +   pipeline_cap->pipeline_flags = 0;
> +   pipeline_cap->filter_flags = 0;
> +   pipeline_cap->num_forward_references = 0;
> +   pipeline_cap->num_backward_references = 0;
> +   pipeline_cap->num_input_color_standards = 1;
> +   pipeline_cap->input_color_standards = vpp_input_color_standards;
> +   pipeline_cap->num_output_color_standards = 1;
> +   pipeline_cap->output_color_standards = vpp_output_color_standards;
> +
> +   for (i = 0; i < num_filters; i++) {
> +      vlVaBuffer *buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, filters[i]);
> +
> +      if (!buf || buf->type >= VABufferTypeMax)
> +         return VA_STATUS_ERROR_INVALID_BUFFER;
> +   }
> +
> +   return VA_STATUS_SUCCESS;
> +}
> diff --git a/src/gallium/state_trackers/va/va_private.h b/src/gallium/state_trackers/va/va_private.h
> index 3a02e58..b062357 100644
> --- a/src/gallium/state_trackers/va/va_private.h
> +++ b/src/gallium/state_trackers/va/va_private.h
> @@ -33,6 +33,7 @@
>   
>   #include <va/va.h>
>   #include <va/va_backend.h>
> +#include <va/va_backend_vpp.h>
>   
>   #include "pipe/p_video_enums.h"
>   #include "pipe/p_video_codec.h"
> @@ -324,4 +325,11 @@ VAStatus vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format, unsigned
>                                unsigned int num_attribs);
>   VAStatus vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config, VASurfaceAttrib *attrib_list,
>                                       unsigned int *num_attribs);
> +
> +VAStatus vlVaQueryVideoProcFilters(VADriverContextP ctx, VAContextID context, VAProcFilterType *filters,
> +                                   unsigned int *num_filters);
> +VAStatus vlVaQueryVideoProcFilterCaps(VADriverContextP ctx, VAContextID context, VAProcFilterType type,
> +                                      void *filter_caps, unsigned int *num_filter_caps);
> +VAStatus vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context, VABufferID *filters,
> +                                        unsigned int num_filters, VAProcPipelineCaps *pipeline_cap);
>   #endif //VA_PRIVATE_H



More information about the mesa-dev mailing list