summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Thompson <sw@jkqxz.net>2017-10-08 16:00:47 +0100
committerMark Thompson <sw@jkqxz.net>2017-10-09 00:46:16 +0100
commitb2f256a9f5db148ab96974400ca7e170494407d0 (patch)
treefec98b8bbb34144cd3af6e84f795f6becfcda004
parent309d660775e2b47af6723a0477c4d753bc0c54f4 (diff)
hwcontext_vaapi: Add support for mapping to DRM objects
Uses vaExportSurfaceHandle() from libva2.
-rw-r--r--libavutil/hwcontext_vaapi.c108
1 files changed, 106 insertions, 2 deletions
diff --git a/libavutil/hwcontext_vaapi.c b/libavutil/hwcontext_vaapi.c
index b2f2e376d8..40a85d288c 100644
--- a/libavutil/hwcontext_vaapi.c
+++ b/libavutil/hwcontext_vaapi.c
@@ -884,8 +884,8 @@ fail:
return err;
}
-static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
- const AVFrame *src, int flags)
+static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
+ const AVFrame *src, int flags)
{
int err;
@@ -1060,6 +1060,97 @@ static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
return 0;
}
+
+static void vaapi_unmap_to_drm(AVHWFramesContext *dst_fc,
+ HWMapDescriptor *hwmap)
+{
+ AVDRMFrameDescriptor *drm_desc = hwmap->priv;
+ int i;
+
+ for (i = 0; i < drm_desc->nb_objects; i++)
+ close(drm_desc->objects[i].fd);
+
+ av_freep(&drm_desc);
+}
+
+static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
+ const AVFrame *src, int flags)
+{
+#if CONFIG_VAAPI_1
+ AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
+ VASurfaceID surface_id;
+ VAStatus vas;
+ VADRMPRIMESurfaceDescriptor va_desc;
+ AVDRMFrameDescriptor *drm_desc = NULL;
+ int err, i, j;
+
+ surface_id = (VASurfaceID)(uintptr_t)src->data[3];
+
+ vas = vaExportSurfaceHandle(hwctx->display, surface_id,
+ VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
+ VA_EXPORT_SURFACE_READ_ONLY |
+ VA_EXPORT_SURFACE_SEPARATE_LAYERS,
+ &va_desc);
+ if (vas != VA_STATUS_SUCCESS) {
+ if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
+ return AVERROR(ENOSYS);
+ av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
+ "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
+ return AVERROR(EIO);
+ }
+
+ drm_desc = av_mallocz(sizeof(*drm_desc));
+ if (!drm_desc) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ // By some bizarre coincidence, these structures are very similar...
+ drm_desc->nb_objects = va_desc.num_objects;
+ for (i = 0; i < va_desc.num_objects; i++) {
+ drm_desc->objects[i].fd = va_desc.objects[i].fd;
+ drm_desc->objects[i].size = va_desc.objects[i].size;
+ drm_desc->objects[i].format_modifier =
+ va_desc.objects[i].drm_format_modifier;
+ }
+ drm_desc->nb_layers = va_desc.num_layers;
+ for (i = 0; i < va_desc.num_layers; i++) {
+ drm_desc->layers[i].format = va_desc.layers[i].drm_format;
+ drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
+ for (j = 0; j < va_desc.layers[i].num_planes; j++) {
+ drm_desc->layers[i].planes[j].object_index =
+ va_desc.layers[i].object_index[j];
+ drm_desc->layers[i].planes[j].offset =
+ va_desc.layers[i].offset[j];
+ drm_desc->layers[i].planes[j].pitch =
+ va_desc.layers[i].pitch[j];
+ }
+ }
+
+ err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
+ &vaapi_unmap_to_drm, drm_desc);
+ if (err < 0)
+ goto fail;
+
+ dst->width = src->width;
+ dst->height = src->height;
+ dst->data[0] = (uint8_t*)drm_desc;
+
+ return 0;
+
+fail:
+ for (i = 0; i < va_desc.num_objects; i++)
+ 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
+}
#endif
static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
@@ -1075,6 +1166,19 @@ static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
}
}
+static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
+ const AVFrame *src, int flags)
+{
+ switch (dst->format) {
+#if CONFIG_LIBDRM
+ case AV_PIX_FMT_DRM_PRIME:
+ return vaapi_map_to_drm(hwfc, dst, src, flags);
+#endif
+ default:
+ return vaapi_map_to_memory(hwfc, dst, src, flags);
+ }
+}
+
static void vaapi_device_free(AVHWDeviceContext *ctx)
{
AVVAAPIDeviceContext *hwctx = ctx->hwctx;