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.

976 lines
31KB

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