1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * This file is part of FFmpeg. 3cabdff1aSopenharmony_ci * 4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 8cabdff1aSopenharmony_ci * 9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cabdff1aSopenharmony_ci * Lesser General Public License for more details. 13cabdff1aSopenharmony_ci * 14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17cabdff1aSopenharmony_ci */ 18cabdff1aSopenharmony_ci 19cabdff1aSopenharmony_ci#include "config.h" 20cabdff1aSopenharmony_ci 21cabdff1aSopenharmony_ci#if HAVE_VAAPI_X11 22cabdff1aSopenharmony_ci# include <va/va_x11.h> 23cabdff1aSopenharmony_ci#endif 24cabdff1aSopenharmony_ci#if HAVE_VAAPI_DRM 25cabdff1aSopenharmony_ci# include <va/va_drm.h> 26cabdff1aSopenharmony_ci#endif 27cabdff1aSopenharmony_ci 28cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 29cabdff1aSopenharmony_ci# include <va/va_drmcommon.h> 30cabdff1aSopenharmony_ci# include <xf86drm.h> 31cabdff1aSopenharmony_ci# include <drm_fourcc.h> 32cabdff1aSopenharmony_ci# ifndef DRM_FORMAT_MOD_INVALID 33cabdff1aSopenharmony_ci# define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) 34cabdff1aSopenharmony_ci# endif 35cabdff1aSopenharmony_ci#endif 36cabdff1aSopenharmony_ci 37cabdff1aSopenharmony_ci#include <fcntl.h> 38cabdff1aSopenharmony_ci#if HAVE_UNISTD_H 39cabdff1aSopenharmony_ci# include <unistd.h> 40cabdff1aSopenharmony_ci#endif 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_ci 43cabdff1aSopenharmony_ci#include "avassert.h" 44cabdff1aSopenharmony_ci#include "buffer.h" 45cabdff1aSopenharmony_ci#include "common.h" 46cabdff1aSopenharmony_ci#include "hwcontext.h" 47cabdff1aSopenharmony_ci#include "hwcontext_drm.h" 48cabdff1aSopenharmony_ci#include "hwcontext_internal.h" 49cabdff1aSopenharmony_ci#include "hwcontext_vaapi.h" 50cabdff1aSopenharmony_ci#include "mem.h" 51cabdff1aSopenharmony_ci#include "pixdesc.h" 52cabdff1aSopenharmony_ci#include "pixfmt.h" 53cabdff1aSopenharmony_ci 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_citypedef struct VAAPIDevicePriv { 56cabdff1aSopenharmony_ci#if HAVE_VAAPI_X11 57cabdff1aSopenharmony_ci Display *x11_display; 58cabdff1aSopenharmony_ci#endif 59cabdff1aSopenharmony_ci 60cabdff1aSopenharmony_ci int drm_fd; 61cabdff1aSopenharmony_ci} VAAPIDevicePriv; 62cabdff1aSopenharmony_ci 63cabdff1aSopenharmony_citypedef struct VAAPISurfaceFormat { 64cabdff1aSopenharmony_ci enum AVPixelFormat pix_fmt; 65cabdff1aSopenharmony_ci VAImageFormat image_format; 66cabdff1aSopenharmony_ci} VAAPISurfaceFormat; 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_citypedef struct VAAPIDeviceContext { 69cabdff1aSopenharmony_ci // Surface formats which can be used with this device. 70cabdff1aSopenharmony_ci VAAPISurfaceFormat *formats; 71cabdff1aSopenharmony_ci int nb_formats; 72cabdff1aSopenharmony_ci} VAAPIDeviceContext; 73cabdff1aSopenharmony_ci 74cabdff1aSopenharmony_citypedef struct VAAPIFramesContext { 75cabdff1aSopenharmony_ci // Surface attributes set at create time. 76cabdff1aSopenharmony_ci VASurfaceAttrib *attributes; 77cabdff1aSopenharmony_ci int nb_attributes; 78cabdff1aSopenharmony_ci // RT format of the underlying surface (Intel driver ignores this anyway). 79cabdff1aSopenharmony_ci unsigned int rt_format; 80cabdff1aSopenharmony_ci // Whether vaDeriveImage works. 81cabdff1aSopenharmony_ci int derive_works; 82cabdff1aSopenharmony_ci // Caches whether VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 is unsupported for 83cabdff1aSopenharmony_ci // surface imports. 84cabdff1aSopenharmony_ci int prime_2_import_unsupported; 85cabdff1aSopenharmony_ci} VAAPIFramesContext; 86cabdff1aSopenharmony_ci 87cabdff1aSopenharmony_citypedef struct VAAPIMapping { 88cabdff1aSopenharmony_ci // Handle to the derived or copied image which is mapped. 89cabdff1aSopenharmony_ci VAImage image; 90cabdff1aSopenharmony_ci // The mapping flags actually used. 91cabdff1aSopenharmony_ci int flags; 92cabdff1aSopenharmony_ci} VAAPIMapping; 93cabdff1aSopenharmony_ci 94cabdff1aSopenharmony_citypedef struct VAAPIFormat { 95cabdff1aSopenharmony_ci unsigned int fourcc; 96cabdff1aSopenharmony_ci unsigned int rt_format; 97cabdff1aSopenharmony_ci enum AVPixelFormat pix_fmt; 98cabdff1aSopenharmony_ci int chroma_planes_swapped; 99cabdff1aSopenharmony_ci} VAAPIFormatDescriptor; 100cabdff1aSopenharmony_ci 101cabdff1aSopenharmony_ci#define MAP(va, rt, av, swap_uv) { \ 102cabdff1aSopenharmony_ci VA_FOURCC_ ## va, \ 103cabdff1aSopenharmony_ci VA_RT_FORMAT_ ## rt, \ 104cabdff1aSopenharmony_ci AV_PIX_FMT_ ## av, \ 105cabdff1aSopenharmony_ci swap_uv, \ 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci// The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V 108cabdff1aSopenharmony_ci// plane swap cases. The frame handling below tries to hide these. 109cabdff1aSopenharmony_cistatic const VAAPIFormatDescriptor vaapi_format_map[] = { 110cabdff1aSopenharmony_ci MAP(NV12, YUV420, NV12, 0), 111cabdff1aSopenharmony_ci#ifdef VA_FOURCC_I420 112cabdff1aSopenharmony_ci MAP(I420, YUV420, YUV420P, 0), 113cabdff1aSopenharmony_ci#endif 114cabdff1aSopenharmony_ci MAP(YV12, YUV420, YUV420P, 1), 115cabdff1aSopenharmony_ci MAP(IYUV, YUV420, YUV420P, 0), 116cabdff1aSopenharmony_ci MAP(422H, YUV422, YUV422P, 0), 117cabdff1aSopenharmony_ci#ifdef VA_FOURCC_YV16 118cabdff1aSopenharmony_ci MAP(YV16, YUV422, YUV422P, 1), 119cabdff1aSopenharmony_ci#endif 120cabdff1aSopenharmony_ci MAP(UYVY, YUV422, UYVY422, 0), 121cabdff1aSopenharmony_ci MAP(YUY2, YUV422, YUYV422, 0), 122cabdff1aSopenharmony_ci#ifdef VA_FOURCC_Y210 123cabdff1aSopenharmony_ci MAP(Y210, YUV422_10, Y210, 0), 124cabdff1aSopenharmony_ci#endif 125cabdff1aSopenharmony_ci MAP(411P, YUV411, YUV411P, 0), 126cabdff1aSopenharmony_ci MAP(422V, YUV422, YUV440P, 0), 127cabdff1aSopenharmony_ci MAP(444P, YUV444, YUV444P, 0), 128cabdff1aSopenharmony_ci MAP(Y800, YUV400, GRAY8, 0), 129cabdff1aSopenharmony_ci#ifdef VA_FOURCC_P010 130cabdff1aSopenharmony_ci MAP(P010, YUV420_10BPP, P010, 0), 131cabdff1aSopenharmony_ci#endif 132cabdff1aSopenharmony_ci MAP(BGRA, RGB32, BGRA, 0), 133cabdff1aSopenharmony_ci MAP(BGRX, RGB32, BGR0, 0), 134cabdff1aSopenharmony_ci MAP(RGBA, RGB32, RGBA, 0), 135cabdff1aSopenharmony_ci MAP(RGBX, RGB32, RGB0, 0), 136cabdff1aSopenharmony_ci#ifdef VA_FOURCC_ABGR 137cabdff1aSopenharmony_ci MAP(ABGR, RGB32, ABGR, 0), 138cabdff1aSopenharmony_ci MAP(XBGR, RGB32, 0BGR, 0), 139cabdff1aSopenharmony_ci#endif 140cabdff1aSopenharmony_ci MAP(ARGB, RGB32, ARGB, 0), 141cabdff1aSopenharmony_ci MAP(XRGB, RGB32, 0RGB, 0), 142cabdff1aSopenharmony_ci#ifdef VA_FOURCC_X2R10G10B10 143cabdff1aSopenharmony_ci MAP(X2R10G10B10, RGB32_10, X2RGB10, 0), 144cabdff1aSopenharmony_ci#endif 145cabdff1aSopenharmony_ci}; 146cabdff1aSopenharmony_ci#undef MAP 147cabdff1aSopenharmony_ci 148cabdff1aSopenharmony_cistatic const VAAPIFormatDescriptor * 149cabdff1aSopenharmony_ci vaapi_format_from_fourcc(unsigned int fourcc) 150cabdff1aSopenharmony_ci{ 151cabdff1aSopenharmony_ci int i; 152cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) 153cabdff1aSopenharmony_ci if (vaapi_format_map[i].fourcc == fourcc) 154cabdff1aSopenharmony_ci return &vaapi_format_map[i]; 155cabdff1aSopenharmony_ci return NULL; 156cabdff1aSopenharmony_ci} 157cabdff1aSopenharmony_ci 158cabdff1aSopenharmony_cistatic const VAAPIFormatDescriptor * 159cabdff1aSopenharmony_ci vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt) 160cabdff1aSopenharmony_ci{ 161cabdff1aSopenharmony_ci int i; 162cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) 163cabdff1aSopenharmony_ci if (vaapi_format_map[i].pix_fmt == pix_fmt) 164cabdff1aSopenharmony_ci return &vaapi_format_map[i]; 165cabdff1aSopenharmony_ci return NULL; 166cabdff1aSopenharmony_ci} 167cabdff1aSopenharmony_ci 168cabdff1aSopenharmony_cistatic enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc) 169cabdff1aSopenharmony_ci{ 170cabdff1aSopenharmony_ci const VAAPIFormatDescriptor *desc; 171cabdff1aSopenharmony_ci desc = vaapi_format_from_fourcc(fourcc); 172cabdff1aSopenharmony_ci if (desc) 173cabdff1aSopenharmony_ci return desc->pix_fmt; 174cabdff1aSopenharmony_ci else 175cabdff1aSopenharmony_ci return AV_PIX_FMT_NONE; 176cabdff1aSopenharmony_ci} 177cabdff1aSopenharmony_ci 178cabdff1aSopenharmony_cistatic int vaapi_get_image_format(AVHWDeviceContext *hwdev, 179cabdff1aSopenharmony_ci enum AVPixelFormat pix_fmt, 180cabdff1aSopenharmony_ci VAImageFormat **image_format) 181cabdff1aSopenharmony_ci{ 182cabdff1aSopenharmony_ci VAAPIDeviceContext *ctx = hwdev->internal->priv; 183cabdff1aSopenharmony_ci int i; 184cabdff1aSopenharmony_ci 185cabdff1aSopenharmony_ci for (i = 0; i < ctx->nb_formats; i++) { 186cabdff1aSopenharmony_ci if (ctx->formats[i].pix_fmt == pix_fmt) { 187cabdff1aSopenharmony_ci if (image_format) 188cabdff1aSopenharmony_ci *image_format = &ctx->formats[i].image_format; 189cabdff1aSopenharmony_ci return 0; 190cabdff1aSopenharmony_ci } 191cabdff1aSopenharmony_ci } 192cabdff1aSopenharmony_ci return AVERROR(EINVAL); 193cabdff1aSopenharmony_ci} 194cabdff1aSopenharmony_ci 195cabdff1aSopenharmony_cistatic int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev, 196cabdff1aSopenharmony_ci const void *hwconfig, 197cabdff1aSopenharmony_ci AVHWFramesConstraints *constraints) 198cabdff1aSopenharmony_ci{ 199cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwdev->hwctx; 200cabdff1aSopenharmony_ci const AVVAAPIHWConfig *config = hwconfig; 201cabdff1aSopenharmony_ci VAAPIDeviceContext *ctx = hwdev->internal->priv; 202cabdff1aSopenharmony_ci VASurfaceAttrib *attr_list = NULL; 203cabdff1aSopenharmony_ci VAStatus vas; 204cabdff1aSopenharmony_ci enum AVPixelFormat pix_fmt; 205cabdff1aSopenharmony_ci unsigned int fourcc; 206cabdff1aSopenharmony_ci int err, i, j, attr_count, pix_fmt_count; 207cabdff1aSopenharmony_ci 208cabdff1aSopenharmony_ci if (config && 209cabdff1aSopenharmony_ci !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) { 210cabdff1aSopenharmony_ci attr_count = 0; 211cabdff1aSopenharmony_ci vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id, 212cabdff1aSopenharmony_ci 0, &attr_count); 213cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 214cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: " 215cabdff1aSopenharmony_ci "%d (%s).\n", vas, vaErrorStr(vas)); 216cabdff1aSopenharmony_ci err = AVERROR(ENOSYS); 217cabdff1aSopenharmony_ci goto fail; 218cabdff1aSopenharmony_ci } 219cabdff1aSopenharmony_ci 220cabdff1aSopenharmony_ci attr_list = av_malloc(attr_count * sizeof(*attr_list)); 221cabdff1aSopenharmony_ci if (!attr_list) { 222cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 223cabdff1aSopenharmony_ci goto fail; 224cabdff1aSopenharmony_ci } 225cabdff1aSopenharmony_ci 226cabdff1aSopenharmony_ci vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id, 227cabdff1aSopenharmony_ci attr_list, &attr_count); 228cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 229cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: " 230cabdff1aSopenharmony_ci "%d (%s).\n", vas, vaErrorStr(vas)); 231cabdff1aSopenharmony_ci err = AVERROR(ENOSYS); 232cabdff1aSopenharmony_ci goto fail; 233cabdff1aSopenharmony_ci } 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_ci pix_fmt_count = 0; 236cabdff1aSopenharmony_ci for (i = 0; i < attr_count; i++) { 237cabdff1aSopenharmony_ci switch (attr_list[i].type) { 238cabdff1aSopenharmony_ci case VASurfaceAttribPixelFormat: 239cabdff1aSopenharmony_ci fourcc = attr_list[i].value.value.i; 240cabdff1aSopenharmony_ci pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); 241cabdff1aSopenharmony_ci if (pix_fmt != AV_PIX_FMT_NONE) { 242cabdff1aSopenharmony_ci ++pix_fmt_count; 243cabdff1aSopenharmony_ci } else { 244cabdff1aSopenharmony_ci // Something unsupported - ignore. 245cabdff1aSopenharmony_ci } 246cabdff1aSopenharmony_ci break; 247cabdff1aSopenharmony_ci case VASurfaceAttribMinWidth: 248cabdff1aSopenharmony_ci constraints->min_width = attr_list[i].value.value.i; 249cabdff1aSopenharmony_ci break; 250cabdff1aSopenharmony_ci case VASurfaceAttribMinHeight: 251cabdff1aSopenharmony_ci constraints->min_height = attr_list[i].value.value.i; 252cabdff1aSopenharmony_ci break; 253cabdff1aSopenharmony_ci case VASurfaceAttribMaxWidth: 254cabdff1aSopenharmony_ci constraints->max_width = attr_list[i].value.value.i; 255cabdff1aSopenharmony_ci break; 256cabdff1aSopenharmony_ci case VASurfaceAttribMaxHeight: 257cabdff1aSopenharmony_ci constraints->max_height = attr_list[i].value.value.i; 258cabdff1aSopenharmony_ci break; 259cabdff1aSopenharmony_ci } 260cabdff1aSopenharmony_ci } 261cabdff1aSopenharmony_ci if (pix_fmt_count == 0) { 262cabdff1aSopenharmony_ci // Nothing usable found. Presumably there exists something which 263cabdff1aSopenharmony_ci // works, so leave the set null to indicate unknown. 264cabdff1aSopenharmony_ci constraints->valid_sw_formats = NULL; 265cabdff1aSopenharmony_ci } else { 266cabdff1aSopenharmony_ci constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1, 267cabdff1aSopenharmony_ci sizeof(pix_fmt)); 268cabdff1aSopenharmony_ci if (!constraints->valid_sw_formats) { 269cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 270cabdff1aSopenharmony_ci goto fail; 271cabdff1aSopenharmony_ci } 272cabdff1aSopenharmony_ci 273cabdff1aSopenharmony_ci for (i = j = 0; i < attr_count; i++) { 274cabdff1aSopenharmony_ci int k; 275cabdff1aSopenharmony_ci 276cabdff1aSopenharmony_ci if (attr_list[i].type != VASurfaceAttribPixelFormat) 277cabdff1aSopenharmony_ci continue; 278cabdff1aSopenharmony_ci fourcc = attr_list[i].value.value.i; 279cabdff1aSopenharmony_ci pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); 280cabdff1aSopenharmony_ci 281cabdff1aSopenharmony_ci if (pix_fmt == AV_PIX_FMT_NONE) 282cabdff1aSopenharmony_ci continue; 283cabdff1aSopenharmony_ci 284cabdff1aSopenharmony_ci for (k = 0; k < j; k++) { 285cabdff1aSopenharmony_ci if (constraints->valid_sw_formats[k] == pix_fmt) 286cabdff1aSopenharmony_ci break; 287cabdff1aSopenharmony_ci } 288cabdff1aSopenharmony_ci 289cabdff1aSopenharmony_ci if (k == j) 290cabdff1aSopenharmony_ci constraints->valid_sw_formats[j++] = pix_fmt; 291cabdff1aSopenharmony_ci } 292cabdff1aSopenharmony_ci constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE; 293cabdff1aSopenharmony_ci } 294cabdff1aSopenharmony_ci } else { 295cabdff1aSopenharmony_ci // No configuration supplied. 296cabdff1aSopenharmony_ci // Return the full set of image formats known by the implementation. 297cabdff1aSopenharmony_ci constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1, 298cabdff1aSopenharmony_ci sizeof(pix_fmt)); 299cabdff1aSopenharmony_ci if (!constraints->valid_sw_formats) { 300cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 301cabdff1aSopenharmony_ci goto fail; 302cabdff1aSopenharmony_ci } 303cabdff1aSopenharmony_ci for (i = j = 0; i < ctx->nb_formats; i++) { 304cabdff1aSopenharmony_ci int k; 305cabdff1aSopenharmony_ci 306cabdff1aSopenharmony_ci for (k = 0; k < j; k++) { 307cabdff1aSopenharmony_ci if (constraints->valid_sw_formats[k] == ctx->formats[i].pix_fmt) 308cabdff1aSopenharmony_ci break; 309cabdff1aSopenharmony_ci } 310cabdff1aSopenharmony_ci 311cabdff1aSopenharmony_ci if (k == j) 312cabdff1aSopenharmony_ci constraints->valid_sw_formats[j++] = ctx->formats[i].pix_fmt; 313cabdff1aSopenharmony_ci } 314cabdff1aSopenharmony_ci 315cabdff1aSopenharmony_ci constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE; 316cabdff1aSopenharmony_ci } 317cabdff1aSopenharmony_ci 318cabdff1aSopenharmony_ci constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt)); 319cabdff1aSopenharmony_ci if (!constraints->valid_hw_formats) { 320cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 321cabdff1aSopenharmony_ci goto fail; 322cabdff1aSopenharmony_ci } 323cabdff1aSopenharmony_ci constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI; 324cabdff1aSopenharmony_ci constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; 325cabdff1aSopenharmony_ci 326cabdff1aSopenharmony_ci err = 0; 327cabdff1aSopenharmony_cifail: 328cabdff1aSopenharmony_ci av_freep(&attr_list); 329cabdff1aSopenharmony_ci return err; 330cabdff1aSopenharmony_ci} 331cabdff1aSopenharmony_ci 332cabdff1aSopenharmony_cistatic const struct { 333cabdff1aSopenharmony_ci const char *friendly_name; 334cabdff1aSopenharmony_ci const char *match_string; 335cabdff1aSopenharmony_ci unsigned int quirks; 336cabdff1aSopenharmony_ci} vaapi_driver_quirks_table[] = { 337cabdff1aSopenharmony_ci#if !VA_CHECK_VERSION(1, 0, 0) 338cabdff1aSopenharmony_ci // The i965 driver did not conform before version 2.0. 339cabdff1aSopenharmony_ci { 340cabdff1aSopenharmony_ci "Intel i965 (Quick Sync)", 341cabdff1aSopenharmony_ci "i965", 342cabdff1aSopenharmony_ci AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS, 343cabdff1aSopenharmony_ci }, 344cabdff1aSopenharmony_ci#endif 345cabdff1aSopenharmony_ci { 346cabdff1aSopenharmony_ci "Intel iHD", 347cabdff1aSopenharmony_ci "ubit", 348cabdff1aSopenharmony_ci AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE, 349cabdff1aSopenharmony_ci }, 350cabdff1aSopenharmony_ci { 351cabdff1aSopenharmony_ci "VDPAU wrapper", 352cabdff1aSopenharmony_ci "Splitted-Desktop Systems VDPAU backend for VA-API", 353cabdff1aSopenharmony_ci AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES, 354cabdff1aSopenharmony_ci }, 355cabdff1aSopenharmony_ci}; 356cabdff1aSopenharmony_ci 357cabdff1aSopenharmony_cistatic int vaapi_device_init(AVHWDeviceContext *hwdev) 358cabdff1aSopenharmony_ci{ 359cabdff1aSopenharmony_ci VAAPIDeviceContext *ctx = hwdev->internal->priv; 360cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwdev->hwctx; 361cabdff1aSopenharmony_ci VAImageFormat *image_list = NULL; 362cabdff1aSopenharmony_ci VAStatus vas; 363cabdff1aSopenharmony_ci const char *vendor_string; 364cabdff1aSopenharmony_ci int err, i, image_count; 365cabdff1aSopenharmony_ci enum AVPixelFormat pix_fmt; 366cabdff1aSopenharmony_ci unsigned int fourcc; 367cabdff1aSopenharmony_ci 368cabdff1aSopenharmony_ci image_count = vaMaxNumImageFormats(hwctx->display); 369cabdff1aSopenharmony_ci if (image_count <= 0) { 370cabdff1aSopenharmony_ci err = AVERROR(EIO); 371cabdff1aSopenharmony_ci goto fail; 372cabdff1aSopenharmony_ci } 373cabdff1aSopenharmony_ci image_list = av_malloc(image_count * sizeof(*image_list)); 374cabdff1aSopenharmony_ci if (!image_list) { 375cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 376cabdff1aSopenharmony_ci goto fail; 377cabdff1aSopenharmony_ci } 378cabdff1aSopenharmony_ci vas = vaQueryImageFormats(hwctx->display, image_list, &image_count); 379cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 380cabdff1aSopenharmony_ci err = AVERROR(EIO); 381cabdff1aSopenharmony_ci goto fail; 382cabdff1aSopenharmony_ci } 383cabdff1aSopenharmony_ci 384cabdff1aSopenharmony_ci ctx->formats = av_malloc(image_count * sizeof(*ctx->formats)); 385cabdff1aSopenharmony_ci if (!ctx->formats) { 386cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 387cabdff1aSopenharmony_ci goto fail; 388cabdff1aSopenharmony_ci } 389cabdff1aSopenharmony_ci ctx->nb_formats = 0; 390cabdff1aSopenharmony_ci for (i = 0; i < image_count; i++) { 391cabdff1aSopenharmony_ci fourcc = image_list[i].fourcc; 392cabdff1aSopenharmony_ci pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc); 393cabdff1aSopenharmony_ci if (pix_fmt == AV_PIX_FMT_NONE) { 394cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n", 395cabdff1aSopenharmony_ci fourcc); 396cabdff1aSopenharmony_ci } else { 397cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n", 398cabdff1aSopenharmony_ci fourcc, av_get_pix_fmt_name(pix_fmt)); 399cabdff1aSopenharmony_ci ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt; 400cabdff1aSopenharmony_ci ctx->formats[ctx->nb_formats].image_format = image_list[i]; 401cabdff1aSopenharmony_ci ++ctx->nb_formats; 402cabdff1aSopenharmony_ci } 403cabdff1aSopenharmony_ci } 404cabdff1aSopenharmony_ci 405cabdff1aSopenharmony_ci vendor_string = vaQueryVendorString(hwctx->display); 406cabdff1aSopenharmony_ci if (vendor_string) 407cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string); 408cabdff1aSopenharmony_ci 409cabdff1aSopenharmony_ci if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) { 410cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n", 411cabdff1aSopenharmony_ci hwctx->driver_quirks); 412cabdff1aSopenharmony_ci } else { 413cabdff1aSopenharmony_ci // Detect the driver in use and set quirk flags if necessary. 414cabdff1aSopenharmony_ci hwctx->driver_quirks = 0; 415cabdff1aSopenharmony_ci if (vendor_string) { 416cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) { 417cabdff1aSopenharmony_ci if (strstr(vendor_string, 418cabdff1aSopenharmony_ci vaapi_driver_quirks_table[i].match_string)) { 419cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string " 420cabdff1aSopenharmony_ci "as known nonstandard driver \"%s\", setting " 421cabdff1aSopenharmony_ci "quirks (%#x).\n", 422cabdff1aSopenharmony_ci vaapi_driver_quirks_table[i].friendly_name, 423cabdff1aSopenharmony_ci vaapi_driver_quirks_table[i].quirks); 424cabdff1aSopenharmony_ci hwctx->driver_quirks |= 425cabdff1aSopenharmony_ci vaapi_driver_quirks_table[i].quirks; 426cabdff1aSopenharmony_ci break; 427cabdff1aSopenharmony_ci } 428cabdff1aSopenharmony_ci } 429cabdff1aSopenharmony_ci if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) { 430cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known " 431cabdff1aSopenharmony_ci "nonstandard list, using standard behaviour.\n"); 432cabdff1aSopenharmony_ci } 433cabdff1aSopenharmony_ci } else { 434cabdff1aSopenharmony_ci av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, " 435cabdff1aSopenharmony_ci "assuming standard behaviour.\n"); 436cabdff1aSopenharmony_ci } 437cabdff1aSopenharmony_ci } 438cabdff1aSopenharmony_ci 439cabdff1aSopenharmony_ci av_free(image_list); 440cabdff1aSopenharmony_ci return 0; 441cabdff1aSopenharmony_cifail: 442cabdff1aSopenharmony_ci av_freep(&ctx->formats); 443cabdff1aSopenharmony_ci av_free(image_list); 444cabdff1aSopenharmony_ci return err; 445cabdff1aSopenharmony_ci} 446cabdff1aSopenharmony_ci 447cabdff1aSopenharmony_cistatic void vaapi_device_uninit(AVHWDeviceContext *hwdev) 448cabdff1aSopenharmony_ci{ 449cabdff1aSopenharmony_ci VAAPIDeviceContext *ctx = hwdev->internal->priv; 450cabdff1aSopenharmony_ci 451cabdff1aSopenharmony_ci av_freep(&ctx->formats); 452cabdff1aSopenharmony_ci} 453cabdff1aSopenharmony_ci 454cabdff1aSopenharmony_cistatic void vaapi_buffer_free(void *opaque, uint8_t *data) 455cabdff1aSopenharmony_ci{ 456cabdff1aSopenharmony_ci AVHWFramesContext *hwfc = opaque; 457cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 458cabdff1aSopenharmony_ci VASurfaceID surface_id; 459cabdff1aSopenharmony_ci VAStatus vas; 460cabdff1aSopenharmony_ci 461cabdff1aSopenharmony_ci surface_id = (VASurfaceID)(uintptr_t)data; 462cabdff1aSopenharmony_ci 463cabdff1aSopenharmony_ci vas = vaDestroySurfaces(hwctx->display, &surface_id, 1); 464cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 465cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: " 466cabdff1aSopenharmony_ci "%d (%s).\n", surface_id, vas, vaErrorStr(vas)); 467cabdff1aSopenharmony_ci } 468cabdff1aSopenharmony_ci} 469cabdff1aSopenharmony_ci 470cabdff1aSopenharmony_cistatic AVBufferRef *vaapi_pool_alloc(void *opaque, size_t size) 471cabdff1aSopenharmony_ci{ 472cabdff1aSopenharmony_ci AVHWFramesContext *hwfc = opaque; 473cabdff1aSopenharmony_ci VAAPIFramesContext *ctx = hwfc->internal->priv; 474cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 475cabdff1aSopenharmony_ci AVVAAPIFramesContext *avfc = hwfc->hwctx; 476cabdff1aSopenharmony_ci VASurfaceID surface_id; 477cabdff1aSopenharmony_ci VAStatus vas; 478cabdff1aSopenharmony_ci AVBufferRef *ref; 479cabdff1aSopenharmony_ci 480cabdff1aSopenharmony_ci if (hwfc->initial_pool_size > 0 && 481cabdff1aSopenharmony_ci avfc->nb_surfaces >= hwfc->initial_pool_size) 482cabdff1aSopenharmony_ci return NULL; 483cabdff1aSopenharmony_ci 484cabdff1aSopenharmony_ci vas = vaCreateSurfaces(hwctx->display, ctx->rt_format, 485cabdff1aSopenharmony_ci hwfc->width, hwfc->height, 486cabdff1aSopenharmony_ci &surface_id, 1, 487cabdff1aSopenharmony_ci ctx->attributes, ctx->nb_attributes); 488cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 489cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: " 490cabdff1aSopenharmony_ci "%d (%s).\n", vas, vaErrorStr(vas)); 491cabdff1aSopenharmony_ci return NULL; 492cabdff1aSopenharmony_ci } 493cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id); 494cabdff1aSopenharmony_ci 495cabdff1aSopenharmony_ci ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id, 496cabdff1aSopenharmony_ci sizeof(surface_id), &vaapi_buffer_free, 497cabdff1aSopenharmony_ci hwfc, AV_BUFFER_FLAG_READONLY); 498cabdff1aSopenharmony_ci if (!ref) { 499cabdff1aSopenharmony_ci vaDestroySurfaces(hwctx->display, &surface_id, 1); 500cabdff1aSopenharmony_ci return NULL; 501cabdff1aSopenharmony_ci } 502cabdff1aSopenharmony_ci 503cabdff1aSopenharmony_ci if (hwfc->initial_pool_size > 0) { 504cabdff1aSopenharmony_ci // This is a fixed-size pool, so we must still be in the initial 505cabdff1aSopenharmony_ci // allocation sequence. 506cabdff1aSopenharmony_ci av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size); 507cabdff1aSopenharmony_ci avfc->surface_ids[avfc->nb_surfaces] = surface_id; 508cabdff1aSopenharmony_ci ++avfc->nb_surfaces; 509cabdff1aSopenharmony_ci } 510cabdff1aSopenharmony_ci 511cabdff1aSopenharmony_ci return ref; 512cabdff1aSopenharmony_ci} 513cabdff1aSopenharmony_ci 514cabdff1aSopenharmony_cistatic int vaapi_frames_init(AVHWFramesContext *hwfc) 515cabdff1aSopenharmony_ci{ 516cabdff1aSopenharmony_ci AVVAAPIFramesContext *avfc = hwfc->hwctx; 517cabdff1aSopenharmony_ci VAAPIFramesContext *ctx = hwfc->internal->priv; 518cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 519cabdff1aSopenharmony_ci const VAAPIFormatDescriptor *desc; 520cabdff1aSopenharmony_ci VAImageFormat *expected_format; 521cabdff1aSopenharmony_ci AVBufferRef *test_surface = NULL; 522cabdff1aSopenharmony_ci VASurfaceID test_surface_id; 523cabdff1aSopenharmony_ci VAImage test_image; 524cabdff1aSopenharmony_ci VAStatus vas; 525cabdff1aSopenharmony_ci int err, i; 526cabdff1aSopenharmony_ci 527cabdff1aSopenharmony_ci desc = vaapi_format_from_pix_fmt(hwfc->sw_format); 528cabdff1aSopenharmony_ci if (!desc) { 529cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n", 530cabdff1aSopenharmony_ci av_get_pix_fmt_name(hwfc->sw_format)); 531cabdff1aSopenharmony_ci return AVERROR(EINVAL); 532cabdff1aSopenharmony_ci } 533cabdff1aSopenharmony_ci 534cabdff1aSopenharmony_ci if (!hwfc->pool) { 535cabdff1aSopenharmony_ci if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) { 536cabdff1aSopenharmony_ci int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE); 537cabdff1aSopenharmony_ci int need_pixel_format = 1; 538cabdff1aSopenharmony_ci for (i = 0; i < avfc->nb_attributes; i++) { 539cabdff1aSopenharmony_ci if (avfc->attributes[i].type == VASurfaceAttribMemoryType) 540cabdff1aSopenharmony_ci need_memory_type = 0; 541cabdff1aSopenharmony_ci if (avfc->attributes[i].type == VASurfaceAttribPixelFormat) 542cabdff1aSopenharmony_ci need_pixel_format = 0; 543cabdff1aSopenharmony_ci } 544cabdff1aSopenharmony_ci ctx->nb_attributes = 545cabdff1aSopenharmony_ci avfc->nb_attributes + need_memory_type + need_pixel_format; 546cabdff1aSopenharmony_ci 547cabdff1aSopenharmony_ci ctx->attributes = av_malloc(ctx->nb_attributes * 548cabdff1aSopenharmony_ci sizeof(*ctx->attributes)); 549cabdff1aSopenharmony_ci if (!ctx->attributes) { 550cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 551cabdff1aSopenharmony_ci goto fail; 552cabdff1aSopenharmony_ci } 553cabdff1aSopenharmony_ci 554cabdff1aSopenharmony_ci for (i = 0; i < avfc->nb_attributes; i++) 555cabdff1aSopenharmony_ci ctx->attributes[i] = avfc->attributes[i]; 556cabdff1aSopenharmony_ci if (need_memory_type) { 557cabdff1aSopenharmony_ci ctx->attributes[i++] = (VASurfaceAttrib) { 558cabdff1aSopenharmony_ci .type = VASurfaceAttribMemoryType, 559cabdff1aSopenharmony_ci .flags = VA_SURFACE_ATTRIB_SETTABLE, 560cabdff1aSopenharmony_ci .value.type = VAGenericValueTypeInteger, 561cabdff1aSopenharmony_ci .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA, 562cabdff1aSopenharmony_ci }; 563cabdff1aSopenharmony_ci } 564cabdff1aSopenharmony_ci if (need_pixel_format) { 565cabdff1aSopenharmony_ci ctx->attributes[i++] = (VASurfaceAttrib) { 566cabdff1aSopenharmony_ci .type = VASurfaceAttribPixelFormat, 567cabdff1aSopenharmony_ci .flags = VA_SURFACE_ATTRIB_SETTABLE, 568cabdff1aSopenharmony_ci .value.type = VAGenericValueTypeInteger, 569cabdff1aSopenharmony_ci .value.value.i = desc->fourcc, 570cabdff1aSopenharmony_ci }; 571cabdff1aSopenharmony_ci } 572cabdff1aSopenharmony_ci av_assert0(i == ctx->nb_attributes); 573cabdff1aSopenharmony_ci } else { 574cabdff1aSopenharmony_ci ctx->attributes = NULL; 575cabdff1aSopenharmony_ci ctx->nb_attributes = 0; 576cabdff1aSopenharmony_ci } 577cabdff1aSopenharmony_ci 578cabdff1aSopenharmony_ci ctx->rt_format = desc->rt_format; 579cabdff1aSopenharmony_ci 580cabdff1aSopenharmony_ci if (hwfc->initial_pool_size > 0) { 581cabdff1aSopenharmony_ci // This pool will be usable as a render target, so we need to store 582cabdff1aSopenharmony_ci // all of the surface IDs somewhere that vaCreateContext() calls 583cabdff1aSopenharmony_ci // will be able to access them. 584cabdff1aSopenharmony_ci avfc->nb_surfaces = 0; 585cabdff1aSopenharmony_ci avfc->surface_ids = av_malloc(hwfc->initial_pool_size * 586cabdff1aSopenharmony_ci sizeof(*avfc->surface_ids)); 587cabdff1aSopenharmony_ci if (!avfc->surface_ids) { 588cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 589cabdff1aSopenharmony_ci goto fail; 590cabdff1aSopenharmony_ci } 591cabdff1aSopenharmony_ci } else { 592cabdff1aSopenharmony_ci // This pool allows dynamic sizing, and will not be usable as a 593cabdff1aSopenharmony_ci // render target. 594cabdff1aSopenharmony_ci avfc->nb_surfaces = 0; 595cabdff1aSopenharmony_ci avfc->surface_ids = NULL; 596cabdff1aSopenharmony_ci } 597cabdff1aSopenharmony_ci 598cabdff1aSopenharmony_ci hwfc->internal->pool_internal = 599cabdff1aSopenharmony_ci av_buffer_pool_init2(sizeof(VASurfaceID), hwfc, 600cabdff1aSopenharmony_ci &vaapi_pool_alloc, NULL); 601cabdff1aSopenharmony_ci if (!hwfc->internal->pool_internal) { 602cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n"); 603cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 604cabdff1aSopenharmony_ci goto fail; 605cabdff1aSopenharmony_ci } 606cabdff1aSopenharmony_ci } 607cabdff1aSopenharmony_ci 608cabdff1aSopenharmony_ci // Allocate a single surface to test whether vaDeriveImage() is going 609cabdff1aSopenharmony_ci // to work for the specific configuration. 610cabdff1aSopenharmony_ci if (hwfc->pool) { 611cabdff1aSopenharmony_ci test_surface = av_buffer_pool_get(hwfc->pool); 612cabdff1aSopenharmony_ci if (!test_surface) { 613cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from " 614cabdff1aSopenharmony_ci "user-configured buffer pool.\n"); 615cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 616cabdff1aSopenharmony_ci goto fail; 617cabdff1aSopenharmony_ci } 618cabdff1aSopenharmony_ci } else { 619cabdff1aSopenharmony_ci test_surface = av_buffer_pool_get(hwfc->internal->pool_internal); 620cabdff1aSopenharmony_ci if (!test_surface) { 621cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from " 622cabdff1aSopenharmony_ci "internal buffer pool.\n"); 623cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 624cabdff1aSopenharmony_ci goto fail; 625cabdff1aSopenharmony_ci } 626cabdff1aSopenharmony_ci } 627cabdff1aSopenharmony_ci test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data; 628cabdff1aSopenharmony_ci 629cabdff1aSopenharmony_ci ctx->derive_works = 0; 630cabdff1aSopenharmony_ci 631cabdff1aSopenharmony_ci err = vaapi_get_image_format(hwfc->device_ctx, 632cabdff1aSopenharmony_ci hwfc->sw_format, &expected_format); 633cabdff1aSopenharmony_ci if (err == 0) { 634cabdff1aSopenharmony_ci vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image); 635cabdff1aSopenharmony_ci if (vas == VA_STATUS_SUCCESS) { 636cabdff1aSopenharmony_ci if (expected_format->fourcc == test_image.format.fourcc) { 637cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n"); 638cabdff1aSopenharmony_ci ctx->derive_works = 1; 639cabdff1aSopenharmony_ci } else { 640cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " 641cabdff1aSopenharmony_ci "derived image format %08x does not match " 642cabdff1aSopenharmony_ci "expected format %08x.\n", 643cabdff1aSopenharmony_ci expected_format->fourcc, test_image.format.fourcc); 644cabdff1aSopenharmony_ci } 645cabdff1aSopenharmony_ci vaDestroyImage(hwctx->display, test_image.image_id); 646cabdff1aSopenharmony_ci } else { 647cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " 648cabdff1aSopenharmony_ci "deriving image does not work: " 649cabdff1aSopenharmony_ci "%d (%s).\n", vas, vaErrorStr(vas)); 650cabdff1aSopenharmony_ci } 651cabdff1aSopenharmony_ci } else { 652cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: " 653cabdff1aSopenharmony_ci "image format is not supported.\n"); 654cabdff1aSopenharmony_ci } 655cabdff1aSopenharmony_ci 656cabdff1aSopenharmony_ci av_buffer_unref(&test_surface); 657cabdff1aSopenharmony_ci return 0; 658cabdff1aSopenharmony_ci 659cabdff1aSopenharmony_cifail: 660cabdff1aSopenharmony_ci av_buffer_unref(&test_surface); 661cabdff1aSopenharmony_ci av_freep(&avfc->surface_ids); 662cabdff1aSopenharmony_ci av_freep(&ctx->attributes); 663cabdff1aSopenharmony_ci return err; 664cabdff1aSopenharmony_ci} 665cabdff1aSopenharmony_ci 666cabdff1aSopenharmony_cistatic void vaapi_frames_uninit(AVHWFramesContext *hwfc) 667cabdff1aSopenharmony_ci{ 668cabdff1aSopenharmony_ci AVVAAPIFramesContext *avfc = hwfc->hwctx; 669cabdff1aSopenharmony_ci VAAPIFramesContext *ctx = hwfc->internal->priv; 670cabdff1aSopenharmony_ci 671cabdff1aSopenharmony_ci av_freep(&avfc->surface_ids); 672cabdff1aSopenharmony_ci av_freep(&ctx->attributes); 673cabdff1aSopenharmony_ci} 674cabdff1aSopenharmony_ci 675cabdff1aSopenharmony_cistatic int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) 676cabdff1aSopenharmony_ci{ 677cabdff1aSopenharmony_ci frame->buf[0] = av_buffer_pool_get(hwfc->pool); 678cabdff1aSopenharmony_ci if (!frame->buf[0]) 679cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 680cabdff1aSopenharmony_ci 681cabdff1aSopenharmony_ci frame->data[3] = frame->buf[0]->data; 682cabdff1aSopenharmony_ci frame->format = AV_PIX_FMT_VAAPI; 683cabdff1aSopenharmony_ci frame->width = hwfc->width; 684cabdff1aSopenharmony_ci frame->height = hwfc->height; 685cabdff1aSopenharmony_ci 686cabdff1aSopenharmony_ci return 0; 687cabdff1aSopenharmony_ci} 688cabdff1aSopenharmony_ci 689cabdff1aSopenharmony_cistatic int vaapi_transfer_get_formats(AVHWFramesContext *hwfc, 690cabdff1aSopenharmony_ci enum AVHWFrameTransferDirection dir, 691cabdff1aSopenharmony_ci enum AVPixelFormat **formats) 692cabdff1aSopenharmony_ci{ 693cabdff1aSopenharmony_ci VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv; 694cabdff1aSopenharmony_ci enum AVPixelFormat *pix_fmts; 695cabdff1aSopenharmony_ci int i, k, sw_format_available; 696cabdff1aSopenharmony_ci 697cabdff1aSopenharmony_ci sw_format_available = 0; 698cabdff1aSopenharmony_ci for (i = 0; i < ctx->nb_formats; i++) { 699cabdff1aSopenharmony_ci if (ctx->formats[i].pix_fmt == hwfc->sw_format) 700cabdff1aSopenharmony_ci sw_format_available = 1; 701cabdff1aSopenharmony_ci } 702cabdff1aSopenharmony_ci 703cabdff1aSopenharmony_ci pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts)); 704cabdff1aSopenharmony_ci if (!pix_fmts) 705cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 706cabdff1aSopenharmony_ci 707cabdff1aSopenharmony_ci if (sw_format_available) { 708cabdff1aSopenharmony_ci pix_fmts[0] = hwfc->sw_format; 709cabdff1aSopenharmony_ci k = 1; 710cabdff1aSopenharmony_ci } else { 711cabdff1aSopenharmony_ci k = 0; 712cabdff1aSopenharmony_ci } 713cabdff1aSopenharmony_ci for (i = 0; i < ctx->nb_formats; i++) { 714cabdff1aSopenharmony_ci if (ctx->formats[i].pix_fmt == hwfc->sw_format) 715cabdff1aSopenharmony_ci continue; 716cabdff1aSopenharmony_ci av_assert0(k < ctx->nb_formats); 717cabdff1aSopenharmony_ci pix_fmts[k++] = ctx->formats[i].pix_fmt; 718cabdff1aSopenharmony_ci } 719cabdff1aSopenharmony_ci pix_fmts[k] = AV_PIX_FMT_NONE; 720cabdff1aSopenharmony_ci 721cabdff1aSopenharmony_ci *formats = pix_fmts; 722cabdff1aSopenharmony_ci return 0; 723cabdff1aSopenharmony_ci} 724cabdff1aSopenharmony_ci 725cabdff1aSopenharmony_cistatic void vaapi_unmap_frame(AVHWFramesContext *hwfc, 726cabdff1aSopenharmony_ci HWMapDescriptor *hwmap) 727cabdff1aSopenharmony_ci{ 728cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 729cabdff1aSopenharmony_ci VAAPIMapping *map = hwmap->priv; 730cabdff1aSopenharmony_ci VASurfaceID surface_id; 731cabdff1aSopenharmony_ci VAStatus vas; 732cabdff1aSopenharmony_ci 733cabdff1aSopenharmony_ci surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3]; 734cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id); 735cabdff1aSopenharmony_ci 736cabdff1aSopenharmony_ci vas = vaUnmapBuffer(hwctx->display, map->image.buf); 737cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 738cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface " 739cabdff1aSopenharmony_ci "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 740cabdff1aSopenharmony_ci } 741cabdff1aSopenharmony_ci 742cabdff1aSopenharmony_ci if ((map->flags & AV_HWFRAME_MAP_WRITE) && 743cabdff1aSopenharmony_ci !(map->flags & AV_HWFRAME_MAP_DIRECT)) { 744cabdff1aSopenharmony_ci vas = vaPutImage(hwctx->display, surface_id, map->image.image_id, 745cabdff1aSopenharmony_ci 0, 0, hwfc->width, hwfc->height, 746cabdff1aSopenharmony_ci 0, 0, hwfc->width, hwfc->height); 747cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 748cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface " 749cabdff1aSopenharmony_ci "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 750cabdff1aSopenharmony_ci } 751cabdff1aSopenharmony_ci } 752cabdff1aSopenharmony_ci 753cabdff1aSopenharmony_ci vas = vaDestroyImage(hwctx->display, map->image.image_id); 754cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 755cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface " 756cabdff1aSopenharmony_ci "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 757cabdff1aSopenharmony_ci } 758cabdff1aSopenharmony_ci 759cabdff1aSopenharmony_ci av_free(map); 760cabdff1aSopenharmony_ci} 761cabdff1aSopenharmony_ci 762cabdff1aSopenharmony_cistatic int vaapi_map_frame(AVHWFramesContext *hwfc, 763cabdff1aSopenharmony_ci AVFrame *dst, const AVFrame *src, int flags) 764cabdff1aSopenharmony_ci{ 765cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 766cabdff1aSopenharmony_ci VAAPIFramesContext *ctx = hwfc->internal->priv; 767cabdff1aSopenharmony_ci VASurfaceID surface_id; 768cabdff1aSopenharmony_ci const VAAPIFormatDescriptor *desc; 769cabdff1aSopenharmony_ci VAImageFormat *image_format; 770cabdff1aSopenharmony_ci VAAPIMapping *map; 771cabdff1aSopenharmony_ci VAStatus vas; 772cabdff1aSopenharmony_ci void *address = NULL; 773cabdff1aSopenharmony_ci int err, i; 774cabdff1aSopenharmony_ci 775cabdff1aSopenharmony_ci surface_id = (VASurfaceID)(uintptr_t)src->data[3]; 776cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id); 777cabdff1aSopenharmony_ci 778cabdff1aSopenharmony_ci if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) { 779cabdff1aSopenharmony_ci // Requested direct mapping but it is not possible. 780cabdff1aSopenharmony_ci return AVERROR(EINVAL); 781cabdff1aSopenharmony_ci } 782cabdff1aSopenharmony_ci if (dst->format == AV_PIX_FMT_NONE) 783cabdff1aSopenharmony_ci dst->format = hwfc->sw_format; 784cabdff1aSopenharmony_ci if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) { 785cabdff1aSopenharmony_ci // Requested direct mapping but the formats do not match. 786cabdff1aSopenharmony_ci return AVERROR(EINVAL); 787cabdff1aSopenharmony_ci } 788cabdff1aSopenharmony_ci 789cabdff1aSopenharmony_ci err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format); 790cabdff1aSopenharmony_ci if (err < 0) { 791cabdff1aSopenharmony_ci // Requested format is not a valid output format. 792cabdff1aSopenharmony_ci return AVERROR(EINVAL); 793cabdff1aSopenharmony_ci } 794cabdff1aSopenharmony_ci 795cabdff1aSopenharmony_ci map = av_malloc(sizeof(*map)); 796cabdff1aSopenharmony_ci if (!map) 797cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 798cabdff1aSopenharmony_ci map->flags = flags; 799cabdff1aSopenharmony_ci map->image.image_id = VA_INVALID_ID; 800cabdff1aSopenharmony_ci 801cabdff1aSopenharmony_ci vas = vaSyncSurface(hwctx->display, surface_id); 802cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 803cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface " 804cabdff1aSopenharmony_ci "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 805cabdff1aSopenharmony_ci err = AVERROR(EIO); 806cabdff1aSopenharmony_ci goto fail; 807cabdff1aSopenharmony_ci } 808cabdff1aSopenharmony_ci 809cabdff1aSopenharmony_ci // The memory which we map using derive need not be connected to the CPU 810cabdff1aSopenharmony_ci // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the 811cabdff1aSopenharmony_ci // memory is mappable but not cached, so normal memcpy()-like access is 812cabdff1aSopenharmony_ci // very slow to read it (but writing is ok). It is possible to read much 813cabdff1aSopenharmony_ci // faster with a copy routine which is aware of the limitation, but we 814cabdff1aSopenharmony_ci // assume for now that the user is not aware of that and would therefore 815cabdff1aSopenharmony_ci // prefer not to be given direct-mapped memory if they request read access. 816cabdff1aSopenharmony_ci if (ctx->derive_works && dst->format == hwfc->sw_format && 817cabdff1aSopenharmony_ci ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) { 818cabdff1aSopenharmony_ci vas = vaDeriveImage(hwctx->display, surface_id, &map->image); 819cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 820cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from " 821cabdff1aSopenharmony_ci "surface %#x: %d (%s).\n", 822cabdff1aSopenharmony_ci surface_id, vas, vaErrorStr(vas)); 823cabdff1aSopenharmony_ci err = AVERROR(EIO); 824cabdff1aSopenharmony_ci goto fail; 825cabdff1aSopenharmony_ci } 826cabdff1aSopenharmony_ci if (map->image.format.fourcc != image_format->fourcc) { 827cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x " 828cabdff1aSopenharmony_ci "is in wrong format: expected %#08x, got %#08x.\n", 829cabdff1aSopenharmony_ci surface_id, image_format->fourcc, map->image.format.fourcc); 830cabdff1aSopenharmony_ci err = AVERROR(EIO); 831cabdff1aSopenharmony_ci goto fail; 832cabdff1aSopenharmony_ci } 833cabdff1aSopenharmony_ci map->flags |= AV_HWFRAME_MAP_DIRECT; 834cabdff1aSopenharmony_ci } else { 835cabdff1aSopenharmony_ci vas = vaCreateImage(hwctx->display, image_format, 836cabdff1aSopenharmony_ci hwfc->width, hwfc->height, &map->image); 837cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 838cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to create image for " 839cabdff1aSopenharmony_ci "surface %#x: %d (%s).\n", 840cabdff1aSopenharmony_ci surface_id, vas, vaErrorStr(vas)); 841cabdff1aSopenharmony_ci err = AVERROR(EIO); 842cabdff1aSopenharmony_ci goto fail; 843cabdff1aSopenharmony_ci } 844cabdff1aSopenharmony_ci if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) { 845cabdff1aSopenharmony_ci vas = vaGetImage(hwctx->display, surface_id, 0, 0, 846cabdff1aSopenharmony_ci hwfc->width, hwfc->height, map->image.image_id); 847cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 848cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to read image from " 849cabdff1aSopenharmony_ci "surface %#x: %d (%s).\n", 850cabdff1aSopenharmony_ci surface_id, vas, vaErrorStr(vas)); 851cabdff1aSopenharmony_ci err = AVERROR(EIO); 852cabdff1aSopenharmony_ci goto fail; 853cabdff1aSopenharmony_ci } 854cabdff1aSopenharmony_ci } 855cabdff1aSopenharmony_ci } 856cabdff1aSopenharmony_ci 857cabdff1aSopenharmony_ci vas = vaMapBuffer(hwctx->display, map->image.buf, &address); 858cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 859cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface " 860cabdff1aSopenharmony_ci "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas)); 861cabdff1aSopenharmony_ci err = AVERROR(EIO); 862cabdff1aSopenharmony_ci goto fail; 863cabdff1aSopenharmony_ci } 864cabdff1aSopenharmony_ci 865cabdff1aSopenharmony_ci err = ff_hwframe_map_create(src->hw_frames_ctx, 866cabdff1aSopenharmony_ci dst, src, &vaapi_unmap_frame, map); 867cabdff1aSopenharmony_ci if (err < 0) 868cabdff1aSopenharmony_ci goto fail; 869cabdff1aSopenharmony_ci 870cabdff1aSopenharmony_ci dst->width = src->width; 871cabdff1aSopenharmony_ci dst->height = src->height; 872cabdff1aSopenharmony_ci 873cabdff1aSopenharmony_ci for (i = 0; i < map->image.num_planes; i++) { 874cabdff1aSopenharmony_ci dst->data[i] = (uint8_t*)address + map->image.offsets[i]; 875cabdff1aSopenharmony_ci dst->linesize[i] = map->image.pitches[i]; 876cabdff1aSopenharmony_ci } 877cabdff1aSopenharmony_ci 878cabdff1aSopenharmony_ci desc = vaapi_format_from_fourcc(map->image.format.fourcc); 879cabdff1aSopenharmony_ci if (desc && desc->chroma_planes_swapped) { 880cabdff1aSopenharmony_ci // Chroma planes are YVU rather than YUV, so swap them. 881cabdff1aSopenharmony_ci FFSWAP(uint8_t*, dst->data[1], dst->data[2]); 882cabdff1aSopenharmony_ci } 883cabdff1aSopenharmony_ci 884cabdff1aSopenharmony_ci return 0; 885cabdff1aSopenharmony_ci 886cabdff1aSopenharmony_cifail: 887cabdff1aSopenharmony_ci if (map) { 888cabdff1aSopenharmony_ci if (address) 889cabdff1aSopenharmony_ci vaUnmapBuffer(hwctx->display, map->image.buf); 890cabdff1aSopenharmony_ci if (map->image.image_id != VA_INVALID_ID) 891cabdff1aSopenharmony_ci vaDestroyImage(hwctx->display, map->image.image_id); 892cabdff1aSopenharmony_ci av_free(map); 893cabdff1aSopenharmony_ci } 894cabdff1aSopenharmony_ci return err; 895cabdff1aSopenharmony_ci} 896cabdff1aSopenharmony_ci 897cabdff1aSopenharmony_cistatic int vaapi_transfer_data_from(AVHWFramesContext *hwfc, 898cabdff1aSopenharmony_ci AVFrame *dst, const AVFrame *src) 899cabdff1aSopenharmony_ci{ 900cabdff1aSopenharmony_ci AVFrame *map; 901cabdff1aSopenharmony_ci int err; 902cabdff1aSopenharmony_ci 903cabdff1aSopenharmony_ci if (dst->width > hwfc->width || dst->height > hwfc->height) 904cabdff1aSopenharmony_ci return AVERROR(EINVAL); 905cabdff1aSopenharmony_ci 906cabdff1aSopenharmony_ci map = av_frame_alloc(); 907cabdff1aSopenharmony_ci if (!map) 908cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 909cabdff1aSopenharmony_ci map->format = dst->format; 910cabdff1aSopenharmony_ci 911cabdff1aSopenharmony_ci err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ); 912cabdff1aSopenharmony_ci if (err) 913cabdff1aSopenharmony_ci goto fail; 914cabdff1aSopenharmony_ci 915cabdff1aSopenharmony_ci map->width = dst->width; 916cabdff1aSopenharmony_ci map->height = dst->height; 917cabdff1aSopenharmony_ci 918cabdff1aSopenharmony_ci err = av_frame_copy(dst, map); 919cabdff1aSopenharmony_ci if (err) 920cabdff1aSopenharmony_ci goto fail; 921cabdff1aSopenharmony_ci 922cabdff1aSopenharmony_ci err = 0; 923cabdff1aSopenharmony_cifail: 924cabdff1aSopenharmony_ci av_frame_free(&map); 925cabdff1aSopenharmony_ci return err; 926cabdff1aSopenharmony_ci} 927cabdff1aSopenharmony_ci 928cabdff1aSopenharmony_cistatic int vaapi_transfer_data_to(AVHWFramesContext *hwfc, 929cabdff1aSopenharmony_ci AVFrame *dst, const AVFrame *src) 930cabdff1aSopenharmony_ci{ 931cabdff1aSopenharmony_ci AVFrame *map; 932cabdff1aSopenharmony_ci int err; 933cabdff1aSopenharmony_ci 934cabdff1aSopenharmony_ci if (src->width > hwfc->width || src->height > hwfc->height) 935cabdff1aSopenharmony_ci return AVERROR(EINVAL); 936cabdff1aSopenharmony_ci 937cabdff1aSopenharmony_ci map = av_frame_alloc(); 938cabdff1aSopenharmony_ci if (!map) 939cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 940cabdff1aSopenharmony_ci map->format = src->format; 941cabdff1aSopenharmony_ci 942cabdff1aSopenharmony_ci err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE); 943cabdff1aSopenharmony_ci if (err) 944cabdff1aSopenharmony_ci goto fail; 945cabdff1aSopenharmony_ci 946cabdff1aSopenharmony_ci map->width = src->width; 947cabdff1aSopenharmony_ci map->height = src->height; 948cabdff1aSopenharmony_ci 949cabdff1aSopenharmony_ci err = av_frame_copy(map, src); 950cabdff1aSopenharmony_ci if (err) 951cabdff1aSopenharmony_ci goto fail; 952cabdff1aSopenharmony_ci 953cabdff1aSopenharmony_ci err = 0; 954cabdff1aSopenharmony_cifail: 955cabdff1aSopenharmony_ci av_frame_free(&map); 956cabdff1aSopenharmony_ci return err; 957cabdff1aSopenharmony_ci} 958cabdff1aSopenharmony_ci 959cabdff1aSopenharmony_cistatic int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst, 960cabdff1aSopenharmony_ci const AVFrame *src, int flags) 961cabdff1aSopenharmony_ci{ 962cabdff1aSopenharmony_ci int err; 963cabdff1aSopenharmony_ci 964cabdff1aSopenharmony_ci if (dst->format != AV_PIX_FMT_NONE) { 965cabdff1aSopenharmony_ci err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL); 966cabdff1aSopenharmony_ci if (err < 0) 967cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 968cabdff1aSopenharmony_ci } 969cabdff1aSopenharmony_ci 970cabdff1aSopenharmony_ci err = vaapi_map_frame(hwfc, dst, src, flags); 971cabdff1aSopenharmony_ci if (err) 972cabdff1aSopenharmony_ci return err; 973cabdff1aSopenharmony_ci 974cabdff1aSopenharmony_ci err = av_frame_copy_props(dst, src); 975cabdff1aSopenharmony_ci if (err) 976cabdff1aSopenharmony_ci return err; 977cabdff1aSopenharmony_ci 978cabdff1aSopenharmony_ci return 0; 979cabdff1aSopenharmony_ci} 980cabdff1aSopenharmony_ci 981cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 982cabdff1aSopenharmony_ci 983cabdff1aSopenharmony_ci#define DRM_MAP(va, layers, ...) { \ 984cabdff1aSopenharmony_ci VA_FOURCC_ ## va, \ 985cabdff1aSopenharmony_ci layers, \ 986cabdff1aSopenharmony_ci { __VA_ARGS__ } \ 987cabdff1aSopenharmony_ci } 988cabdff1aSopenharmony_cistatic const struct { 989cabdff1aSopenharmony_ci uint32_t va_fourcc; 990cabdff1aSopenharmony_ci int nb_layer_formats; 991cabdff1aSopenharmony_ci uint32_t layer_formats[AV_DRM_MAX_PLANES]; 992cabdff1aSopenharmony_ci} vaapi_drm_format_map[] = { 993cabdff1aSopenharmony_ci#ifdef DRM_FORMAT_R8 994cabdff1aSopenharmony_ci DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88), 995cabdff1aSopenharmony_ci DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_GR88), 996cabdff1aSopenharmony_ci#endif 997cabdff1aSopenharmony_ci DRM_MAP(NV12, 1, DRM_FORMAT_NV12), 998cabdff1aSopenharmony_ci#if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16) 999cabdff1aSopenharmony_ci DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616), 1000cabdff1aSopenharmony_ci#endif 1001cabdff1aSopenharmony_ci DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888), 1002cabdff1aSopenharmony_ci DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888), 1003cabdff1aSopenharmony_ci DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888), 1004cabdff1aSopenharmony_ci DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888), 1005cabdff1aSopenharmony_ci#ifdef VA_FOURCC_ABGR 1006cabdff1aSopenharmony_ci DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888), 1007cabdff1aSopenharmony_ci DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888), 1008cabdff1aSopenharmony_ci#endif 1009cabdff1aSopenharmony_ci DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888), 1010cabdff1aSopenharmony_ci DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888), 1011cabdff1aSopenharmony_ci}; 1012cabdff1aSopenharmony_ci#undef DRM_MAP 1013cabdff1aSopenharmony_ci 1014cabdff1aSopenharmony_cistatic void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc, 1015cabdff1aSopenharmony_ci HWMapDescriptor *hwmap) 1016cabdff1aSopenharmony_ci{ 1017cabdff1aSopenharmony_ci AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; 1018cabdff1aSopenharmony_ci 1019cabdff1aSopenharmony_ci VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv; 1020cabdff1aSopenharmony_ci 1021cabdff1aSopenharmony_ci av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id); 1022cabdff1aSopenharmony_ci 1023cabdff1aSopenharmony_ci vaDestroySurfaces(dst_dev->display, &surface_id, 1); 1024cabdff1aSopenharmony_ci} 1025cabdff1aSopenharmony_ci 1026cabdff1aSopenharmony_cistatic int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst, 1027cabdff1aSopenharmony_ci const AVFrame *src, int flags) 1028cabdff1aSopenharmony_ci{ 1029cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(1, 1, 0) 1030cabdff1aSopenharmony_ci VAAPIFramesContext *src_vafc = src_fc->internal->priv; 1031cabdff1aSopenharmony_ci int use_prime2; 1032cabdff1aSopenharmony_ci#else 1033cabdff1aSopenharmony_ci int k; 1034cabdff1aSopenharmony_ci#endif 1035cabdff1aSopenharmony_ci AVHWFramesContext *dst_fc = 1036cabdff1aSopenharmony_ci (AVHWFramesContext*)dst->hw_frames_ctx->data; 1037cabdff1aSopenharmony_ci AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; 1038cabdff1aSopenharmony_ci const AVDRMFrameDescriptor *desc; 1039cabdff1aSopenharmony_ci const VAAPIFormatDescriptor *format_desc; 1040cabdff1aSopenharmony_ci VASurfaceID surface_id; 1041cabdff1aSopenharmony_ci VAStatus vas = VA_STATUS_SUCCESS; 1042cabdff1aSopenharmony_ci uint32_t va_fourcc; 1043cabdff1aSopenharmony_ci int err, i, j; 1044cabdff1aSopenharmony_ci 1045cabdff1aSopenharmony_ci#if !VA_CHECK_VERSION(1, 1, 0) 1046cabdff1aSopenharmony_ci unsigned long buffer_handle; 1047cabdff1aSopenharmony_ci VASurfaceAttribExternalBuffers buffer_desc; 1048cabdff1aSopenharmony_ci VASurfaceAttrib attrs[2] = { 1049cabdff1aSopenharmony_ci { 1050cabdff1aSopenharmony_ci .type = VASurfaceAttribMemoryType, 1051cabdff1aSopenharmony_ci .flags = VA_SURFACE_ATTRIB_SETTABLE, 1052cabdff1aSopenharmony_ci .value.type = VAGenericValueTypeInteger, 1053cabdff1aSopenharmony_ci .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME, 1054cabdff1aSopenharmony_ci }, 1055cabdff1aSopenharmony_ci { 1056cabdff1aSopenharmony_ci .type = VASurfaceAttribExternalBufferDescriptor, 1057cabdff1aSopenharmony_ci .flags = VA_SURFACE_ATTRIB_SETTABLE, 1058cabdff1aSopenharmony_ci .value.type = VAGenericValueTypePointer, 1059cabdff1aSopenharmony_ci .value.value.p = &buffer_desc, 1060cabdff1aSopenharmony_ci } 1061cabdff1aSopenharmony_ci }; 1062cabdff1aSopenharmony_ci#endif 1063cabdff1aSopenharmony_ci 1064cabdff1aSopenharmony_ci desc = (AVDRMFrameDescriptor*)src->data[0]; 1065cabdff1aSopenharmony_ci 1066cabdff1aSopenharmony_ci if (desc->nb_objects != 1) { 1067cabdff1aSopenharmony_ci av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames " 1068cabdff1aSopenharmony_ci "made from a single DRM object.\n"); 1069cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1070cabdff1aSopenharmony_ci } 1071cabdff1aSopenharmony_ci 1072cabdff1aSopenharmony_ci va_fourcc = 0; 1073cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) { 1074cabdff1aSopenharmony_ci if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats) 1075cabdff1aSopenharmony_ci continue; 1076cabdff1aSopenharmony_ci for (j = 0; j < desc->nb_layers; j++) { 1077cabdff1aSopenharmony_ci if (desc->layers[j].format != 1078cabdff1aSopenharmony_ci vaapi_drm_format_map[i].layer_formats[j]) 1079cabdff1aSopenharmony_ci break; 1080cabdff1aSopenharmony_ci } 1081cabdff1aSopenharmony_ci if (j != desc->nb_layers) 1082cabdff1aSopenharmony_ci continue; 1083cabdff1aSopenharmony_ci va_fourcc = vaapi_drm_format_map[i].va_fourcc; 1084cabdff1aSopenharmony_ci break; 1085cabdff1aSopenharmony_ci } 1086cabdff1aSopenharmony_ci if (!va_fourcc) { 1087cabdff1aSopenharmony_ci av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported " 1088cabdff1aSopenharmony_ci "by VAAPI.\n"); 1089cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1090cabdff1aSopenharmony_ci } 1091cabdff1aSopenharmony_ci 1092cabdff1aSopenharmony_ci av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as " 1093cabdff1aSopenharmony_ci "%08x.\n", desc->objects[0].fd, va_fourcc); 1094cabdff1aSopenharmony_ci 1095cabdff1aSopenharmony_ci format_desc = vaapi_format_from_fourcc(va_fourcc); 1096cabdff1aSopenharmony_ci av_assert0(format_desc); 1097cabdff1aSopenharmony_ci 1098cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(1, 1, 0) 1099cabdff1aSopenharmony_ci use_prime2 = !src_vafc->prime_2_import_unsupported && 1100cabdff1aSopenharmony_ci desc->objects[0].format_modifier != DRM_FORMAT_MOD_INVALID; 1101cabdff1aSopenharmony_ci if (use_prime2) { 1102cabdff1aSopenharmony_ci VADRMPRIMESurfaceDescriptor prime_desc; 1103cabdff1aSopenharmony_ci VASurfaceAttrib prime_attrs[2] = { 1104cabdff1aSopenharmony_ci { 1105cabdff1aSopenharmony_ci .type = VASurfaceAttribMemoryType, 1106cabdff1aSopenharmony_ci .flags = VA_SURFACE_ATTRIB_SETTABLE, 1107cabdff1aSopenharmony_ci .value.type = VAGenericValueTypeInteger, 1108cabdff1aSopenharmony_ci .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, 1109cabdff1aSopenharmony_ci }, 1110cabdff1aSopenharmony_ci { 1111cabdff1aSopenharmony_ci .type = VASurfaceAttribExternalBufferDescriptor, 1112cabdff1aSopenharmony_ci .flags = VA_SURFACE_ATTRIB_SETTABLE, 1113cabdff1aSopenharmony_ci .value.type = VAGenericValueTypePointer, 1114cabdff1aSopenharmony_ci .value.value.p = &prime_desc, 1115cabdff1aSopenharmony_ci } 1116cabdff1aSopenharmony_ci }; 1117cabdff1aSopenharmony_ci prime_desc.fourcc = va_fourcc; 1118cabdff1aSopenharmony_ci prime_desc.width = src_fc->width; 1119cabdff1aSopenharmony_ci prime_desc.height = src_fc->height; 1120cabdff1aSopenharmony_ci prime_desc.num_objects = desc->nb_objects; 1121cabdff1aSopenharmony_ci for (i = 0; i < desc->nb_objects; ++i) { 1122cabdff1aSopenharmony_ci prime_desc.objects[i].fd = desc->objects[i].fd; 1123cabdff1aSopenharmony_ci prime_desc.objects[i].size = desc->objects[i].size; 1124cabdff1aSopenharmony_ci prime_desc.objects[i].drm_format_modifier = 1125cabdff1aSopenharmony_ci desc->objects[i].format_modifier; 1126cabdff1aSopenharmony_ci } 1127cabdff1aSopenharmony_ci 1128cabdff1aSopenharmony_ci prime_desc.num_layers = desc->nb_layers; 1129cabdff1aSopenharmony_ci for (i = 0; i < desc->nb_layers; ++i) { 1130cabdff1aSopenharmony_ci prime_desc.layers[i].drm_format = desc->layers[i].format; 1131cabdff1aSopenharmony_ci prime_desc.layers[i].num_planes = desc->layers[i].nb_planes; 1132cabdff1aSopenharmony_ci for (j = 0; j < desc->layers[i].nb_planes; ++j) { 1133cabdff1aSopenharmony_ci prime_desc.layers[i].object_index[j] = 1134cabdff1aSopenharmony_ci desc->layers[i].planes[j].object_index; 1135cabdff1aSopenharmony_ci prime_desc.layers[i].offset[j] = desc->layers[i].planes[j].offset; 1136cabdff1aSopenharmony_ci prime_desc.layers[i].pitch[j] = desc->layers[i].planes[j].pitch; 1137cabdff1aSopenharmony_ci } 1138cabdff1aSopenharmony_ci 1139cabdff1aSopenharmony_ci if (format_desc->chroma_planes_swapped && 1140cabdff1aSopenharmony_ci desc->layers[i].nb_planes == 3) { 1141cabdff1aSopenharmony_ci FFSWAP(uint32_t, prime_desc.layers[i].pitch[1], 1142cabdff1aSopenharmony_ci prime_desc.layers[i].pitch[2]); 1143cabdff1aSopenharmony_ci FFSWAP(uint32_t, prime_desc.layers[i].offset[1], 1144cabdff1aSopenharmony_ci prime_desc.layers[i].offset[2]); 1145cabdff1aSopenharmony_ci } 1146cabdff1aSopenharmony_ci } 1147cabdff1aSopenharmony_ci 1148cabdff1aSopenharmony_ci /* 1149cabdff1aSopenharmony_ci * We can query for PRIME_2 support with vaQuerySurfaceAttributes, but that 1150cabdff1aSopenharmony_ci * that needs the config_id which we don't have here . Both Intel and 1151cabdff1aSopenharmony_ci * Gallium seem to do the correct error checks, so lets just try the 1152cabdff1aSopenharmony_ci * PRIME_2 import first. 1153cabdff1aSopenharmony_ci */ 1154cabdff1aSopenharmony_ci vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format, 1155cabdff1aSopenharmony_ci src->width, src->height, &surface_id, 1, 1156cabdff1aSopenharmony_ci prime_attrs, FF_ARRAY_ELEMS(prime_attrs)); 1157cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) 1158cabdff1aSopenharmony_ci src_vafc->prime_2_import_unsupported = 1; 1159cabdff1aSopenharmony_ci } 1160cabdff1aSopenharmony_ci 1161cabdff1aSopenharmony_ci if (!use_prime2 || vas != VA_STATUS_SUCCESS) { 1162cabdff1aSopenharmony_ci int k; 1163cabdff1aSopenharmony_ci unsigned long buffer_handle; 1164cabdff1aSopenharmony_ci VASurfaceAttribExternalBuffers buffer_desc; 1165cabdff1aSopenharmony_ci VASurfaceAttrib buffer_attrs[2] = { 1166cabdff1aSopenharmony_ci { 1167cabdff1aSopenharmony_ci .type = VASurfaceAttribMemoryType, 1168cabdff1aSopenharmony_ci .flags = VA_SURFACE_ATTRIB_SETTABLE, 1169cabdff1aSopenharmony_ci .value.type = VAGenericValueTypeInteger, 1170cabdff1aSopenharmony_ci .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME, 1171cabdff1aSopenharmony_ci }, 1172cabdff1aSopenharmony_ci { 1173cabdff1aSopenharmony_ci .type = VASurfaceAttribExternalBufferDescriptor, 1174cabdff1aSopenharmony_ci .flags = VA_SURFACE_ATTRIB_SETTABLE, 1175cabdff1aSopenharmony_ci .value.type = VAGenericValueTypePointer, 1176cabdff1aSopenharmony_ci .value.value.p = &buffer_desc, 1177cabdff1aSopenharmony_ci } 1178cabdff1aSopenharmony_ci }; 1179cabdff1aSopenharmony_ci 1180cabdff1aSopenharmony_ci buffer_handle = desc->objects[0].fd; 1181cabdff1aSopenharmony_ci buffer_desc.pixel_format = va_fourcc; 1182cabdff1aSopenharmony_ci buffer_desc.width = src_fc->width; 1183cabdff1aSopenharmony_ci buffer_desc.height = src_fc->height; 1184cabdff1aSopenharmony_ci buffer_desc.data_size = desc->objects[0].size; 1185cabdff1aSopenharmony_ci buffer_desc.buffers = &buffer_handle; 1186cabdff1aSopenharmony_ci buffer_desc.num_buffers = 1; 1187cabdff1aSopenharmony_ci buffer_desc.flags = 0; 1188cabdff1aSopenharmony_ci 1189cabdff1aSopenharmony_ci k = 0; 1190cabdff1aSopenharmony_ci for (i = 0; i < desc->nb_layers; i++) { 1191cabdff1aSopenharmony_ci for (j = 0; j < desc->layers[i].nb_planes; j++) { 1192cabdff1aSopenharmony_ci buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch; 1193cabdff1aSopenharmony_ci buffer_desc.offsets[k] = desc->layers[i].planes[j].offset; 1194cabdff1aSopenharmony_ci ++k; 1195cabdff1aSopenharmony_ci } 1196cabdff1aSopenharmony_ci } 1197cabdff1aSopenharmony_ci buffer_desc.num_planes = k; 1198cabdff1aSopenharmony_ci 1199cabdff1aSopenharmony_ci if (format_desc->chroma_planes_swapped && 1200cabdff1aSopenharmony_ci buffer_desc.num_planes == 3) { 1201cabdff1aSopenharmony_ci FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]); 1202cabdff1aSopenharmony_ci FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]); 1203cabdff1aSopenharmony_ci } 1204cabdff1aSopenharmony_ci 1205cabdff1aSopenharmony_ci vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format, 1206cabdff1aSopenharmony_ci src->width, src->height, 1207cabdff1aSopenharmony_ci &surface_id, 1, 1208cabdff1aSopenharmony_ci buffer_attrs, FF_ARRAY_ELEMS(buffer_attrs)); 1209cabdff1aSopenharmony_ci } 1210cabdff1aSopenharmony_ci#else 1211cabdff1aSopenharmony_ci buffer_handle = desc->objects[0].fd; 1212cabdff1aSopenharmony_ci buffer_desc.pixel_format = va_fourcc; 1213cabdff1aSopenharmony_ci buffer_desc.width = src_fc->width; 1214cabdff1aSopenharmony_ci buffer_desc.height = src_fc->height; 1215cabdff1aSopenharmony_ci buffer_desc.data_size = desc->objects[0].size; 1216cabdff1aSopenharmony_ci buffer_desc.buffers = &buffer_handle; 1217cabdff1aSopenharmony_ci buffer_desc.num_buffers = 1; 1218cabdff1aSopenharmony_ci buffer_desc.flags = 0; 1219cabdff1aSopenharmony_ci 1220cabdff1aSopenharmony_ci k = 0; 1221cabdff1aSopenharmony_ci for (i = 0; i < desc->nb_layers; i++) { 1222cabdff1aSopenharmony_ci for (j = 0; j < desc->layers[i].nb_planes; j++) { 1223cabdff1aSopenharmony_ci buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch; 1224cabdff1aSopenharmony_ci buffer_desc.offsets[k] = desc->layers[i].planes[j].offset; 1225cabdff1aSopenharmony_ci ++k; 1226cabdff1aSopenharmony_ci } 1227cabdff1aSopenharmony_ci } 1228cabdff1aSopenharmony_ci buffer_desc.num_planes = k; 1229cabdff1aSopenharmony_ci 1230cabdff1aSopenharmony_ci if (format_desc->chroma_planes_swapped && 1231cabdff1aSopenharmony_ci buffer_desc.num_planes == 3) { 1232cabdff1aSopenharmony_ci FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]); 1233cabdff1aSopenharmony_ci FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]); 1234cabdff1aSopenharmony_ci } 1235cabdff1aSopenharmony_ci 1236cabdff1aSopenharmony_ci vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format, 1237cabdff1aSopenharmony_ci src->width, src->height, 1238cabdff1aSopenharmony_ci &surface_id, 1, 1239cabdff1aSopenharmony_ci attrs, FF_ARRAY_ELEMS(attrs)); 1240cabdff1aSopenharmony_ci#endif 1241cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 1242cabdff1aSopenharmony_ci av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM " 1243cabdff1aSopenharmony_ci "object: %d (%s).\n", vas, vaErrorStr(vas)); 1244cabdff1aSopenharmony_ci return AVERROR(EIO); 1245cabdff1aSopenharmony_ci } 1246cabdff1aSopenharmony_ci av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id); 1247cabdff1aSopenharmony_ci 1248cabdff1aSopenharmony_ci err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, 1249cabdff1aSopenharmony_ci &vaapi_unmap_from_drm, 1250cabdff1aSopenharmony_ci (void*)(uintptr_t)surface_id); 1251cabdff1aSopenharmony_ci if (err < 0) 1252cabdff1aSopenharmony_ci return err; 1253cabdff1aSopenharmony_ci 1254cabdff1aSopenharmony_ci dst->width = src->width; 1255cabdff1aSopenharmony_ci dst->height = src->height; 1256cabdff1aSopenharmony_ci dst->data[3] = (uint8_t*)(uintptr_t)surface_id; 1257cabdff1aSopenharmony_ci 1258cabdff1aSopenharmony_ci av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to " 1259cabdff1aSopenharmony_ci "surface %#x.\n", desc->objects[0].fd, surface_id); 1260cabdff1aSopenharmony_ci 1261cabdff1aSopenharmony_ci return 0; 1262cabdff1aSopenharmony_ci} 1263cabdff1aSopenharmony_ci 1264cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(1, 1, 0) 1265cabdff1aSopenharmony_cistatic void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc, 1266cabdff1aSopenharmony_ci HWMapDescriptor *hwmap) 1267cabdff1aSopenharmony_ci{ 1268cabdff1aSopenharmony_ci AVDRMFrameDescriptor *drm_desc = hwmap->priv; 1269cabdff1aSopenharmony_ci int i; 1270cabdff1aSopenharmony_ci 1271cabdff1aSopenharmony_ci for (i = 0; i < drm_desc->nb_objects; i++) 1272cabdff1aSopenharmony_ci close(drm_desc->objects[i].fd); 1273cabdff1aSopenharmony_ci 1274cabdff1aSopenharmony_ci av_freep(&drm_desc); 1275cabdff1aSopenharmony_ci} 1276cabdff1aSopenharmony_ci 1277cabdff1aSopenharmony_cistatic int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst, 1278cabdff1aSopenharmony_ci const AVFrame *src, int flags) 1279cabdff1aSopenharmony_ci{ 1280cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1281cabdff1aSopenharmony_ci VASurfaceID surface_id; 1282cabdff1aSopenharmony_ci VAStatus vas; 1283cabdff1aSopenharmony_ci VADRMPRIMESurfaceDescriptor va_desc; 1284cabdff1aSopenharmony_ci AVDRMFrameDescriptor *drm_desc = NULL; 1285cabdff1aSopenharmony_ci uint32_t export_flags; 1286cabdff1aSopenharmony_ci int err, i, j; 1287cabdff1aSopenharmony_ci 1288cabdff1aSopenharmony_ci surface_id = (VASurfaceID)(uintptr_t)src->data[3]; 1289cabdff1aSopenharmony_ci 1290cabdff1aSopenharmony_ci export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS; 1291cabdff1aSopenharmony_ci if (flags & AV_HWFRAME_MAP_READ) 1292cabdff1aSopenharmony_ci export_flags |= VA_EXPORT_SURFACE_READ_ONLY; 1293cabdff1aSopenharmony_ci if (flags & AV_HWFRAME_MAP_WRITE) 1294cabdff1aSopenharmony_ci export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY; 1295cabdff1aSopenharmony_ci 1296cabdff1aSopenharmony_ci vas = vaExportSurfaceHandle(hwctx->display, surface_id, 1297cabdff1aSopenharmony_ci VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, 1298cabdff1aSopenharmony_ci export_flags, &va_desc); 1299cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 1300cabdff1aSopenharmony_ci if (vas == VA_STATUS_ERROR_UNIMPLEMENTED) 1301cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 1302cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: " 1303cabdff1aSopenharmony_ci "%d (%s).\n", surface_id, vas, vaErrorStr(vas)); 1304cabdff1aSopenharmony_ci return AVERROR(EIO); 1305cabdff1aSopenharmony_ci } 1306cabdff1aSopenharmony_ci 1307cabdff1aSopenharmony_ci drm_desc = av_mallocz(sizeof(*drm_desc)); 1308cabdff1aSopenharmony_ci if (!drm_desc) { 1309cabdff1aSopenharmony_ci err = AVERROR(ENOMEM); 1310cabdff1aSopenharmony_ci goto fail; 1311cabdff1aSopenharmony_ci } 1312cabdff1aSopenharmony_ci 1313cabdff1aSopenharmony_ci // By some bizarre coincidence, these structures are very similar... 1314cabdff1aSopenharmony_ci drm_desc->nb_objects = va_desc.num_objects; 1315cabdff1aSopenharmony_ci for (i = 0; i < va_desc.num_objects; i++) { 1316cabdff1aSopenharmony_ci drm_desc->objects[i].fd = va_desc.objects[i].fd; 1317cabdff1aSopenharmony_ci drm_desc->objects[i].size = va_desc.objects[i].size; 1318cabdff1aSopenharmony_ci drm_desc->objects[i].format_modifier = 1319cabdff1aSopenharmony_ci va_desc.objects[i].drm_format_modifier; 1320cabdff1aSopenharmony_ci } 1321cabdff1aSopenharmony_ci drm_desc->nb_layers = va_desc.num_layers; 1322cabdff1aSopenharmony_ci for (i = 0; i < va_desc.num_layers; i++) { 1323cabdff1aSopenharmony_ci drm_desc->layers[i].format = va_desc.layers[i].drm_format; 1324cabdff1aSopenharmony_ci drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes; 1325cabdff1aSopenharmony_ci for (j = 0; j < va_desc.layers[i].num_planes; j++) { 1326cabdff1aSopenharmony_ci drm_desc->layers[i].planes[j].object_index = 1327cabdff1aSopenharmony_ci va_desc.layers[i].object_index[j]; 1328cabdff1aSopenharmony_ci drm_desc->layers[i].planes[j].offset = 1329cabdff1aSopenharmony_ci va_desc.layers[i].offset[j]; 1330cabdff1aSopenharmony_ci drm_desc->layers[i].planes[j].pitch = 1331cabdff1aSopenharmony_ci va_desc.layers[i].pitch[j]; 1332cabdff1aSopenharmony_ci } 1333cabdff1aSopenharmony_ci } 1334cabdff1aSopenharmony_ci 1335cabdff1aSopenharmony_ci err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, 1336cabdff1aSopenharmony_ci &vaapi_unmap_to_drm_esh, drm_desc); 1337cabdff1aSopenharmony_ci if (err < 0) 1338cabdff1aSopenharmony_ci goto fail; 1339cabdff1aSopenharmony_ci 1340cabdff1aSopenharmony_ci dst->width = src->width; 1341cabdff1aSopenharmony_ci dst->height = src->height; 1342cabdff1aSopenharmony_ci dst->data[0] = (uint8_t*)drm_desc; 1343cabdff1aSopenharmony_ci 1344cabdff1aSopenharmony_ci return 0; 1345cabdff1aSopenharmony_ci 1346cabdff1aSopenharmony_cifail: 1347cabdff1aSopenharmony_ci for (i = 0; i < va_desc.num_objects; i++) 1348cabdff1aSopenharmony_ci close(va_desc.objects[i].fd); 1349cabdff1aSopenharmony_ci av_freep(&drm_desc); 1350cabdff1aSopenharmony_ci return err; 1351cabdff1aSopenharmony_ci} 1352cabdff1aSopenharmony_ci#endif 1353cabdff1aSopenharmony_ci 1354cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(0, 36, 0) 1355cabdff1aSopenharmony_citypedef struct VAAPIDRMImageBufferMapping { 1356cabdff1aSopenharmony_ci VAImage image; 1357cabdff1aSopenharmony_ci VABufferInfo buffer_info; 1358cabdff1aSopenharmony_ci 1359cabdff1aSopenharmony_ci AVDRMFrameDescriptor drm_desc; 1360cabdff1aSopenharmony_ci} VAAPIDRMImageBufferMapping; 1361cabdff1aSopenharmony_ci 1362cabdff1aSopenharmony_cistatic void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc, 1363cabdff1aSopenharmony_ci HWMapDescriptor *hwmap) 1364cabdff1aSopenharmony_ci{ 1365cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1366cabdff1aSopenharmony_ci VAAPIDRMImageBufferMapping *mapping = hwmap->priv; 1367cabdff1aSopenharmony_ci VASurfaceID surface_id; 1368cabdff1aSopenharmony_ci VAStatus vas; 1369cabdff1aSopenharmony_ci 1370cabdff1aSopenharmony_ci surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3]; 1371cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n", 1372cabdff1aSopenharmony_ci surface_id); 1373cabdff1aSopenharmony_ci 1374cabdff1aSopenharmony_ci // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(), 1375cabdff1aSopenharmony_ci // so we shouldn't close them separately. 1376cabdff1aSopenharmony_ci 1377cabdff1aSopenharmony_ci vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf); 1378cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 1379cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer " 1380cabdff1aSopenharmony_ci "handle of image %#x (derived from surface %#x): " 1381cabdff1aSopenharmony_ci "%d (%s).\n", mapping->image.buf, surface_id, 1382cabdff1aSopenharmony_ci vas, vaErrorStr(vas)); 1383cabdff1aSopenharmony_ci } 1384cabdff1aSopenharmony_ci 1385cabdff1aSopenharmony_ci vas = vaDestroyImage(hwctx->display, mapping->image.image_id); 1386cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 1387cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image " 1388cabdff1aSopenharmony_ci "derived from surface %#x: %d (%s).\n", 1389cabdff1aSopenharmony_ci surface_id, vas, vaErrorStr(vas)); 1390cabdff1aSopenharmony_ci } 1391cabdff1aSopenharmony_ci 1392cabdff1aSopenharmony_ci av_free(mapping); 1393cabdff1aSopenharmony_ci} 1394cabdff1aSopenharmony_ci 1395cabdff1aSopenharmony_cistatic int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst, 1396cabdff1aSopenharmony_ci const AVFrame *src, int flags) 1397cabdff1aSopenharmony_ci{ 1398cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; 1399cabdff1aSopenharmony_ci VAAPIDRMImageBufferMapping *mapping = NULL; 1400cabdff1aSopenharmony_ci VASurfaceID surface_id; 1401cabdff1aSopenharmony_ci VAStatus vas; 1402cabdff1aSopenharmony_ci int err, i, p; 1403cabdff1aSopenharmony_ci 1404cabdff1aSopenharmony_ci surface_id = (VASurfaceID)(uintptr_t)src->data[3]; 1405cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n", 1406cabdff1aSopenharmony_ci surface_id); 1407cabdff1aSopenharmony_ci 1408cabdff1aSopenharmony_ci mapping = av_mallocz(sizeof(*mapping)); 1409cabdff1aSopenharmony_ci if (!mapping) 1410cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1411cabdff1aSopenharmony_ci 1412cabdff1aSopenharmony_ci vas = vaDeriveImage(hwctx->display, surface_id, 1413cabdff1aSopenharmony_ci &mapping->image); 1414cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 1415cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from " 1416cabdff1aSopenharmony_ci "surface %#x: %d (%s).\n", 1417cabdff1aSopenharmony_ci surface_id, vas, vaErrorStr(vas)); 1418cabdff1aSopenharmony_ci err = AVERROR(EIO); 1419cabdff1aSopenharmony_ci goto fail; 1420cabdff1aSopenharmony_ci } 1421cabdff1aSopenharmony_ci 1422cabdff1aSopenharmony_ci for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) { 1423cabdff1aSopenharmony_ci if (vaapi_drm_format_map[i].va_fourcc == 1424cabdff1aSopenharmony_ci mapping->image.format.fourcc) 1425cabdff1aSopenharmony_ci break; 1426cabdff1aSopenharmony_ci } 1427cabdff1aSopenharmony_ci if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) { 1428cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for " 1429cabdff1aSopenharmony_ci "VAAPI format %#x.\n", mapping->image.format.fourcc); 1430cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 1431cabdff1aSopenharmony_ci goto fail_derived; 1432cabdff1aSopenharmony_ci } 1433cabdff1aSopenharmony_ci 1434cabdff1aSopenharmony_ci mapping->buffer_info.mem_type = 1435cabdff1aSopenharmony_ci VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; 1436cabdff1aSopenharmony_ci 1437cabdff1aSopenharmony_ci mapping->drm_desc.nb_layers = 1438cabdff1aSopenharmony_ci vaapi_drm_format_map[i].nb_layer_formats; 1439cabdff1aSopenharmony_ci if (mapping->drm_desc.nb_layers > 1) { 1440cabdff1aSopenharmony_ci if (mapping->drm_desc.nb_layers != mapping->image.num_planes) { 1441cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Image properties do not match " 1442cabdff1aSopenharmony_ci "expected format: got %d planes, but expected %d.\n", 1443cabdff1aSopenharmony_ci mapping->image.num_planes, mapping->drm_desc.nb_layers); 1444cabdff1aSopenharmony_ci err = AVERROR(EINVAL); 1445cabdff1aSopenharmony_ci goto fail_derived; 1446cabdff1aSopenharmony_ci } 1447cabdff1aSopenharmony_ci 1448cabdff1aSopenharmony_ci for(p = 0; p < mapping->drm_desc.nb_layers; p++) { 1449cabdff1aSopenharmony_ci mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) { 1450cabdff1aSopenharmony_ci .format = vaapi_drm_format_map[i].layer_formats[p], 1451cabdff1aSopenharmony_ci .nb_planes = 1, 1452cabdff1aSopenharmony_ci .planes[0] = { 1453cabdff1aSopenharmony_ci .object_index = 0, 1454cabdff1aSopenharmony_ci .offset = mapping->image.offsets[p], 1455cabdff1aSopenharmony_ci .pitch = mapping->image.pitches[p], 1456cabdff1aSopenharmony_ci }, 1457cabdff1aSopenharmony_ci }; 1458cabdff1aSopenharmony_ci } 1459cabdff1aSopenharmony_ci } else { 1460cabdff1aSopenharmony_ci mapping->drm_desc.layers[0].format = 1461cabdff1aSopenharmony_ci vaapi_drm_format_map[i].layer_formats[0]; 1462cabdff1aSopenharmony_ci mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes; 1463cabdff1aSopenharmony_ci for (p = 0; p < mapping->image.num_planes; p++) { 1464cabdff1aSopenharmony_ci mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) { 1465cabdff1aSopenharmony_ci .object_index = 0, 1466cabdff1aSopenharmony_ci .offset = mapping->image.offsets[p], 1467cabdff1aSopenharmony_ci .pitch = mapping->image.pitches[p], 1468cabdff1aSopenharmony_ci }; 1469cabdff1aSopenharmony_ci } 1470cabdff1aSopenharmony_ci } 1471cabdff1aSopenharmony_ci 1472cabdff1aSopenharmony_ci vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf, 1473cabdff1aSopenharmony_ci &mapping->buffer_info); 1474cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 1475cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer " 1476cabdff1aSopenharmony_ci "handle from image %#x (derived from surface %#x): " 1477cabdff1aSopenharmony_ci "%d (%s).\n", mapping->image.buf, surface_id, 1478cabdff1aSopenharmony_ci vas, vaErrorStr(vas)); 1479cabdff1aSopenharmony_ci err = AVERROR(EIO); 1480cabdff1aSopenharmony_ci goto fail_derived; 1481cabdff1aSopenharmony_ci } 1482cabdff1aSopenharmony_ci 1483cabdff1aSopenharmony_ci av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n", 1484cabdff1aSopenharmony_ci mapping->buffer_info.handle); 1485cabdff1aSopenharmony_ci 1486cabdff1aSopenharmony_ci mapping->drm_desc.nb_objects = 1; 1487cabdff1aSopenharmony_ci mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) { 1488cabdff1aSopenharmony_ci .fd = mapping->buffer_info.handle, 1489cabdff1aSopenharmony_ci .size = mapping->image.data_size, 1490cabdff1aSopenharmony_ci // There is no way to get the format modifier with this API. 1491cabdff1aSopenharmony_ci .format_modifier = DRM_FORMAT_MOD_INVALID, 1492cabdff1aSopenharmony_ci }; 1493cabdff1aSopenharmony_ci 1494cabdff1aSopenharmony_ci err = ff_hwframe_map_create(src->hw_frames_ctx, 1495cabdff1aSopenharmony_ci dst, src, &vaapi_unmap_to_drm_abh, 1496cabdff1aSopenharmony_ci mapping); 1497cabdff1aSopenharmony_ci if (err < 0) 1498cabdff1aSopenharmony_ci goto fail_mapped; 1499cabdff1aSopenharmony_ci 1500cabdff1aSopenharmony_ci dst->data[0] = (uint8_t*)&mapping->drm_desc; 1501cabdff1aSopenharmony_ci dst->width = src->width; 1502cabdff1aSopenharmony_ci dst->height = src->height; 1503cabdff1aSopenharmony_ci 1504cabdff1aSopenharmony_ci return 0; 1505cabdff1aSopenharmony_ci 1506cabdff1aSopenharmony_cifail_mapped: 1507cabdff1aSopenharmony_ci vaReleaseBufferHandle(hwctx->display, mapping->image.buf); 1508cabdff1aSopenharmony_cifail_derived: 1509cabdff1aSopenharmony_ci vaDestroyImage(hwctx->display, mapping->image.image_id); 1510cabdff1aSopenharmony_cifail: 1511cabdff1aSopenharmony_ci av_freep(&mapping); 1512cabdff1aSopenharmony_ci return err; 1513cabdff1aSopenharmony_ci} 1514cabdff1aSopenharmony_ci#endif 1515cabdff1aSopenharmony_ci 1516cabdff1aSopenharmony_cistatic int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, 1517cabdff1aSopenharmony_ci const AVFrame *src, int flags) 1518cabdff1aSopenharmony_ci{ 1519cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(1, 1, 0) 1520cabdff1aSopenharmony_ci int err; 1521cabdff1aSopenharmony_ci err = vaapi_map_to_drm_esh(hwfc, dst, src, flags); 1522cabdff1aSopenharmony_ci if (err != AVERROR(ENOSYS)) 1523cabdff1aSopenharmony_ci return err; 1524cabdff1aSopenharmony_ci#endif 1525cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(0, 36, 0) 1526cabdff1aSopenharmony_ci return vaapi_map_to_drm_abh(hwfc, dst, src, flags); 1527cabdff1aSopenharmony_ci#endif 1528cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 1529cabdff1aSopenharmony_ci} 1530cabdff1aSopenharmony_ci 1531cabdff1aSopenharmony_ci#endif /* CONFIG_LIBDRM */ 1532cabdff1aSopenharmony_ci 1533cabdff1aSopenharmony_cistatic int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst, 1534cabdff1aSopenharmony_ci const AVFrame *src, int flags) 1535cabdff1aSopenharmony_ci{ 1536cabdff1aSopenharmony_ci switch (src->format) { 1537cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 1538cabdff1aSopenharmony_ci case AV_PIX_FMT_DRM_PRIME: 1539cabdff1aSopenharmony_ci return vaapi_map_from_drm(hwfc, dst, src, flags); 1540cabdff1aSopenharmony_ci#endif 1541cabdff1aSopenharmony_ci default: 1542cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 1543cabdff1aSopenharmony_ci } 1544cabdff1aSopenharmony_ci} 1545cabdff1aSopenharmony_ci 1546cabdff1aSopenharmony_cistatic int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst, 1547cabdff1aSopenharmony_ci const AVFrame *src, int flags) 1548cabdff1aSopenharmony_ci{ 1549cabdff1aSopenharmony_ci switch (dst->format) { 1550cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 1551cabdff1aSopenharmony_ci case AV_PIX_FMT_DRM_PRIME: 1552cabdff1aSopenharmony_ci return vaapi_map_to_drm(hwfc, dst, src, flags); 1553cabdff1aSopenharmony_ci#endif 1554cabdff1aSopenharmony_ci default: 1555cabdff1aSopenharmony_ci return vaapi_map_to_memory(hwfc, dst, src, flags); 1556cabdff1aSopenharmony_ci } 1557cabdff1aSopenharmony_ci} 1558cabdff1aSopenharmony_ci 1559cabdff1aSopenharmony_cistatic void vaapi_device_free(AVHWDeviceContext *ctx) 1560cabdff1aSopenharmony_ci{ 1561cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = ctx->hwctx; 1562cabdff1aSopenharmony_ci VAAPIDevicePriv *priv = ctx->user_opaque; 1563cabdff1aSopenharmony_ci 1564cabdff1aSopenharmony_ci if (hwctx->display) 1565cabdff1aSopenharmony_ci vaTerminate(hwctx->display); 1566cabdff1aSopenharmony_ci 1567cabdff1aSopenharmony_ci#if HAVE_VAAPI_X11 1568cabdff1aSopenharmony_ci if (priv->x11_display) 1569cabdff1aSopenharmony_ci XCloseDisplay(priv->x11_display); 1570cabdff1aSopenharmony_ci#endif 1571cabdff1aSopenharmony_ci 1572cabdff1aSopenharmony_ci if (priv->drm_fd >= 0) 1573cabdff1aSopenharmony_ci close(priv->drm_fd); 1574cabdff1aSopenharmony_ci 1575cabdff1aSopenharmony_ci av_freep(&priv); 1576cabdff1aSopenharmony_ci} 1577cabdff1aSopenharmony_ci 1578cabdff1aSopenharmony_ci#if CONFIG_VAAPI_1 1579cabdff1aSopenharmony_cistatic void vaapi_device_log_error(void *context, const char *message) 1580cabdff1aSopenharmony_ci{ 1581cabdff1aSopenharmony_ci AVHWDeviceContext *ctx = context; 1582cabdff1aSopenharmony_ci 1583cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "libva: %s", message); 1584cabdff1aSopenharmony_ci} 1585cabdff1aSopenharmony_ci 1586cabdff1aSopenharmony_cistatic void vaapi_device_log_info(void *context, const char *message) 1587cabdff1aSopenharmony_ci{ 1588cabdff1aSopenharmony_ci AVHWDeviceContext *ctx = context; 1589cabdff1aSopenharmony_ci 1590cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message); 1591cabdff1aSopenharmony_ci} 1592cabdff1aSopenharmony_ci#endif 1593cabdff1aSopenharmony_ci 1594cabdff1aSopenharmony_cistatic int vaapi_device_connect(AVHWDeviceContext *ctx, 1595cabdff1aSopenharmony_ci VADisplay display) 1596cabdff1aSopenharmony_ci{ 1597cabdff1aSopenharmony_ci AVVAAPIDeviceContext *hwctx = ctx->hwctx; 1598cabdff1aSopenharmony_ci int major, minor; 1599cabdff1aSopenharmony_ci VAStatus vas; 1600cabdff1aSopenharmony_ci 1601cabdff1aSopenharmony_ci#if CONFIG_VAAPI_1 1602cabdff1aSopenharmony_ci vaSetErrorCallback(display, &vaapi_device_log_error, ctx); 1603cabdff1aSopenharmony_ci vaSetInfoCallback (display, &vaapi_device_log_info, ctx); 1604cabdff1aSopenharmony_ci#endif 1605cabdff1aSopenharmony_ci 1606cabdff1aSopenharmony_ci hwctx->display = display; 1607cabdff1aSopenharmony_ci 1608cabdff1aSopenharmony_ci vas = vaInitialize(display, &major, &minor); 1609cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 1610cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI " 1611cabdff1aSopenharmony_ci "connection: %d (%s).\n", vas, vaErrorStr(vas)); 1612cabdff1aSopenharmony_ci return AVERROR(EIO); 1613cabdff1aSopenharmony_ci } 1614cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: " 1615cabdff1aSopenharmony_ci "version %d.%d\n", major, minor); 1616cabdff1aSopenharmony_ci 1617cabdff1aSopenharmony_ci return 0; 1618cabdff1aSopenharmony_ci} 1619cabdff1aSopenharmony_ci 1620cabdff1aSopenharmony_cistatic int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, 1621cabdff1aSopenharmony_ci AVDictionary *opts, int flags) 1622cabdff1aSopenharmony_ci{ 1623cabdff1aSopenharmony_ci VAAPIDevicePriv *priv; 1624cabdff1aSopenharmony_ci VADisplay display = NULL; 1625cabdff1aSopenharmony_ci const AVDictionaryEntry *ent; 1626cabdff1aSopenharmony_ci int try_drm, try_x11, try_all; 1627cabdff1aSopenharmony_ci 1628cabdff1aSopenharmony_ci priv = av_mallocz(sizeof(*priv)); 1629cabdff1aSopenharmony_ci if (!priv) 1630cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1631cabdff1aSopenharmony_ci 1632cabdff1aSopenharmony_ci priv->drm_fd = -1; 1633cabdff1aSopenharmony_ci 1634cabdff1aSopenharmony_ci ctx->user_opaque = priv; 1635cabdff1aSopenharmony_ci ctx->free = vaapi_device_free; 1636cabdff1aSopenharmony_ci 1637cabdff1aSopenharmony_ci ent = av_dict_get(opts, "connection_type", NULL, 0); 1638cabdff1aSopenharmony_ci if (ent) { 1639cabdff1aSopenharmony_ci try_all = try_drm = try_x11 = 0; 1640cabdff1aSopenharmony_ci if (!strcmp(ent->value, "drm")) { 1641cabdff1aSopenharmony_ci try_drm = 1; 1642cabdff1aSopenharmony_ci } else if (!strcmp(ent->value, "x11")) { 1643cabdff1aSopenharmony_ci try_x11 = 1; 1644cabdff1aSopenharmony_ci } else { 1645cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n", 1646cabdff1aSopenharmony_ci ent->value); 1647cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1648cabdff1aSopenharmony_ci } 1649cabdff1aSopenharmony_ci } else { 1650cabdff1aSopenharmony_ci try_all = 1; 1651cabdff1aSopenharmony_ci try_drm = HAVE_VAAPI_DRM; 1652cabdff1aSopenharmony_ci try_x11 = HAVE_VAAPI_X11; 1653cabdff1aSopenharmony_ci } 1654cabdff1aSopenharmony_ci 1655cabdff1aSopenharmony_ci#if HAVE_VAAPI_DRM 1656cabdff1aSopenharmony_ci while (!display && try_drm) { 1657cabdff1aSopenharmony_ci // If the device is specified, try to open it as a DRM device node. 1658cabdff1aSopenharmony_ci // If not, look for a usable render node, possibly restricted to those 1659cabdff1aSopenharmony_ci // using a specified kernel driver. 1660cabdff1aSopenharmony_ci int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR; 1661cabdff1aSopenharmony_ci if (device) { 1662cabdff1aSopenharmony_ci priv->drm_fd = open(device, O_RDWR); 1663cabdff1aSopenharmony_ci if (priv->drm_fd < 0) { 1664cabdff1aSopenharmony_ci av_log(ctx, loglevel, "Failed to open %s as " 1665cabdff1aSopenharmony_ci "DRM device node.\n", device); 1666cabdff1aSopenharmony_ci break; 1667cabdff1aSopenharmony_ci } 1668cabdff1aSopenharmony_ci } else { 1669cabdff1aSopenharmony_ci char path[64]; 1670cabdff1aSopenharmony_ci int n, max_devices = 8; 1671cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 1672cabdff1aSopenharmony_ci const AVDictionaryEntry *kernel_driver; 1673cabdff1aSopenharmony_ci kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0); 1674cabdff1aSopenharmony_ci#endif 1675cabdff1aSopenharmony_ci for (n = 0; n < max_devices; n++) { 1676cabdff1aSopenharmony_ci snprintf(path, sizeof(path), 1677cabdff1aSopenharmony_ci "/dev/dri/renderD%d", 128 + n); 1678cabdff1aSopenharmony_ci priv->drm_fd = open(path, O_RDWR); 1679cabdff1aSopenharmony_ci if (priv->drm_fd < 0) { 1680cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Cannot open " 1681cabdff1aSopenharmony_ci "DRM render node for device %d.\n", n); 1682cabdff1aSopenharmony_ci break; 1683cabdff1aSopenharmony_ci } 1684cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 1685cabdff1aSopenharmony_ci if (kernel_driver) { 1686cabdff1aSopenharmony_ci drmVersion *info; 1687cabdff1aSopenharmony_ci info = drmGetVersion(priv->drm_fd); 1688cabdff1aSopenharmony_ci if (strcmp(kernel_driver->value, info->name)) { 1689cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d " 1690cabdff1aSopenharmony_ci "with non-matching kernel driver (%s).\n", 1691cabdff1aSopenharmony_ci n, info->name); 1692cabdff1aSopenharmony_ci drmFreeVersion(info); 1693cabdff1aSopenharmony_ci close(priv->drm_fd); 1694cabdff1aSopenharmony_ci priv->drm_fd = -1; 1695cabdff1aSopenharmony_ci continue; 1696cabdff1aSopenharmony_ci } 1697cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Trying to use " 1698cabdff1aSopenharmony_ci "DRM render node for device %d, " 1699cabdff1aSopenharmony_ci "with matching kernel driver (%s).\n", 1700cabdff1aSopenharmony_ci n, info->name); 1701cabdff1aSopenharmony_ci drmFreeVersion(info); 1702cabdff1aSopenharmony_ci } else 1703cabdff1aSopenharmony_ci#endif 1704cabdff1aSopenharmony_ci { 1705cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Trying to use " 1706cabdff1aSopenharmony_ci "DRM render node for device %d.\n", n); 1707cabdff1aSopenharmony_ci } 1708cabdff1aSopenharmony_ci break; 1709cabdff1aSopenharmony_ci } 1710cabdff1aSopenharmony_ci if (n >= max_devices) 1711cabdff1aSopenharmony_ci break; 1712cabdff1aSopenharmony_ci } 1713cabdff1aSopenharmony_ci 1714cabdff1aSopenharmony_ci display = vaGetDisplayDRM(priv->drm_fd); 1715cabdff1aSopenharmony_ci if (!display) { 1716cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display " 1717cabdff1aSopenharmony_ci "from DRM device %s.\n", device); 1718cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1719cabdff1aSopenharmony_ci } 1720cabdff1aSopenharmony_ci break; 1721cabdff1aSopenharmony_ci } 1722cabdff1aSopenharmony_ci#endif 1723cabdff1aSopenharmony_ci 1724cabdff1aSopenharmony_ci#if HAVE_VAAPI_X11 1725cabdff1aSopenharmony_ci if (!display && try_x11) { 1726cabdff1aSopenharmony_ci // Try to open the device as an X11 display. 1727cabdff1aSopenharmony_ci priv->x11_display = XOpenDisplay(device); 1728cabdff1aSopenharmony_ci if (!priv->x11_display) { 1729cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display " 1730cabdff1aSopenharmony_ci "%s.\n", XDisplayName(device)); 1731cabdff1aSopenharmony_ci } else { 1732cabdff1aSopenharmony_ci display = vaGetDisplay(priv->x11_display); 1733cabdff1aSopenharmony_ci if (!display) { 1734cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display " 1735cabdff1aSopenharmony_ci "from X11 display %s.\n", XDisplayName(device)); 1736cabdff1aSopenharmony_ci return AVERROR_UNKNOWN; 1737cabdff1aSopenharmony_ci } 1738cabdff1aSopenharmony_ci 1739cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via " 1740cabdff1aSopenharmony_ci "X11 display %s.\n", XDisplayName(device)); 1741cabdff1aSopenharmony_ci } 1742cabdff1aSopenharmony_ci } 1743cabdff1aSopenharmony_ci#endif 1744cabdff1aSopenharmony_ci 1745cabdff1aSopenharmony_ci if (!display) { 1746cabdff1aSopenharmony_ci if (device) 1747cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "No VA display found for " 1748cabdff1aSopenharmony_ci "device %s.\n", device); 1749cabdff1aSopenharmony_ci else 1750cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "No VA display found for " 1751cabdff1aSopenharmony_ci "any default device.\n"); 1752cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1753cabdff1aSopenharmony_ci } 1754cabdff1aSopenharmony_ci 1755cabdff1aSopenharmony_ci ent = av_dict_get(opts, "driver", NULL, 0); 1756cabdff1aSopenharmony_ci if (ent) { 1757cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(0, 38, 0) 1758cabdff1aSopenharmony_ci VAStatus vas; 1759cabdff1aSopenharmony_ci vas = vaSetDriverName(display, ent->value); 1760cabdff1aSopenharmony_ci if (vas != VA_STATUS_SUCCESS) { 1761cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to " 1762cabdff1aSopenharmony_ci "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas)); 1763cabdff1aSopenharmony_ci vaTerminate(display); 1764cabdff1aSopenharmony_ci return AVERROR_EXTERNAL; 1765cabdff1aSopenharmony_ci } 1766cabdff1aSopenharmony_ci#else 1767cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_WARNING, "Driver name setting is not " 1768cabdff1aSopenharmony_ci "supported with this VAAPI version.\n"); 1769cabdff1aSopenharmony_ci#endif 1770cabdff1aSopenharmony_ci } 1771cabdff1aSopenharmony_ci 1772cabdff1aSopenharmony_ci return vaapi_device_connect(ctx, display); 1773cabdff1aSopenharmony_ci} 1774cabdff1aSopenharmony_ci 1775cabdff1aSopenharmony_cistatic int vaapi_device_derive(AVHWDeviceContext *ctx, 1776cabdff1aSopenharmony_ci AVHWDeviceContext *src_ctx, 1777cabdff1aSopenharmony_ci AVDictionary *opts, int flags) 1778cabdff1aSopenharmony_ci{ 1779cabdff1aSopenharmony_ci#if HAVE_VAAPI_DRM 1780cabdff1aSopenharmony_ci if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) { 1781cabdff1aSopenharmony_ci AVDRMDeviceContext *src_hwctx = src_ctx->hwctx; 1782cabdff1aSopenharmony_ci VADisplay *display; 1783cabdff1aSopenharmony_ci VAAPIDevicePriv *priv; 1784cabdff1aSopenharmony_ci int fd; 1785cabdff1aSopenharmony_ci 1786cabdff1aSopenharmony_ci if (src_hwctx->fd < 0) { 1787cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated " 1788cabdff1aSopenharmony_ci "device to derive a VA display from.\n"); 1789cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1790cabdff1aSopenharmony_ci } 1791cabdff1aSopenharmony_ci 1792cabdff1aSopenharmony_ci#if CONFIG_LIBDRM 1793cabdff1aSopenharmony_ci { 1794cabdff1aSopenharmony_ci int node_type = drmGetNodeTypeFromFd(src_hwctx->fd); 1795cabdff1aSopenharmony_ci char *render_node; 1796cabdff1aSopenharmony_ci if (node_type < 0) { 1797cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "DRM instance fd does not appear " 1798cabdff1aSopenharmony_ci "to refer to a DRM device.\n"); 1799cabdff1aSopenharmony_ci return AVERROR(EINVAL); 1800cabdff1aSopenharmony_ci } 1801cabdff1aSopenharmony_ci if (node_type == DRM_NODE_RENDER) { 1802cabdff1aSopenharmony_ci fd = src_hwctx->fd; 1803cabdff1aSopenharmony_ci } else { 1804cabdff1aSopenharmony_ci render_node = drmGetRenderDeviceNameFromFd(src_hwctx->fd); 1805cabdff1aSopenharmony_ci if (!render_node) { 1806cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Using non-render node " 1807cabdff1aSopenharmony_ci "because the device does not have an " 1808cabdff1aSopenharmony_ci "associated render node.\n"); 1809cabdff1aSopenharmony_ci fd = src_hwctx->fd; 1810cabdff1aSopenharmony_ci } else { 1811cabdff1aSopenharmony_ci fd = open(render_node, O_RDWR); 1812cabdff1aSopenharmony_ci if (fd < 0) { 1813cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Using non-render node " 1814cabdff1aSopenharmony_ci "because the associated render node " 1815cabdff1aSopenharmony_ci "could not be opened.\n"); 1816cabdff1aSopenharmony_ci fd = src_hwctx->fd; 1817cabdff1aSopenharmony_ci } else { 1818cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_VERBOSE, "Using render node %s " 1819cabdff1aSopenharmony_ci "in place of non-render DRM device.\n", 1820cabdff1aSopenharmony_ci render_node); 1821cabdff1aSopenharmony_ci } 1822cabdff1aSopenharmony_ci free(render_node); 1823cabdff1aSopenharmony_ci } 1824cabdff1aSopenharmony_ci } 1825cabdff1aSopenharmony_ci } 1826cabdff1aSopenharmony_ci#else 1827cabdff1aSopenharmony_ci fd = src_hwctx->fd; 1828cabdff1aSopenharmony_ci#endif 1829cabdff1aSopenharmony_ci 1830cabdff1aSopenharmony_ci priv = av_mallocz(sizeof(*priv)); 1831cabdff1aSopenharmony_ci if (!priv) { 1832cabdff1aSopenharmony_ci if (fd != src_hwctx->fd) { 1833cabdff1aSopenharmony_ci // The fd was opened in this function. 1834cabdff1aSopenharmony_ci close(fd); 1835cabdff1aSopenharmony_ci } 1836cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 1837cabdff1aSopenharmony_ci } 1838cabdff1aSopenharmony_ci 1839cabdff1aSopenharmony_ci if (fd == src_hwctx->fd) { 1840cabdff1aSopenharmony_ci // The fd is inherited from the source context and we are holding 1841cabdff1aSopenharmony_ci // a reference to that, we don't want to close it from here. 1842cabdff1aSopenharmony_ci priv->drm_fd = -1; 1843cabdff1aSopenharmony_ci } else { 1844cabdff1aSopenharmony_ci priv->drm_fd = fd; 1845cabdff1aSopenharmony_ci } 1846cabdff1aSopenharmony_ci 1847cabdff1aSopenharmony_ci ctx->user_opaque = priv; 1848cabdff1aSopenharmony_ci ctx->free = &vaapi_device_free; 1849cabdff1aSopenharmony_ci 1850cabdff1aSopenharmony_ci display = vaGetDisplayDRM(fd); 1851cabdff1aSopenharmony_ci if (!display) { 1852cabdff1aSopenharmony_ci av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from " 1853cabdff1aSopenharmony_ci "DRM device.\n"); 1854cabdff1aSopenharmony_ci return AVERROR(EIO); 1855cabdff1aSopenharmony_ci } 1856cabdff1aSopenharmony_ci 1857cabdff1aSopenharmony_ci return vaapi_device_connect(ctx, display); 1858cabdff1aSopenharmony_ci } 1859cabdff1aSopenharmony_ci#endif 1860cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 1861cabdff1aSopenharmony_ci} 1862cabdff1aSopenharmony_ci 1863cabdff1aSopenharmony_ciconst HWContextType ff_hwcontext_type_vaapi = { 1864cabdff1aSopenharmony_ci .type = AV_HWDEVICE_TYPE_VAAPI, 1865cabdff1aSopenharmony_ci .name = "VAAPI", 1866cabdff1aSopenharmony_ci 1867cabdff1aSopenharmony_ci .device_hwctx_size = sizeof(AVVAAPIDeviceContext), 1868cabdff1aSopenharmony_ci .device_priv_size = sizeof(VAAPIDeviceContext), 1869cabdff1aSopenharmony_ci .device_hwconfig_size = sizeof(AVVAAPIHWConfig), 1870cabdff1aSopenharmony_ci .frames_hwctx_size = sizeof(AVVAAPIFramesContext), 1871cabdff1aSopenharmony_ci .frames_priv_size = sizeof(VAAPIFramesContext), 1872cabdff1aSopenharmony_ci 1873cabdff1aSopenharmony_ci .device_create = &vaapi_device_create, 1874cabdff1aSopenharmony_ci .device_derive = &vaapi_device_derive, 1875cabdff1aSopenharmony_ci .device_init = &vaapi_device_init, 1876cabdff1aSopenharmony_ci .device_uninit = &vaapi_device_uninit, 1877cabdff1aSopenharmony_ci .frames_get_constraints = &vaapi_frames_get_constraints, 1878cabdff1aSopenharmony_ci .frames_init = &vaapi_frames_init, 1879cabdff1aSopenharmony_ci .frames_uninit = &vaapi_frames_uninit, 1880cabdff1aSopenharmony_ci .frames_get_buffer = &vaapi_get_buffer, 1881cabdff1aSopenharmony_ci .transfer_get_formats = &vaapi_transfer_get_formats, 1882cabdff1aSopenharmony_ci .transfer_data_to = &vaapi_transfer_data_to, 1883cabdff1aSopenharmony_ci .transfer_data_from = &vaapi_transfer_data_from, 1884cabdff1aSopenharmony_ci .map_to = &vaapi_map_to, 1885cabdff1aSopenharmony_ci .map_from = &vaapi_map_from, 1886cabdff1aSopenharmony_ci 1887cabdff1aSopenharmony_ci .pix_fmts = (const enum AVPixelFormat[]) { 1888cabdff1aSopenharmony_ci AV_PIX_FMT_VAAPI, 1889cabdff1aSopenharmony_ci AV_PIX_FMT_NONE 1890cabdff1aSopenharmony_ci }, 1891cabdff1aSopenharmony_ci}; 1892