Commit 8ad9f9d6 authored by Mark Thompson's avatar Mark Thompson

hwcontext_vaapi: Frame mapping support

Can map to any supported software format (using a GPU copy if it
doesn't actually match the surface format underneath).
parent 124e2697
...@@ -70,20 +70,12 @@ typedef struct VAAPIFramesContext { ...@@ -70,20 +70,12 @@ typedef struct VAAPIFramesContext {
int derive_works; int derive_works;
} VAAPIFramesContext; } VAAPIFramesContext;
enum { typedef struct VAAPIMapping {
VAAPI_MAP_READ = 0x01,
VAAPI_MAP_WRITE = 0x02,
VAAPI_MAP_DIRECT = 0x04,
};
typedef struct VAAPISurfaceMap {
// The source hardware frame of this mapping (with hw_frames_ctx set).
const AVFrame *source;
// VAAPI_MAP_* flags which apply to this mapping.
int flags;
// Handle to the derived or copied image which is mapped. // Handle to the derived or copied image which is mapped.
VAImage image; VAImage image;
} VAAPISurfaceMap; // The mapping flags actually used.
int flags;
} VAAPIMapping;
#define MAP(va, rt, av) { \ #define MAP(va, rt, av) { \
VA_FOURCC_ ## va, \ VA_FOURCC_ ## va, \
...@@ -140,7 +132,8 @@ static int vaapi_get_image_format(AVHWDeviceContext *hwdev, ...@@ -140,7 +132,8 @@ static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
for (i = 0; i < ctx->nb_formats; i++) { for (i = 0; i < ctx->nb_formats; i++) {
if (ctx->formats[i].pix_fmt == pix_fmt) { if (ctx->formats[i].pix_fmt == pix_fmt) {
*image_format = &ctx->formats[i].image_format; if (image_format)
*image_format = &ctx->formats[i].image_format;
return 0; return 0;
} }
} }
...@@ -630,17 +623,15 @@ static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc, ...@@ -630,17 +623,15 @@ static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
return 0; return 0;
} }
static void vaapi_unmap_frame(void *opaque, uint8_t *data) static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
HWMapDescriptor *hwmap)
{ {
AVHWFramesContext *hwfc = opaque;
AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
VAAPISurfaceMap *map = (VAAPISurfaceMap*)data; VAAPIMapping *map = hwmap->priv;
const AVFrame *src;
VASurfaceID surface_id; VASurfaceID surface_id;
VAStatus vas; VAStatus vas;
src = map->source; surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
surface_id = (VASurfaceID)(uintptr_t)src->data[3];
av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id); av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
vas = vaUnmapBuffer(hwctx->display, map->image.buf); vas = vaUnmapBuffer(hwctx->display, map->image.buf);
...@@ -649,8 +640,8 @@ static void vaapi_unmap_frame(void *opaque, uint8_t *data) ...@@ -649,8 +640,8 @@ static void vaapi_unmap_frame(void *opaque, uint8_t *data)
"%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
} }
if ((map->flags & VAAPI_MAP_WRITE) && if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
!(map->flags & VAAPI_MAP_DIRECT)) { !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
vas = vaPutImage(hwctx->display, surface_id, map->image.image_id, vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
0, 0, hwfc->width, hwfc->height, 0, 0, hwfc->width, hwfc->height,
0, 0, hwfc->width, hwfc->height); 0, 0, hwfc->width, hwfc->height);
...@@ -676,7 +667,7 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, ...@@ -676,7 +667,7 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc,
VAAPIFramesContext *ctx = hwfc->internal->priv; VAAPIFramesContext *ctx = hwfc->internal->priv;
VASurfaceID surface_id; VASurfaceID surface_id;
VAImageFormat *image_format; VAImageFormat *image_format;
VAAPISurfaceMap *map; VAAPIMapping *map;
VAStatus vas; VAStatus vas;
void *address = NULL; void *address = NULL;
int err, i; int err, i;
...@@ -684,13 +675,13 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, ...@@ -684,13 +675,13 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc,
surface_id = (VASurfaceID)(uintptr_t)src->data[3]; surface_id = (VASurfaceID)(uintptr_t)src->data[3];
av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id); av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
if (!ctx->derive_works && (flags & VAAPI_MAP_DIRECT)) { if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
// Requested direct mapping but it is not possible. // Requested direct mapping but it is not possible.
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
if (dst->format == AV_PIX_FMT_NONE) if (dst->format == AV_PIX_FMT_NONE)
dst->format = hwfc->sw_format; dst->format = hwfc->sw_format;
if (dst->format != hwfc->sw_format && (flags & VAAPI_MAP_DIRECT)) { if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
// Requested direct mapping but the formats do not match. // Requested direct mapping but the formats do not match.
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
...@@ -701,12 +692,10 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, ...@@ -701,12 +692,10 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc,
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
map = av_malloc(sizeof(VAAPISurfaceMap)); map = av_malloc(sizeof(*map));
if (!map) if (!map)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
map->flags = flags;
map->source = src;
map->flags = flags;
map->image.image_id = VA_INVALID_ID; map->image.image_id = VA_INVALID_ID;
vas = vaSyncSurface(hwctx->display, surface_id); vas = vaSyncSurface(hwctx->display, surface_id);
...@@ -724,8 +713,8 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, ...@@ -724,8 +713,8 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc,
// faster with a copy routine which is aware of the limitation, but we // faster with a copy routine which is aware of the limitation, but we
// assume for now that the user is not aware of that and would therefore // assume for now that the user is not aware of that and would therefore
// prefer not to be given direct-mapped memory if they request read access. // prefer not to be given direct-mapped memory if they request read access.
if (ctx->derive_works && if (ctx->derive_works && dst->format == hwfc->sw_format &&
((flags & VAAPI_MAP_DIRECT) || !(flags & VAAPI_MAP_READ))) { ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
vas = vaDeriveImage(hwctx->display, surface_id, &map->image); vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
if (vas != VA_STATUS_SUCCESS) { if (vas != VA_STATUS_SUCCESS) {
av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from " av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
...@@ -741,7 +730,7 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, ...@@ -741,7 +730,7 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc,
err = AVERROR(EIO); err = AVERROR(EIO);
goto fail; goto fail;
} }
map->flags |= VAAPI_MAP_DIRECT; map->flags |= AV_HWFRAME_MAP_DIRECT;
} else { } else {
vas = vaCreateImage(hwctx->display, image_format, vas = vaCreateImage(hwctx->display, image_format,
hwfc->width, hwfc->height, &map->image); hwfc->width, hwfc->height, &map->image);
...@@ -752,7 +741,7 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, ...@@ -752,7 +741,7 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc,
err = AVERROR(EIO); err = AVERROR(EIO);
goto fail; goto fail;
} }
if (flags & VAAPI_MAP_READ) { if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
vas = vaGetImage(hwctx->display, surface_id, 0, 0, vas = vaGetImage(hwctx->display, surface_id, 0, 0,
hwfc->width, hwfc->height, map->image.image_id); hwfc->width, hwfc->height, map->image.image_id);
if (vas != VA_STATUS_SUCCESS) { if (vas != VA_STATUS_SUCCESS) {
...@@ -773,6 +762,11 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, ...@@ -773,6 +762,11 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc,
goto fail; goto fail;
} }
err = ff_hwframe_map_create(src->hw_frames_ctx,
dst, src, &vaapi_unmap_frame, map);
if (err < 0)
goto fail;
dst->width = src->width; dst->width = src->width;
dst->height = src->height; dst->height = src->height;
...@@ -789,13 +783,6 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, ...@@ -789,13 +783,6 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc,
FFSWAP(uint8_t*, dst->data[1], dst->data[2]); FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
} }
dst->buf[0] = av_buffer_create((uint8_t*)map, sizeof(*map),
&vaapi_unmap_frame, hwfc, 0);
if (!dst->buf[0]) {
err = AVERROR(ENOMEM);
goto fail;
}
return 0; return 0;
fail: fail:
...@@ -823,7 +810,7 @@ static int vaapi_transfer_data_from(AVHWFramesContext *hwfc, ...@@ -823,7 +810,7 @@ static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
map->format = dst->format; map->format = dst->format;
err = vaapi_map_frame(hwfc, map, src, VAAPI_MAP_READ); err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
if (err) if (err)
goto fail; goto fail;
...@@ -854,7 +841,7 @@ static int vaapi_transfer_data_to(AVHWFramesContext *hwfc, ...@@ -854,7 +841,7 @@ static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
map->format = src->format; map->format = src->format;
err = vaapi_map_frame(hwfc, map, dst, VAAPI_MAP_WRITE); err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
if (err) if (err)
goto fail; goto fail;
...@@ -871,6 +858,28 @@ fail: ...@@ -871,6 +858,28 @@ fail:
return err; return err;
} }
static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
const AVFrame *src, int flags)
{
int err;
if (dst->format != AV_PIX_FMT_NONE) {
err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
if (err < 0)
return AVERROR(ENOSYS);
}
err = vaapi_map_frame(hwfc, dst, src, flags);
if (err)
return err;
err = av_frame_copy_props(dst, src);
if (err)
return err;
return 0;
}
static void vaapi_device_free(AVHWDeviceContext *ctx) static void vaapi_device_free(AVHWDeviceContext *ctx)
{ {
AVVAAPIDeviceContext *hwctx = ctx->hwctx; AVVAAPIDeviceContext *hwctx = ctx->hwctx;
...@@ -993,6 +1002,8 @@ const HWContextType ff_hwcontext_type_vaapi = { ...@@ -993,6 +1002,8 @@ const HWContextType ff_hwcontext_type_vaapi = {
.transfer_get_formats = &vaapi_transfer_get_formats, .transfer_get_formats = &vaapi_transfer_get_formats,
.transfer_data_to = &vaapi_transfer_data_to, .transfer_data_to = &vaapi_transfer_data_to,
.transfer_data_from = &vaapi_transfer_data_from, .transfer_data_from = &vaapi_transfer_data_from,
.map_to = NULL,
.map_from = &vaapi_map_from,
.pix_fmts = (const enum AVPixelFormat[]) { .pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_VAAPI, AV_PIX_FMT_VAAPI,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment