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.

1584 lines
51KB

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