hwcontext_vaapi.c 30 KB

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