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.

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