[FFmpeg-devel] [PATCH v2 2/7] hwcontext_vaapi: Add support for legacy DRM mapping

Rostislav Pehlivanov atomnuker at gmail.com
Thu Mar 22 01:32:38 EET 2018


On 21 March 2018 at 23:12, Mark Thompson <sw at jkqxz.net> wrote:

> The old vaAcquireBufferHandle() API works in fewer cases and provides
> less information than the current vaExportSurfaceHandle(), but it exists
> on older versions and is already used by the OpenCL code.
> ---
> Now we set the INVALID format modifier so that a user can distinguish
> between ESH with linear format modifier and ABH with unknown format
> modifier.
>
> It is kernel ABI and therefore fixed, but the constant needs a recent
> libdrm; get around that by defining it locally if it isn't present.
>
>
>  libavutil/hwcontext_vaapi.c | 194 ++++++++++++++++++++++++++++++
> +++++++++++---
>  1 file changed, 182 insertions(+), 12 deletions(-)
>
> diff --git a/libavutil/hwcontext_vaapi.c b/libavutil/hwcontext_vaapi.c
> index 3797005433..998e954c44 100644
> --- a/libavutil/hwcontext_vaapi.c
> +++ b/libavutil/hwcontext_vaapi.c
> @@ -28,6 +28,9 @@
>  #if CONFIG_LIBDRM
>  #   include <va/va_drmcommon.h>
>  #   include <drm_fourcc.h>
> +#   ifndef DRM_FORMAT_MOD_INVALID
> +#       define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
> +#   endif
>  #endif
>
>  #include <fcntl.h>
> @@ -1071,8 +1074,9 @@ static int vaapi_map_from_drm(AVHWFramesContext
> *src_fc, AVFrame *dst,
>      return 0;
>  }
>
> -static void vaapi_unmap_to_drm(AVHWFramesContext *dst_fc,
> -                               HWMapDescriptor *hwmap)
> +#if VA_CHECK_VERSION(1, 1, 0)
> +static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
> +                                   HWMapDescriptor *hwmap)
>  {
>      AVDRMFrameDescriptor *drm_desc = hwmap->priv;
>      int i;
> @@ -1083,10 +1087,9 @@ static void vaapi_unmap_to_drm(AVHWFramesContext
> *dst_fc,
>      av_freep(&drm_desc);
>  }
>
> -static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
> -                            const AVFrame *src, int flags)
> +static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
> +                                const AVFrame *src, int flags)
>  {
> -#if VA_CHECK_VERSION(1, 1, 0)
>      AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
>      VASurfaceID surface_id;
>      VAStatus vas;
> @@ -1138,7 +1141,7 @@ static int vaapi_map_to_drm(AVHWFramesContext
> *hwfc, AVFrame *dst,
>      }
>
>      err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
> -                                &vaapi_unmap_to_drm, drm_desc);
> +                                &vaapi_unmap_to_drm_esh, drm_desc);
>      if (err < 0)
>          goto fail;
>
> @@ -1153,15 +1156,182 @@ fail:
>          close(va_desc.objects[i].fd);
>      av_freep(&drm_desc);
>      return err;
> -#else
> -    // Older versions without vaExportSurfaceHandle() are not supported -
> -    // in theory this is possible with a combination of vaDeriveImage()
> -    // and vaAcquireBufferHandle(), but it doesn't carry enough metadata
> -    // to actually use the result in a generic way.
> -    return AVERROR(ENOSYS);
> +}
>  #endif
> +
> +typedef struct VAAPIDRMImageBufferMapping {
> +    VAImage      image;
> +    VABufferInfo buffer_info;
> +
> +    AVDRMFrameDescriptor drm_desc;
> +} VAAPIDRMImageBufferMapping;
> +
> +static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
> +                                  HWMapDescriptor *hwmap)
> +{
> +    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
> +    VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
> +    VASurfaceID surface_id;
> +    VAStatus vas;
> +
> +    surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
> +    av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
> +           surface_id);
> +
> +    // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
> +    // so we shouldn't close them separately.
> +
> +    vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
> +    if (vas != VA_STATUS_SUCCESS) {
> +        av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
> +               "handle of image %#x (derived from surface %#x): "
> +               "%d (%s).\n", mapping->image.buf, surface_id,
> +               vas, vaErrorStr(vas));
> +    }
> +
> +    vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
> +    if (vas != VA_STATUS_SUCCESS) {
> +        av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
> +               "derived from surface %#x: %d (%s).\n",
> +               surface_id, vas, vaErrorStr(vas));
> +    }
> +
> +    av_free(mapping);
>  }
> +
> +static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
> +                                const AVFrame *src, int flags)
> +{
> +    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
> +    VAAPIDRMImageBufferMapping *mapping = NULL;
> +    VASurfaceID surface_id;
> +    VAStatus vas;
> +    int err, i, p;
> +
> +    surface_id = (VASurfaceID)(uintptr_t)src->data[3];
> +    av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
> +           surface_id);
> +
> +    mapping = av_mallocz(sizeof(*mapping));
> +    if (!mapping)
> +        return AVERROR(ENOMEM);
> +
> +    vas = vaDeriveImage(hwctx->display, surface_id,
> +                        &mapping->image);
> +    if (vas != VA_STATUS_SUCCESS) {
> +        av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
> +               "surface %#x: %d (%s).\n",
> +               surface_id, vas, vaErrorStr(vas));
> +        err = AVERROR(EIO);
> +        goto fail;
> +    }
> +
> +    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
> +        if (vaapi_drm_format_map[i].va_fourcc ==
> +            mapping->image.format.fourcc)
> +            break;
> +    }
> +    if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
> +        av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
> +               "VAAPI format %#x.\n", mapping->image.format.fourcc);
> +        err = AVERROR(EINVAL);
> +        goto fail_derived;
> +    }
> +
> +    mapping->buffer_info.mem_type =
> +        VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
> +
> +    mapping->drm_desc.nb_layers =
> +        vaapi_drm_format_map[i].nb_layer_formats;
> +    if (mapping->drm_desc.nb_layers > 1) {
> +        if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
> +            av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
> +                   "expected format: got %d planes, but expected %d.\n",
> +                   mapping->image.num_planes,
> mapping->drm_desc.nb_layers);
> +            err = AVERROR(EINVAL);
> +            goto fail_derived;
> +        }
> +
> +        for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
> +            mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
> +                .format    = vaapi_drm_format_map[i].layer_formats[p],
> +                .nb_planes = 1,
> +                .planes[0] = {
> +                    .object_index = 0,
> +                    .offset       = mapping->image.offsets[p],
> +                    .pitch        = mapping->image.pitches[p],
> +                },
> +            };
> +        }
> +    } else {
> +        mapping->drm_desc.layers[0].format =
> +            vaapi_drm_format_map[i].layer_formats[0];
> +        mapping->drm_desc.layers[0].nb_planes =
> mapping->image.num_planes;
> +        for (p = 0; p < mapping->image.num_planes; p++) {
> +            mapping->drm_desc.layers[0].planes[p] =
> (AVDRMPlaneDescriptor) {
> +                .object_index = 0,
> +                .offset       = mapping->image.offsets[p],
> +                .pitch        = mapping->image.pitches[p],
> +            };
> +        }
> +    }
> +
> +    vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
> +                                &mapping->buffer_info);
> +    if (vas != VA_STATUS_SUCCESS) {
> +        av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
> +               "handle from image %#x (derived from surface %#x): "
> +               "%d (%s).\n", mapping->image.buf, surface_id,
> +               vas, vaErrorStr(vas));
> +        err = AVERROR(EIO);
> +        goto fail_derived;
> +    }
> +
> +    av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
> +           mapping->buffer_info.handle);
> +
> +    mapping->drm_desc.nb_objects = 1;
> +    mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
> +        .fd   = mapping->buffer_info.handle,
> +        .size = mapping->image.data_size,
> +        // There is no way to get the format modifier with this API.
> +        .format_modifier = DRM_FORMAT_MOD_INVALID,
> +    };
> +
> +    err = ff_hwframe_map_create(src->hw_frames_ctx,
> +                                dst, src, &vaapi_unmap_to_drm_abh,
> +                                mapping);
> +    if (err < 0)
> +        goto fail_mapped;
> +
> +    dst->data[0] = (uint8_t*)&mapping->drm_desc;
> +    dst->width   = src->width;
> +    dst->height  = src->height;
> +
> +    return 0;
> +
> +fail_mapped:
> +    vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
> +fail_derived:
> +    vaDestroyImage(hwctx->display, mapping->image.image_id);
> +fail:
> +    av_freep(&mapping);
> +    return err;
> +}
> +
> +static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
> +                            const AVFrame *src, int flags)
> +{
> +#if VA_CHECK_VERSION(1, 1, 0)
> +    int err;
> +    err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
> +    if (err != AVERROR(ENOSYS))
> +        return err;
>  #endif
> +    return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
> +}
> +
> +#endif /* CONFIG_LIBDRM */
>
>  static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
>                          const AVFrame *src, int flags)
> --
> 2.16.1
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>

Still a bit ugly but oh well, va/drm seem to move slow, LGTM


More information about the ffmpeg-devel mailing list