[Mesa-dev] [PATCH 6/7] st/va: add initial Video Post Processing support
Julien Isorce
julien.isorce at gmail.com
Thu Oct 22 09:03:10 PDT 2015
Hi,
Thx for your review. I'll submit a new version of the patch. Just replying
here first to answer your questions:
On 19 October 2015 at 18:10, Emil Velikov <emil.l.velikov at gmail.com> wrote:
> On 17 October 2015 at 00:14, Julien Isorce <julien.isorce at gmail.com>
> wrote:
> > Improve following functions to support VA_PROFILE_NONE profile (vpp):
> > vlVaQueryConfigProfiles
> > vlVaQueryConfigEntrypoints
> > vlVaCreateConfig
> > vlVaQueryConfigAttributes
> >
> > Add VADriverVTableVPP and improve following functions to support vpp:
> > vlVaCreateContext
> > vlVaDestroyContext
> > vlVaBeginPicture
> > vlVaRenderPicture
> > vlVaEndPicture
> >
> Please split into two patches - roughly as per above grouping or
> otherwise you feel is appropriate.
>
oki I'll split as above.
>
> > Add handleVAProcPipelineParameterBufferType helper.
> >
> > One of the application is:
> > VASurfaceNV12 -> gstvaapipostproc -> VASurfaceRGBA
> >
> > Signed-off-by: Julien Isorce <j.isorce at samsung.com>
> > ---
> > src/gallium/state_trackers/va/config.c | 20 +++++++
> > src/gallium/state_trackers/va/context.c | 94
> +++++++++++++++++++-----------
> > src/gallium/state_trackers/va/picture.c | 89
> +++++++++++++++++++++++++++-
> > src/gallium/state_trackers/va/surface.c | 73 +++++++++++++++++++++++
> > src/gallium/state_trackers/va/va_private.h | 13 ++++-
> > 5 files changed, 254 insertions(+), 35 deletions(-)
> >
> > diff --git a/src/gallium/state_trackers/va/config.c
> b/src/gallium/state_trackers/va/config.c
> > index cfb0b25..bde6615 100644
> > --- a/src/gallium/state_trackers/va/config.c
> > +++ b/src/gallium/state_trackers/va/config.c
> > @@ -52,6 +52,9 @@ vlVaQueryConfigProfiles(VADriverContextP ctx,
> VAProfile *profile_list, int *num_
> > profile_list[(*num_profiles)++] = vap;
> > }
> >
> > + /* Support postprocessing through vl_compositor */
> > + profile_list[(*num_profiles)++] = VAProfileNone;
> > +
> > return VA_STATUS_SUCCESS;
> > }
> >
> > @@ -67,6 +70,11 @@ vlVaQueryConfigEntrypoints(VADriverContextP ctx,
> VAProfile profile,
> >
> > *num_entrypoints = 0;
> >
> > + if (profile == VAProfileNone) {
> > + entrypoint_list[(*num_entrypoints)++] = VAEntrypointVideoProc;
> > + return VA_STATUS_SUCCESS;
> > + }
> > +
> > p = ProfileToPipe(profile);
> > if (p == PIPE_VIDEO_PROFILE_UNKNOWN)
> > return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
> > @@ -118,6 +126,11 @@ vlVaCreateConfig(VADriverContextP ctx, VAProfile
> profile, VAEntrypoint entrypoin
> > if (!ctx)
> > return VA_STATUS_ERROR_INVALID_CONTEXT;
> >
> > + if (profile == VAProfileNone && entrypoint == VAEntrypointVideoProc)
> {
> > + *config_id = PIPE_VIDEO_PROFILE_UNKNOWN;
> > + return VA_STATUS_SUCCESS;
> > + }
> > +
> > p = ProfileToPipe(profile);
> > if (p == PIPE_VIDEO_PROFILE_UNKNOWN)
> > return VA_STATUS_ERROR_UNSUPPORTED_PROFILE;
> > @@ -151,6 +164,13 @@ vlVaQueryConfigAttributes(VADriverContextP ctx,
> VAConfigID config_id, VAProfile
> > return VA_STATUS_ERROR_INVALID_CONTEXT;
> >
> > *profile = PipeToProfile(config_id);
> > +
> > + if (config_id == PIPE_VIDEO_PROFILE_UNKNOWN) {
> > + *entrypoint = VAEntrypointVideoProc;
> > + *num_attribs = 0;
> > + return VA_STATUS_SUCCESS;
> > + }
> > +
> > *entrypoint = VAEntrypointVLD;
> >
> > *num_attribs = 1;
> > diff --git a/src/gallium/state_trackers/va/context.c
> b/src/gallium/state_trackers/va/context.c
> > index 8949d42..ddc863b 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 =
> > +{
> > + VA_DRIVER_VTABLE_VPP_VERSION,
> Please _never_ do such a thing. Afaict the define provides the VERSION
> currently defined in the API, rather than the one implemented here.
> They might align now, but things will break badly as the API gets
> updated.
>
oki I'll put just 1 then.
>
> > + &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,16 @@ vlVaCreateContext(VADriverContextP ctx, VAConfigID
> config_id, int picture_width,
> > struct pipe_video_codec templat = {};
> > vlVaDriver *drv;
> > vlVaContext *context;
> > + int is_vpp = 0;
> Drop the = 0 part.
>
> >
> > if (!ctx)
> > return VA_STATUS_ERROR_INVALID_CONTEXT;
> >
> > - if (!(picture_width && picture_height))
> > + is_vpp = config_id == PIPE_VIDEO_PROFILE_UNKNOWN &&
> > + picture_width == 0 && picture_height == 0 && flag ==0 &&
> !render_targets
> > + && num_render_targets == 0;
> Please indent - all the conditionals should start at the same column
> and nuke the == 0.
>
> > +
> > + if (!(picture_width && picture_height) && !is_vpp)
> > return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
> >
> > drv = VL_VA_DRIVER(ctx);
> > @@ -163,38 +177,48 @@ 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 = 2;
> > + templat.expect_chunked_decode = true;
> > +
> > + if (u_reduce_video_profile(templat.profile) ==
> > + PIPE_VIDEO_FORMAT_MPEG4_AVC) {
> > + templat.max_references = 16;
> > + templat.level = u_get_h264_level(templat.width, templat.height,
> > + &templat.max_references);
> > + }
> > +
> Why the max_references changes ? Shouldn't those be a separate patch ?
>
> > + 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) {
> > + 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);
> (Mildly related) Keeping track of all these might not fair well. Most
> of st/va and other video st do this, yet (iirc) Christian did not see
> any issues with opting for goto statements.
>
Do you want me to do something here ? Not sure to follow, it is just
indenting existing code. I'll prefer not to change anything here just in
case :)
>
> > + return VA_STATUS_ERROR_ALLOCATION_FAILED;
> > + }
> > + }
> > }
> >
> > context->desc.base.profile = config_id;
> > @@ -214,12 +238,16 @@ 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 (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);
> > + }
> > + 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 9b94b39..0b42afe 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,
> NULL);
> >
> > return VA_STATUS_SUCCESS;
> > @@ -521,11 +532,79 @@ 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 = {0};
> > + struct u_rect dst_rect = {0};
> > + struct u_rect *dirty_area = NULL;
> > + vlVaSurface *src_surface = NULL;
> > + VAProcPipelineParameterBuffer *pipeline_param = NULL;
> > + struct pipe_surface **surfaces = NULL;
> > + struct pipe_screen *screen = NULL;
> > + struct pipe_surface *psurf = NULL;
> Cough :)
>
> > +
> > + 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 = buf->data; // cast
> > +
> > + src_surface = handle_table_get(drv->htab, pipeline_param->surface);
> > + if (!src_surface || !src_surface->buffer)
> > + return VA_STATUS_ERROR_INVALID_SURFACE;
> > +
> > + screen = drv->pipe->screen;
> > +
> > + if(src_surface->fence) {
> > + screen->fence_finish(screen, src_surface->fence,
> PIPE_TIMEOUT_INFINITE);
> > + screen->fence_reference(screen, &src_surface->fence, NULL);
> > + }
> > +
> > + surfaces = context->target->get_surfaces(context->target);
> > +
> > + if (!surfaces)
> if (!surfaces || !surfaces[0]) ?
>
> oki, it will save some lines.
> > + return VA_STATUS_ERROR_INVALID_SURFACE;
> > +
> > + psurf = surfaces[0];
> > +
> > + if (!psurf)
> > + return VA_STATUS_ERROR_INVALID_SURFACE;
> > +
> > + 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;
> >
> > @@ -561,13 +640,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
> > @@ -587,6 +669,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 eb5b8ca..bfa4803 100644
> > --- a/src/gallium/state_trackers/va/surface.c
> > +++ b/src/gallium/state_trackers/va/surface.c
> > @@ -625,3 +625,76 @@ 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)
> > +{
> > + if (!ctx)
> > + return VA_STATUS_ERROR_INVALID_CONTEXT;
> > +
> > + return VA_STATUS_ERROR_UNIMPLEMENTED;
> Something looks fishy here. Shouldn't one return SUCCESS or ENOTSUPP
> like error, when we have FilterNone ?
>
Your are right, I was only testing with gstreamer-vaapi and it seems to
really this function only for other VPP than VAProcFilterNone. But I am
going to provide a minimal impl just to handle FilterNone.
>
> > +}
> > +
> > +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 2cdd787..d3a29bc 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 <va/va_drmcommon.h>
> >
> > #include "pipe/p_video_enums.h"
> > @@ -148,7 +149,8 @@ PipeToProfile(enum pipe_video_profile profile)
> > case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
> > return VAProfileH264High;
> > case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
> > - return VAProfileNone;
> > + case PIPE_VIDEO_PROFILE_UNKNOWN:
> > + return VAProfileNone;
> > default:
> > assert(0);
> > return -1;
> > @@ -179,6 +181,8 @@ ProfileToPipe(VAProfile profile)
> > return PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN;
> > case VAProfileH264High:
> > return PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH;
> > + case VAProfileNone:
> > + return PIPE_VIDEO_PROFILE_UNKNOWN;
> Mapping ProfileNone to PROFILE_UNKNOW and vice versa (incl. all the
> uses above) seems like an abuse ?
>
Yeah I have not found a better solution. There is no
PIPE_VIDEO_PROFILE_NONE so I picked PIPE_VIDEO_PROFILE_UNKNOWN.
At least vlVaCreateConfig returns PIPE_VIDEO_PROFILE_UNKNOWN only for
VAEntrypointVideoProc.
Cheers
Julien
>
>
> Cheers
> Emil
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/mesa-dev/attachments/20151022/220c85aa/attachment-0001.html>
More information about the mesa-dev
mailing list