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.

1019 lines
33KB

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