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 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 "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. };