You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1734 lines
56KB

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