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.

996 lines
32KB

  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. enum {
  63. VAAPI_MAP_READ = 0x01,
  64. VAAPI_MAP_WRITE = 0x02,
  65. VAAPI_MAP_DIRECT = 0x04,
  66. };
  67. typedef struct VAAPISurfaceMap {
  68. // The source hardware frame of this mapping (with hw_frames_ctx set).
  69. const AVFrame *source;
  70. // VAAPI_MAP_* flags which apply to this mapping.
  71. int flags;
  72. // Handle to the derived or copied image which is mapped.
  73. VAImage image;
  74. } VAAPISurfaceMap;
  75. #define MAP(va, rt, av) { \
  76. VA_FOURCC_ ## va, \
  77. VA_RT_FORMAT_ ## rt, \
  78. AV_PIX_FMT_ ## av \
  79. }
  80. // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
  81. // plane swap cases. The frame handling below tries to hide these.
  82. static struct {
  83. unsigned int fourcc;
  84. unsigned int rt_format;
  85. enum AVPixelFormat pix_fmt;
  86. } vaapi_format_map[] = {
  87. MAP(NV12, YUV420, NV12),
  88. MAP(YV12, YUV420, YUV420P), // With U/V planes swapped.
  89. MAP(IYUV, YUV420, YUV420P),
  90. //MAP(I420, YUV420, YUV420P), // Not in libva but used by Intel driver.
  91. #ifdef VA_FOURCC_YV16
  92. MAP(YV16, YUV422, YUV422P), // With U/V planes swapped.
  93. #endif
  94. MAP(422H, YUV422, YUV422P),
  95. MAP(UYVY, YUV422, UYVY422),
  96. MAP(YUY2, YUV422, YUYV422),
  97. MAP(Y800, YUV400, GRAY8),
  98. #ifdef VA_FOURCC_P010
  99. //MAP(P010, YUV420_10BPP, P010),
  100. #endif
  101. MAP(BGRA, RGB32, BGRA),
  102. //MAP(BGRX, RGB32, BGR0),
  103. MAP(RGBA, RGB32, RGBA),
  104. //MAP(RGBX, RGB32, RGB0),
  105. MAP(ABGR, RGB32, ABGR),
  106. //MAP(XBGR, RGB32, 0BGR),
  107. MAP(ARGB, RGB32, ARGB),
  108. //MAP(XRGB, RGB32, 0RGB),
  109. };
  110. #undef MAP
  111. static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
  112. {
  113. int i;
  114. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
  115. if (vaapi_format_map[i].fourcc == fourcc)
  116. return vaapi_format_map[i].pix_fmt;
  117. return AV_PIX_FMT_NONE;
  118. }
  119. static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
  120. enum AVPixelFormat pix_fmt,
  121. VAImageFormat **image_format)
  122. {
  123. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  124. int i;
  125. for (i = 0; i < ctx->nb_formats; i++) {
  126. if (ctx->formats[i].pix_fmt == pix_fmt) {
  127. *image_format = &ctx->formats[i].image_format;
  128. return 0;
  129. }
  130. }
  131. return AVERROR(EINVAL);
  132. }
  133. static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
  134. const void *hwconfig,
  135. AVHWFramesConstraints *constraints)
  136. {
  137. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  138. const AVVAAPIHWConfig *config = hwconfig;
  139. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  140. VASurfaceAttrib *attr_list = NULL;
  141. VAStatus vas;
  142. enum AVPixelFormat pix_fmt;
  143. unsigned int fourcc;
  144. int err, i, j, attr_count, pix_fmt_count;
  145. if (config) {
  146. attr_count = 0;
  147. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  148. 0, &attr_count);
  149. if (vas != VA_STATUS_SUCCESS) {
  150. av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
  151. "%d (%s).\n", vas, vaErrorStr(vas));
  152. err = AVERROR(ENOSYS);
  153. goto fail;
  154. }
  155. attr_list = av_malloc(attr_count * sizeof(*attr_list));
  156. if (!attr_list) {
  157. err = AVERROR(ENOMEM);
  158. goto fail;
  159. }
  160. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  161. attr_list, &attr_count);
  162. if (vas != VA_STATUS_SUCCESS) {
  163. av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
  164. "%d (%s).\n", vas, vaErrorStr(vas));
  165. err = AVERROR(ENOSYS);
  166. goto fail;
  167. }
  168. pix_fmt_count = 0;
  169. for (i = 0; i < attr_count; i++) {
  170. switch (attr_list[i].type) {
  171. case VASurfaceAttribPixelFormat:
  172. fourcc = attr_list[i].value.value.i;
  173. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  174. if (pix_fmt != AV_PIX_FMT_NONE) {
  175. ++pix_fmt_count;
  176. } else {
  177. // Something unsupported - ignore.
  178. }
  179. break;
  180. case VASurfaceAttribMinWidth:
  181. constraints->min_width = attr_list[i].value.value.i;
  182. break;
  183. case VASurfaceAttribMinHeight:
  184. constraints->min_height = attr_list[i].value.value.i;
  185. break;
  186. case VASurfaceAttribMaxWidth:
  187. constraints->max_width = attr_list[i].value.value.i;
  188. break;
  189. case VASurfaceAttribMaxHeight:
  190. constraints->max_height = attr_list[i].value.value.i;
  191. break;
  192. }
  193. }
  194. if (pix_fmt_count == 0) {
  195. // Nothing usable found. Presumably there exists something which
  196. // works, so leave the set null to indicate unknown.
  197. constraints->valid_sw_formats = NULL;
  198. } else {
  199. constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
  200. sizeof(pix_fmt));
  201. if (!constraints->valid_sw_formats) {
  202. err = AVERROR(ENOMEM);
  203. goto fail;
  204. }
  205. for (i = j = 0; i < attr_count; i++) {
  206. if (attr_list[i].type != VASurfaceAttribPixelFormat)
  207. continue;
  208. fourcc = attr_list[i].value.value.i;
  209. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  210. if (pix_fmt != AV_PIX_FMT_NONE)
  211. constraints->valid_sw_formats[j++] = pix_fmt;
  212. }
  213. av_assert0(j == pix_fmt_count);
  214. constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
  215. }
  216. } else {
  217. // No configuration supplied.
  218. // Return the full set of image formats known by the implementation.
  219. constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
  220. sizeof(pix_fmt));
  221. if (!constraints->valid_sw_formats) {
  222. err = AVERROR(ENOMEM);
  223. goto fail;
  224. }
  225. for (i = 0; i < ctx->nb_formats; i++)
  226. constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
  227. constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
  228. }
  229. constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
  230. if (!constraints->valid_hw_formats) {
  231. err = AVERROR(ENOMEM);
  232. goto fail;
  233. }
  234. constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
  235. constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
  236. err = 0;
  237. fail:
  238. av_freep(&attr_list);
  239. return err;
  240. }
  241. static const struct {
  242. const char *friendly_name;
  243. const char *match_string;
  244. unsigned int quirks;
  245. } vaapi_driver_quirks_table[] = {
  246. {
  247. "Intel i965 (Quick Sync)",
  248. "i965",
  249. AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
  250. },
  251. };
  252. static int vaapi_device_init(AVHWDeviceContext *hwdev)
  253. {
  254. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  255. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  256. VAImageFormat *image_list = NULL;
  257. VAStatus vas;
  258. const char *vendor_string;
  259. int err, i, image_count;
  260. enum AVPixelFormat pix_fmt;
  261. unsigned int fourcc;
  262. image_count = vaMaxNumImageFormats(hwctx->display);
  263. if (image_count <= 0) {
  264. err = AVERROR(EIO);
  265. goto fail;
  266. }
  267. image_list = av_malloc(image_count * sizeof(*image_list));
  268. if (!image_list) {
  269. err = AVERROR(ENOMEM);
  270. goto fail;
  271. }
  272. vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
  273. if (vas != VA_STATUS_SUCCESS) {
  274. err = AVERROR(EIO);
  275. goto fail;
  276. }
  277. ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
  278. if (!ctx->formats) {
  279. err = AVERROR(ENOMEM);
  280. goto fail;
  281. }
  282. ctx->nb_formats = 0;
  283. for (i = 0; i < image_count; i++) {
  284. fourcc = image_list[i].fourcc;
  285. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  286. if (pix_fmt == AV_PIX_FMT_NONE) {
  287. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
  288. fourcc);
  289. } else {
  290. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
  291. fourcc, av_get_pix_fmt_name(pix_fmt));
  292. ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
  293. ctx->formats[ctx->nb_formats].image_format = image_list[i];
  294. ++ctx->nb_formats;
  295. }
  296. }
  297. if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
  298. av_log(hwdev, AV_LOG_VERBOSE, "Not detecting driver: "
  299. "quirks set by user.\n");
  300. } else {
  301. // Detect the driver in use and set quirk flags if necessary.
  302. vendor_string = vaQueryVendorString(hwctx->display);
  303. hwctx->driver_quirks = 0;
  304. if (vendor_string) {
  305. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
  306. if (strstr(vendor_string,
  307. vaapi_driver_quirks_table[i].match_string)) {
  308. av_log(hwdev, AV_LOG_VERBOSE, "Matched \"%s\" as known "
  309. "driver \"%s\".\n", vendor_string,
  310. vaapi_driver_quirks_table[i].friendly_name);
  311. hwctx->driver_quirks |=
  312. vaapi_driver_quirks_table[i].quirks;
  313. break;
  314. }
  315. }
  316. if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
  317. av_log(hwdev, AV_LOG_VERBOSE, "Unknown driver \"%s\", "
  318. "assuming standard behaviour.\n", vendor_string);
  319. }
  320. }
  321. }
  322. av_free(image_list);
  323. return 0;
  324. fail:
  325. av_freep(&ctx->formats);
  326. av_free(image_list);
  327. return err;
  328. }
  329. static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
  330. {
  331. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  332. av_freep(&ctx->formats);
  333. }
  334. static void vaapi_buffer_free(void *opaque, uint8_t *data)
  335. {
  336. AVHWFramesContext *hwfc = opaque;
  337. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  338. VASurfaceID surface_id;
  339. VAStatus vas;
  340. surface_id = (VASurfaceID)(uintptr_t)data;
  341. vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
  342. if (vas != VA_STATUS_SUCCESS) {
  343. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
  344. "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
  345. }
  346. }
  347. static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
  348. {
  349. AVHWFramesContext *hwfc = opaque;
  350. VAAPIFramesContext *ctx = hwfc->internal->priv;
  351. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  352. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  353. VASurfaceID surface_id;
  354. VAStatus vas;
  355. AVBufferRef *ref;
  356. vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
  357. hwfc->width, hwfc->height,
  358. &surface_id, 1,
  359. ctx->attributes, ctx->nb_attributes);
  360. if (vas != VA_STATUS_SUCCESS) {
  361. av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
  362. "%d (%s).\n", vas, vaErrorStr(vas));
  363. return NULL;
  364. }
  365. av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
  366. ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
  367. sizeof(surface_id), &vaapi_buffer_free,
  368. hwfc, AV_BUFFER_FLAG_READONLY);
  369. if (!ref) {
  370. vaDestroySurfaces(hwctx->display, &surface_id, 1);
  371. return NULL;
  372. }
  373. if (hwfc->initial_pool_size > 0) {
  374. // This is a fixed-size pool, so we must still be in the initial
  375. // allocation sequence.
  376. av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
  377. avfc->surface_ids[avfc->nb_surfaces] = surface_id;
  378. ++avfc->nb_surfaces;
  379. }
  380. return ref;
  381. }
  382. static int vaapi_frames_init(AVHWFramesContext *hwfc)
  383. {
  384. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  385. VAAPIFramesContext *ctx = hwfc->internal->priv;
  386. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  387. VAImageFormat *expected_format;
  388. AVBufferRef *test_surface = NULL;
  389. VASurfaceID test_surface_id;
  390. VAImage test_image;
  391. VAStatus vas;
  392. int err, i;
  393. unsigned int fourcc, rt_format;
  394. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
  395. if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
  396. fourcc = vaapi_format_map[i].fourcc;
  397. rt_format = vaapi_format_map[i].rt_format;
  398. break;
  399. }
  400. }
  401. if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
  402. av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
  403. av_get_pix_fmt_name(hwfc->sw_format));
  404. return AVERROR(EINVAL);
  405. }
  406. if (!hwfc->pool) {
  407. int need_memory_type = 1, 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(void *opaque, uint8_t *data)
  564. {
  565. AVHWFramesContext *hwfc = opaque;
  566. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  567. VAAPISurfaceMap *map = (VAAPISurfaceMap*)data;
  568. const AVFrame *src;
  569. VASurfaceID surface_id;
  570. VAStatus vas;
  571. src = map->source;
  572. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  573. av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
  574. vas = vaUnmapBuffer(hwctx->display, map->image.buf);
  575. if (vas != VA_STATUS_SUCCESS) {
  576. av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
  577. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  578. }
  579. if ((map->flags & VAAPI_MAP_WRITE) &&
  580. !(map->flags & VAAPI_MAP_DIRECT)) {
  581. vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
  582. 0, 0, hwfc->width, hwfc->height,
  583. 0, 0, hwfc->width, hwfc->height);
  584. if (vas != VA_STATUS_SUCCESS) {
  585. av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
  586. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  587. }
  588. }
  589. vas = vaDestroyImage(hwctx->display, map->image.image_id);
  590. if (vas != VA_STATUS_SUCCESS) {
  591. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
  592. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  593. }
  594. av_free(map);
  595. }
  596. static int vaapi_map_frame(AVHWFramesContext *hwfc,
  597. AVFrame *dst, const AVFrame *src, int flags)
  598. {
  599. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  600. VAAPIFramesContext *ctx = hwfc->internal->priv;
  601. VASurfaceID surface_id;
  602. VAImageFormat *image_format;
  603. VAAPISurfaceMap *map;
  604. VAStatus vas;
  605. void *address = NULL;
  606. int err, i;
  607. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  608. av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
  609. if (!ctx->derive_works && (flags & VAAPI_MAP_DIRECT)) {
  610. // Requested direct mapping but it is not possible.
  611. return AVERROR(EINVAL);
  612. }
  613. if (dst->format == AV_PIX_FMT_NONE)
  614. dst->format = hwfc->sw_format;
  615. if (dst->format != hwfc->sw_format && (flags & VAAPI_MAP_DIRECT)) {
  616. // Requested direct mapping but the formats do not match.
  617. return AVERROR(EINVAL);
  618. }
  619. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
  620. if (err < 0) {
  621. // Requested format is not a valid output format.
  622. return AVERROR(EINVAL);
  623. }
  624. map = av_malloc(sizeof(VAAPISurfaceMap));
  625. if (!map)
  626. return AVERROR(ENOMEM);
  627. map->source = src;
  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 &&
  645. ((flags & VAAPI_MAP_DIRECT) || !(flags & VAAPI_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 |= VAAPI_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 & VAAPI_MAP_READ) {
  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. dst->width = src->width;
  692. dst->height = src->height;
  693. for (i = 0; i < map->image.num_planes; i++) {
  694. dst->data[i] = (uint8_t*)address + map->image.offsets[i];
  695. dst->linesize[i] = map->image.pitches[i];
  696. }
  697. if (
  698. #ifdef VA_FOURCC_YV16
  699. map->image.format.fourcc == VA_FOURCC_YV16 ||
  700. #endif
  701. map->image.format.fourcc == VA_FOURCC_YV12) {
  702. // Chroma planes are YVU rather than YUV, so swap them.
  703. FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
  704. }
  705. dst->buf[0] = av_buffer_create((uint8_t*)map, sizeof(*map),
  706. &vaapi_unmap_frame, hwfc, 0);
  707. if (!dst->buf[0]) {
  708. err = AVERROR(ENOMEM);
  709. goto fail;
  710. }
  711. return 0;
  712. fail:
  713. if (map) {
  714. if (address)
  715. vaUnmapBuffer(hwctx->display, map->image.buf);
  716. if (map->image.image_id != VA_INVALID_ID)
  717. vaDestroyImage(hwctx->display, map->image.image_id);
  718. av_free(map);
  719. }
  720. return err;
  721. }
  722. static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
  723. AVFrame *dst, const AVFrame *src)
  724. {
  725. AVFrame *map;
  726. int err;
  727. if (dst->width > hwfc->width || dst->height > hwfc->height)
  728. return AVERROR(EINVAL);
  729. map = av_frame_alloc();
  730. if (!map)
  731. return AVERROR(ENOMEM);
  732. map->format = dst->format;
  733. err = vaapi_map_frame(hwfc, map, src, VAAPI_MAP_READ);
  734. if (err)
  735. goto fail;
  736. map->width = dst->width;
  737. map->height = dst->height;
  738. err = av_frame_copy(dst, map);
  739. if (err)
  740. goto fail;
  741. err = 0;
  742. fail:
  743. av_frame_free(&map);
  744. return err;
  745. }
  746. static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
  747. AVFrame *dst, const AVFrame *src)
  748. {
  749. AVFrame *map;
  750. int err;
  751. if (src->width > hwfc->width || src->height > hwfc->height)
  752. return AVERROR(EINVAL);
  753. map = av_frame_alloc();
  754. if (!map)
  755. return AVERROR(ENOMEM);
  756. map->format = src->format;
  757. err = vaapi_map_frame(hwfc, map, dst, VAAPI_MAP_WRITE);
  758. if (err)
  759. goto fail;
  760. map->width = src->width;
  761. map->height = src->height;
  762. err = av_frame_copy(map, src);
  763. if (err)
  764. goto fail;
  765. err = 0;
  766. fail:
  767. av_frame_free(&map);
  768. return err;
  769. }
  770. static void vaapi_device_free(AVHWDeviceContext *ctx)
  771. {
  772. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  773. VAAPIDevicePriv *priv = ctx->user_opaque;
  774. if (hwctx->display)
  775. vaTerminate(hwctx->display);
  776. #if HAVE_VAAPI_X11
  777. if (priv->x11_display)
  778. XCloseDisplay(priv->x11_display);
  779. #endif
  780. if (priv->drm_fd >= 0)
  781. close(priv->drm_fd);
  782. av_freep(&priv);
  783. }
  784. static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
  785. AVDictionary *opts, int flags)
  786. {
  787. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  788. VAAPIDevicePriv *priv;
  789. VADisplay display = 0;
  790. VAStatus vas;
  791. int major, minor;
  792. priv = av_mallocz(sizeof(*priv));
  793. if (!priv)
  794. return AVERROR(ENOMEM);
  795. priv->drm_fd = -1;
  796. ctx->user_opaque = priv;
  797. ctx->free = vaapi_device_free;
  798. #if HAVE_VAAPI_X11
  799. if (!display && !(device && device[0] == '/')) {
  800. // Try to open the device as an X11 display.
  801. priv->x11_display = XOpenDisplay(device);
  802. if (!priv->x11_display) {
  803. av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
  804. "%s.\n", XDisplayName(device));
  805. } else {
  806. display = vaGetDisplay(priv->x11_display);
  807. if (!display) {
  808. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  809. "from X11 display %s.\n", XDisplayName(device));
  810. return AVERROR_UNKNOWN;
  811. }
  812. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  813. "X11 display %s.\n", XDisplayName(device));
  814. }
  815. }
  816. #endif
  817. #if HAVE_VAAPI_DRM
  818. if (!display) {
  819. // Try to open the device as a DRM path.
  820. // Default to using the first render node if the user did not
  821. // supply a path.
  822. const char *path = device ? device : "/dev/dri/renderD128";
  823. priv->drm_fd = open(path, O_RDWR);
  824. if (priv->drm_fd < 0) {
  825. av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
  826. path);
  827. } else {
  828. display = vaGetDisplayDRM(priv->drm_fd);
  829. if (!display) {
  830. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  831. "from DRM device %s.\n", path);
  832. return AVERROR_UNKNOWN;
  833. }
  834. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  835. "DRM device %s.\n", path);
  836. }
  837. }
  838. #endif
  839. if (!display) {
  840. av_log(ctx, AV_LOG_ERROR, "No VA display found for "
  841. "device: %s.\n", device ? device : "");
  842. return AVERROR(EINVAL);
  843. }
  844. hwctx->display = display;
  845. vas = vaInitialize(display, &major, &minor);
  846. if (vas != VA_STATUS_SUCCESS) {
  847. av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
  848. "connection: %d (%s).\n", vas, vaErrorStr(vas));
  849. return AVERROR(EIO);
  850. }
  851. av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
  852. "version %d.%d\n", major, minor);
  853. return 0;
  854. }
  855. const HWContextType ff_hwcontext_type_vaapi = {
  856. .type = AV_HWDEVICE_TYPE_VAAPI,
  857. .name = "VAAPI",
  858. .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
  859. .device_priv_size = sizeof(VAAPIDeviceContext),
  860. .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
  861. .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
  862. .frames_priv_size = sizeof(VAAPIFramesContext),
  863. .device_create = &vaapi_device_create,
  864. .device_init = &vaapi_device_init,
  865. .device_uninit = &vaapi_device_uninit,
  866. .frames_get_constraints = &vaapi_frames_get_constraints,
  867. .frames_init = &vaapi_frames_init,
  868. .frames_uninit = &vaapi_frames_uninit,
  869. .frames_get_buffer = &vaapi_get_buffer,
  870. .transfer_get_formats = &vaapi_transfer_get_formats,
  871. .transfer_data_to = &vaapi_transfer_data_to,
  872. .transfer_data_from = &vaapi_transfer_data_from,
  873. .pix_fmts = (const enum AVPixelFormat[]) {
  874. AV_PIX_FMT_VAAPI,
  875. AV_PIX_FMT_NONE
  876. },
  877. };