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.

851 lines
28KB

  1. /*
  2. * This file is part of Libav.
  3. *
  4. * Libav is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * Libav is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with Libav; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "avassert.h"
  19. #include "buffer.h"
  20. #include "common.h"
  21. #include "hwcontext.h"
  22. #include "hwcontext_internal.h"
  23. #include "hwcontext_vaapi.h"
  24. #include "mem.h"
  25. #include "pixdesc.h"
  26. #include "pixfmt.h"
  27. typedef struct VAAPISurfaceFormat {
  28. enum AVPixelFormat pix_fmt;
  29. VAImageFormat image_format;
  30. } VAAPISurfaceFormat;
  31. typedef struct VAAPIDeviceContext {
  32. // Surface formats which can be used with this device.
  33. VAAPISurfaceFormat *formats;
  34. int nb_formats;
  35. } VAAPIDeviceContext;
  36. typedef struct VAAPIFramesContext {
  37. // Surface attributes set at create time.
  38. VASurfaceAttrib *attributes;
  39. int nb_attributes;
  40. // RT format of the underlying surface (Intel driver ignores this anyway).
  41. unsigned int rt_format;
  42. // Whether vaDeriveImage works.
  43. int derive_works;
  44. } VAAPIFramesContext;
  45. enum {
  46. VAAPI_MAP_READ = 0x01,
  47. VAAPI_MAP_WRITE = 0x02,
  48. VAAPI_MAP_DIRECT = 0x04,
  49. };
  50. typedef struct VAAPISurfaceMap {
  51. // The source hardware frame of this mapping (with hw_frames_ctx set).
  52. const AVFrame *source;
  53. // VAAPI_MAP_* flags which apply to this mapping.
  54. int flags;
  55. // Handle to the derived or copied image which is mapped.
  56. VAImage image;
  57. } VAAPISurfaceMap;
  58. #define MAP(va, rt, av) { \
  59. VA_FOURCC_ ## va, \
  60. VA_RT_FORMAT_ ## rt, \
  61. AV_PIX_FMT_ ## av \
  62. }
  63. // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
  64. // plane swap cases. The frame handling below tries to hide these.
  65. static struct {
  66. unsigned int fourcc;
  67. unsigned int rt_format;
  68. enum AVPixelFormat pix_fmt;
  69. } vaapi_format_map[] = {
  70. MAP(NV12, YUV420, NV12),
  71. MAP(YV12, YUV420, YUV420P), // With U/V planes swapped.
  72. MAP(IYUV, YUV420, YUV420P),
  73. //MAP(I420, YUV420, YUV420P), // Not in libva but used by Intel driver.
  74. #ifdef VA_FOURCC_YV16
  75. MAP(YV16, YUV422, YUV422P), // With U/V planes swapped.
  76. #endif
  77. MAP(422H, YUV422, YUV422P),
  78. MAP(UYVY, YUV422, UYVY422),
  79. MAP(YUY2, YUV422, YUYV422),
  80. MAP(Y800, YUV400, GRAY8),
  81. #ifdef VA_FOURCC_P010
  82. //MAP(P010, YUV420_10BPP, P010),
  83. #endif
  84. MAP(BGRA, RGB32, BGRA),
  85. //MAP(BGRX, RGB32, BGR0),
  86. MAP(RGBA, RGB32, RGBA),
  87. //MAP(RGBX, RGB32, RGB0),
  88. MAP(ABGR, RGB32, ABGR),
  89. //MAP(XBGR, RGB32, 0BGR),
  90. MAP(ARGB, RGB32, ARGB),
  91. //MAP(XRGB, RGB32, 0RGB),
  92. };
  93. #undef MAP
  94. static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
  95. {
  96. int i;
  97. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
  98. if (vaapi_format_map[i].fourcc == fourcc)
  99. return vaapi_format_map[i].pix_fmt;
  100. return AV_PIX_FMT_NONE;
  101. }
  102. static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
  103. enum AVPixelFormat pix_fmt,
  104. VAImageFormat **image_format)
  105. {
  106. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  107. int i;
  108. for (i = 0; i < ctx->nb_formats; i++) {
  109. if (ctx->formats[i].pix_fmt == pix_fmt) {
  110. *image_format = &ctx->formats[i].image_format;
  111. return 0;
  112. }
  113. }
  114. return AVERROR(EINVAL);
  115. }
  116. static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
  117. const void *hwconfig,
  118. AVHWFramesConstraints *constraints)
  119. {
  120. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  121. const AVVAAPIHWConfig *config = hwconfig;
  122. AVVAAPIHWConfig *tmp_config;
  123. VASurfaceAttrib *attr_list = NULL;
  124. VAStatus vas;
  125. enum AVPixelFormat pix_fmt;
  126. unsigned int fourcc;
  127. int err, i, j, attr_count, pix_fmt_count;
  128. if (!hwconfig) {
  129. // No configuration was provided, so we create a temporary pipeline
  130. // configuration in order to query all supported image formats.
  131. tmp_config = av_mallocz(sizeof(*config));
  132. if (!tmp_config)
  133. return AVERROR(ENOMEM);
  134. vas = vaCreateConfig(hwctx->display,
  135. VAProfileNone, VAEntrypointVideoProc,
  136. NULL, 0, &tmp_config->config_id);
  137. if (vas != VA_STATUS_SUCCESS) {
  138. // No vpp. We might still be able to do something useful if
  139. // codecs are supported, so try to make the most-commonly
  140. // supported decoder configuration we can to query instead.
  141. vas = vaCreateConfig(hwctx->display,
  142. VAProfileH264ConstrainedBaseline,
  143. VAEntrypointVLD, NULL, 0,
  144. &tmp_config->config_id);
  145. if (vas != VA_STATUS_SUCCESS) {
  146. av_freep(&tmp_config);
  147. return AVERROR(ENOSYS);
  148. }
  149. }
  150. config = tmp_config;
  151. }
  152. attr_count = 0;
  153. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  154. 0, &attr_count);
  155. if (vas != VA_STATUS_SUCCESS) {
  156. av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
  157. "%d (%s).\n", vas, vaErrorStr(vas));
  158. err = AVERROR(ENOSYS);
  159. goto fail;
  160. }
  161. attr_list = av_malloc(attr_count * sizeof(*attr_list));
  162. if (!attr_list) {
  163. err = AVERROR(ENOMEM);
  164. goto fail;
  165. }
  166. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  167. attr_list, &attr_count);
  168. if (vas != VA_STATUS_SUCCESS) {
  169. av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
  170. "%d (%s).\n", vas, vaErrorStr(vas));
  171. err = AVERROR(ENOSYS);
  172. goto fail;
  173. }
  174. pix_fmt_count = 0;
  175. for (i = 0; i < attr_count; i++) {
  176. switch (attr_list[i].type) {
  177. case VASurfaceAttribPixelFormat:
  178. fourcc = attr_list[i].value.value.i;
  179. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  180. if (pix_fmt != AV_PIX_FMT_NONE) {
  181. ++pix_fmt_count;
  182. } else {
  183. // Something unsupported - ignore.
  184. }
  185. break;
  186. case VASurfaceAttribMinWidth:
  187. constraints->min_width = attr_list[i].value.value.i;
  188. break;
  189. case VASurfaceAttribMinHeight:
  190. constraints->min_height = attr_list[i].value.value.i;
  191. break;
  192. case VASurfaceAttribMaxWidth:
  193. constraints->max_width = attr_list[i].value.value.i;
  194. break;
  195. case VASurfaceAttribMaxHeight:
  196. constraints->max_height = attr_list[i].value.value.i;
  197. break;
  198. }
  199. }
  200. if (pix_fmt_count == 0) {
  201. // Nothing usable found. Presumably there exists something which
  202. // works, so leave the set null to indicate unknown.
  203. constraints->valid_sw_formats = NULL;
  204. } else {
  205. constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
  206. sizeof(pix_fmt));
  207. if (!constraints->valid_sw_formats) {
  208. err = AVERROR(ENOMEM);
  209. goto fail;
  210. }
  211. for (i = j = 0; i < attr_count; i++) {
  212. if (attr_list[i].type != VASurfaceAttribPixelFormat)
  213. continue;
  214. fourcc = attr_list[i].value.value.i;
  215. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  216. if (pix_fmt != AV_PIX_FMT_NONE)
  217. constraints->valid_sw_formats[j++] = pix_fmt;
  218. }
  219. av_assert0(j == pix_fmt_count);
  220. constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
  221. }
  222. constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
  223. if (!constraints->valid_hw_formats) {
  224. err = AVERROR(ENOMEM);
  225. goto fail;
  226. }
  227. constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
  228. constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
  229. err = 0;
  230. fail:
  231. av_freep(&attr_list);
  232. if (!hwconfig) {
  233. vaDestroyConfig(hwctx->display, tmp_config->config_id);
  234. av_freep(&tmp_config);
  235. }
  236. return err;
  237. }
  238. static int vaapi_device_init(AVHWDeviceContext *hwdev)
  239. {
  240. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  241. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  242. AVHWFramesConstraints *constraints = NULL;
  243. VAImageFormat *image_list = NULL;
  244. VAStatus vas;
  245. int err, i, j, image_count;
  246. enum AVPixelFormat pix_fmt;
  247. unsigned int fourcc;
  248. constraints = av_mallocz(sizeof(*constraints));
  249. if (!constraints)
  250. goto fail;
  251. err = vaapi_frames_get_constraints(hwdev, NULL, constraints);
  252. if (err < 0)
  253. goto fail;
  254. image_count = vaMaxNumImageFormats(hwctx->display);
  255. if (image_count <= 0) {
  256. err = AVERROR(EIO);
  257. goto fail;
  258. }
  259. image_list = av_malloc(image_count * sizeof(*image_list));
  260. if (!image_list) {
  261. err = AVERROR(ENOMEM);
  262. goto fail;
  263. }
  264. vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
  265. if (vas != VA_STATUS_SUCCESS) {
  266. err = AVERROR(EIO);
  267. goto fail;
  268. }
  269. ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
  270. if (!ctx->formats) {
  271. err = AVERROR(ENOMEM);
  272. goto fail;
  273. }
  274. ctx->nb_formats = 0;
  275. for (i = 0; i < image_count; i++) {
  276. fourcc = image_list[i].fourcc;
  277. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  278. for (j = 0; constraints->valid_sw_formats[j] != AV_PIX_FMT_NONE; j++) {
  279. if (pix_fmt == constraints->valid_sw_formats[j])
  280. break;
  281. }
  282. if (constraints->valid_sw_formats[j] != AV_PIX_FMT_NONE) {
  283. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
  284. fourcc, av_get_pix_fmt_name(pix_fmt));
  285. ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
  286. ctx->formats[ctx->nb_formats].image_format = image_list[i];
  287. ++ctx->nb_formats;
  288. } else {
  289. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n", fourcc);
  290. }
  291. }
  292. av_free(image_list);
  293. av_hwframe_constraints_free(&constraints);
  294. return 0;
  295. fail:
  296. av_freep(&ctx->formats);
  297. av_free(image_list);
  298. av_hwframe_constraints_free(&constraints);
  299. return err;
  300. }
  301. static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
  302. {
  303. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  304. av_freep(&ctx->formats);
  305. }
  306. static void vaapi_buffer_free(void *opaque, uint8_t *data)
  307. {
  308. AVHWFramesContext *hwfc = opaque;
  309. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  310. VASurfaceID surface_id;
  311. VAStatus vas;
  312. surface_id = (VASurfaceID)(uintptr_t)data;
  313. vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
  314. if (vas != VA_STATUS_SUCCESS) {
  315. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
  316. "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
  317. }
  318. }
  319. static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
  320. {
  321. AVHWFramesContext *hwfc = opaque;
  322. VAAPIFramesContext *ctx = hwfc->internal->priv;
  323. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  324. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  325. VASurfaceID surface_id;
  326. VAStatus vas;
  327. AVBufferRef *ref;
  328. vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
  329. hwfc->width, hwfc->height,
  330. &surface_id, 1,
  331. ctx->attributes, ctx->nb_attributes);
  332. if (vas != VA_STATUS_SUCCESS) {
  333. av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
  334. "%d (%s).\n", vas, vaErrorStr(vas));
  335. return NULL;
  336. }
  337. av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
  338. ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
  339. sizeof(surface_id), &vaapi_buffer_free,
  340. hwfc, AV_BUFFER_FLAG_READONLY);
  341. if (!ref) {
  342. vaDestroySurfaces(hwctx->display, &surface_id, 1);
  343. return NULL;
  344. }
  345. if (hwfc->initial_pool_size > 0) {
  346. // This is a fixed-size pool, so we must still be in the initial
  347. // allocation sequence.
  348. av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
  349. avfc->surface_ids[avfc->nb_surfaces] = surface_id;
  350. ++avfc->nb_surfaces;
  351. }
  352. return ref;
  353. }
  354. static int vaapi_frames_init(AVHWFramesContext *hwfc)
  355. {
  356. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  357. VAAPIFramesContext *ctx = hwfc->internal->priv;
  358. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  359. VAImageFormat *expected_format;
  360. AVBufferRef *test_surface = NULL;
  361. VASurfaceID test_surface_id;
  362. VAImage test_image;
  363. VAStatus vas;
  364. int err, i;
  365. unsigned int fourcc, rt_format;
  366. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
  367. if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
  368. fourcc = vaapi_format_map[i].fourcc;
  369. rt_format = vaapi_format_map[i].rt_format;
  370. break;
  371. }
  372. }
  373. if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
  374. av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
  375. av_get_pix_fmt_name(hwfc->sw_format));
  376. return AVERROR(EINVAL);
  377. }
  378. if (!hwfc->pool) {
  379. int need_memory_type = 1, need_pixel_format = 1;
  380. for (i = 0; i < avfc->nb_attributes; i++) {
  381. if (ctx->attributes[i].type == VASurfaceAttribMemoryType)
  382. need_memory_type = 0;
  383. if (ctx->attributes[i].type == VASurfaceAttribPixelFormat)
  384. need_pixel_format = 0;
  385. }
  386. ctx->nb_attributes =
  387. avfc->nb_attributes + need_memory_type + need_pixel_format;
  388. ctx->attributes = av_malloc(ctx->nb_attributes *
  389. sizeof(*ctx->attributes));
  390. if (!ctx->attributes) {
  391. err = AVERROR(ENOMEM);
  392. goto fail;
  393. }
  394. for (i = 0; i < avfc->nb_attributes; i++)
  395. ctx->attributes[i] = avfc->attributes[i];
  396. if (need_memory_type) {
  397. ctx->attributes[i++] = (VASurfaceAttrib) {
  398. .type = VASurfaceAttribMemoryType,
  399. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  400. .value.type = VAGenericValueTypeInteger,
  401. .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
  402. };
  403. }
  404. if (need_pixel_format) {
  405. ctx->attributes[i++] = (VASurfaceAttrib) {
  406. .type = VASurfaceAttribPixelFormat,
  407. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  408. .value.type = VAGenericValueTypeInteger,
  409. .value.value.i = fourcc,
  410. };
  411. }
  412. av_assert0(i == ctx->nb_attributes);
  413. ctx->rt_format = rt_format;
  414. if (hwfc->initial_pool_size > 0) {
  415. // This pool will be usable as a render target, so we need to store
  416. // all of the surface IDs somewhere that vaCreateContext() calls
  417. // will be able to access them.
  418. avfc->nb_surfaces = 0;
  419. avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
  420. sizeof(*avfc->surface_ids));
  421. if (!avfc->surface_ids) {
  422. err = AVERROR(ENOMEM);
  423. goto fail;
  424. }
  425. } else {
  426. // This pool allows dynamic sizing, and will not be usable as a
  427. // render target.
  428. avfc->nb_surfaces = 0;
  429. avfc->surface_ids = NULL;
  430. }
  431. hwfc->internal->pool_internal =
  432. av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
  433. &vaapi_pool_alloc, NULL);
  434. if (!hwfc->internal->pool_internal) {
  435. av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
  436. err = AVERROR(ENOMEM);
  437. goto fail;
  438. }
  439. }
  440. // Allocate a single surface to test whether vaDeriveImage() is going
  441. // to work for the specific configuration.
  442. if (hwfc->pool) {
  443. test_surface = av_buffer_pool_get(hwfc->pool);
  444. if (!test_surface) {
  445. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  446. "user-configured buffer pool.\n");
  447. err = AVERROR(ENOMEM);
  448. goto fail;
  449. }
  450. } else {
  451. test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
  452. if (!test_surface) {
  453. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  454. "internal buffer pool.\n");
  455. err = AVERROR(ENOMEM);
  456. goto fail;
  457. }
  458. }
  459. test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
  460. ctx->derive_works = 0;
  461. err = vaapi_get_image_format(hwfc->device_ctx,
  462. hwfc->sw_format, &expected_format);
  463. if (err == 0) {
  464. vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
  465. if (vas == VA_STATUS_SUCCESS) {
  466. if (expected_format->fourcc == test_image.format.fourcc) {
  467. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
  468. ctx->derive_works = 1;
  469. } else {
  470. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  471. "derived image format %08x does not match "
  472. "expected format %08x.\n",
  473. expected_format->fourcc, test_image.format.fourcc);
  474. }
  475. vaDestroyImage(hwctx->display, test_image.image_id);
  476. } else {
  477. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  478. "deriving image does not work: "
  479. "%d (%s).\n", vas, vaErrorStr(vas));
  480. }
  481. } else {
  482. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  483. "image format is not supported.\n");
  484. }
  485. av_buffer_unref(&test_surface);
  486. return 0;
  487. fail:
  488. av_buffer_unref(&test_surface);
  489. av_freep(&avfc->surface_ids);
  490. av_freep(&ctx->attributes);
  491. return err;
  492. }
  493. static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
  494. {
  495. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  496. VAAPIFramesContext *ctx = hwfc->internal->priv;
  497. av_freep(&avfc->surface_ids);
  498. av_freep(&ctx->attributes);
  499. }
  500. static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
  501. {
  502. frame->buf[0] = av_buffer_pool_get(hwfc->pool);
  503. if (!frame->buf[0])
  504. return AVERROR(ENOMEM);
  505. frame->data[3] = frame->buf[0]->data;
  506. frame->format = AV_PIX_FMT_VAAPI;
  507. frame->width = hwfc->width;
  508. frame->height = hwfc->height;
  509. return 0;
  510. }
  511. static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
  512. enum AVHWFrameTransferDirection dir,
  513. enum AVPixelFormat **formats)
  514. {
  515. VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
  516. enum AVPixelFormat *pix_fmts, preferred_format;
  517. int i, k;
  518. preferred_format = hwfc->sw_format;
  519. pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
  520. if (!pix_fmts)
  521. return AVERROR(ENOMEM);
  522. pix_fmts[0] = preferred_format;
  523. k = 1;
  524. for (i = 0; i < ctx->nb_formats; i++) {
  525. if (ctx->formats[i].pix_fmt == preferred_format)
  526. continue;
  527. av_assert0(k < ctx->nb_formats);
  528. pix_fmts[k++] = ctx->formats[i].pix_fmt;
  529. }
  530. av_assert0(k == ctx->nb_formats);
  531. pix_fmts[k] = AV_PIX_FMT_NONE;
  532. *formats = pix_fmts;
  533. return 0;
  534. }
  535. static void vaapi_unmap_frame(void *opaque, uint8_t *data)
  536. {
  537. AVHWFramesContext *hwfc = opaque;
  538. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  539. VAAPISurfaceMap *map = (VAAPISurfaceMap*)data;
  540. const AVFrame *src;
  541. VASurfaceID surface_id;
  542. VAStatus vas;
  543. src = map->source;
  544. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  545. av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
  546. vas = vaUnmapBuffer(hwctx->display, map->image.buf);
  547. if (vas != VA_STATUS_SUCCESS) {
  548. av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
  549. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  550. }
  551. if ((map->flags & VAAPI_MAP_WRITE) &&
  552. !(map->flags & VAAPI_MAP_DIRECT)) {
  553. vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
  554. 0, 0, hwfc->width, hwfc->height,
  555. 0, 0, hwfc->width, hwfc->height);
  556. if (vas != VA_STATUS_SUCCESS) {
  557. av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
  558. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  559. }
  560. }
  561. vas = vaDestroyImage(hwctx->display, map->image.image_id);
  562. if (vas != VA_STATUS_SUCCESS) {
  563. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
  564. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  565. }
  566. av_free(map);
  567. }
  568. static int vaapi_map_frame(AVHWFramesContext *hwfc,
  569. AVFrame *dst, const AVFrame *src, int flags)
  570. {
  571. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  572. VAAPIFramesContext *ctx = hwfc->internal->priv;
  573. VASurfaceID surface_id;
  574. VAImageFormat *image_format;
  575. VAAPISurfaceMap *map;
  576. VAStatus vas;
  577. void *address = NULL;
  578. int err, i;
  579. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  580. av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
  581. if (!ctx->derive_works && (flags & VAAPI_MAP_DIRECT)) {
  582. // Requested direct mapping but it is not possible.
  583. return AVERROR(EINVAL);
  584. }
  585. if (dst->format == AV_PIX_FMT_NONE)
  586. dst->format = hwfc->sw_format;
  587. if (dst->format != hwfc->sw_format && (flags & VAAPI_MAP_DIRECT)) {
  588. // Requested direct mapping but the formats do not match.
  589. return AVERROR(EINVAL);
  590. }
  591. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
  592. if (err < 0) {
  593. // Requested format is not a valid output format.
  594. return AVERROR(EINVAL);
  595. }
  596. map = av_malloc(sizeof(VAAPISurfaceMap));
  597. if (!map)
  598. return AVERROR(ENOMEM);
  599. map->source = src;
  600. map->flags = flags;
  601. map->image.image_id = VA_INVALID_ID;
  602. vas = vaSyncSurface(hwctx->display, surface_id);
  603. if (vas != VA_STATUS_SUCCESS) {
  604. av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
  605. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  606. err = AVERROR(EIO);
  607. goto fail;
  608. }
  609. // The memory which we map using derive need not be connected to the CPU
  610. // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
  611. // memory is mappable but not cached, so normal memcpy()-like access is
  612. // very slow to read it (but writing is ok). It is possible to read much
  613. // faster with a copy routine which is aware of the limitation, but we
  614. // assume for now that the user is not aware of that and would therefore
  615. // prefer not to be given direct-mapped memory if they request read access.
  616. if (ctx->derive_works &&
  617. ((flags & VAAPI_MAP_DIRECT) || !(flags & VAAPI_MAP_READ))) {
  618. vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
  619. if (vas != VA_STATUS_SUCCESS) {
  620. av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
  621. "surface %#x: %d (%s).\n",
  622. surface_id, vas, vaErrorStr(vas));
  623. err = AVERROR(EIO);
  624. goto fail;
  625. }
  626. if (map->image.format.fourcc != image_format->fourcc) {
  627. av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
  628. "is in wrong format: expected %#08x, got %#08x.\n",
  629. surface_id, image_format->fourcc, map->image.format.fourcc);
  630. err = AVERROR(EIO);
  631. goto fail;
  632. }
  633. map->flags |= VAAPI_MAP_DIRECT;
  634. } else {
  635. vas = vaCreateImage(hwctx->display, image_format,
  636. hwfc->width, hwfc->height, &map->image);
  637. if (vas != VA_STATUS_SUCCESS) {
  638. av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
  639. "surface %#x: %d (%s).\n",
  640. surface_id, vas, vaErrorStr(vas));
  641. err = AVERROR(EIO);
  642. goto fail;
  643. }
  644. if (flags & VAAPI_MAP_READ) {
  645. vas = vaGetImage(hwctx->display, surface_id, 0, 0,
  646. hwfc->width, hwfc->height, map->image.image_id);
  647. if (vas != VA_STATUS_SUCCESS) {
  648. av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
  649. "surface %#x: %d (%s).\n",
  650. surface_id, vas, vaErrorStr(vas));
  651. err = AVERROR(EIO);
  652. goto fail;
  653. }
  654. }
  655. }
  656. vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
  657. if (vas != VA_STATUS_SUCCESS) {
  658. av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
  659. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  660. err = AVERROR(EIO);
  661. goto fail;
  662. }
  663. dst->width = src->width;
  664. dst->height = src->height;
  665. for (i = 0; i < map->image.num_planes; i++) {
  666. dst->data[i] = (uint8_t*)address + map->image.offsets[i];
  667. dst->linesize[i] = map->image.pitches[i];
  668. }
  669. if (
  670. #ifdef VA_FOURCC_YV16
  671. map->image.format.fourcc == VA_FOURCC_YV16 ||
  672. #endif
  673. map->image.format.fourcc == VA_FOURCC_YV12) {
  674. // Chroma planes are YVU rather than YUV, so swap them.
  675. FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
  676. }
  677. dst->buf[0] = av_buffer_create((uint8_t*)map, sizeof(*map),
  678. &vaapi_unmap_frame, hwfc, 0);
  679. if (!dst->buf[0]) {
  680. err = AVERROR(ENOMEM);
  681. goto fail;
  682. }
  683. return 0;
  684. fail:
  685. if (map) {
  686. if (address)
  687. vaUnmapBuffer(hwctx->display, map->image.buf);
  688. if (map->image.image_id != VA_INVALID_ID)
  689. vaDestroyImage(hwctx->display, map->image.image_id);
  690. av_free(map);
  691. }
  692. return err;
  693. }
  694. static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
  695. AVFrame *dst, const AVFrame *src)
  696. {
  697. AVFrame *map;
  698. int err;
  699. map = av_frame_alloc();
  700. if (!map)
  701. return AVERROR(ENOMEM);
  702. map->format = dst->format;
  703. err = vaapi_map_frame(hwfc, map, src, VAAPI_MAP_READ);
  704. if (err)
  705. goto fail;
  706. err = av_frame_copy(dst, map);
  707. if (err)
  708. goto fail;
  709. err = 0;
  710. fail:
  711. av_frame_free(&map);
  712. return err;
  713. }
  714. static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
  715. AVFrame *dst, const AVFrame *src)
  716. {
  717. AVFrame *map;
  718. int err;
  719. map = av_frame_alloc();
  720. if (!map)
  721. return AVERROR(ENOMEM);
  722. map->format = src->format;
  723. err = vaapi_map_frame(hwfc, map, dst, VAAPI_MAP_WRITE);
  724. if (err)
  725. goto fail;
  726. err = av_frame_copy(map, src);
  727. if (err)
  728. goto fail;
  729. err = 0;
  730. fail:
  731. av_frame_free(&map);
  732. return err;
  733. }
  734. const HWContextType ff_hwcontext_type_vaapi = {
  735. .type = AV_HWDEVICE_TYPE_VAAPI,
  736. .name = "VAAPI",
  737. .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
  738. .device_priv_size = sizeof(VAAPIDeviceContext),
  739. .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
  740. .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
  741. .frames_priv_size = sizeof(VAAPIFramesContext),
  742. .device_init = &vaapi_device_init,
  743. .device_uninit = &vaapi_device_uninit,
  744. .frames_get_constraints = &vaapi_frames_get_constraints,
  745. .frames_init = &vaapi_frames_init,
  746. .frames_uninit = &vaapi_frames_uninit,
  747. .frames_get_buffer = &vaapi_get_buffer,
  748. .transfer_get_formats = &vaapi_transfer_get_formats,
  749. .transfer_data_to = &vaapi_transfer_data_to,
  750. .transfer_data_from = &vaapi_transfer_data_from,
  751. .pix_fmts = (const enum AVPixelFormat[]) {
  752. AV_PIX_FMT_VAAPI,
  753. AV_PIX_FMT_NONE
  754. },
  755. };