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.

1017 lines
33KB

  1. /*
  2. * This file is part of Libav.
  3. *
  4. * Libav 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. * Libav 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 Libav; 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. #include <fcntl.h>
  26. #if HAVE_UNISTD_H
  27. # include <unistd.h>
  28. #endif
  29. #include "avassert.h"
  30. #include "buffer.h"
  31. #include "common.h"
  32. #include "hwcontext.h"
  33. #include "hwcontext_internal.h"
  34. #include "hwcontext_vaapi.h"
  35. #include "mem.h"
  36. #include "pixdesc.h"
  37. #include "pixfmt.h"
  38. typedef struct VAAPIDevicePriv {
  39. #if HAVE_VAAPI_X11
  40. Display *x11_display;
  41. #endif
  42. int drm_fd;
  43. } VAAPIDevicePriv;
  44. typedef struct VAAPISurfaceFormat {
  45. enum AVPixelFormat pix_fmt;
  46. VAImageFormat image_format;
  47. } VAAPISurfaceFormat;
  48. typedef struct VAAPIDeviceContext {
  49. // Surface formats which can be used with this device.
  50. VAAPISurfaceFormat *formats;
  51. int nb_formats;
  52. } VAAPIDeviceContext;
  53. typedef struct VAAPIFramesContext {
  54. // Surface attributes set at create time.
  55. VASurfaceAttrib *attributes;
  56. int nb_attributes;
  57. // RT format of the underlying surface (Intel driver ignores this anyway).
  58. unsigned int rt_format;
  59. // Whether vaDeriveImage works.
  60. int derive_works;
  61. } VAAPIFramesContext;
  62. typedef struct VAAPIMapping {
  63. // Handle to the derived or copied image which is mapped.
  64. VAImage image;
  65. // The mapping flags actually used.
  66. int flags;
  67. } VAAPIMapping;
  68. #define MAP(va, rt, av) { \
  69. VA_FOURCC_ ## va, \
  70. VA_RT_FORMAT_ ## rt, \
  71. AV_PIX_FMT_ ## av \
  72. }
  73. // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
  74. // plane swap cases. The frame handling below tries to hide these.
  75. static const struct {
  76. unsigned int fourcc;
  77. unsigned int rt_format;
  78. enum AVPixelFormat pix_fmt;
  79. } vaapi_format_map[] = {
  80. MAP(NV12, YUV420, NV12),
  81. MAP(YV12, YUV420, YUV420P), // With U/V planes swapped.
  82. MAP(IYUV, YUV420, YUV420P),
  83. //MAP(I420, YUV420, YUV420P), // Not in libva but used by Intel driver.
  84. #ifdef VA_FOURCC_YV16
  85. MAP(YV16, YUV422, YUV422P), // With U/V planes swapped.
  86. #endif
  87. MAP(422H, YUV422, YUV422P),
  88. MAP(UYVY, YUV422, UYVY422),
  89. MAP(YUY2, YUV422, YUYV422),
  90. MAP(Y800, YUV400, GRAY8),
  91. #ifdef VA_FOURCC_P010
  92. MAP(P010, YUV420_10BPP, P010),
  93. #endif
  94. MAP(BGRA, RGB32, BGRA),
  95. //MAP(BGRX, RGB32, BGR0),
  96. MAP(RGBA, RGB32, RGBA),
  97. //MAP(RGBX, RGB32, RGB0),
  98. MAP(ABGR, RGB32, ABGR),
  99. //MAP(XBGR, RGB32, 0BGR),
  100. MAP(ARGB, RGB32, ARGB),
  101. //MAP(XRGB, RGB32, 0RGB),
  102. };
  103. #undef MAP
  104. static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
  105. {
  106. int i;
  107. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
  108. if (vaapi_format_map[i].fourcc == fourcc)
  109. return vaapi_format_map[i].pix_fmt;
  110. return AV_PIX_FMT_NONE;
  111. }
  112. static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
  113. enum AVPixelFormat pix_fmt,
  114. VAImageFormat **image_format)
  115. {
  116. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  117. int i;
  118. for (i = 0; i < ctx->nb_formats; i++) {
  119. if (ctx->formats[i].pix_fmt == pix_fmt) {
  120. if (image_format)
  121. *image_format = &ctx->formats[i].image_format;
  122. return 0;
  123. }
  124. }
  125. return AVERROR(EINVAL);
  126. }
  127. static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
  128. const void *hwconfig,
  129. AVHWFramesConstraints *constraints)
  130. {
  131. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  132. const AVVAAPIHWConfig *config = hwconfig;
  133. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  134. VASurfaceAttrib *attr_list = NULL;
  135. VAStatus vas;
  136. enum AVPixelFormat pix_fmt;
  137. unsigned int fourcc;
  138. int err, i, j, attr_count, pix_fmt_count;
  139. if (config) {
  140. attr_count = 0;
  141. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  142. 0, &attr_count);
  143. if (vas != VA_STATUS_SUCCESS) {
  144. av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
  145. "%d (%s).\n", vas, vaErrorStr(vas));
  146. err = AVERROR(ENOSYS);
  147. goto fail;
  148. }
  149. attr_list = av_malloc(attr_count * sizeof(*attr_list));
  150. if (!attr_list) {
  151. err = AVERROR(ENOMEM);
  152. goto fail;
  153. }
  154. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  155. attr_list, &attr_count);
  156. if (vas != VA_STATUS_SUCCESS) {
  157. av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
  158. "%d (%s).\n", vas, vaErrorStr(vas));
  159. err = AVERROR(ENOSYS);
  160. goto fail;
  161. }
  162. pix_fmt_count = 0;
  163. for (i = 0; i < attr_count; i++) {
  164. switch (attr_list[i].type) {
  165. case VASurfaceAttribPixelFormat:
  166. fourcc = attr_list[i].value.value.i;
  167. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  168. if (pix_fmt != AV_PIX_FMT_NONE) {
  169. ++pix_fmt_count;
  170. } else {
  171. // Something unsupported - ignore.
  172. }
  173. break;
  174. case VASurfaceAttribMinWidth:
  175. constraints->min_width = attr_list[i].value.value.i;
  176. break;
  177. case VASurfaceAttribMinHeight:
  178. constraints->min_height = attr_list[i].value.value.i;
  179. break;
  180. case VASurfaceAttribMaxWidth:
  181. constraints->max_width = attr_list[i].value.value.i;
  182. break;
  183. case VASurfaceAttribMaxHeight:
  184. constraints->max_height = attr_list[i].value.value.i;
  185. break;
  186. }
  187. }
  188. if (pix_fmt_count == 0) {
  189. // Nothing usable found. Presumably there exists something which
  190. // works, so leave the set null to indicate unknown.
  191. constraints->valid_sw_formats = NULL;
  192. } else {
  193. constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
  194. sizeof(pix_fmt));
  195. if (!constraints->valid_sw_formats) {
  196. err = AVERROR(ENOMEM);
  197. goto fail;
  198. }
  199. for (i = j = 0; i < attr_count; i++) {
  200. if (attr_list[i].type != VASurfaceAttribPixelFormat)
  201. continue;
  202. fourcc = attr_list[i].value.value.i;
  203. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  204. if (pix_fmt != AV_PIX_FMT_NONE)
  205. constraints->valid_sw_formats[j++] = pix_fmt;
  206. }
  207. av_assert0(j == pix_fmt_count);
  208. constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
  209. }
  210. } else {
  211. // No configuration supplied.
  212. // Return the full set of image formats known by the implementation.
  213. constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
  214. sizeof(pix_fmt));
  215. if (!constraints->valid_sw_formats) {
  216. err = AVERROR(ENOMEM);
  217. goto fail;
  218. }
  219. for (i = 0; i < ctx->nb_formats; i++)
  220. constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
  221. constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
  222. }
  223. constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
  224. if (!constraints->valid_hw_formats) {
  225. err = AVERROR(ENOMEM);
  226. goto fail;
  227. }
  228. constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
  229. constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
  230. err = 0;
  231. fail:
  232. av_freep(&attr_list);
  233. return err;
  234. }
  235. static const struct {
  236. const char *friendly_name;
  237. const char *match_string;
  238. unsigned int quirks;
  239. } vaapi_driver_quirks_table[] = {
  240. {
  241. "Intel i965 (Quick Sync)",
  242. "i965",
  243. AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
  244. },
  245. {
  246. "Intel iHD",
  247. "ubit",
  248. AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
  249. },
  250. };
  251. static int vaapi_device_init(AVHWDeviceContext *hwdev)
  252. {
  253. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  254. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  255. VAImageFormat *image_list = NULL;
  256. VAStatus vas;
  257. const char *vendor_string;
  258. int err, i, image_count;
  259. enum AVPixelFormat pix_fmt;
  260. unsigned int fourcc;
  261. image_count = vaMaxNumImageFormats(hwctx->display);
  262. if (image_count <= 0) {
  263. err = AVERROR(EIO);
  264. goto fail;
  265. }
  266. image_list = av_malloc(image_count * sizeof(*image_list));
  267. if (!image_list) {
  268. err = AVERROR(ENOMEM);
  269. goto fail;
  270. }
  271. vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
  272. if (vas != VA_STATUS_SUCCESS) {
  273. err = AVERROR(EIO);
  274. goto fail;
  275. }
  276. ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
  277. if (!ctx->formats) {
  278. err = AVERROR(ENOMEM);
  279. goto fail;
  280. }
  281. ctx->nb_formats = 0;
  282. for (i = 0; i < image_count; i++) {
  283. fourcc = image_list[i].fourcc;
  284. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  285. if (pix_fmt == AV_PIX_FMT_NONE) {
  286. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
  287. fourcc);
  288. } else {
  289. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
  290. fourcc, av_get_pix_fmt_name(pix_fmt));
  291. ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
  292. ctx->formats[ctx->nb_formats].image_format = image_list[i];
  293. ++ctx->nb_formats;
  294. }
  295. }
  296. if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
  297. av_log(hwdev, AV_LOG_VERBOSE, "Not detecting driver: "
  298. "quirks set by user.\n");
  299. } else {
  300. // Detect the driver in use and set quirk flags if necessary.
  301. vendor_string = vaQueryVendorString(hwctx->display);
  302. hwctx->driver_quirks = 0;
  303. if (vendor_string) {
  304. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
  305. if (strstr(vendor_string,
  306. vaapi_driver_quirks_table[i].match_string)) {
  307. av_log(hwdev, AV_LOG_VERBOSE, "Matched \"%s\" as known "
  308. "driver \"%s\".\n", vendor_string,
  309. vaapi_driver_quirks_table[i].friendly_name);
  310. hwctx->driver_quirks |=
  311. vaapi_driver_quirks_table[i].quirks;
  312. break;
  313. }
  314. }
  315. if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
  316. av_log(hwdev, AV_LOG_VERBOSE, "Unknown driver \"%s\", "
  317. "assuming standard behaviour.\n", vendor_string);
  318. }
  319. }
  320. }
  321. av_free(image_list);
  322. return 0;
  323. fail:
  324. av_freep(&ctx->formats);
  325. av_free(image_list);
  326. return err;
  327. }
  328. static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
  329. {
  330. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  331. av_freep(&ctx->formats);
  332. }
  333. static void vaapi_buffer_free(void *opaque, uint8_t *data)
  334. {
  335. AVHWFramesContext *hwfc = opaque;
  336. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  337. VASurfaceID surface_id;
  338. VAStatus vas;
  339. surface_id = (VASurfaceID)(uintptr_t)data;
  340. vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
  341. if (vas != VA_STATUS_SUCCESS) {
  342. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
  343. "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
  344. }
  345. }
  346. static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
  347. {
  348. AVHWFramesContext *hwfc = opaque;
  349. VAAPIFramesContext *ctx = hwfc->internal->priv;
  350. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  351. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  352. VASurfaceID surface_id;
  353. VAStatus vas;
  354. AVBufferRef *ref;
  355. if (hwfc->initial_pool_size > 0 &&
  356. avfc->nb_surfaces >= hwfc->initial_pool_size)
  357. return NULL;
  358. vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
  359. hwfc->width, hwfc->height,
  360. &surface_id, 1,
  361. ctx->attributes, ctx->nb_attributes);
  362. if (vas != VA_STATUS_SUCCESS) {
  363. av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
  364. "%d (%s).\n", vas, vaErrorStr(vas));
  365. return NULL;
  366. }
  367. av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
  368. ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
  369. sizeof(surface_id), &vaapi_buffer_free,
  370. hwfc, AV_BUFFER_FLAG_READONLY);
  371. if (!ref) {
  372. vaDestroySurfaces(hwctx->display, &surface_id, 1);
  373. return NULL;
  374. }
  375. if (hwfc->initial_pool_size > 0) {
  376. // This is a fixed-size pool, so we must still be in the initial
  377. // allocation sequence.
  378. av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
  379. avfc->surface_ids[avfc->nb_surfaces] = surface_id;
  380. ++avfc->nb_surfaces;
  381. }
  382. return ref;
  383. }
  384. static int vaapi_frames_init(AVHWFramesContext *hwfc)
  385. {
  386. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  387. VAAPIFramesContext *ctx = hwfc->internal->priv;
  388. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  389. VAImageFormat *expected_format;
  390. AVBufferRef *test_surface = NULL;
  391. VASurfaceID test_surface_id;
  392. VAImage test_image;
  393. VAStatus vas;
  394. int err, i;
  395. unsigned int fourcc, rt_format;
  396. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
  397. if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
  398. fourcc = vaapi_format_map[i].fourcc;
  399. rt_format = vaapi_format_map[i].rt_format;
  400. break;
  401. }
  402. }
  403. if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
  404. av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
  405. av_get_pix_fmt_name(hwfc->sw_format));
  406. return AVERROR(EINVAL);
  407. }
  408. if (!hwfc->pool) {
  409. int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
  410. int need_pixel_format = 1;
  411. for (i = 0; i < avfc->nb_attributes; i++) {
  412. if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
  413. need_memory_type = 0;
  414. if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
  415. need_pixel_format = 0;
  416. }
  417. ctx->nb_attributes =
  418. avfc->nb_attributes + need_memory_type + need_pixel_format;
  419. ctx->attributes = av_malloc(ctx->nb_attributes *
  420. sizeof(*ctx->attributes));
  421. if (!ctx->attributes) {
  422. err = AVERROR(ENOMEM);
  423. goto fail;
  424. }
  425. for (i = 0; i < avfc->nb_attributes; i++)
  426. ctx->attributes[i] = avfc->attributes[i];
  427. if (need_memory_type) {
  428. ctx->attributes[i++] = (VASurfaceAttrib) {
  429. .type = VASurfaceAttribMemoryType,
  430. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  431. .value.type = VAGenericValueTypeInteger,
  432. .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
  433. };
  434. }
  435. if (need_pixel_format) {
  436. ctx->attributes[i++] = (VASurfaceAttrib) {
  437. .type = VASurfaceAttribPixelFormat,
  438. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  439. .value.type = VAGenericValueTypeInteger,
  440. .value.value.i = fourcc,
  441. };
  442. }
  443. av_assert0(i == ctx->nb_attributes);
  444. ctx->rt_format = rt_format;
  445. if (hwfc->initial_pool_size > 0) {
  446. // This pool will be usable as a render target, so we need to store
  447. // all of the surface IDs somewhere that vaCreateContext() calls
  448. // will be able to access them.
  449. avfc->nb_surfaces = 0;
  450. avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
  451. sizeof(*avfc->surface_ids));
  452. if (!avfc->surface_ids) {
  453. err = AVERROR(ENOMEM);
  454. goto fail;
  455. }
  456. } else {
  457. // This pool allows dynamic sizing, and will not be usable as a
  458. // render target.
  459. avfc->nb_surfaces = 0;
  460. avfc->surface_ids = NULL;
  461. }
  462. hwfc->internal->pool_internal =
  463. av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
  464. &vaapi_pool_alloc, NULL);
  465. if (!hwfc->internal->pool_internal) {
  466. av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
  467. err = AVERROR(ENOMEM);
  468. goto fail;
  469. }
  470. }
  471. // Allocate a single surface to test whether vaDeriveImage() is going
  472. // to work for the specific configuration.
  473. if (hwfc->pool) {
  474. test_surface = av_buffer_pool_get(hwfc->pool);
  475. if (!test_surface) {
  476. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  477. "user-configured buffer pool.\n");
  478. err = AVERROR(ENOMEM);
  479. goto fail;
  480. }
  481. } else {
  482. test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
  483. if (!test_surface) {
  484. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  485. "internal buffer pool.\n");
  486. err = AVERROR(ENOMEM);
  487. goto fail;
  488. }
  489. }
  490. test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
  491. ctx->derive_works = 0;
  492. err = vaapi_get_image_format(hwfc->device_ctx,
  493. hwfc->sw_format, &expected_format);
  494. if (err == 0) {
  495. vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
  496. if (vas == VA_STATUS_SUCCESS) {
  497. if (expected_format->fourcc == test_image.format.fourcc) {
  498. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
  499. ctx->derive_works = 1;
  500. } else {
  501. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  502. "derived image format %08x does not match "
  503. "expected format %08x.\n",
  504. expected_format->fourcc, test_image.format.fourcc);
  505. }
  506. vaDestroyImage(hwctx->display, test_image.image_id);
  507. } else {
  508. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  509. "deriving image does not work: "
  510. "%d (%s).\n", vas, vaErrorStr(vas));
  511. }
  512. } else {
  513. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  514. "image format is not supported.\n");
  515. }
  516. av_buffer_unref(&test_surface);
  517. return 0;
  518. fail:
  519. av_buffer_unref(&test_surface);
  520. av_freep(&avfc->surface_ids);
  521. av_freep(&ctx->attributes);
  522. return err;
  523. }
  524. static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
  525. {
  526. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  527. VAAPIFramesContext *ctx = hwfc->internal->priv;
  528. av_freep(&avfc->surface_ids);
  529. av_freep(&ctx->attributes);
  530. }
  531. static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
  532. {
  533. frame->buf[0] = av_buffer_pool_get(hwfc->pool);
  534. if (!frame->buf[0])
  535. return AVERROR(ENOMEM);
  536. frame->data[3] = frame->buf[0]->data;
  537. frame->format = AV_PIX_FMT_VAAPI;
  538. frame->width = hwfc->width;
  539. frame->height = hwfc->height;
  540. return 0;
  541. }
  542. static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
  543. enum AVHWFrameTransferDirection dir,
  544. enum AVPixelFormat **formats)
  545. {
  546. VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
  547. enum AVPixelFormat *pix_fmts, preferred_format;
  548. int i, k;
  549. preferred_format = hwfc->sw_format;
  550. pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
  551. if (!pix_fmts)
  552. return AVERROR(ENOMEM);
  553. pix_fmts[0] = preferred_format;
  554. k = 1;
  555. for (i = 0; i < ctx->nb_formats; i++) {
  556. if (ctx->formats[i].pix_fmt == preferred_format)
  557. continue;
  558. av_assert0(k < ctx->nb_formats);
  559. pix_fmts[k++] = ctx->formats[i].pix_fmt;
  560. }
  561. av_assert0(k == ctx->nb_formats);
  562. pix_fmts[k] = AV_PIX_FMT_NONE;
  563. *formats = pix_fmts;
  564. return 0;
  565. }
  566. static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
  567. HWMapDescriptor *hwmap)
  568. {
  569. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  570. VAAPIMapping *map = hwmap->priv;
  571. VASurfaceID surface_id;
  572. VAStatus vas;
  573. surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
  574. av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
  575. vas = vaUnmapBuffer(hwctx->display, map->image.buf);
  576. if (vas != VA_STATUS_SUCCESS) {
  577. av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
  578. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  579. }
  580. if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
  581. !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
  582. vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
  583. 0, 0, hwfc->width, hwfc->height,
  584. 0, 0, hwfc->width, hwfc->height);
  585. if (vas != VA_STATUS_SUCCESS) {
  586. av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
  587. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  588. }
  589. }
  590. vas = vaDestroyImage(hwctx->display, map->image.image_id);
  591. if (vas != VA_STATUS_SUCCESS) {
  592. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
  593. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  594. }
  595. av_free(map);
  596. }
  597. static int vaapi_map_frame(AVHWFramesContext *hwfc,
  598. AVFrame *dst, const AVFrame *src, int flags)
  599. {
  600. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  601. VAAPIFramesContext *ctx = hwfc->internal->priv;
  602. VASurfaceID surface_id;
  603. VAImageFormat *image_format;
  604. VAAPIMapping *map;
  605. VAStatus vas;
  606. void *address = NULL;
  607. int err, i;
  608. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  609. av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
  610. if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
  611. // Requested direct mapping but it is not possible.
  612. return AVERROR(EINVAL);
  613. }
  614. if (dst->format == AV_PIX_FMT_NONE)
  615. dst->format = hwfc->sw_format;
  616. if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
  617. // Requested direct mapping but the formats do not match.
  618. return AVERROR(EINVAL);
  619. }
  620. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
  621. if (err < 0) {
  622. // Requested format is not a valid output format.
  623. return AVERROR(EINVAL);
  624. }
  625. map = av_malloc(sizeof(*map));
  626. if (!map)
  627. return AVERROR(ENOMEM);
  628. map->flags = flags;
  629. map->image.image_id = VA_INVALID_ID;
  630. vas = vaSyncSurface(hwctx->display, surface_id);
  631. if (vas != VA_STATUS_SUCCESS) {
  632. av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
  633. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  634. err = AVERROR(EIO);
  635. goto fail;
  636. }
  637. // The memory which we map using derive need not be connected to the CPU
  638. // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
  639. // memory is mappable but not cached, so normal memcpy()-like access is
  640. // very slow to read it (but writing is ok). It is possible to read much
  641. // faster with a copy routine which is aware of the limitation, but we
  642. // assume for now that the user is not aware of that and would therefore
  643. // prefer not to be given direct-mapped memory if they request read access.
  644. if (ctx->derive_works && dst->format == hwfc->sw_format &&
  645. ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
  646. vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
  647. if (vas != VA_STATUS_SUCCESS) {
  648. av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
  649. "surface %#x: %d (%s).\n",
  650. surface_id, vas, vaErrorStr(vas));
  651. err = AVERROR(EIO);
  652. goto fail;
  653. }
  654. if (map->image.format.fourcc != image_format->fourcc) {
  655. av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
  656. "is in wrong format: expected %#08x, got %#08x.\n",
  657. surface_id, image_format->fourcc, map->image.format.fourcc);
  658. err = AVERROR(EIO);
  659. goto fail;
  660. }
  661. map->flags |= AV_HWFRAME_MAP_DIRECT;
  662. } else {
  663. vas = vaCreateImage(hwctx->display, image_format,
  664. hwfc->width, hwfc->height, &map->image);
  665. if (vas != VA_STATUS_SUCCESS) {
  666. av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
  667. "surface %#x: %d (%s).\n",
  668. surface_id, vas, vaErrorStr(vas));
  669. err = AVERROR(EIO);
  670. goto fail;
  671. }
  672. if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
  673. vas = vaGetImage(hwctx->display, surface_id, 0, 0,
  674. hwfc->width, hwfc->height, map->image.image_id);
  675. if (vas != VA_STATUS_SUCCESS) {
  676. av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
  677. "surface %#x: %d (%s).\n",
  678. surface_id, vas, vaErrorStr(vas));
  679. err = AVERROR(EIO);
  680. goto fail;
  681. }
  682. }
  683. }
  684. vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
  685. if (vas != VA_STATUS_SUCCESS) {
  686. av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
  687. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  688. err = AVERROR(EIO);
  689. goto fail;
  690. }
  691. err = ff_hwframe_map_create(src->hw_frames_ctx,
  692. dst, src, &vaapi_unmap_frame, map);
  693. if (err < 0)
  694. goto fail;
  695. dst->width = src->width;
  696. dst->height = src->height;
  697. for (i = 0; i < map->image.num_planes; i++) {
  698. dst->data[i] = (uint8_t*)address + map->image.offsets[i];
  699. dst->linesize[i] = map->image.pitches[i];
  700. }
  701. if (
  702. #ifdef VA_FOURCC_YV16
  703. map->image.format.fourcc == VA_FOURCC_YV16 ||
  704. #endif
  705. map->image.format.fourcc == VA_FOURCC_YV12) {
  706. // Chroma planes are YVU rather than YUV, so swap them.
  707. FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
  708. }
  709. return 0;
  710. fail:
  711. if (map) {
  712. if (address)
  713. vaUnmapBuffer(hwctx->display, map->image.buf);
  714. if (map->image.image_id != VA_INVALID_ID)
  715. vaDestroyImage(hwctx->display, map->image.image_id);
  716. av_free(map);
  717. }
  718. return err;
  719. }
  720. static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
  721. AVFrame *dst, const AVFrame *src)
  722. {
  723. AVFrame *map;
  724. int err;
  725. if (dst->width > hwfc->width || dst->height > hwfc->height)
  726. return AVERROR(EINVAL);
  727. map = av_frame_alloc();
  728. if (!map)
  729. return AVERROR(ENOMEM);
  730. map->format = dst->format;
  731. err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
  732. if (err)
  733. goto fail;
  734. map->width = dst->width;
  735. map->height = dst->height;
  736. err = av_frame_copy(dst, map);
  737. if (err)
  738. goto fail;
  739. err = 0;
  740. fail:
  741. av_frame_free(&map);
  742. return err;
  743. }
  744. static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
  745. AVFrame *dst, const AVFrame *src)
  746. {
  747. AVFrame *map;
  748. int err;
  749. if (src->width > hwfc->width || src->height > hwfc->height)
  750. return AVERROR(EINVAL);
  751. map = av_frame_alloc();
  752. if (!map)
  753. return AVERROR(ENOMEM);
  754. map->format = src->format;
  755. err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
  756. if (err)
  757. goto fail;
  758. map->width = src->width;
  759. map->height = src->height;
  760. err = av_frame_copy(map, src);
  761. if (err)
  762. goto fail;
  763. err = 0;
  764. fail:
  765. av_frame_free(&map);
  766. return err;
  767. }
  768. static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
  769. const AVFrame *src, int flags)
  770. {
  771. int err;
  772. if (dst->format != AV_PIX_FMT_NONE) {
  773. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
  774. if (err < 0)
  775. return AVERROR(ENOSYS);
  776. }
  777. err = vaapi_map_frame(hwfc, dst, src, flags);
  778. if (err)
  779. return err;
  780. err = av_frame_copy_props(dst, src);
  781. if (err)
  782. return err;
  783. return 0;
  784. }
  785. static void vaapi_device_free(AVHWDeviceContext *ctx)
  786. {
  787. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  788. VAAPIDevicePriv *priv = ctx->user_opaque;
  789. if (hwctx->display)
  790. vaTerminate(hwctx->display);
  791. #if HAVE_VAAPI_X11
  792. if (priv->x11_display)
  793. XCloseDisplay(priv->x11_display);
  794. #endif
  795. if (priv->drm_fd >= 0)
  796. close(priv->drm_fd);
  797. av_freep(&priv);
  798. }
  799. static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
  800. AVDictionary *opts, int flags)
  801. {
  802. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  803. VAAPIDevicePriv *priv;
  804. VADisplay display = 0;
  805. VAStatus vas;
  806. int major, minor;
  807. priv = av_mallocz(sizeof(*priv));
  808. if (!priv)
  809. return AVERROR(ENOMEM);
  810. priv->drm_fd = -1;
  811. ctx->user_opaque = priv;
  812. ctx->free = vaapi_device_free;
  813. #if HAVE_VAAPI_X11
  814. if (!display && !(device && device[0] == '/')) {
  815. // Try to open the device as an X11 display.
  816. priv->x11_display = XOpenDisplay(device);
  817. if (!priv->x11_display) {
  818. av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
  819. "%s.\n", XDisplayName(device));
  820. } else {
  821. display = vaGetDisplay(priv->x11_display);
  822. if (!display) {
  823. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  824. "from X11 display %s.\n", XDisplayName(device));
  825. return AVERROR_UNKNOWN;
  826. }
  827. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  828. "X11 display %s.\n", XDisplayName(device));
  829. }
  830. }
  831. #endif
  832. #if HAVE_VAAPI_DRM
  833. if (!display) {
  834. // Try to open the device as a DRM path.
  835. // Default to using the first render node if the user did not
  836. // supply a path.
  837. const char *path = device ? device : "/dev/dri/renderD128";
  838. priv->drm_fd = open(path, O_RDWR);
  839. if (priv->drm_fd < 0) {
  840. av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
  841. path);
  842. } else {
  843. display = vaGetDisplayDRM(priv->drm_fd);
  844. if (!display) {
  845. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  846. "from DRM device %s.\n", path);
  847. return AVERROR_UNKNOWN;
  848. }
  849. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  850. "DRM device %s.\n", path);
  851. }
  852. }
  853. #endif
  854. if (!display) {
  855. av_log(ctx, AV_LOG_ERROR, "No VA display found for "
  856. "device: %s.\n", device ? device : "");
  857. return AVERROR(EINVAL);
  858. }
  859. hwctx->display = display;
  860. vas = vaInitialize(display, &major, &minor);
  861. if (vas != VA_STATUS_SUCCESS) {
  862. av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
  863. "connection: %d (%s).\n", vas, vaErrorStr(vas));
  864. return AVERROR(EIO);
  865. }
  866. av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
  867. "version %d.%d\n", major, minor);
  868. return 0;
  869. }
  870. const HWContextType ff_hwcontext_type_vaapi = {
  871. .type = AV_HWDEVICE_TYPE_VAAPI,
  872. .name = "VAAPI",
  873. .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
  874. .device_priv_size = sizeof(VAAPIDeviceContext),
  875. .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
  876. .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
  877. .frames_priv_size = sizeof(VAAPIFramesContext),
  878. .device_create = &vaapi_device_create,
  879. .device_init = &vaapi_device_init,
  880. .device_uninit = &vaapi_device_uninit,
  881. .frames_get_constraints = &vaapi_frames_get_constraints,
  882. .frames_init = &vaapi_frames_init,
  883. .frames_uninit = &vaapi_frames_uninit,
  884. .frames_get_buffer = &vaapi_get_buffer,
  885. .transfer_get_formats = &vaapi_transfer_get_formats,
  886. .transfer_data_to = &vaapi_transfer_data_to,
  887. .transfer_data_from = &vaapi_transfer_data_from,
  888. .map_to = NULL,
  889. .map_from = &vaapi_map_from,
  890. .pix_fmts = (const enum AVPixelFormat[]) {
  891. AV_PIX_FMT_VAAPI,
  892. AV_PIX_FMT_NONE
  893. },
  894. };