hwcontext_vaapi.c 31 KB

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