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.

1388 lines
44KB

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