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.

1013 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 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. vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
  356. hwfc->width, hwfc->height,
  357. &surface_id, 1,
  358. ctx->attributes, ctx->nb_attributes);
  359. if (vas != VA_STATUS_SUCCESS) {
  360. av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
  361. "%d (%s).\n", vas, vaErrorStr(vas));
  362. return NULL;
  363. }
  364. av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
  365. ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
  366. sizeof(surface_id), &vaapi_buffer_free,
  367. hwfc, AV_BUFFER_FLAG_READONLY);
  368. if (!ref) {
  369. vaDestroySurfaces(hwctx->display, &surface_id, 1);
  370. return NULL;
  371. }
  372. if (hwfc->initial_pool_size > 0) {
  373. // This is a fixed-size pool, so we must still be in the initial
  374. // allocation sequence.
  375. av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
  376. avfc->surface_ids[avfc->nb_surfaces] = surface_id;
  377. ++avfc->nb_surfaces;
  378. }
  379. return ref;
  380. }
  381. static int vaapi_frames_init(AVHWFramesContext *hwfc)
  382. {
  383. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  384. VAAPIFramesContext *ctx = hwfc->internal->priv;
  385. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  386. VAImageFormat *expected_format;
  387. AVBufferRef *test_surface = NULL;
  388. VASurfaceID test_surface_id;
  389. VAImage test_image;
  390. VAStatus vas;
  391. int err, i;
  392. unsigned int fourcc, rt_format;
  393. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
  394. if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
  395. fourcc = vaapi_format_map[i].fourcc;
  396. rt_format = vaapi_format_map[i].rt_format;
  397. break;
  398. }
  399. }
  400. if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
  401. av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
  402. av_get_pix_fmt_name(hwfc->sw_format));
  403. return AVERROR(EINVAL);
  404. }
  405. if (!hwfc->pool) {
  406. int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
  407. int need_pixel_format = 1;
  408. for (i = 0; i < avfc->nb_attributes; i++) {
  409. if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
  410. need_memory_type = 0;
  411. if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
  412. need_pixel_format = 0;
  413. }
  414. ctx->nb_attributes =
  415. avfc->nb_attributes + need_memory_type + need_pixel_format;
  416. ctx->attributes = av_malloc(ctx->nb_attributes *
  417. sizeof(*ctx->attributes));
  418. if (!ctx->attributes) {
  419. err = AVERROR(ENOMEM);
  420. goto fail;
  421. }
  422. for (i = 0; i < avfc->nb_attributes; i++)
  423. ctx->attributes[i] = avfc->attributes[i];
  424. if (need_memory_type) {
  425. ctx->attributes[i++] = (VASurfaceAttrib) {
  426. .type = VASurfaceAttribMemoryType,
  427. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  428. .value.type = VAGenericValueTypeInteger,
  429. .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
  430. };
  431. }
  432. if (need_pixel_format) {
  433. ctx->attributes[i++] = (VASurfaceAttrib) {
  434. .type = VASurfaceAttribPixelFormat,
  435. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  436. .value.type = VAGenericValueTypeInteger,
  437. .value.value.i = fourcc,
  438. };
  439. }
  440. av_assert0(i == ctx->nb_attributes);
  441. ctx->rt_format = rt_format;
  442. if (hwfc->initial_pool_size > 0) {
  443. // This pool will be usable as a render target, so we need to store
  444. // all of the surface IDs somewhere that vaCreateContext() calls
  445. // will be able to access them.
  446. avfc->nb_surfaces = 0;
  447. avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
  448. sizeof(*avfc->surface_ids));
  449. if (!avfc->surface_ids) {
  450. err = AVERROR(ENOMEM);
  451. goto fail;
  452. }
  453. } else {
  454. // This pool allows dynamic sizing, and will not be usable as a
  455. // render target.
  456. avfc->nb_surfaces = 0;
  457. avfc->surface_ids = NULL;
  458. }
  459. hwfc->internal->pool_internal =
  460. av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
  461. &vaapi_pool_alloc, NULL);
  462. if (!hwfc->internal->pool_internal) {
  463. av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
  464. err = AVERROR(ENOMEM);
  465. goto fail;
  466. }
  467. }
  468. // Allocate a single surface to test whether vaDeriveImage() is going
  469. // to work for the specific configuration.
  470. if (hwfc->pool) {
  471. test_surface = av_buffer_pool_get(hwfc->pool);
  472. if (!test_surface) {
  473. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  474. "user-configured buffer pool.\n");
  475. err = AVERROR(ENOMEM);
  476. goto fail;
  477. }
  478. } else {
  479. test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
  480. if (!test_surface) {
  481. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  482. "internal buffer pool.\n");
  483. err = AVERROR(ENOMEM);
  484. goto fail;
  485. }
  486. }
  487. test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
  488. ctx->derive_works = 0;
  489. err = vaapi_get_image_format(hwfc->device_ctx,
  490. hwfc->sw_format, &expected_format);
  491. if (err == 0) {
  492. vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
  493. if (vas == VA_STATUS_SUCCESS) {
  494. if (expected_format->fourcc == test_image.format.fourcc) {
  495. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
  496. ctx->derive_works = 1;
  497. } else {
  498. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  499. "derived image format %08x does not match "
  500. "expected format %08x.\n",
  501. expected_format->fourcc, test_image.format.fourcc);
  502. }
  503. vaDestroyImage(hwctx->display, test_image.image_id);
  504. } else {
  505. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  506. "deriving image does not work: "
  507. "%d (%s).\n", vas, vaErrorStr(vas));
  508. }
  509. } else {
  510. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  511. "image format is not supported.\n");
  512. }
  513. av_buffer_unref(&test_surface);
  514. return 0;
  515. fail:
  516. av_buffer_unref(&test_surface);
  517. av_freep(&avfc->surface_ids);
  518. av_freep(&ctx->attributes);
  519. return err;
  520. }
  521. static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
  522. {
  523. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  524. VAAPIFramesContext *ctx = hwfc->internal->priv;
  525. av_freep(&avfc->surface_ids);
  526. av_freep(&ctx->attributes);
  527. }
  528. static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
  529. {
  530. frame->buf[0] = av_buffer_pool_get(hwfc->pool);
  531. if (!frame->buf[0])
  532. return AVERROR(ENOMEM);
  533. frame->data[3] = frame->buf[0]->data;
  534. frame->format = AV_PIX_FMT_VAAPI;
  535. frame->width = hwfc->width;
  536. frame->height = hwfc->height;
  537. return 0;
  538. }
  539. static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
  540. enum AVHWFrameTransferDirection dir,
  541. enum AVPixelFormat **formats)
  542. {
  543. VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
  544. enum AVPixelFormat *pix_fmts, preferred_format;
  545. int i, k;
  546. preferred_format = hwfc->sw_format;
  547. pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
  548. if (!pix_fmts)
  549. return AVERROR(ENOMEM);
  550. pix_fmts[0] = preferred_format;
  551. k = 1;
  552. for (i = 0; i < ctx->nb_formats; i++) {
  553. if (ctx->formats[i].pix_fmt == preferred_format)
  554. continue;
  555. av_assert0(k < ctx->nb_formats);
  556. pix_fmts[k++] = ctx->formats[i].pix_fmt;
  557. }
  558. av_assert0(k == ctx->nb_formats);
  559. pix_fmts[k] = AV_PIX_FMT_NONE;
  560. *formats = pix_fmts;
  561. return 0;
  562. }
  563. static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
  564. HWMapDescriptor *hwmap)
  565. {
  566. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  567. VAAPIMapping *map = hwmap->priv;
  568. VASurfaceID surface_id;
  569. VAStatus vas;
  570. surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
  571. av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
  572. vas = vaUnmapBuffer(hwctx->display, map->image.buf);
  573. if (vas != VA_STATUS_SUCCESS) {
  574. av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
  575. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  576. }
  577. if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
  578. !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
  579. vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
  580. 0, 0, hwfc->width, hwfc->height,
  581. 0, 0, hwfc->width, hwfc->height);
  582. if (vas != VA_STATUS_SUCCESS) {
  583. av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
  584. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  585. }
  586. }
  587. vas = vaDestroyImage(hwctx->display, map->image.image_id);
  588. if (vas != VA_STATUS_SUCCESS) {
  589. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
  590. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  591. }
  592. av_free(map);
  593. }
  594. static int vaapi_map_frame(AVHWFramesContext *hwfc,
  595. AVFrame *dst, const AVFrame *src, int flags)
  596. {
  597. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  598. VAAPIFramesContext *ctx = hwfc->internal->priv;
  599. VASurfaceID surface_id;
  600. VAImageFormat *image_format;
  601. VAAPIMapping *map;
  602. VAStatus vas;
  603. void *address = NULL;
  604. int err, i;
  605. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  606. av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
  607. if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
  608. // Requested direct mapping but it is not possible.
  609. return AVERROR(EINVAL);
  610. }
  611. if (dst->format == AV_PIX_FMT_NONE)
  612. dst->format = hwfc->sw_format;
  613. if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
  614. // Requested direct mapping but the formats do not match.
  615. return AVERROR(EINVAL);
  616. }
  617. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
  618. if (err < 0) {
  619. // Requested format is not a valid output format.
  620. return AVERROR(EINVAL);
  621. }
  622. map = av_malloc(sizeof(*map));
  623. if (!map)
  624. return AVERROR(ENOMEM);
  625. map->flags = flags;
  626. map->image.image_id = VA_INVALID_ID;
  627. vas = vaSyncSurface(hwctx->display, surface_id);
  628. if (vas != VA_STATUS_SUCCESS) {
  629. av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
  630. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  631. err = AVERROR(EIO);
  632. goto fail;
  633. }
  634. // The memory which we map using derive need not be connected to the CPU
  635. // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
  636. // memory is mappable but not cached, so normal memcpy()-like access is
  637. // very slow to read it (but writing is ok). It is possible to read much
  638. // faster with a copy routine which is aware of the limitation, but we
  639. // assume for now that the user is not aware of that and would therefore
  640. // prefer not to be given direct-mapped memory if they request read access.
  641. if (ctx->derive_works && dst->format == hwfc->sw_format &&
  642. ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
  643. vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
  644. if (vas != VA_STATUS_SUCCESS) {
  645. av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
  646. "surface %#x: %d (%s).\n",
  647. surface_id, vas, vaErrorStr(vas));
  648. err = AVERROR(EIO);
  649. goto fail;
  650. }
  651. if (map->image.format.fourcc != image_format->fourcc) {
  652. av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
  653. "is in wrong format: expected %#08x, got %#08x.\n",
  654. surface_id, image_format->fourcc, map->image.format.fourcc);
  655. err = AVERROR(EIO);
  656. goto fail;
  657. }
  658. map->flags |= AV_HWFRAME_MAP_DIRECT;
  659. } else {
  660. vas = vaCreateImage(hwctx->display, image_format,
  661. hwfc->width, hwfc->height, &map->image);
  662. if (vas != VA_STATUS_SUCCESS) {
  663. av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
  664. "surface %#x: %d (%s).\n",
  665. surface_id, vas, vaErrorStr(vas));
  666. err = AVERROR(EIO);
  667. goto fail;
  668. }
  669. if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
  670. vas = vaGetImage(hwctx->display, surface_id, 0, 0,
  671. hwfc->width, hwfc->height, map->image.image_id);
  672. if (vas != VA_STATUS_SUCCESS) {
  673. av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
  674. "surface %#x: %d (%s).\n",
  675. surface_id, vas, vaErrorStr(vas));
  676. err = AVERROR(EIO);
  677. goto fail;
  678. }
  679. }
  680. }
  681. vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
  682. if (vas != VA_STATUS_SUCCESS) {
  683. av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
  684. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  685. err = AVERROR(EIO);
  686. goto fail;
  687. }
  688. err = ff_hwframe_map_create(src->hw_frames_ctx,
  689. dst, src, &vaapi_unmap_frame, map);
  690. if (err < 0)
  691. goto fail;
  692. dst->width = src->width;
  693. dst->height = src->height;
  694. for (i = 0; i < map->image.num_planes; i++) {
  695. dst->data[i] = (uint8_t*)address + map->image.offsets[i];
  696. dst->linesize[i] = map->image.pitches[i];
  697. }
  698. if (
  699. #ifdef VA_FOURCC_YV16
  700. map->image.format.fourcc == VA_FOURCC_YV16 ||
  701. #endif
  702. map->image.format.fourcc == VA_FOURCC_YV12) {
  703. // Chroma planes are YVU rather than YUV, so swap them.
  704. FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
  705. }
  706. return 0;
  707. fail:
  708. if (map) {
  709. if (address)
  710. vaUnmapBuffer(hwctx->display, map->image.buf);
  711. if (map->image.image_id != VA_INVALID_ID)
  712. vaDestroyImage(hwctx->display, map->image.image_id);
  713. av_free(map);
  714. }
  715. return err;
  716. }
  717. static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
  718. AVFrame *dst, const AVFrame *src)
  719. {
  720. AVFrame *map;
  721. int err;
  722. if (dst->width > hwfc->width || dst->height > hwfc->height)
  723. return AVERROR(EINVAL);
  724. map = av_frame_alloc();
  725. if (!map)
  726. return AVERROR(ENOMEM);
  727. map->format = dst->format;
  728. err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
  729. if (err)
  730. goto fail;
  731. map->width = dst->width;
  732. map->height = dst->height;
  733. err = av_frame_copy(dst, map);
  734. if (err)
  735. goto fail;
  736. err = 0;
  737. fail:
  738. av_frame_free(&map);
  739. return err;
  740. }
  741. static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
  742. AVFrame *dst, const AVFrame *src)
  743. {
  744. AVFrame *map;
  745. int err;
  746. if (src->width > hwfc->width || src->height > hwfc->height)
  747. return AVERROR(EINVAL);
  748. map = av_frame_alloc();
  749. if (!map)
  750. return AVERROR(ENOMEM);
  751. map->format = src->format;
  752. err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
  753. if (err)
  754. goto fail;
  755. map->width = src->width;
  756. map->height = src->height;
  757. err = av_frame_copy(map, src);
  758. if (err)
  759. goto fail;
  760. err = 0;
  761. fail:
  762. av_frame_free(&map);
  763. return err;
  764. }
  765. static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
  766. const AVFrame *src, int flags)
  767. {
  768. int err;
  769. if (dst->format != AV_PIX_FMT_NONE) {
  770. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
  771. if (err < 0)
  772. return AVERROR(ENOSYS);
  773. }
  774. err = vaapi_map_frame(hwfc, dst, src, flags);
  775. if (err)
  776. return err;
  777. err = av_frame_copy_props(dst, src);
  778. if (err)
  779. return err;
  780. return 0;
  781. }
  782. static void vaapi_device_free(AVHWDeviceContext *ctx)
  783. {
  784. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  785. VAAPIDevicePriv *priv = ctx->user_opaque;
  786. if (hwctx->display)
  787. vaTerminate(hwctx->display);
  788. #if HAVE_VAAPI_X11
  789. if (priv->x11_display)
  790. XCloseDisplay(priv->x11_display);
  791. #endif
  792. if (priv->drm_fd >= 0)
  793. close(priv->drm_fd);
  794. av_freep(&priv);
  795. }
  796. static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
  797. AVDictionary *opts, int flags)
  798. {
  799. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  800. VAAPIDevicePriv *priv;
  801. VADisplay display = 0;
  802. VAStatus vas;
  803. int major, minor;
  804. priv = av_mallocz(sizeof(*priv));
  805. if (!priv)
  806. return AVERROR(ENOMEM);
  807. priv->drm_fd = -1;
  808. ctx->user_opaque = priv;
  809. ctx->free = vaapi_device_free;
  810. #if HAVE_VAAPI_X11
  811. if (!display && !(device && device[0] == '/')) {
  812. // Try to open the device as an X11 display.
  813. priv->x11_display = XOpenDisplay(device);
  814. if (!priv->x11_display) {
  815. av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
  816. "%s.\n", XDisplayName(device));
  817. } else {
  818. display = vaGetDisplay(priv->x11_display);
  819. if (!display) {
  820. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  821. "from X11 display %s.\n", XDisplayName(device));
  822. return AVERROR_UNKNOWN;
  823. }
  824. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  825. "X11 display %s.\n", XDisplayName(device));
  826. }
  827. }
  828. #endif
  829. #if HAVE_VAAPI_DRM
  830. if (!display) {
  831. // Try to open the device as a DRM path.
  832. // Default to using the first render node if the user did not
  833. // supply a path.
  834. const char *path = device ? device : "/dev/dri/renderD128";
  835. priv->drm_fd = open(path, O_RDWR);
  836. if (priv->drm_fd < 0) {
  837. av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
  838. path);
  839. } else {
  840. display = vaGetDisplayDRM(priv->drm_fd);
  841. if (!display) {
  842. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  843. "from DRM device %s.\n", path);
  844. return AVERROR_UNKNOWN;
  845. }
  846. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  847. "DRM device %s.\n", path);
  848. }
  849. }
  850. #endif
  851. if (!display) {
  852. av_log(ctx, AV_LOG_ERROR, "No VA display found for "
  853. "device: %s.\n", device ? device : "");
  854. return AVERROR(EINVAL);
  855. }
  856. hwctx->display = display;
  857. vas = vaInitialize(display, &major, &minor);
  858. if (vas != VA_STATUS_SUCCESS) {
  859. av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
  860. "connection: %d (%s).\n", vas, vaErrorStr(vas));
  861. return AVERROR(EIO);
  862. }
  863. av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
  864. "version %d.%d\n", major, minor);
  865. return 0;
  866. }
  867. const HWContextType ff_hwcontext_type_vaapi = {
  868. .type = AV_HWDEVICE_TYPE_VAAPI,
  869. .name = "VAAPI",
  870. .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
  871. .device_priv_size = sizeof(VAAPIDeviceContext),
  872. .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
  873. .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
  874. .frames_priv_size = sizeof(VAAPIFramesContext),
  875. .device_create = &vaapi_device_create,
  876. .device_init = &vaapi_device_init,
  877. .device_uninit = &vaapi_device_uninit,
  878. .frames_get_constraints = &vaapi_frames_get_constraints,
  879. .frames_init = &vaapi_frames_init,
  880. .frames_uninit = &vaapi_frames_uninit,
  881. .frames_get_buffer = &vaapi_get_buffer,
  882. .transfer_get_formats = &vaapi_transfer_get_formats,
  883. .transfer_data_to = &vaapi_transfer_data_to,
  884. .transfer_data_from = &vaapi_transfer_data_from,
  885. .map_to = NULL,
  886. .map_from = &vaapi_map_from,
  887. .pix_fmts = (const enum AVPixelFormat[]) {
  888. AV_PIX_FMT_VAAPI,
  889. AV_PIX_FMT_NONE
  890. },
  891. };