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.

1381 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, preferred_format;
  570. int i, k;
  571. preferred_format = hwfc->sw_format;
  572. pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
  573. if (!pix_fmts)
  574. return AVERROR(ENOMEM);
  575. pix_fmts[0] = preferred_format;
  576. k = 1;
  577. for (i = 0; i < ctx->nb_formats; i++) {
  578. if (ctx->formats[i].pix_fmt == preferred_format)
  579. continue;
  580. av_assert0(k < ctx->nb_formats);
  581. pix_fmts[k++] = ctx->formats[i].pix_fmt;
  582. }
  583. av_assert0(k == ctx->nb_formats);
  584. pix_fmts[k] = AV_PIX_FMT_NONE;
  585. *formats = pix_fmts;
  586. return 0;
  587. }
  588. static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
  589. HWMapDescriptor *hwmap)
  590. {
  591. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  592. VAAPIMapping *map = hwmap->priv;
  593. VASurfaceID surface_id;
  594. VAStatus vas;
  595. surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
  596. av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
  597. vas = vaUnmapBuffer(hwctx->display, map->image.buf);
  598. if (vas != VA_STATUS_SUCCESS) {
  599. av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
  600. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  601. }
  602. if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
  603. !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
  604. vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
  605. 0, 0, hwfc->width, hwfc->height,
  606. 0, 0, hwfc->width, hwfc->height);
  607. if (vas != VA_STATUS_SUCCESS) {
  608. av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
  609. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  610. }
  611. }
  612. vas = vaDestroyImage(hwctx->display, map->image.image_id);
  613. if (vas != VA_STATUS_SUCCESS) {
  614. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
  615. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  616. }
  617. av_free(map);
  618. }
  619. static int vaapi_map_frame(AVHWFramesContext *hwfc,
  620. AVFrame *dst, const AVFrame *src, int flags)
  621. {
  622. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  623. VAAPIFramesContext *ctx = hwfc->internal->priv;
  624. VASurfaceID surface_id;
  625. VAImageFormat *image_format;
  626. VAAPIMapping *map;
  627. VAStatus vas;
  628. void *address = NULL;
  629. int err, i;
  630. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  631. av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
  632. if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
  633. // Requested direct mapping but it is not possible.
  634. return AVERROR(EINVAL);
  635. }
  636. if (dst->format == AV_PIX_FMT_NONE)
  637. dst->format = hwfc->sw_format;
  638. if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
  639. // Requested direct mapping but the formats do not match.
  640. return AVERROR(EINVAL);
  641. }
  642. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
  643. if (err < 0) {
  644. // Requested format is not a valid output format.
  645. return AVERROR(EINVAL);
  646. }
  647. map = av_malloc(sizeof(*map));
  648. if (!map)
  649. return AVERROR(ENOMEM);
  650. map->flags = flags;
  651. map->image.image_id = VA_INVALID_ID;
  652. vas = vaSyncSurface(hwctx->display, surface_id);
  653. if (vas != VA_STATUS_SUCCESS) {
  654. av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
  655. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  656. err = AVERROR(EIO);
  657. goto fail;
  658. }
  659. // The memory which we map using derive need not be connected to the CPU
  660. // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
  661. // memory is mappable but not cached, so normal memcpy()-like access is
  662. // very slow to read it (but writing is ok). It is possible to read much
  663. // faster with a copy routine which is aware of the limitation, but we
  664. // assume for now that the user is not aware of that and would therefore
  665. // prefer not to be given direct-mapped memory if they request read access.
  666. if (ctx->derive_works && dst->format == hwfc->sw_format &&
  667. ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
  668. vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
  669. if (vas != VA_STATUS_SUCCESS) {
  670. av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
  671. "surface %#x: %d (%s).\n",
  672. surface_id, vas, vaErrorStr(vas));
  673. err = AVERROR(EIO);
  674. goto fail;
  675. }
  676. if (map->image.format.fourcc != image_format->fourcc) {
  677. av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
  678. "is in wrong format: expected %#08x, got %#08x.\n",
  679. surface_id, image_format->fourcc, map->image.format.fourcc);
  680. err = AVERROR(EIO);
  681. goto fail;
  682. }
  683. map->flags |= AV_HWFRAME_MAP_DIRECT;
  684. } else {
  685. vas = vaCreateImage(hwctx->display, image_format,
  686. hwfc->width, hwfc->height, &map->image);
  687. if (vas != VA_STATUS_SUCCESS) {
  688. av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
  689. "surface %#x: %d (%s).\n",
  690. surface_id, vas, vaErrorStr(vas));
  691. err = AVERROR(EIO);
  692. goto fail;
  693. }
  694. if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
  695. vas = vaGetImage(hwctx->display, surface_id, 0, 0,
  696. hwfc->width, hwfc->height, map->image.image_id);
  697. if (vas != VA_STATUS_SUCCESS) {
  698. av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
  699. "surface %#x: %d (%s).\n",
  700. surface_id, vas, vaErrorStr(vas));
  701. err = AVERROR(EIO);
  702. goto fail;
  703. }
  704. }
  705. }
  706. vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
  707. if (vas != VA_STATUS_SUCCESS) {
  708. av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
  709. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  710. err = AVERROR(EIO);
  711. goto fail;
  712. }
  713. err = ff_hwframe_map_create(src->hw_frames_ctx,
  714. dst, src, &vaapi_unmap_frame, map);
  715. if (err < 0)
  716. goto fail;
  717. dst->width = src->width;
  718. dst->height = src->height;
  719. for (i = 0; i < map->image.num_planes; i++) {
  720. dst->data[i] = (uint8_t*)address + map->image.offsets[i];
  721. dst->linesize[i] = map->image.pitches[i];
  722. }
  723. if (
  724. #ifdef VA_FOURCC_YV16
  725. map->image.format.fourcc == VA_FOURCC_YV16 ||
  726. #endif
  727. map->image.format.fourcc == VA_FOURCC_YV12) {
  728. // Chroma planes are YVU rather than YUV, so swap them.
  729. FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
  730. }
  731. return 0;
  732. fail:
  733. if (map) {
  734. if (address)
  735. vaUnmapBuffer(hwctx->display, map->image.buf);
  736. if (map->image.image_id != VA_INVALID_ID)
  737. vaDestroyImage(hwctx->display, map->image.image_id);
  738. av_free(map);
  739. }
  740. return err;
  741. }
  742. static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
  743. AVFrame *dst, const AVFrame *src)
  744. {
  745. AVFrame *map;
  746. int err;
  747. if (dst->width > hwfc->width || dst->height > hwfc->height)
  748. return AVERROR(EINVAL);
  749. map = av_frame_alloc();
  750. if (!map)
  751. return AVERROR(ENOMEM);
  752. map->format = dst->format;
  753. err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
  754. if (err)
  755. goto fail;
  756. map->width = dst->width;
  757. map->height = dst->height;
  758. err = av_frame_copy(dst, map);
  759. if (err)
  760. goto fail;
  761. err = 0;
  762. fail:
  763. av_frame_free(&map);
  764. return err;
  765. }
  766. static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
  767. AVFrame *dst, const AVFrame *src)
  768. {
  769. AVFrame *map;
  770. int err;
  771. if (src->width > hwfc->width || src->height > hwfc->height)
  772. return AVERROR(EINVAL);
  773. map = av_frame_alloc();
  774. if (!map)
  775. return AVERROR(ENOMEM);
  776. map->format = src->format;
  777. err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
  778. if (err)
  779. goto fail;
  780. map->width = src->width;
  781. map->height = src->height;
  782. err = av_frame_copy(map, src);
  783. if (err)
  784. goto fail;
  785. err = 0;
  786. fail:
  787. av_frame_free(&map);
  788. return err;
  789. }
  790. static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
  791. const AVFrame *src, int flags)
  792. {
  793. int err;
  794. if (dst->format != AV_PIX_FMT_NONE) {
  795. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
  796. if (err < 0)
  797. return AVERROR(ENOSYS);
  798. }
  799. err = vaapi_map_frame(hwfc, dst, src, flags);
  800. if (err)
  801. return err;
  802. err = av_frame_copy_props(dst, src);
  803. if (err)
  804. return err;
  805. return 0;
  806. }
  807. #if CONFIG_LIBDRM
  808. #define DRM_MAP(va, layers, ...) { \
  809. VA_FOURCC_ ## va, \
  810. layers, \
  811. { __VA_ARGS__ } \
  812. }
  813. static const struct {
  814. uint32_t va_fourcc;
  815. int nb_layer_formats;
  816. uint32_t layer_formats[AV_DRM_MAX_PLANES];
  817. } vaapi_drm_format_map[] = {
  818. #ifdef DRM_FORMAT_R8
  819. DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
  820. #endif
  821. DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
  822. #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
  823. DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
  824. #endif
  825. DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
  826. DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
  827. DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
  828. DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
  829. #ifdef VA_FOURCC_ABGR
  830. DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
  831. DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
  832. #endif
  833. DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
  834. DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
  835. };
  836. #undef DRM_MAP
  837. static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
  838. HWMapDescriptor *hwmap)
  839. {
  840. AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  841. VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
  842. av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
  843. vaDestroySurfaces(dst_dev->display, &surface_id, 1);
  844. }
  845. static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
  846. const AVFrame *src, int flags)
  847. {
  848. AVHWFramesContext *dst_fc =
  849. (AVHWFramesContext*)dst->hw_frames_ctx->data;
  850. AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  851. const AVDRMFrameDescriptor *desc;
  852. VASurfaceID surface_id;
  853. VAStatus vas;
  854. uint32_t va_fourcc, va_rt_format;
  855. int err, i, j, k;
  856. unsigned long buffer_handle;
  857. VASurfaceAttribExternalBuffers buffer_desc;
  858. VASurfaceAttrib attrs[2] = {
  859. {
  860. .type = VASurfaceAttribMemoryType,
  861. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  862. .value.type = VAGenericValueTypeInteger,
  863. .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
  864. },
  865. {
  866. .type = VASurfaceAttribExternalBufferDescriptor,
  867. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  868. .value.type = VAGenericValueTypePointer,
  869. .value.value.p = &buffer_desc,
  870. }
  871. };
  872. desc = (AVDRMFrameDescriptor*)src->data[0];
  873. if (desc->nb_objects != 1) {
  874. av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
  875. "made from a single DRM object.\n");
  876. return AVERROR(EINVAL);
  877. }
  878. va_fourcc = 0;
  879. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
  880. if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
  881. continue;
  882. for (j = 0; j < desc->nb_layers; j++) {
  883. if (desc->layers[j].format !=
  884. vaapi_drm_format_map[i].layer_formats[j])
  885. break;
  886. }
  887. if (j != desc->nb_layers)
  888. continue;
  889. va_fourcc = vaapi_drm_format_map[i].va_fourcc;
  890. break;
  891. }
  892. if (!va_fourcc) {
  893. av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
  894. "by VAAPI.\n");
  895. return AVERROR(EINVAL);
  896. }
  897. av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
  898. "%08x.\n", desc->objects[0].fd, va_fourcc);
  899. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
  900. if (vaapi_format_map[i].fourcc == va_fourcc)
  901. va_rt_format = vaapi_format_map[i].rt_format;
  902. }
  903. buffer_handle = desc->objects[0].fd;
  904. buffer_desc.pixel_format = va_fourcc;
  905. buffer_desc.width = src_fc->width;
  906. buffer_desc.height = src_fc->height;
  907. buffer_desc.data_size = desc->objects[0].size;
  908. buffer_desc.buffers = &buffer_handle;
  909. buffer_desc.num_buffers = 1;
  910. buffer_desc.flags = 0;
  911. k = 0;
  912. for (i = 0; i < desc->nb_layers; i++) {
  913. for (j = 0; j < desc->layers[i].nb_planes; j++) {
  914. buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
  915. buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
  916. ++k;
  917. }
  918. }
  919. buffer_desc.num_planes = k;
  920. vas = vaCreateSurfaces(dst_dev->display, va_rt_format,
  921. src->width, src->height,
  922. &surface_id, 1,
  923. attrs, FF_ARRAY_ELEMS(attrs));
  924. if (vas != VA_STATUS_SUCCESS) {
  925. av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
  926. "object: %d (%s).\n", vas, vaErrorStr(vas));
  927. return AVERROR(EIO);
  928. }
  929. av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
  930. err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
  931. &vaapi_unmap_from_drm,
  932. (void*)(uintptr_t)surface_id);
  933. if (err < 0)
  934. return err;
  935. dst->width = src->width;
  936. dst->height = src->height;
  937. dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
  938. av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
  939. "surface %#x.\n", desc->objects[0].fd, surface_id);
  940. return 0;
  941. }
  942. static void vaapi_unmap_to_drm(AVHWFramesContext *dst_fc,
  943. HWMapDescriptor *hwmap)
  944. {
  945. AVDRMFrameDescriptor *drm_desc = hwmap->priv;
  946. int i;
  947. for (i = 0; i < drm_desc->nb_objects; i++)
  948. close(drm_desc->objects[i].fd);
  949. av_freep(&drm_desc);
  950. }
  951. static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
  952. const AVFrame *src, int flags)
  953. {
  954. #if VA_CHECK_VERSION(1, 1, 0)
  955. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  956. VASurfaceID surface_id;
  957. VAStatus vas;
  958. VADRMPRIMESurfaceDescriptor va_desc;
  959. AVDRMFrameDescriptor *drm_desc = NULL;
  960. int err, i, j;
  961. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  962. vas = vaExportSurfaceHandle(hwctx->display, surface_id,
  963. VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
  964. VA_EXPORT_SURFACE_READ_ONLY |
  965. VA_EXPORT_SURFACE_SEPARATE_LAYERS,
  966. &va_desc);
  967. if (vas != VA_STATUS_SUCCESS) {
  968. if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
  969. return AVERROR(ENOSYS);
  970. av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
  971. "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
  972. return AVERROR(EIO);
  973. }
  974. drm_desc = av_mallocz(sizeof(*drm_desc));
  975. if (!drm_desc) {
  976. err = AVERROR(ENOMEM);
  977. goto fail;
  978. }
  979. // By some bizarre coincidence, these structures are very similar...
  980. drm_desc->nb_objects = va_desc.num_objects;
  981. for (i = 0; i < va_desc.num_objects; i++) {
  982. drm_desc->objects[i].fd = va_desc.objects[i].fd;
  983. drm_desc->objects[i].size = va_desc.objects[i].size;
  984. drm_desc->objects[i].format_modifier =
  985. va_desc.objects[i].drm_format_modifier;
  986. }
  987. drm_desc->nb_layers = va_desc.num_layers;
  988. for (i = 0; i < va_desc.num_layers; i++) {
  989. drm_desc->layers[i].format = va_desc.layers[i].drm_format;
  990. drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
  991. for (j = 0; j < va_desc.layers[i].num_planes; j++) {
  992. drm_desc->layers[i].planes[j].object_index =
  993. va_desc.layers[i].object_index[j];
  994. drm_desc->layers[i].planes[j].offset =
  995. va_desc.layers[i].offset[j];
  996. drm_desc->layers[i].planes[j].pitch =
  997. va_desc.layers[i].pitch[j];
  998. }
  999. }
  1000. err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
  1001. &vaapi_unmap_to_drm, drm_desc);
  1002. if (err < 0)
  1003. goto fail;
  1004. dst->width = src->width;
  1005. dst->height = src->height;
  1006. dst->data[0] = (uint8_t*)drm_desc;
  1007. return 0;
  1008. fail:
  1009. for (i = 0; i < va_desc.num_objects; i++)
  1010. close(va_desc.objects[i].fd);
  1011. av_freep(&drm_desc);
  1012. return err;
  1013. #else
  1014. // Older versions without vaExportSurfaceHandle() are not supported -
  1015. // in theory this is possible with a combination of vaDeriveImage()
  1016. // and vaAcquireBufferHandle(), but it doesn't carry enough metadata
  1017. // to actually use the result in a generic way.
  1018. return AVERROR(ENOSYS);
  1019. #endif
  1020. }
  1021. #endif
  1022. static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
  1023. const AVFrame *src, int flags)
  1024. {
  1025. switch (src->format) {
  1026. #if CONFIG_LIBDRM
  1027. case AV_PIX_FMT_DRM_PRIME:
  1028. return vaapi_map_from_drm(hwfc, dst, src, flags);
  1029. #endif
  1030. default:
  1031. return AVERROR(ENOSYS);
  1032. }
  1033. }
  1034. static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
  1035. const AVFrame *src, int flags)
  1036. {
  1037. switch (dst->format) {
  1038. #if CONFIG_LIBDRM
  1039. case AV_PIX_FMT_DRM_PRIME:
  1040. return vaapi_map_to_drm(hwfc, dst, src, flags);
  1041. #endif
  1042. default:
  1043. return vaapi_map_to_memory(hwfc, dst, src, flags);
  1044. }
  1045. }
  1046. static void vaapi_device_free(AVHWDeviceContext *ctx)
  1047. {
  1048. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  1049. VAAPIDevicePriv *priv = ctx->user_opaque;
  1050. if (hwctx->display)
  1051. vaTerminate(hwctx->display);
  1052. #if HAVE_VAAPI_X11
  1053. if (priv->x11_display)
  1054. XCloseDisplay(priv->x11_display);
  1055. #endif
  1056. if (priv->drm_fd >= 0)
  1057. close(priv->drm_fd);
  1058. av_freep(&priv);
  1059. }
  1060. #if CONFIG_VAAPI_1
  1061. static void vaapi_device_log_error(void *context, const char *message)
  1062. {
  1063. AVHWDeviceContext *ctx = context;
  1064. av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
  1065. }
  1066. static void vaapi_device_log_info(void *context, const char *message)
  1067. {
  1068. AVHWDeviceContext *ctx = context;
  1069. av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
  1070. }
  1071. #endif
  1072. static int vaapi_device_connect(AVHWDeviceContext *ctx,
  1073. VADisplay display)
  1074. {
  1075. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  1076. int major, minor;
  1077. VAStatus vas;
  1078. #if CONFIG_VAAPI_1
  1079. vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
  1080. vaSetInfoCallback (display, &vaapi_device_log_info, ctx);
  1081. #endif
  1082. hwctx->display = display;
  1083. vas = vaInitialize(display, &major, &minor);
  1084. if (vas != VA_STATUS_SUCCESS) {
  1085. av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
  1086. "connection: %d (%s).\n", vas, vaErrorStr(vas));
  1087. return AVERROR(EIO);
  1088. }
  1089. av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
  1090. "version %d.%d\n", major, minor);
  1091. return 0;
  1092. }
  1093. static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
  1094. AVDictionary *opts, int flags)
  1095. {
  1096. VAAPIDevicePriv *priv;
  1097. VADisplay display = NULL;
  1098. priv = av_mallocz(sizeof(*priv));
  1099. if (!priv)
  1100. return AVERROR(ENOMEM);
  1101. priv->drm_fd = -1;
  1102. ctx->user_opaque = priv;
  1103. ctx->free = vaapi_device_free;
  1104. #if HAVE_VAAPI_X11
  1105. if (!display && !(device && device[0] == '/')) {
  1106. // Try to open the device as an X11 display.
  1107. priv->x11_display = XOpenDisplay(device);
  1108. if (!priv->x11_display) {
  1109. av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
  1110. "%s.\n", XDisplayName(device));
  1111. } else {
  1112. display = vaGetDisplay(priv->x11_display);
  1113. if (!display) {
  1114. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  1115. "from X11 display %s.\n", XDisplayName(device));
  1116. return AVERROR_UNKNOWN;
  1117. }
  1118. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  1119. "X11 display %s.\n", XDisplayName(device));
  1120. }
  1121. }
  1122. #endif
  1123. #if HAVE_VAAPI_DRM
  1124. if (!display) {
  1125. // Try to open the device as a DRM path.
  1126. // Default to using the first render node if the user did not
  1127. // supply a path.
  1128. const char *path = device ? device : "/dev/dri/renderD128";
  1129. priv->drm_fd = open(path, O_RDWR);
  1130. if (priv->drm_fd < 0) {
  1131. av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
  1132. path);
  1133. } else {
  1134. display = vaGetDisplayDRM(priv->drm_fd);
  1135. if (!display) {
  1136. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  1137. "from DRM device %s.\n", path);
  1138. return AVERROR_UNKNOWN;
  1139. }
  1140. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  1141. "DRM device %s.\n", path);
  1142. }
  1143. }
  1144. #endif
  1145. if (!display) {
  1146. av_log(ctx, AV_LOG_ERROR, "No VA display found for "
  1147. "device: %s.\n", device ? device : "");
  1148. return AVERROR(EINVAL);
  1149. }
  1150. return vaapi_device_connect(ctx, display);
  1151. }
  1152. static int vaapi_device_derive(AVHWDeviceContext *ctx,
  1153. AVHWDeviceContext *src_ctx, int flags)
  1154. {
  1155. #if CONFIG_LIBDRM
  1156. if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
  1157. AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
  1158. VADisplay *display;
  1159. VAAPIDevicePriv *priv;
  1160. if (src_hwctx->fd < 0) {
  1161. av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
  1162. "device to derive a VA display from.\n");
  1163. return AVERROR(EINVAL);
  1164. }
  1165. priv = av_mallocz(sizeof(*priv));
  1166. if (!priv)
  1167. return AVERROR(ENOMEM);
  1168. // Inherits the fd from the source context, which will close it.
  1169. priv->drm_fd = -1;
  1170. ctx->user_opaque = priv;
  1171. ctx->free = &vaapi_device_free;
  1172. display = vaGetDisplayDRM(src_hwctx->fd);
  1173. if (!display) {
  1174. av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
  1175. "DRM device.\n");
  1176. return AVERROR(EIO);
  1177. }
  1178. return vaapi_device_connect(ctx, display);
  1179. }
  1180. #endif
  1181. return AVERROR(ENOSYS);
  1182. }
  1183. const HWContextType ff_hwcontext_type_vaapi = {
  1184. .type = AV_HWDEVICE_TYPE_VAAPI,
  1185. .name = "VAAPI",
  1186. .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
  1187. .device_priv_size = sizeof(VAAPIDeviceContext),
  1188. .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
  1189. .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
  1190. .frames_priv_size = sizeof(VAAPIFramesContext),
  1191. .device_create = &vaapi_device_create,
  1192. .device_derive = &vaapi_device_derive,
  1193. .device_init = &vaapi_device_init,
  1194. .device_uninit = &vaapi_device_uninit,
  1195. .frames_get_constraints = &vaapi_frames_get_constraints,
  1196. .frames_init = &vaapi_frames_init,
  1197. .frames_uninit = &vaapi_frames_uninit,
  1198. .frames_get_buffer = &vaapi_get_buffer,
  1199. .transfer_get_formats = &vaapi_transfer_get_formats,
  1200. .transfer_data_to = &vaapi_transfer_data_to,
  1201. .transfer_data_from = &vaapi_transfer_data_from,
  1202. .map_to = &vaapi_map_to,
  1203. .map_from = &vaapi_map_from,
  1204. .pix_fmts = (const enum AVPixelFormat[]) {
  1205. AV_PIX_FMT_VAAPI,
  1206. AV_PIX_FMT_NONE
  1207. },
  1208. };