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.

1737 lines
56KB

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