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.

1259 lines
40KB

  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. #if CONFIG_LIBDRM
  26. # include <va/va_drmcommon.h>
  27. # include <drm_fourcc.h>
  28. #endif
  29. #include <fcntl.h>
  30. #if HAVE_UNISTD_H
  31. # include <unistd.h>
  32. #endif
  33. #include "avassert.h"
  34. #include "buffer.h"
  35. #include "common.h"
  36. #include "hwcontext.h"
  37. #include "hwcontext_internal.h"
  38. #include "hwcontext_vaapi.h"
  39. #include "mem.h"
  40. #include "pixdesc.h"
  41. #include "pixfmt.h"
  42. #if CONFIG_LIBDRM
  43. # include "hwcontext_drm.h"
  44. #endif
  45. typedef struct VAAPIDevicePriv {
  46. #if HAVE_VAAPI_X11
  47. Display *x11_display;
  48. #endif
  49. int drm_fd;
  50. } VAAPIDevicePriv;
  51. typedef struct VAAPISurfaceFormat {
  52. enum AVPixelFormat pix_fmt;
  53. VAImageFormat image_format;
  54. } VAAPISurfaceFormat;
  55. typedef struct VAAPIDeviceContext {
  56. // Surface formats which can be used with this device.
  57. VAAPISurfaceFormat *formats;
  58. int nb_formats;
  59. } VAAPIDeviceContext;
  60. typedef struct VAAPIFramesContext {
  61. // Surface attributes set at create time.
  62. VASurfaceAttrib *attributes;
  63. int nb_attributes;
  64. // RT format of the underlying surface (Intel driver ignores this anyway).
  65. unsigned int rt_format;
  66. // Whether vaDeriveImage works.
  67. int derive_works;
  68. } VAAPIFramesContext;
  69. typedef struct VAAPIMapping {
  70. // Handle to the derived or copied image which is mapped.
  71. VAImage image;
  72. // The mapping flags actually used.
  73. int flags;
  74. } VAAPIMapping;
  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. if (image_format)
  130. *image_format = &ctx->formats[i].image_format;
  131. return 0;
  132. }
  133. }
  134. return AVERROR(EINVAL);
  135. }
  136. static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
  137. const void *hwconfig,
  138. AVHWFramesConstraints *constraints)
  139. {
  140. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  141. const AVVAAPIHWConfig *config = hwconfig;
  142. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  143. VASurfaceAttrib *attr_list = NULL;
  144. VAStatus vas;
  145. enum AVPixelFormat pix_fmt;
  146. unsigned int fourcc;
  147. int err, i, j, attr_count, pix_fmt_count;
  148. if (config &&
  149. !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
  150. attr_count = 0;
  151. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  152. 0, &attr_count);
  153. if (vas != VA_STATUS_SUCCESS) {
  154. av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
  155. "%d (%s).\n", vas, vaErrorStr(vas));
  156. err = AVERROR(ENOSYS);
  157. goto fail;
  158. }
  159. attr_list = av_malloc(attr_count * sizeof(*attr_list));
  160. if (!attr_list) {
  161. err = AVERROR(ENOMEM);
  162. goto fail;
  163. }
  164. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  165. attr_list, &attr_count);
  166. if (vas != VA_STATUS_SUCCESS) {
  167. av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
  168. "%d (%s).\n", vas, vaErrorStr(vas));
  169. err = AVERROR(ENOSYS);
  170. goto fail;
  171. }
  172. pix_fmt_count = 0;
  173. for (i = 0; i < attr_count; i++) {
  174. switch (attr_list[i].type) {
  175. case VASurfaceAttribPixelFormat:
  176. fourcc = attr_list[i].value.value.i;
  177. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  178. if (pix_fmt != AV_PIX_FMT_NONE) {
  179. ++pix_fmt_count;
  180. } else {
  181. // Something unsupported - ignore.
  182. }
  183. break;
  184. case VASurfaceAttribMinWidth:
  185. constraints->min_width = attr_list[i].value.value.i;
  186. break;
  187. case VASurfaceAttribMinHeight:
  188. constraints->min_height = attr_list[i].value.value.i;
  189. break;
  190. case VASurfaceAttribMaxWidth:
  191. constraints->max_width = attr_list[i].value.value.i;
  192. break;
  193. case VASurfaceAttribMaxHeight:
  194. constraints->max_height = attr_list[i].value.value.i;
  195. break;
  196. }
  197. }
  198. if (pix_fmt_count == 0) {
  199. // Nothing usable found. Presumably there exists something which
  200. // works, so leave the set null to indicate unknown.
  201. constraints->valid_sw_formats = NULL;
  202. } else {
  203. constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
  204. sizeof(pix_fmt));
  205. if (!constraints->valid_sw_formats) {
  206. err = AVERROR(ENOMEM);
  207. goto fail;
  208. }
  209. for (i = j = 0; i < attr_count; i++) {
  210. if (attr_list[i].type != VASurfaceAttribPixelFormat)
  211. continue;
  212. fourcc = attr_list[i].value.value.i;
  213. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  214. if (pix_fmt != AV_PIX_FMT_NONE)
  215. constraints->valid_sw_formats[j++] = pix_fmt;
  216. }
  217. av_assert0(j == pix_fmt_count);
  218. constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
  219. }
  220. } else {
  221. // No configuration supplied.
  222. // Return the full set of image formats known by the implementation.
  223. constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
  224. sizeof(pix_fmt));
  225. if (!constraints->valid_sw_formats) {
  226. err = AVERROR(ENOMEM);
  227. goto fail;
  228. }
  229. for (i = 0; i < ctx->nb_formats; i++)
  230. constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
  231. constraints->valid_sw_formats[i] = AV_PIX_FMT_NONE;
  232. }
  233. constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
  234. if (!constraints->valid_hw_formats) {
  235. err = AVERROR(ENOMEM);
  236. goto fail;
  237. }
  238. constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
  239. constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
  240. err = 0;
  241. fail:
  242. av_freep(&attr_list);
  243. return err;
  244. }
  245. static const struct {
  246. const char *friendly_name;
  247. const char *match_string;
  248. unsigned int quirks;
  249. } vaapi_driver_quirks_table[] = {
  250. {
  251. "Intel i965 (Quick Sync)",
  252. "i965",
  253. AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
  254. },
  255. {
  256. "Intel iHD",
  257. "ubit",
  258. AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
  259. },
  260. {
  261. "VDPAU wrapper",
  262. "Splitted-Desktop Systems VDPAU backend for VA-API",
  263. AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
  264. },
  265. };
  266. static int vaapi_device_init(AVHWDeviceContext *hwdev)
  267. {
  268. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  269. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  270. VAImageFormat *image_list = NULL;
  271. VAStatus vas;
  272. const char *vendor_string;
  273. int err, i, image_count;
  274. enum AVPixelFormat pix_fmt;
  275. unsigned int fourcc;
  276. image_count = vaMaxNumImageFormats(hwctx->display);
  277. if (image_count <= 0) {
  278. err = AVERROR(EIO);
  279. goto fail;
  280. }
  281. image_list = av_malloc(image_count * sizeof(*image_list));
  282. if (!image_list) {
  283. err = AVERROR(ENOMEM);
  284. goto fail;
  285. }
  286. vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
  287. if (vas != VA_STATUS_SUCCESS) {
  288. err = AVERROR(EIO);
  289. goto fail;
  290. }
  291. ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
  292. if (!ctx->formats) {
  293. err = AVERROR(ENOMEM);
  294. goto fail;
  295. }
  296. ctx->nb_formats = 0;
  297. for (i = 0; i < image_count; i++) {
  298. fourcc = image_list[i].fourcc;
  299. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  300. if (pix_fmt == AV_PIX_FMT_NONE) {
  301. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
  302. fourcc);
  303. } else {
  304. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
  305. fourcc, av_get_pix_fmt_name(pix_fmt));
  306. ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
  307. ctx->formats[ctx->nb_formats].image_format = image_list[i];
  308. ++ctx->nb_formats;
  309. }
  310. }
  311. if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
  312. av_log(hwdev, AV_LOG_VERBOSE, "Not detecting driver: "
  313. "quirks set by user.\n");
  314. } else {
  315. // Detect the driver in use and set quirk flags if necessary.
  316. vendor_string = vaQueryVendorString(hwctx->display);
  317. hwctx->driver_quirks = 0;
  318. if (vendor_string) {
  319. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
  320. if (strstr(vendor_string,
  321. vaapi_driver_quirks_table[i].match_string)) {
  322. av_log(hwdev, AV_LOG_VERBOSE, "Matched \"%s\" as known "
  323. "driver \"%s\".\n", vendor_string,
  324. vaapi_driver_quirks_table[i].friendly_name);
  325. hwctx->driver_quirks |=
  326. vaapi_driver_quirks_table[i].quirks;
  327. break;
  328. }
  329. }
  330. if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
  331. av_log(hwdev, AV_LOG_VERBOSE, "Unknown driver \"%s\", "
  332. "assuming standard behaviour.\n", vendor_string);
  333. }
  334. }
  335. }
  336. av_free(image_list);
  337. return 0;
  338. fail:
  339. av_freep(&ctx->formats);
  340. av_free(image_list);
  341. return err;
  342. }
  343. static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
  344. {
  345. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  346. av_freep(&ctx->formats);
  347. }
  348. static void vaapi_buffer_free(void *opaque, uint8_t *data)
  349. {
  350. AVHWFramesContext *hwfc = opaque;
  351. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  352. VASurfaceID surface_id;
  353. VAStatus vas;
  354. surface_id = (VASurfaceID)(uintptr_t)data;
  355. vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
  356. if (vas != VA_STATUS_SUCCESS) {
  357. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
  358. "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
  359. }
  360. }
  361. static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
  362. {
  363. AVHWFramesContext *hwfc = opaque;
  364. VAAPIFramesContext *ctx = hwfc->internal->priv;
  365. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  366. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  367. VASurfaceID surface_id;
  368. VAStatus vas;
  369. AVBufferRef *ref;
  370. if (hwfc->initial_pool_size > 0 &&
  371. avfc->nb_surfaces >= hwfc->initial_pool_size)
  372. return NULL;
  373. vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
  374. hwfc->width, hwfc->height,
  375. &surface_id, 1,
  376. ctx->attributes, ctx->nb_attributes);
  377. if (vas != VA_STATUS_SUCCESS) {
  378. av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
  379. "%d (%s).\n", vas, vaErrorStr(vas));
  380. return NULL;
  381. }
  382. av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
  383. ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
  384. sizeof(surface_id), &vaapi_buffer_free,
  385. hwfc, AV_BUFFER_FLAG_READONLY);
  386. if (!ref) {
  387. vaDestroySurfaces(hwctx->display, &surface_id, 1);
  388. return NULL;
  389. }
  390. if (hwfc->initial_pool_size > 0) {
  391. // This is a fixed-size pool, so we must still be in the initial
  392. // allocation sequence.
  393. av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
  394. avfc->surface_ids[avfc->nb_surfaces] = surface_id;
  395. ++avfc->nb_surfaces;
  396. }
  397. return ref;
  398. }
  399. static int vaapi_frames_init(AVHWFramesContext *hwfc)
  400. {
  401. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  402. VAAPIFramesContext *ctx = hwfc->internal->priv;
  403. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  404. VAImageFormat *expected_format;
  405. AVBufferRef *test_surface = NULL;
  406. VASurfaceID test_surface_id;
  407. VAImage test_image;
  408. VAStatus vas;
  409. int err, i;
  410. unsigned int fourcc, rt_format;
  411. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
  412. if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
  413. fourcc = vaapi_format_map[i].fourcc;
  414. rt_format = vaapi_format_map[i].rt_format;
  415. break;
  416. }
  417. }
  418. if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
  419. av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
  420. av_get_pix_fmt_name(hwfc->sw_format));
  421. return AVERROR(EINVAL);
  422. }
  423. if (!hwfc->pool) {
  424. if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
  425. int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
  426. int need_pixel_format = 1;
  427. for (i = 0; i < avfc->nb_attributes; i++) {
  428. if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
  429. need_memory_type = 0;
  430. if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
  431. need_pixel_format = 0;
  432. }
  433. ctx->nb_attributes =
  434. avfc->nb_attributes + need_memory_type + need_pixel_format;
  435. ctx->attributes = av_malloc(ctx->nb_attributes *
  436. sizeof(*ctx->attributes));
  437. if (!ctx->attributes) {
  438. err = AVERROR(ENOMEM);
  439. goto fail;
  440. }
  441. for (i = 0; i < avfc->nb_attributes; i++)
  442. ctx->attributes[i] = avfc->attributes[i];
  443. if (need_memory_type) {
  444. ctx->attributes[i++] = (VASurfaceAttrib) {
  445. .type = VASurfaceAttribMemoryType,
  446. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  447. .value.type = VAGenericValueTypeInteger,
  448. .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
  449. };
  450. }
  451. if (need_pixel_format) {
  452. ctx->attributes[i++] = (VASurfaceAttrib) {
  453. .type = VASurfaceAttribPixelFormat,
  454. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  455. .value.type = VAGenericValueTypeInteger,
  456. .value.value.i = fourcc,
  457. };
  458. }
  459. av_assert0(i == ctx->nb_attributes);
  460. } else {
  461. ctx->attributes = NULL;
  462. ctx->nb_attributes = 0;
  463. }
  464. ctx->rt_format = rt_format;
  465. if (hwfc->initial_pool_size > 0) {
  466. // This pool will be usable as a render target, so we need to store
  467. // all of the surface IDs somewhere that vaCreateContext() calls
  468. // will be able to access them.
  469. avfc->nb_surfaces = 0;
  470. avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
  471. sizeof(*avfc->surface_ids));
  472. if (!avfc->surface_ids) {
  473. err = AVERROR(ENOMEM);
  474. goto fail;
  475. }
  476. } else {
  477. // This pool allows dynamic sizing, and will not be usable as a
  478. // render target.
  479. avfc->nb_surfaces = 0;
  480. avfc->surface_ids = NULL;
  481. }
  482. hwfc->internal->pool_internal =
  483. av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
  484. &vaapi_pool_alloc, NULL);
  485. if (!hwfc->internal->pool_internal) {
  486. av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
  487. err = AVERROR(ENOMEM);
  488. goto fail;
  489. }
  490. }
  491. // Allocate a single surface to test whether vaDeriveImage() is going
  492. // to work for the specific configuration.
  493. if (hwfc->pool) {
  494. test_surface = av_buffer_pool_get(hwfc->pool);
  495. if (!test_surface) {
  496. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  497. "user-configured buffer pool.\n");
  498. err = AVERROR(ENOMEM);
  499. goto fail;
  500. }
  501. } else {
  502. test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
  503. if (!test_surface) {
  504. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  505. "internal buffer pool.\n");
  506. err = AVERROR(ENOMEM);
  507. goto fail;
  508. }
  509. }
  510. test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
  511. ctx->derive_works = 0;
  512. err = vaapi_get_image_format(hwfc->device_ctx,
  513. hwfc->sw_format, &expected_format);
  514. if (err == 0) {
  515. vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
  516. if (vas == VA_STATUS_SUCCESS) {
  517. if (expected_format->fourcc == test_image.format.fourcc) {
  518. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
  519. ctx->derive_works = 1;
  520. } else {
  521. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  522. "derived image format %08x does not match "
  523. "expected format %08x.\n",
  524. expected_format->fourcc, test_image.format.fourcc);
  525. }
  526. vaDestroyImage(hwctx->display, test_image.image_id);
  527. } else {
  528. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  529. "deriving image does not work: "
  530. "%d (%s).\n", vas, vaErrorStr(vas));
  531. }
  532. } else {
  533. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  534. "image format is not supported.\n");
  535. }
  536. av_buffer_unref(&test_surface);
  537. return 0;
  538. fail:
  539. av_buffer_unref(&test_surface);
  540. av_freep(&avfc->surface_ids);
  541. av_freep(&ctx->attributes);
  542. return err;
  543. }
  544. static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
  545. {
  546. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  547. VAAPIFramesContext *ctx = hwfc->internal->priv;
  548. av_freep(&avfc->surface_ids);
  549. av_freep(&ctx->attributes);
  550. }
  551. static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
  552. {
  553. frame->buf[0] = av_buffer_pool_get(hwfc->pool);
  554. if (!frame->buf[0])
  555. return AVERROR(ENOMEM);
  556. frame->data[3] = frame->buf[0]->data;
  557. frame->format = AV_PIX_FMT_VAAPI;
  558. frame->width = hwfc->width;
  559. frame->height = hwfc->height;
  560. return 0;
  561. }
  562. static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
  563. enum AVHWFrameTransferDirection dir,
  564. enum AVPixelFormat **formats)
  565. {
  566. VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
  567. enum AVPixelFormat *pix_fmts, preferred_format;
  568. int i, k;
  569. preferred_format = hwfc->sw_format;
  570. pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
  571. if (!pix_fmts)
  572. return AVERROR(ENOMEM);
  573. pix_fmts[0] = preferred_format;
  574. k = 1;
  575. for (i = 0; i < ctx->nb_formats; i++) {
  576. if (ctx->formats[i].pix_fmt == preferred_format)
  577. continue;
  578. av_assert0(k < ctx->nb_formats);
  579. pix_fmts[k++] = ctx->formats[i].pix_fmt;
  580. }
  581. av_assert0(k == ctx->nb_formats);
  582. pix_fmts[k] = AV_PIX_FMT_NONE;
  583. *formats = pix_fmts;
  584. return 0;
  585. }
  586. static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
  587. HWMapDescriptor *hwmap)
  588. {
  589. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  590. VAAPIMapping *map = hwmap->priv;
  591. VASurfaceID surface_id;
  592. VAStatus vas;
  593. surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
  594. av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
  595. vas = vaUnmapBuffer(hwctx->display, map->image.buf);
  596. if (vas != VA_STATUS_SUCCESS) {
  597. av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
  598. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  599. }
  600. if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
  601. !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
  602. vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
  603. 0, 0, hwfc->width, hwfc->height,
  604. 0, 0, hwfc->width, hwfc->height);
  605. if (vas != VA_STATUS_SUCCESS) {
  606. av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
  607. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  608. }
  609. }
  610. vas = vaDestroyImage(hwctx->display, map->image.image_id);
  611. if (vas != VA_STATUS_SUCCESS) {
  612. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
  613. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  614. }
  615. av_free(map);
  616. }
  617. static int vaapi_map_frame(AVHWFramesContext *hwfc,
  618. AVFrame *dst, const AVFrame *src, int flags)
  619. {
  620. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  621. VAAPIFramesContext *ctx = hwfc->internal->priv;
  622. VASurfaceID surface_id;
  623. VAImageFormat *image_format;
  624. VAAPIMapping *map;
  625. VAStatus vas;
  626. void *address = NULL;
  627. int err, i;
  628. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  629. av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
  630. if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
  631. // Requested direct mapping but it is not possible.
  632. return AVERROR(EINVAL);
  633. }
  634. if (dst->format == AV_PIX_FMT_NONE)
  635. dst->format = hwfc->sw_format;
  636. if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
  637. // Requested direct mapping but the formats do not match.
  638. return AVERROR(EINVAL);
  639. }
  640. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
  641. if (err < 0) {
  642. // Requested format is not a valid output format.
  643. return AVERROR(EINVAL);
  644. }
  645. map = av_malloc(sizeof(*map));
  646. if (!map)
  647. return AVERROR(ENOMEM);
  648. map->flags = flags;
  649. map->image.image_id = VA_INVALID_ID;
  650. vas = vaSyncSurface(hwctx->display, surface_id);
  651. if (vas != VA_STATUS_SUCCESS) {
  652. av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
  653. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  654. err = AVERROR(EIO);
  655. goto fail;
  656. }
  657. // The memory which we map using derive need not be connected to the CPU
  658. // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
  659. // memory is mappable but not cached, so normal memcpy()-like access is
  660. // very slow to read it (but writing is ok). It is possible to read much
  661. // faster with a copy routine which is aware of the limitation, but we
  662. // assume for now that the user is not aware of that and would therefore
  663. // prefer not to be given direct-mapped memory if they request read access.
  664. if (ctx->derive_works && dst->format == hwfc->sw_format &&
  665. ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
  666. vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
  667. if (vas != VA_STATUS_SUCCESS) {
  668. av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
  669. "surface %#x: %d (%s).\n",
  670. surface_id, vas, vaErrorStr(vas));
  671. err = AVERROR(EIO);
  672. goto fail;
  673. }
  674. if (map->image.format.fourcc != image_format->fourcc) {
  675. av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
  676. "is in wrong format: expected %#08x, got %#08x.\n",
  677. surface_id, image_format->fourcc, map->image.format.fourcc);
  678. err = AVERROR(EIO);
  679. goto fail;
  680. }
  681. map->flags |= AV_HWFRAME_MAP_DIRECT;
  682. } else {
  683. vas = vaCreateImage(hwctx->display, image_format,
  684. hwfc->width, hwfc->height, &map->image);
  685. if (vas != VA_STATUS_SUCCESS) {
  686. av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
  687. "surface %#x: %d (%s).\n",
  688. surface_id, vas, vaErrorStr(vas));
  689. err = AVERROR(EIO);
  690. goto fail;
  691. }
  692. if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
  693. vas = vaGetImage(hwctx->display, surface_id, 0, 0,
  694. hwfc->width, hwfc->height, map->image.image_id);
  695. if (vas != VA_STATUS_SUCCESS) {
  696. av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
  697. "surface %#x: %d (%s).\n",
  698. surface_id, vas, vaErrorStr(vas));
  699. err = AVERROR(EIO);
  700. goto fail;
  701. }
  702. }
  703. }
  704. vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
  705. if (vas != VA_STATUS_SUCCESS) {
  706. av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
  707. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  708. err = AVERROR(EIO);
  709. goto fail;
  710. }
  711. err = ff_hwframe_map_create(src->hw_frames_ctx,
  712. dst, src, &vaapi_unmap_frame, map);
  713. if (err < 0)
  714. goto fail;
  715. dst->width = src->width;
  716. dst->height = src->height;
  717. for (i = 0; i < map->image.num_planes; i++) {
  718. dst->data[i] = (uint8_t*)address + map->image.offsets[i];
  719. dst->linesize[i] = map->image.pitches[i];
  720. }
  721. if (
  722. #ifdef VA_FOURCC_YV16
  723. map->image.format.fourcc == VA_FOURCC_YV16 ||
  724. #endif
  725. map->image.format.fourcc == VA_FOURCC_YV12) {
  726. // Chroma planes are YVU rather than YUV, so swap them.
  727. FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
  728. }
  729. return 0;
  730. fail:
  731. if (map) {
  732. if (address)
  733. vaUnmapBuffer(hwctx->display, map->image.buf);
  734. if (map->image.image_id != VA_INVALID_ID)
  735. vaDestroyImage(hwctx->display, map->image.image_id);
  736. av_free(map);
  737. }
  738. return err;
  739. }
  740. static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
  741. AVFrame *dst, const AVFrame *src)
  742. {
  743. AVFrame *map;
  744. int err;
  745. if (dst->width > hwfc->width || dst->height > hwfc->height)
  746. return AVERROR(EINVAL);
  747. map = av_frame_alloc();
  748. if (!map)
  749. return AVERROR(ENOMEM);
  750. map->format = dst->format;
  751. err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
  752. if (err)
  753. goto fail;
  754. map->width = dst->width;
  755. map->height = dst->height;
  756. err = av_frame_copy(dst, map);
  757. if (err)
  758. goto fail;
  759. err = 0;
  760. fail:
  761. av_frame_free(&map);
  762. return err;
  763. }
  764. static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
  765. AVFrame *dst, const AVFrame *src)
  766. {
  767. AVFrame *map;
  768. int err;
  769. if (src->width > hwfc->width || src->height > hwfc->height)
  770. return AVERROR(EINVAL);
  771. map = av_frame_alloc();
  772. if (!map)
  773. return AVERROR(ENOMEM);
  774. map->format = src->format;
  775. err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
  776. if (err)
  777. goto fail;
  778. map->width = src->width;
  779. map->height = src->height;
  780. err = av_frame_copy(map, src);
  781. if (err)
  782. goto fail;
  783. err = 0;
  784. fail:
  785. av_frame_free(&map);
  786. return err;
  787. }
  788. static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
  789. const AVFrame *src, int flags)
  790. {
  791. int err;
  792. if (dst->format != AV_PIX_FMT_NONE) {
  793. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
  794. if (err < 0)
  795. return AVERROR(ENOSYS);
  796. }
  797. err = vaapi_map_frame(hwfc, dst, src, flags);
  798. if (err)
  799. return err;
  800. err = av_frame_copy_props(dst, src);
  801. if (err)
  802. return err;
  803. return 0;
  804. }
  805. #if CONFIG_LIBDRM
  806. #define DRM_MAP(va, layers, ...) { \
  807. VA_FOURCC_ ## va, \
  808. layers, \
  809. { __VA_ARGS__ } \
  810. }
  811. static const struct {
  812. uint32_t va_fourcc;
  813. int nb_layer_formats;
  814. uint32_t layer_formats[AV_DRM_MAX_PLANES];
  815. } vaapi_drm_format_map[] = {
  816. #ifdef DRM_FORMAT_R8
  817. DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
  818. #endif
  819. DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
  820. #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
  821. DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
  822. #endif
  823. DRM_MAP(BGRA, 1, DRM_FORMAT_BGRA8888),
  824. DRM_MAP(BGRX, 1, DRM_FORMAT_BGRX8888),
  825. DRM_MAP(RGBA, 1, DRM_FORMAT_RGBA8888),
  826. DRM_MAP(RGBX, 1, DRM_FORMAT_RGBX8888),
  827. #ifdef VA_FOURCC_ABGR
  828. DRM_MAP(ABGR, 1, DRM_FORMAT_ABGR8888),
  829. DRM_MAP(XBGR, 1, DRM_FORMAT_XBGR8888),
  830. #endif
  831. DRM_MAP(ARGB, 1, DRM_FORMAT_ARGB8888),
  832. DRM_MAP(XRGB, 1, DRM_FORMAT_XRGB8888),
  833. };
  834. #undef DRM_MAP
  835. static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
  836. HWMapDescriptor *hwmap)
  837. {
  838. AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  839. VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
  840. av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
  841. vaDestroySurfaces(dst_dev->display, &surface_id, 1);
  842. }
  843. static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
  844. const AVFrame *src, int flags)
  845. {
  846. AVHWFramesContext *dst_fc =
  847. (AVHWFramesContext*)dst->hw_frames_ctx->data;
  848. AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  849. const AVDRMFrameDescriptor *desc;
  850. VASurfaceID surface_id;
  851. VAStatus vas;
  852. uint32_t va_fourcc, va_rt_format;
  853. int err, i, j, k;
  854. unsigned long buffer_handle;
  855. VASurfaceAttribExternalBuffers buffer_desc;
  856. VASurfaceAttrib attrs[2] = {
  857. {
  858. .type = VASurfaceAttribMemoryType,
  859. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  860. .value.type = VAGenericValueTypeInteger,
  861. .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
  862. },
  863. {
  864. .type = VASurfaceAttribExternalBufferDescriptor,
  865. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  866. .value.type = VAGenericValueTypePointer,
  867. .value.value.p = &buffer_desc,
  868. }
  869. };
  870. desc = (AVDRMFrameDescriptor*)src->data[0];
  871. if (desc->nb_objects != 1) {
  872. av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
  873. "made from a single DRM object.\n");
  874. return AVERROR(EINVAL);
  875. }
  876. va_fourcc = 0;
  877. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
  878. if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
  879. continue;
  880. for (j = 0; j < desc->nb_layers; j++) {
  881. if (desc->layers[j].format !=
  882. vaapi_drm_format_map[i].layer_formats[j])
  883. break;
  884. }
  885. if (j != desc->nb_layers)
  886. continue;
  887. va_fourcc = vaapi_drm_format_map[i].va_fourcc;
  888. break;
  889. }
  890. if (!va_fourcc) {
  891. av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
  892. "by VAAPI.\n");
  893. return AVERROR(EINVAL);
  894. }
  895. av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
  896. "%08x.\n", desc->objects[0].fd, va_fourcc);
  897. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
  898. if (vaapi_format_map[i].fourcc == va_fourcc)
  899. va_rt_format = vaapi_format_map[i].rt_format;
  900. }
  901. buffer_handle = desc->objects[0].fd;
  902. buffer_desc.pixel_format = va_fourcc;
  903. buffer_desc.width = src_fc->width;
  904. buffer_desc.height = src_fc->height;
  905. buffer_desc.data_size = desc->objects[0].size;
  906. buffer_desc.buffers = &buffer_handle;
  907. buffer_desc.num_buffers = 1;
  908. buffer_desc.flags = 0;
  909. k = 0;
  910. for (i = 0; i < desc->nb_layers; i++) {
  911. for (j = 0; j < desc->layers[i].nb_planes; j++) {
  912. buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
  913. buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
  914. ++k;
  915. }
  916. }
  917. buffer_desc.num_planes = k;
  918. vas = vaCreateSurfaces(dst_dev->display, va_rt_format,
  919. src->width, src->height,
  920. &surface_id, 1,
  921. attrs, FF_ARRAY_ELEMS(attrs));
  922. if (vas != VA_STATUS_SUCCESS) {
  923. av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
  924. "object: %d (%s).\n", vas, vaErrorStr(vas));
  925. return AVERROR(EIO);
  926. }
  927. av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
  928. err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
  929. &vaapi_unmap_from_drm,
  930. (void*)(uintptr_t)surface_id);
  931. if (err < 0)
  932. return err;
  933. dst->width = src->width;
  934. dst->height = src->height;
  935. dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
  936. av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
  937. "surface %#x.\n", desc->objects[0].fd, surface_id);
  938. return 0;
  939. }
  940. #endif
  941. static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
  942. const AVFrame *src, int flags)
  943. {
  944. switch (src->format) {
  945. #if CONFIG_LIBDRM
  946. case AV_PIX_FMT_DRM_PRIME:
  947. return vaapi_map_from_drm(hwfc, dst, src, flags);
  948. #endif
  949. default:
  950. return AVERROR(ENOSYS);
  951. }
  952. }
  953. static void vaapi_device_free(AVHWDeviceContext *ctx)
  954. {
  955. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  956. VAAPIDevicePriv *priv = ctx->user_opaque;
  957. if (hwctx->display)
  958. vaTerminate(hwctx->display);
  959. #if HAVE_VAAPI_X11
  960. if (priv->x11_display)
  961. XCloseDisplay(priv->x11_display);
  962. #endif
  963. if (priv->drm_fd >= 0)
  964. close(priv->drm_fd);
  965. av_freep(&priv);
  966. }
  967. static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
  968. AVDictionary *opts, int flags)
  969. {
  970. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  971. VAAPIDevicePriv *priv;
  972. VADisplay display = 0;
  973. VAStatus vas;
  974. int major, minor;
  975. priv = av_mallocz(sizeof(*priv));
  976. if (!priv)
  977. return AVERROR(ENOMEM);
  978. priv->drm_fd = -1;
  979. ctx->user_opaque = priv;
  980. ctx->free = vaapi_device_free;
  981. #if HAVE_VAAPI_X11
  982. if (!display && !(device && device[0] == '/')) {
  983. // Try to open the device as an X11 display.
  984. priv->x11_display = XOpenDisplay(device);
  985. if (!priv->x11_display) {
  986. av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
  987. "%s.\n", XDisplayName(device));
  988. } else {
  989. display = vaGetDisplay(priv->x11_display);
  990. if (!display) {
  991. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  992. "from X11 display %s.\n", XDisplayName(device));
  993. return AVERROR_UNKNOWN;
  994. }
  995. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  996. "X11 display %s.\n", XDisplayName(device));
  997. }
  998. }
  999. #endif
  1000. #if HAVE_VAAPI_DRM
  1001. if (!display) {
  1002. // Try to open the device as a DRM path.
  1003. // Default to using the first render node if the user did not
  1004. // supply a path.
  1005. const char *path = device ? device : "/dev/dri/renderD128";
  1006. priv->drm_fd = open(path, O_RDWR);
  1007. if (priv->drm_fd < 0) {
  1008. av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
  1009. path);
  1010. } else {
  1011. display = vaGetDisplayDRM(priv->drm_fd);
  1012. if (!display) {
  1013. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  1014. "from DRM device %s.\n", path);
  1015. return AVERROR_UNKNOWN;
  1016. }
  1017. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  1018. "DRM device %s.\n", path);
  1019. }
  1020. }
  1021. #endif
  1022. if (!display) {
  1023. av_log(ctx, AV_LOG_ERROR, "No VA display found for "
  1024. "device: %s.\n", device ? device : "");
  1025. return AVERROR(EINVAL);
  1026. }
  1027. hwctx->display = display;
  1028. vas = vaInitialize(display, &major, &minor);
  1029. if (vas != VA_STATUS_SUCCESS) {
  1030. av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
  1031. "connection: %d (%s).\n", vas, vaErrorStr(vas));
  1032. return AVERROR(EIO);
  1033. }
  1034. av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
  1035. "version %d.%d\n", major, minor);
  1036. return 0;
  1037. }
  1038. static int vaapi_device_derive(AVHWDeviceContext *ctx,
  1039. AVHWDeviceContext *src_ctx, int flags)
  1040. {
  1041. #if CONFIG_LIBDRM
  1042. if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
  1043. AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
  1044. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  1045. VADisplay *display;
  1046. VAStatus vas;
  1047. VAAPIDevicePriv *priv;
  1048. int major, minor;
  1049. if (src_hwctx->fd < 0) {
  1050. av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
  1051. "device to derive a VA display from.\n");
  1052. return AVERROR(EINVAL);
  1053. }
  1054. priv = av_mallocz(sizeof(*priv));
  1055. if (!priv)
  1056. return AVERROR(ENOMEM);
  1057. // Inherits the fd from the source context, which will close it.
  1058. priv->drm_fd = -1;
  1059. ctx->user_opaque = priv;
  1060. ctx->free = &vaapi_device_free;
  1061. display = vaGetDisplayDRM(src_hwctx->fd);
  1062. if (!display) {
  1063. av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
  1064. "DRM device.\n");
  1065. return AVERROR(EIO);
  1066. }
  1067. hwctx->display = display;
  1068. vas = vaInitialize(display, &major, &minor);
  1069. if (vas != VA_STATUS_SUCCESS) {
  1070. av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
  1071. "connection: %d (%s).\n", vas, vaErrorStr(vas));
  1072. return AVERROR(EIO);
  1073. }
  1074. return 0;
  1075. }
  1076. #endif
  1077. return AVERROR(ENOSYS);
  1078. }
  1079. const HWContextType ff_hwcontext_type_vaapi = {
  1080. .type = AV_HWDEVICE_TYPE_VAAPI,
  1081. .name = "VAAPI",
  1082. .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
  1083. .device_priv_size = sizeof(VAAPIDeviceContext),
  1084. .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
  1085. .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
  1086. .frames_priv_size = sizeof(VAAPIFramesContext),
  1087. .device_create = &vaapi_device_create,
  1088. .device_derive = &vaapi_device_derive,
  1089. .device_init = &vaapi_device_init,
  1090. .device_uninit = &vaapi_device_uninit,
  1091. .frames_get_constraints = &vaapi_frames_get_constraints,
  1092. .frames_init = &vaapi_frames_init,
  1093. .frames_uninit = &vaapi_frames_uninit,
  1094. .frames_get_buffer = &vaapi_get_buffer,
  1095. .transfer_get_formats = &vaapi_transfer_get_formats,
  1096. .transfer_data_to = &vaapi_transfer_data_to,
  1097. .transfer_data_from = &vaapi_transfer_data_from,
  1098. .map_to = &vaapi_map_to,
  1099. .map_from = &vaapi_map_from,
  1100. .pix_fmts = (const enum AVPixelFormat[]) {
  1101. AV_PIX_FMT_VAAPI,
  1102. AV_PIX_FMT_NONE
  1103. },
  1104. };