hwcontext_vaapi.c 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568
  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "config.h"
  19. #if HAVE_VAAPI_X11
  20. # include <va/va_x11.h>
  21. #endif
  22. #if HAVE_VAAPI_DRM
  23. # include <va/va_drm.h>
  24. #endif
  25. #if CONFIG_LIBDRM
  26. # include <va/va_drmcommon.h>
  27. # include <drm_fourcc.h>
  28. # ifndef DRM_FORMAT_MOD_INVALID
  29. # define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
  30. # endif
  31. #endif
  32. #include <fcntl.h>
  33. #if HAVE_UNISTD_H
  34. # include <unistd.h>
  35. #endif
  36. #include "avassert.h"
  37. #include "buffer.h"
  38. #include "common.h"
  39. #include "hwcontext.h"
  40. #include "hwcontext_drm.h"
  41. #include "hwcontext_internal.h"
  42. #include "hwcontext_vaapi.h"
  43. #include "mem.h"
  44. #include "pixdesc.h"
  45. #include "pixfmt.h"
  46. typedef struct VAAPIDevicePriv {
  47. #if HAVE_VAAPI_X11
  48. Display *x11_display;
  49. #endif
  50. int drm_fd;
  51. } VAAPIDevicePriv;
  52. typedef struct VAAPISurfaceFormat {
  53. enum AVPixelFormat pix_fmt;
  54. VAImageFormat image_format;
  55. } VAAPISurfaceFormat;
  56. typedef struct VAAPIDeviceContext {
  57. // Surface formats which can be used with this device.
  58. VAAPISurfaceFormat *formats;
  59. int nb_formats;
  60. } VAAPIDeviceContext;
  61. typedef struct VAAPIFramesContext {
  62. // Surface attributes set at create time.
  63. VASurfaceAttrib *attributes;
  64. int nb_attributes;
  65. // RT format of the underlying surface (Intel driver ignores this anyway).
  66. unsigned int rt_format;
  67. // Whether vaDeriveImage works.
  68. int derive_works;
  69. } VAAPIFramesContext;
  70. typedef struct VAAPIMapping {
  71. // Handle to the derived or copied image which is mapped.
  72. VAImage image;
  73. // The mapping flags actually used.
  74. int flags;
  75. } VAAPIMapping;
  76. #define MAP(va, rt, av) { \
  77. VA_FOURCC_ ## va, \
  78. VA_RT_FORMAT_ ## rt, \
  79. AV_PIX_FMT_ ## av \
  80. }
  81. // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
  82. // plane swap cases. The frame handling below tries to hide these.
  83. static const struct {
  84. unsigned int fourcc;
  85. unsigned int rt_format;
  86. enum AVPixelFormat pix_fmt;
  87. } vaapi_format_map[] = {
  88. MAP(NV12, YUV420, NV12),
  89. MAP(YV12, YUV420, YUV420P), // With U/V planes swapped.
  90. MAP(IYUV, YUV420, YUV420P),
  91. #ifdef VA_FOURCC_I420
  92. MAP(I420, YUV420, YUV420P),
  93. #endif
  94. #ifdef VA_FOURCC_YV16
  95. MAP(YV16, YUV422, YUV422P), // With U/V planes swapped.
  96. #endif
  97. MAP(422H, YUV422, YUV422P),
  98. MAP(UYVY, YUV422, UYVY422),
  99. MAP(YUY2, YUV422, YUYV422),
  100. MAP(411P, YUV411, YUV411P),
  101. MAP(422V, YUV422, YUV440P),
  102. MAP(444P, YUV444, YUV444P),
  103. MAP(Y800, YUV400, GRAY8),
  104. #ifdef VA_FOURCC_P010
  105. MAP(P010, YUV420_10BPP, P010),
  106. #endif
  107. MAP(BGRA, RGB32, BGRA),
  108. MAP(BGRX, RGB32, BGR0),
  109. MAP(RGBA, RGB32, RGBA),
  110. MAP(RGBX, RGB32, RGB0),
  111. #ifdef VA_FOURCC_ABGR
  112. MAP(ABGR, RGB32, ABGR),
  113. MAP(XBGR, RGB32, 0BGR),
  114. #endif
  115. MAP(ARGB, RGB32, ARGB),
  116. MAP(XRGB, RGB32, 0RGB),
  117. };
  118. #undef MAP
  119. static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
  120. {
  121. int i;
  122. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
  123. if (vaapi_format_map[i].fourcc == fourcc)
  124. return vaapi_format_map[i].pix_fmt;
  125. return AV_PIX_FMT_NONE;
  126. }
  127. static int vaapi_get_image_format(AVHWDeviceContext *hwdev,
  128. enum AVPixelFormat pix_fmt,
  129. VAImageFormat **image_format)
  130. {
  131. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  132. int i;
  133. for (i = 0; i < ctx->nb_formats; i++) {
  134. if (ctx->formats[i].pix_fmt == pix_fmt) {
  135. if (image_format)
  136. *image_format = &ctx->formats[i].image_format;
  137. return 0;
  138. }
  139. }
  140. return AVERROR(EINVAL);
  141. }
  142. static int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
  143. const void *hwconfig,
  144. AVHWFramesConstraints *constraints)
  145. {
  146. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  147. const AVVAAPIHWConfig *config = hwconfig;
  148. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  149. VASurfaceAttrib *attr_list = NULL;
  150. VAStatus vas;
  151. enum AVPixelFormat pix_fmt;
  152. unsigned int fourcc;
  153. int err, i, j, attr_count, pix_fmt_count;
  154. if (config &&
  155. !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
  156. attr_count = 0;
  157. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  158. 0, &attr_count);
  159. if (vas != VA_STATUS_SUCCESS) {
  160. av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
  161. "%d (%s).\n", vas, vaErrorStr(vas));
  162. err = AVERROR(ENOSYS);
  163. goto fail;
  164. }
  165. attr_list = av_malloc(attr_count * sizeof(*attr_list));
  166. if (!attr_list) {
  167. err = AVERROR(ENOMEM);
  168. goto fail;
  169. }
  170. vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
  171. attr_list, &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. pix_fmt_count = 0;
  179. for (i = 0; i < attr_count; i++) {
  180. switch (attr_list[i].type) {
  181. case VASurfaceAttribPixelFormat:
  182. fourcc = attr_list[i].value.value.i;
  183. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  184. if (pix_fmt != AV_PIX_FMT_NONE) {
  185. ++pix_fmt_count;
  186. } else {
  187. // Something unsupported - ignore.
  188. }
  189. break;
  190. case VASurfaceAttribMinWidth:
  191. constraints->min_width = attr_list[i].value.value.i;
  192. break;
  193. case VASurfaceAttribMinHeight:
  194. constraints->min_height = attr_list[i].value.value.i;
  195. break;
  196. case VASurfaceAttribMaxWidth:
  197. constraints->max_width = attr_list[i].value.value.i;
  198. break;
  199. case VASurfaceAttribMaxHeight:
  200. constraints->max_height = attr_list[i].value.value.i;
  201. break;
  202. }
  203. }
  204. if (pix_fmt_count == 0) {
  205. // Nothing usable found. Presumably there exists something which
  206. // works, so leave the set null to indicate unknown.
  207. constraints->valid_sw_formats = NULL;
  208. } else {
  209. constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
  210. sizeof(pix_fmt));
  211. if (!constraints->valid_sw_formats) {
  212. err = AVERROR(ENOMEM);
  213. goto fail;
  214. }
  215. for (i = j = 0; i < attr_count; i++) {
  216. if (attr_list[i].type != VASurfaceAttribPixelFormat)
  217. continue;
  218. fourcc = attr_list[i].value.value.i;
  219. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  220. if (pix_fmt != AV_PIX_FMT_NONE)
  221. constraints->valid_sw_formats[j++] = pix_fmt;
  222. }
  223. av_assert0(j == pix_fmt_count);
  224. constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
  225. }
  226. } else {
  227. // No configuration supplied.
  228. // Return the full set of image formats known by the implementation.
  229. constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
  230. sizeof(pix_fmt));
  231. if (!constraints->valid_sw_formats) {
  232. err = AVERROR(ENOMEM);
  233. goto fail;
  234. }
  235. for (i = 0; i < ctx->nb_formats; i++)
  236. constraints->valid_sw_formats[i] = ctx->formats[i].pix_fmt;
  237. constraints->valid_sw_formats[i] = 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. return err;
  250. }
  251. static const struct {
  252. const char *friendly_name;
  253. const char *match_string;
  254. unsigned int quirks;
  255. } vaapi_driver_quirks_table[] = {
  256. {
  257. "Intel i965 (Quick Sync)",
  258. "i965",
  259. AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
  260. },
  261. {
  262. "Intel iHD",
  263. "ubit",
  264. AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
  265. },
  266. {
  267. "VDPAU wrapper",
  268. "Splitted-Desktop Systems VDPAU backend for VA-API",
  269. AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
  270. },
  271. };
  272. static int vaapi_device_init(AVHWDeviceContext *hwdev)
  273. {
  274. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  275. AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
  276. VAImageFormat *image_list = NULL;
  277. VAStatus vas;
  278. const char *vendor_string;
  279. int err, i, image_count;
  280. enum AVPixelFormat pix_fmt;
  281. unsigned int fourcc;
  282. image_count = vaMaxNumImageFormats(hwctx->display);
  283. if (image_count <= 0) {
  284. err = AVERROR(EIO);
  285. goto fail;
  286. }
  287. image_list = av_malloc(image_count * sizeof(*image_list));
  288. if (!image_list) {
  289. err = AVERROR(ENOMEM);
  290. goto fail;
  291. }
  292. vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
  293. if (vas != VA_STATUS_SUCCESS) {
  294. err = AVERROR(EIO);
  295. goto fail;
  296. }
  297. ctx->formats = av_malloc(image_count * sizeof(*ctx->formats));
  298. if (!ctx->formats) {
  299. err = AVERROR(ENOMEM);
  300. goto fail;
  301. }
  302. ctx->nb_formats = 0;
  303. for (i = 0; i < image_count; i++) {
  304. fourcc = image_list[i].fourcc;
  305. pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
  306. if (pix_fmt == AV_PIX_FMT_NONE) {
  307. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
  308. fourcc);
  309. } else {
  310. av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
  311. fourcc, av_get_pix_fmt_name(pix_fmt));
  312. ctx->formats[ctx->nb_formats].pix_fmt = pix_fmt;
  313. ctx->formats[ctx->nb_formats].image_format = image_list[i];
  314. ++ctx->nb_formats;
  315. }
  316. }
  317. if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
  318. av_log(hwdev, AV_LOG_VERBOSE, "Not detecting driver: "
  319. "quirks set by user.\n");
  320. } else {
  321. // Detect the driver in use and set quirk flags if necessary.
  322. vendor_string = vaQueryVendorString(hwctx->display);
  323. hwctx->driver_quirks = 0;
  324. if (vendor_string) {
  325. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
  326. if (strstr(vendor_string,
  327. vaapi_driver_quirks_table[i].match_string)) {
  328. av_log(hwdev, AV_LOG_VERBOSE, "Matched \"%s\" as known "
  329. "driver \"%s\".\n", vendor_string,
  330. vaapi_driver_quirks_table[i].friendly_name);
  331. hwctx->driver_quirks |=
  332. vaapi_driver_quirks_table[i].quirks;
  333. break;
  334. }
  335. }
  336. if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
  337. av_log(hwdev, AV_LOG_VERBOSE, "Unknown driver \"%s\", "
  338. "assuming standard behaviour.\n", vendor_string);
  339. }
  340. }
  341. }
  342. av_free(image_list);
  343. return 0;
  344. fail:
  345. av_freep(&ctx->formats);
  346. av_free(image_list);
  347. return err;
  348. }
  349. static void vaapi_device_uninit(AVHWDeviceContext *hwdev)
  350. {
  351. VAAPIDeviceContext *ctx = hwdev->internal->priv;
  352. av_freep(&ctx->formats);
  353. }
  354. static void vaapi_buffer_free(void *opaque, uint8_t *data)
  355. {
  356. AVHWFramesContext *hwfc = opaque;
  357. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  358. VASurfaceID surface_id;
  359. VAStatus vas;
  360. surface_id = (VASurfaceID)(uintptr_t)data;
  361. vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
  362. if (vas != VA_STATUS_SUCCESS) {
  363. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
  364. "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
  365. }
  366. }
  367. static AVBufferRef *vaapi_pool_alloc(void *opaque, int size)
  368. {
  369. AVHWFramesContext *hwfc = opaque;
  370. VAAPIFramesContext *ctx = hwfc->internal->priv;
  371. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  372. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  373. VASurfaceID surface_id;
  374. VAStatus vas;
  375. AVBufferRef *ref;
  376. if (hwfc->initial_pool_size > 0 &&
  377. avfc->nb_surfaces >= hwfc->initial_pool_size)
  378. return NULL;
  379. vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
  380. hwfc->width, hwfc->height,
  381. &surface_id, 1,
  382. ctx->attributes, ctx->nb_attributes);
  383. if (vas != VA_STATUS_SUCCESS) {
  384. av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
  385. "%d (%s).\n", vas, vaErrorStr(vas));
  386. return NULL;
  387. }
  388. av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
  389. ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
  390. sizeof(surface_id), &vaapi_buffer_free,
  391. hwfc, AV_BUFFER_FLAG_READONLY);
  392. if (!ref) {
  393. vaDestroySurfaces(hwctx->display, &surface_id, 1);
  394. return NULL;
  395. }
  396. if (hwfc->initial_pool_size > 0) {
  397. // This is a fixed-size pool, so we must still be in the initial
  398. // allocation sequence.
  399. av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
  400. avfc->surface_ids[avfc->nb_surfaces] = surface_id;
  401. ++avfc->nb_surfaces;
  402. }
  403. return ref;
  404. }
  405. static int vaapi_frames_init(AVHWFramesContext *hwfc)
  406. {
  407. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  408. VAAPIFramesContext *ctx = hwfc->internal->priv;
  409. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  410. VAImageFormat *expected_format;
  411. AVBufferRef *test_surface = NULL;
  412. VASurfaceID test_surface_id;
  413. VAImage test_image;
  414. VAStatus vas;
  415. int err, i;
  416. unsigned int fourcc, rt_format;
  417. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
  418. if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) {
  419. fourcc = vaapi_format_map[i].fourcc;
  420. rt_format = vaapi_format_map[i].rt_format;
  421. break;
  422. }
  423. }
  424. if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) {
  425. av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
  426. av_get_pix_fmt_name(hwfc->sw_format));
  427. return AVERROR(EINVAL);
  428. }
  429. if (!hwfc->pool) {
  430. if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
  431. int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
  432. int need_pixel_format = 1;
  433. for (i = 0; i < avfc->nb_attributes; i++) {
  434. if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
  435. need_memory_type = 0;
  436. if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
  437. need_pixel_format = 0;
  438. }
  439. ctx->nb_attributes =
  440. avfc->nb_attributes + need_memory_type + need_pixel_format;
  441. ctx->attributes = av_malloc(ctx->nb_attributes *
  442. sizeof(*ctx->attributes));
  443. if (!ctx->attributes) {
  444. err = AVERROR(ENOMEM);
  445. goto fail;
  446. }
  447. for (i = 0; i < avfc->nb_attributes; i++)
  448. ctx->attributes[i] = avfc->attributes[i];
  449. if (need_memory_type) {
  450. ctx->attributes[i++] = (VASurfaceAttrib) {
  451. .type = VASurfaceAttribMemoryType,
  452. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  453. .value.type = VAGenericValueTypeInteger,
  454. .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
  455. };
  456. }
  457. if (need_pixel_format) {
  458. ctx->attributes[i++] = (VASurfaceAttrib) {
  459. .type = VASurfaceAttribPixelFormat,
  460. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  461. .value.type = VAGenericValueTypeInteger,
  462. .value.value.i = fourcc,
  463. };
  464. }
  465. av_assert0(i == ctx->nb_attributes);
  466. } else {
  467. ctx->attributes = NULL;
  468. ctx->nb_attributes = 0;
  469. }
  470. ctx->rt_format = rt_format;
  471. if (hwfc->initial_pool_size > 0) {
  472. // This pool will be usable as a render target, so we need to store
  473. // all of the surface IDs somewhere that vaCreateContext() calls
  474. // will be able to access them.
  475. avfc->nb_surfaces = 0;
  476. avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
  477. sizeof(*avfc->surface_ids));
  478. if (!avfc->surface_ids) {
  479. err = AVERROR(ENOMEM);
  480. goto fail;
  481. }
  482. } else {
  483. // This pool allows dynamic sizing, and will not be usable as a
  484. // render target.
  485. avfc->nb_surfaces = 0;
  486. avfc->surface_ids = NULL;
  487. }
  488. hwfc->internal->pool_internal =
  489. av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
  490. &vaapi_pool_alloc, NULL);
  491. if (!hwfc->internal->pool_internal) {
  492. av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
  493. err = AVERROR(ENOMEM);
  494. goto fail;
  495. }
  496. }
  497. // Allocate a single surface to test whether vaDeriveImage() is going
  498. // to work for the specific configuration.
  499. if (hwfc->pool) {
  500. test_surface = av_buffer_pool_get(hwfc->pool);
  501. if (!test_surface) {
  502. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  503. "user-configured buffer pool.\n");
  504. err = AVERROR(ENOMEM);
  505. goto fail;
  506. }
  507. } else {
  508. test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
  509. if (!test_surface) {
  510. av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
  511. "internal buffer pool.\n");
  512. err = AVERROR(ENOMEM);
  513. goto fail;
  514. }
  515. }
  516. test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
  517. ctx->derive_works = 0;
  518. err = vaapi_get_image_format(hwfc->device_ctx,
  519. hwfc->sw_format, &expected_format);
  520. if (err == 0) {
  521. vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
  522. if (vas == VA_STATUS_SUCCESS) {
  523. if (expected_format->fourcc == test_image.format.fourcc) {
  524. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
  525. ctx->derive_works = 1;
  526. } else {
  527. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  528. "derived image format %08x does not match "
  529. "expected format %08x.\n",
  530. expected_format->fourcc, test_image.format.fourcc);
  531. }
  532. vaDestroyImage(hwctx->display, test_image.image_id);
  533. } else {
  534. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  535. "deriving image does not work: "
  536. "%d (%s).\n", vas, vaErrorStr(vas));
  537. }
  538. } else {
  539. av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
  540. "image format is not supported.\n");
  541. }
  542. av_buffer_unref(&test_surface);
  543. return 0;
  544. fail:
  545. av_buffer_unref(&test_surface);
  546. av_freep(&avfc->surface_ids);
  547. av_freep(&ctx->attributes);
  548. return err;
  549. }
  550. static void vaapi_frames_uninit(AVHWFramesContext *hwfc)
  551. {
  552. AVVAAPIFramesContext *avfc = hwfc->hwctx;
  553. VAAPIFramesContext *ctx = hwfc->internal->priv;
  554. av_freep(&avfc->surface_ids);
  555. av_freep(&ctx->attributes);
  556. }
  557. static int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
  558. {
  559. frame->buf[0] = av_buffer_pool_get(hwfc->pool);
  560. if (!frame->buf[0])
  561. return AVERROR(ENOMEM);
  562. frame->data[3] = frame->buf[0]->data;
  563. frame->format = AV_PIX_FMT_VAAPI;
  564. frame->width = hwfc->width;
  565. frame->height = hwfc->height;
  566. return 0;
  567. }
  568. static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
  569. enum AVHWFrameTransferDirection dir,
  570. enum AVPixelFormat **formats)
  571. {
  572. VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
  573. enum AVPixelFormat *pix_fmts;
  574. int i, k, sw_format_available;
  575. sw_format_available = 0;
  576. for (i = 0; i < ctx->nb_formats; i++) {
  577. if (ctx->formats[i].pix_fmt == hwfc->sw_format)
  578. sw_format_available = 1;
  579. }
  580. pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
  581. if (!pix_fmts)
  582. return AVERROR(ENOMEM);
  583. if (sw_format_available) {
  584. pix_fmts[0] = hwfc->sw_format;
  585. k = 1;
  586. } else {
  587. k = 0;
  588. }
  589. for (i = 0; i < ctx->nb_formats; i++) {
  590. if (ctx->formats[i].pix_fmt == hwfc->sw_format)
  591. continue;
  592. av_assert0(k < ctx->nb_formats);
  593. pix_fmts[k++] = ctx->formats[i].pix_fmt;
  594. }
  595. pix_fmts[k] = AV_PIX_FMT_NONE;
  596. *formats = pix_fmts;
  597. return 0;
  598. }
  599. static void vaapi_unmap_frame(AVHWFramesContext *hwfc,
  600. HWMapDescriptor *hwmap)
  601. {
  602. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  603. VAAPIMapping *map = hwmap->priv;
  604. VASurfaceID surface_id;
  605. VAStatus vas;
  606. surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
  607. av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
  608. vas = vaUnmapBuffer(hwctx->display, map->image.buf);
  609. if (vas != VA_STATUS_SUCCESS) {
  610. av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
  611. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  612. }
  613. if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
  614. !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
  615. vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
  616. 0, 0, hwfc->width, hwfc->height,
  617. 0, 0, hwfc->width, hwfc->height);
  618. if (vas != VA_STATUS_SUCCESS) {
  619. av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
  620. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  621. }
  622. }
  623. vas = vaDestroyImage(hwctx->display, map->image.image_id);
  624. if (vas != VA_STATUS_SUCCESS) {
  625. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
  626. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  627. }
  628. av_free(map);
  629. }
  630. static int vaapi_map_frame(AVHWFramesContext *hwfc,
  631. AVFrame *dst, const AVFrame *src, int flags)
  632. {
  633. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  634. VAAPIFramesContext *ctx = hwfc->internal->priv;
  635. VASurfaceID surface_id;
  636. VAImageFormat *image_format;
  637. VAAPIMapping *map;
  638. VAStatus vas;
  639. void *address = NULL;
  640. int err, i;
  641. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  642. av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
  643. if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
  644. // Requested direct mapping but it is not possible.
  645. return AVERROR(EINVAL);
  646. }
  647. if (dst->format == AV_PIX_FMT_NONE)
  648. dst->format = hwfc->sw_format;
  649. if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
  650. // Requested direct mapping but the formats do not match.
  651. return AVERROR(EINVAL);
  652. }
  653. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
  654. if (err < 0) {
  655. // Requested format is not a valid output format.
  656. return AVERROR(EINVAL);
  657. }
  658. map = av_malloc(sizeof(*map));
  659. if (!map)
  660. return AVERROR(ENOMEM);
  661. map->flags = flags;
  662. map->image.image_id = VA_INVALID_ID;
  663. vas = vaSyncSurface(hwctx->display, surface_id);
  664. if (vas != VA_STATUS_SUCCESS) {
  665. av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
  666. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  667. err = AVERROR(EIO);
  668. goto fail;
  669. }
  670. // The memory which we map using derive need not be connected to the CPU
  671. // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
  672. // memory is mappable but not cached, so normal memcpy()-like access is
  673. // very slow to read it (but writing is ok). It is possible to read much
  674. // faster with a copy routine which is aware of the limitation, but we
  675. // assume for now that the user is not aware of that and would therefore
  676. // prefer not to be given direct-mapped memory if they request read access.
  677. if (ctx->derive_works && dst->format == hwfc->sw_format &&
  678. ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
  679. vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
  680. if (vas != VA_STATUS_SUCCESS) {
  681. av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
  682. "surface %#x: %d (%s).\n",
  683. surface_id, vas, vaErrorStr(vas));
  684. err = AVERROR(EIO);
  685. goto fail;
  686. }
  687. if (map->image.format.fourcc != image_format->fourcc) {
  688. av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
  689. "is in wrong format: expected %#08x, got %#08x.\n",
  690. surface_id, image_format->fourcc, map->image.format.fourcc);
  691. err = AVERROR(EIO);
  692. goto fail;
  693. }
  694. map->flags |= AV_HWFRAME_MAP_DIRECT;
  695. } else {
  696. vas = vaCreateImage(hwctx->display, image_format,
  697. hwfc->width, hwfc->height, &map->image);
  698. if (vas != VA_STATUS_SUCCESS) {
  699. av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
  700. "surface %#x: %d (%s).\n",
  701. surface_id, vas, vaErrorStr(vas));
  702. err = AVERROR(EIO);
  703. goto fail;
  704. }
  705. if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
  706. vas = vaGetImage(hwctx->display, surface_id, 0, 0,
  707. hwfc->width, hwfc->height, map->image.image_id);
  708. if (vas != VA_STATUS_SUCCESS) {
  709. av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
  710. "surface %#x: %d (%s).\n",
  711. surface_id, vas, vaErrorStr(vas));
  712. err = AVERROR(EIO);
  713. goto fail;
  714. }
  715. }
  716. }
  717. vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
  718. if (vas != VA_STATUS_SUCCESS) {
  719. av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
  720. "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
  721. err = AVERROR(EIO);
  722. goto fail;
  723. }
  724. err = ff_hwframe_map_create(src->hw_frames_ctx,
  725. dst, src, &vaapi_unmap_frame, map);
  726. if (err < 0)
  727. goto fail;
  728. dst->width = src->width;
  729. dst->height = src->height;
  730. for (i = 0; i < map->image.num_planes; i++) {
  731. dst->data[i] = (uint8_t*)address + map->image.offsets[i];
  732. dst->linesize[i] = map->image.pitches[i];
  733. }
  734. if (
  735. #ifdef VA_FOURCC_YV16
  736. map->image.format.fourcc == VA_FOURCC_YV16 ||
  737. #endif
  738. map->image.format.fourcc == VA_FOURCC_YV12) {
  739. // Chroma planes are YVU rather than YUV, so swap them.
  740. FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
  741. }
  742. return 0;
  743. fail:
  744. if (map) {
  745. if (address)
  746. vaUnmapBuffer(hwctx->display, map->image.buf);
  747. if (map->image.image_id != VA_INVALID_ID)
  748. vaDestroyImage(hwctx->display, map->image.image_id);
  749. av_free(map);
  750. }
  751. return err;
  752. }
  753. static int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
  754. AVFrame *dst, const AVFrame *src)
  755. {
  756. AVFrame *map;
  757. int err;
  758. if (dst->width > hwfc->width || dst->height > hwfc->height)
  759. return AVERROR(EINVAL);
  760. map = av_frame_alloc();
  761. if (!map)
  762. return AVERROR(ENOMEM);
  763. map->format = dst->format;
  764. err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
  765. if (err)
  766. goto fail;
  767. map->width = dst->width;
  768. map->height = dst->height;
  769. err = av_frame_copy(dst, map);
  770. if (err)
  771. goto fail;
  772. err = 0;
  773. fail:
  774. av_frame_free(&map);
  775. return err;
  776. }
  777. static int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
  778. AVFrame *dst, const AVFrame *src)
  779. {
  780. AVFrame *map;
  781. int err;
  782. if (src->width > hwfc->width || src->height > hwfc->height)
  783. return AVERROR(EINVAL);
  784. map = av_frame_alloc();
  785. if (!map)
  786. return AVERROR(ENOMEM);
  787. map->format = src->format;
  788. err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
  789. if (err)
  790. goto fail;
  791. map->width = src->width;
  792. map->height = src->height;
  793. err = av_frame_copy(map, src);
  794. if (err)
  795. goto fail;
  796. err = 0;
  797. fail:
  798. av_frame_free(&map);
  799. return err;
  800. }
  801. static int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
  802. const AVFrame *src, int flags)
  803. {
  804. int err;
  805. if (dst->format != AV_PIX_FMT_NONE) {
  806. err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
  807. if (err < 0)
  808. return AVERROR(ENOSYS);
  809. }
  810. err = vaapi_map_frame(hwfc, dst, src, flags);
  811. if (err)
  812. return err;
  813. err = av_frame_copy_props(dst, src);
  814. if (err)
  815. return err;
  816. return 0;
  817. }
  818. #if CONFIG_LIBDRM
  819. #define DRM_MAP(va, layers, ...) { \
  820. VA_FOURCC_ ## va, \
  821. layers, \
  822. { __VA_ARGS__ } \
  823. }
  824. static const struct {
  825. uint32_t va_fourcc;
  826. int nb_layer_formats;
  827. uint32_t layer_formats[AV_DRM_MAX_PLANES];
  828. } vaapi_drm_format_map[] = {
  829. #ifdef DRM_FORMAT_R8
  830. DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
  831. #endif
  832. DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
  833. #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
  834. DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
  835. #endif
  836. DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
  837. DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
  838. DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
  839. DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
  840. #ifdef VA_FOURCC_ABGR
  841. DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
  842. DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
  843. #endif
  844. DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
  845. DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
  846. };
  847. #undef DRM_MAP
  848. static void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
  849. HWMapDescriptor *hwmap)
  850. {
  851. AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  852. VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
  853. av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
  854. vaDestroySurfaces(dst_dev->display, &surface_id, 1);
  855. }
  856. static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
  857. const AVFrame *src, int flags)
  858. {
  859. AVHWFramesContext *dst_fc =
  860. (AVHWFramesContext*)dst->hw_frames_ctx->data;
  861. AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
  862. const AVDRMFrameDescriptor *desc;
  863. VASurfaceID surface_id;
  864. VAStatus vas;
  865. uint32_t va_fourcc, va_rt_format;
  866. int err, i, j, k;
  867. unsigned long buffer_handle;
  868. VASurfaceAttribExternalBuffers buffer_desc;
  869. VASurfaceAttrib attrs[2] = {
  870. {
  871. .type = VASurfaceAttribMemoryType,
  872. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  873. .value.type = VAGenericValueTypeInteger,
  874. .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
  875. },
  876. {
  877. .type = VASurfaceAttribExternalBufferDescriptor,
  878. .flags = VA_SURFACE_ATTRIB_SETTABLE,
  879. .value.type = VAGenericValueTypePointer,
  880. .value.value.p = &buffer_desc,
  881. }
  882. };
  883. desc = (AVDRMFrameDescriptor*)src->data[0];
  884. if (desc->nb_objects != 1) {
  885. av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
  886. "made from a single DRM object.\n");
  887. return AVERROR(EINVAL);
  888. }
  889. va_fourcc = 0;
  890. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
  891. if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
  892. continue;
  893. for (j = 0; j < desc->nb_layers; j++) {
  894. if (desc->layers[j].format !=
  895. vaapi_drm_format_map[i].layer_formats[j])
  896. break;
  897. }
  898. if (j != desc->nb_layers)
  899. continue;
  900. va_fourcc = vaapi_drm_format_map[i].va_fourcc;
  901. break;
  902. }
  903. if (!va_fourcc) {
  904. av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
  905. "by VAAPI.\n");
  906. return AVERROR(EINVAL);
  907. }
  908. av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
  909. "%08x.\n", desc->objects[0].fd, va_fourcc);
  910. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) {
  911. if (vaapi_format_map[i].fourcc == va_fourcc)
  912. va_rt_format = vaapi_format_map[i].rt_format;
  913. }
  914. buffer_handle = desc->objects[0].fd;
  915. buffer_desc.pixel_format = va_fourcc;
  916. buffer_desc.width = src_fc->width;
  917. buffer_desc.height = src_fc->height;
  918. buffer_desc.data_size = desc->objects[0].size;
  919. buffer_desc.buffers = &buffer_handle;
  920. buffer_desc.num_buffers = 1;
  921. buffer_desc.flags = 0;
  922. k = 0;
  923. for (i = 0; i < desc->nb_layers; i++) {
  924. for (j = 0; j < desc->layers[i].nb_planes; j++) {
  925. buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
  926. buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
  927. ++k;
  928. }
  929. }
  930. buffer_desc.num_planes = k;
  931. vas = vaCreateSurfaces(dst_dev->display, va_rt_format,
  932. src->width, src->height,
  933. &surface_id, 1,
  934. attrs, FF_ARRAY_ELEMS(attrs));
  935. if (vas != VA_STATUS_SUCCESS) {
  936. av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
  937. "object: %d (%s).\n", vas, vaErrorStr(vas));
  938. return AVERROR(EIO);
  939. }
  940. av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
  941. err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
  942. &vaapi_unmap_from_drm,
  943. (void*)(uintptr_t)surface_id);
  944. if (err < 0)
  945. return err;
  946. dst->width = src->width;
  947. dst->height = src->height;
  948. dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
  949. av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
  950. "surface %#x.\n", desc->objects[0].fd, surface_id);
  951. return 0;
  952. }
  953. #if VA_CHECK_VERSION(1, 1, 0)
  954. static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
  955. HWMapDescriptor *hwmap)
  956. {
  957. AVDRMFrameDescriptor *drm_desc = hwmap->priv;
  958. int i;
  959. for (i = 0; i < drm_desc->nb_objects; i++)
  960. close(drm_desc->objects[i].fd);
  961. av_freep(&drm_desc);
  962. }
  963. static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
  964. const AVFrame *src, int flags)
  965. {
  966. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  967. VASurfaceID surface_id;
  968. VAStatus vas;
  969. VADRMPRIMESurfaceDescriptor va_desc;
  970. AVDRMFrameDescriptor *drm_desc = NULL;
  971. uint32_t export_flags;
  972. int err, i, j;
  973. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  974. export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
  975. if (flags & AV_HWFRAME_MAP_READ)
  976. export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
  977. if (flags & AV_HWFRAME_MAP_WRITE)
  978. export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
  979. vas = vaExportSurfaceHandle(hwctx->display, surface_id,
  980. VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
  981. export_flags, &va_desc);
  982. if (vas != VA_STATUS_SUCCESS) {
  983. if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
  984. return AVERROR(ENOSYS);
  985. av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
  986. "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
  987. return AVERROR(EIO);
  988. }
  989. drm_desc = av_mallocz(sizeof(*drm_desc));
  990. if (!drm_desc) {
  991. err = AVERROR(ENOMEM);
  992. goto fail;
  993. }
  994. // By some bizarre coincidence, these structures are very similar...
  995. drm_desc->nb_objects = va_desc.num_objects;
  996. for (i = 0; i < va_desc.num_objects; i++) {
  997. drm_desc->objects[i].fd = va_desc.objects[i].fd;
  998. drm_desc->objects[i].size = va_desc.objects[i].size;
  999. drm_desc->objects[i].format_modifier =
  1000. va_desc.objects[i].drm_format_modifier;
  1001. }
  1002. drm_desc->nb_layers = va_desc.num_layers;
  1003. for (i = 0; i < va_desc.num_layers; i++) {
  1004. drm_desc->layers[i].format = va_desc.layers[i].drm_format;
  1005. drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
  1006. for (j = 0; j < va_desc.layers[i].num_planes; j++) {
  1007. drm_desc->layers[i].planes[j].object_index =
  1008. va_desc.layers[i].object_index[j];
  1009. drm_desc->layers[i].planes[j].offset =
  1010. va_desc.layers[i].offset[j];
  1011. drm_desc->layers[i].planes[j].pitch =
  1012. va_desc.layers[i].pitch[j];
  1013. }
  1014. }
  1015. err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
  1016. &vaapi_unmap_to_drm_esh, drm_desc);
  1017. if (err < 0)
  1018. goto fail;
  1019. dst->width = src->width;
  1020. dst->height = src->height;
  1021. dst->data[0] = (uint8_t*)drm_desc;
  1022. return 0;
  1023. fail:
  1024. for (i = 0; i < va_desc.num_objects; i++)
  1025. close(va_desc.objects[i].fd);
  1026. av_freep(&drm_desc);
  1027. return err;
  1028. }
  1029. #endif
  1030. #if VA_CHECK_VERSION(0, 36, 0)
  1031. typedef struct VAAPIDRMImageBufferMapping {
  1032. VAImage image;
  1033. VABufferInfo buffer_info;
  1034. AVDRMFrameDescriptor drm_desc;
  1035. } VAAPIDRMImageBufferMapping;
  1036. static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
  1037. HWMapDescriptor *hwmap)
  1038. {
  1039. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  1040. VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
  1041. VASurfaceID surface_id;
  1042. VAStatus vas;
  1043. surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
  1044. av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
  1045. surface_id);
  1046. // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
  1047. // so we shouldn't close them separately.
  1048. vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
  1049. if (vas != VA_STATUS_SUCCESS) {
  1050. av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
  1051. "handle of image %#x (derived from surface %#x): "
  1052. "%d (%s).\n", mapping->image.buf, surface_id,
  1053. vas, vaErrorStr(vas));
  1054. }
  1055. vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
  1056. if (vas != VA_STATUS_SUCCESS) {
  1057. av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
  1058. "derived from surface %#x: %d (%s).\n",
  1059. surface_id, vas, vaErrorStr(vas));
  1060. }
  1061. av_free(mapping);
  1062. }
  1063. static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
  1064. const AVFrame *src, int flags)
  1065. {
  1066. AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
  1067. VAAPIDRMImageBufferMapping *mapping = NULL;
  1068. VASurfaceID surface_id;
  1069. VAStatus vas;
  1070. int err, i, p;
  1071. surface_id = (VASurfaceID)(uintptr_t)src->data[3];
  1072. av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
  1073. surface_id);
  1074. mapping = av_mallocz(sizeof(*mapping));
  1075. if (!mapping)
  1076. return AVERROR(ENOMEM);
  1077. vas = vaDeriveImage(hwctx->display, surface_id,
  1078. &mapping->image);
  1079. if (vas != VA_STATUS_SUCCESS) {
  1080. av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
  1081. "surface %#x: %d (%s).\n",
  1082. surface_id, vas, vaErrorStr(vas));
  1083. err = AVERROR(EIO);
  1084. goto fail;
  1085. }
  1086. for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
  1087. if (vaapi_drm_format_map[i].va_fourcc ==
  1088. mapping->image.format.fourcc)
  1089. break;
  1090. }
  1091. if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
  1092. av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
  1093. "VAAPI format %#x.\n", mapping->image.format.fourcc);
  1094. err = AVERROR(EINVAL);
  1095. goto fail_derived;
  1096. }
  1097. mapping->buffer_info.mem_type =
  1098. VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
  1099. mapping->drm_desc.nb_layers =
  1100. vaapi_drm_format_map[i].nb_layer_formats;
  1101. if (mapping->drm_desc.nb_layers > 1) {
  1102. if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
  1103. av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
  1104. "expected format: got %d planes, but expected %d.\n",
  1105. mapping->image.num_planes, mapping->drm_desc.nb_layers);
  1106. err = AVERROR(EINVAL);
  1107. goto fail_derived;
  1108. }
  1109. for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
  1110. mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
  1111. .format = vaapi_drm_format_map[i].layer_formats[p],
  1112. .nb_planes = 1,
  1113. .planes[0] = {
  1114. .object_index = 0,
  1115. .offset = mapping->image.offsets[p],
  1116. .pitch = mapping->image.pitches[p],
  1117. },
  1118. };
  1119. }
  1120. } else {
  1121. mapping->drm_desc.layers[0].format =
  1122. vaapi_drm_format_map[i].layer_formats[0];
  1123. mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
  1124. for (p = 0; p < mapping->image.num_planes; p++) {
  1125. mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
  1126. .object_index = 0,
  1127. .offset = mapping->image.offsets[p],
  1128. .pitch = mapping->image.pitches[p],
  1129. };
  1130. }
  1131. }
  1132. vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
  1133. &mapping->buffer_info);
  1134. if (vas != VA_STATUS_SUCCESS) {
  1135. av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
  1136. "handle from image %#x (derived from surface %#x): "
  1137. "%d (%s).\n", mapping->image.buf, surface_id,
  1138. vas, vaErrorStr(vas));
  1139. err = AVERROR(EIO);
  1140. goto fail_derived;
  1141. }
  1142. av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
  1143. mapping->buffer_info.handle);
  1144. mapping->drm_desc.nb_objects = 1;
  1145. mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
  1146. .fd = mapping->buffer_info.handle,
  1147. .size = mapping->image.data_size,
  1148. // There is no way to get the format modifier with this API.
  1149. .format_modifier = DRM_FORMAT_MOD_INVALID,
  1150. };
  1151. err = ff_hwframe_map_create(src->hw_frames_ctx,
  1152. dst, src, &vaapi_unmap_to_drm_abh,
  1153. mapping);
  1154. if (err < 0)
  1155. goto fail_mapped;
  1156. dst->data[0] = (uint8_t*)&mapping->drm_desc;
  1157. dst->width = src->width;
  1158. dst->height = src->height;
  1159. return 0;
  1160. fail_mapped:
  1161. vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
  1162. fail_derived:
  1163. vaDestroyImage(hwctx->display, mapping->image.image_id);
  1164. fail:
  1165. av_freep(&mapping);
  1166. return err;
  1167. }
  1168. #endif
  1169. static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
  1170. const AVFrame *src, int flags)
  1171. {
  1172. #if VA_CHECK_VERSION(1, 1, 0)
  1173. int err;
  1174. err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
  1175. if (err != AVERROR(ENOSYS))
  1176. return err;
  1177. #endif
  1178. #if VA_CHECK_VERSION(0, 36, 0)
  1179. return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
  1180. #endif
  1181. return AVERROR(ENOSYS);
  1182. }
  1183. #endif /* CONFIG_LIBDRM */
  1184. static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
  1185. const AVFrame *src, int flags)
  1186. {
  1187. switch (src->format) {
  1188. #if CONFIG_LIBDRM
  1189. case AV_PIX_FMT_DRM_PRIME:
  1190. return vaapi_map_from_drm(hwfc, dst, src, flags);
  1191. #endif
  1192. default:
  1193. return AVERROR(ENOSYS);
  1194. }
  1195. }
  1196. static int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
  1197. const AVFrame *src, int flags)
  1198. {
  1199. switch (dst->format) {
  1200. #if CONFIG_LIBDRM
  1201. case AV_PIX_FMT_DRM_PRIME:
  1202. return vaapi_map_to_drm(hwfc, dst, src, flags);
  1203. #endif
  1204. default:
  1205. return vaapi_map_to_memory(hwfc, dst, src, flags);
  1206. }
  1207. }
  1208. static void vaapi_device_free(AVHWDeviceContext *ctx)
  1209. {
  1210. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  1211. VAAPIDevicePriv *priv = ctx->user_opaque;
  1212. if (hwctx->display)
  1213. vaTerminate(hwctx->display);
  1214. #if HAVE_VAAPI_X11
  1215. if (priv->x11_display)
  1216. XCloseDisplay(priv->x11_display);
  1217. #endif
  1218. if (priv->drm_fd >= 0)
  1219. close(priv->drm_fd);
  1220. av_freep(&priv);
  1221. }
  1222. #if CONFIG_VAAPI_1
  1223. static void vaapi_device_log_error(void *context, const char *message)
  1224. {
  1225. AVHWDeviceContext *ctx = context;
  1226. av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
  1227. }
  1228. static void vaapi_device_log_info(void *context, const char *message)
  1229. {
  1230. AVHWDeviceContext *ctx = context;
  1231. av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
  1232. }
  1233. #endif
  1234. static int vaapi_device_connect(AVHWDeviceContext *ctx,
  1235. VADisplay display)
  1236. {
  1237. AVVAAPIDeviceContext *hwctx = ctx->hwctx;
  1238. int major, minor;
  1239. VAStatus vas;
  1240. #if CONFIG_VAAPI_1
  1241. vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
  1242. vaSetInfoCallback (display, &vaapi_device_log_info, ctx);
  1243. #endif
  1244. hwctx->display = display;
  1245. vas = vaInitialize(display, &major, &minor);
  1246. if (vas != VA_STATUS_SUCCESS) {
  1247. av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
  1248. "connection: %d (%s).\n", vas, vaErrorStr(vas));
  1249. return AVERROR(EIO);
  1250. }
  1251. av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
  1252. "version %d.%d\n", major, minor);
  1253. return 0;
  1254. }
  1255. static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
  1256. AVDictionary *opts, int flags)
  1257. {
  1258. VAAPIDevicePriv *priv;
  1259. VADisplay display = NULL;
  1260. priv = av_mallocz(sizeof(*priv));
  1261. if (!priv)
  1262. return AVERROR(ENOMEM);
  1263. priv->drm_fd = -1;
  1264. ctx->user_opaque = priv;
  1265. ctx->free = vaapi_device_free;
  1266. #if HAVE_VAAPI_X11
  1267. if (!display && !(device && device[0] == '/')) {
  1268. // Try to open the device as an X11 display.
  1269. priv->x11_display = XOpenDisplay(device);
  1270. if (!priv->x11_display) {
  1271. av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
  1272. "%s.\n", XDisplayName(device));
  1273. } else {
  1274. display = vaGetDisplay(priv->x11_display);
  1275. if (!display) {
  1276. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  1277. "from X11 display %s.\n", XDisplayName(device));
  1278. return AVERROR_UNKNOWN;
  1279. }
  1280. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  1281. "X11 display %s.\n", XDisplayName(device));
  1282. }
  1283. }
  1284. #endif
  1285. #if HAVE_VAAPI_DRM
  1286. if (!display) {
  1287. // Try to open the device as a DRM path.
  1288. // Default to using the first render node if the user did not
  1289. // supply a path.
  1290. const char *path = device ? device : "/dev/dri/renderD128";
  1291. priv->drm_fd = open(path, O_RDWR);
  1292. if (priv->drm_fd < 0) {
  1293. av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n",
  1294. path);
  1295. } else {
  1296. display = vaGetDisplayDRM(priv->drm_fd);
  1297. if (!display) {
  1298. av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
  1299. "from DRM device %s.\n", path);
  1300. return AVERROR_UNKNOWN;
  1301. }
  1302. av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
  1303. "DRM device %s.\n", path);
  1304. }
  1305. }
  1306. #endif
  1307. if (!display) {
  1308. av_log(ctx, AV_LOG_ERROR, "No VA display found for "
  1309. "device: %s.\n", device ? device : "");
  1310. return AVERROR(EINVAL);
  1311. }
  1312. return vaapi_device_connect(ctx, display);
  1313. }
  1314. static int vaapi_device_derive(AVHWDeviceContext *ctx,
  1315. AVHWDeviceContext *src_ctx, int flags)
  1316. {
  1317. #if HAVE_VAAPI_DRM
  1318. if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
  1319. AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
  1320. VADisplay *display;
  1321. VAAPIDevicePriv *priv;
  1322. if (src_hwctx->fd < 0) {
  1323. av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
  1324. "device to derive a VA display from.\n");
  1325. return AVERROR(EINVAL);
  1326. }
  1327. priv = av_mallocz(sizeof(*priv));
  1328. if (!priv)
  1329. return AVERROR(ENOMEM);
  1330. // Inherits the fd from the source context, which will close it.
  1331. priv->drm_fd = -1;
  1332. ctx->user_opaque = priv;
  1333. ctx->free = &vaapi_device_free;
  1334. display = vaGetDisplayDRM(src_hwctx->fd);
  1335. if (!display) {
  1336. av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
  1337. "DRM device.\n");
  1338. return AVERROR(EIO);
  1339. }
  1340. return vaapi_device_connect(ctx, display);
  1341. }
  1342. #endif
  1343. return AVERROR(ENOSYS);
  1344. }
  1345. const HWContextType ff_hwcontext_type_vaapi = {
  1346. .type = AV_HWDEVICE_TYPE_VAAPI,
  1347. .name = "VAAPI",
  1348. .device_hwctx_size = sizeof(AVVAAPIDeviceContext),
  1349. .device_priv_size = sizeof(VAAPIDeviceContext),
  1350. .device_hwconfig_size = sizeof(AVVAAPIHWConfig),
  1351. .frames_hwctx_size = sizeof(AVVAAPIFramesContext),
  1352. .frames_priv_size = sizeof(VAAPIFramesContext),
  1353. .device_create = &vaapi_device_create,
  1354. .device_derive = &vaapi_device_derive,
  1355. .device_init = &vaapi_device_init,
  1356. .device_uninit = &vaapi_device_uninit,
  1357. .frames_get_constraints = &vaapi_frames_get_constraints,
  1358. .frames_init = &vaapi_frames_init,
  1359. .frames_uninit = &vaapi_frames_uninit,
  1360. .frames_get_buffer = &vaapi_get_buffer,
  1361. .transfer_get_formats = &vaapi_transfer_get_formats,
  1362. .transfer_data_to = &vaapi_transfer_data_to,
  1363. .transfer_data_from = &vaapi_transfer_data_from,
  1364. .map_to = &vaapi_map_to,
  1365. .map_from = &vaapi_map_from,
  1366. .pix_fmts = (const enum AVPixelFormat[]) {
  1367. AV_PIX_FMT_VAAPI,
  1368. AV_PIX_FMT_NONE
  1369. },
  1370. };