|
|
|
@@ -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) |
|
|
|
|