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.

1766 lines
57KB

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