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
19 #include "config.h"
20
21 #if HAVE_VAAPI_WIN32
22 # include <windows.h>
23 #define COBJMACROS
24 # include <initguid.h>
25 # include <dxgi1_2.h>
27 # include <va/va_win32.h>
29 #endif
30 #if HAVE_VAAPI_X11
31 # include <va/va_x11.h>
32 #endif
33 #if HAVE_VAAPI_DRM
34 # include <va/va_drm.h>
35 #endif
36
37 #if CONFIG_LIBDRM
38 # include <va/va_drmcommon.h>
39 # include <xf86drm.h>
40 # include <drm_fourcc.h>
41 # ifndef DRM_FORMAT_MOD_INVALID
42 # define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
43 # endif
44 #endif
45
46 #include <fcntl.h>
47 #if HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif
50
51
62
63
65 #if HAVE_VAAPI_X11
66 Display *x11_display;
67 #endif
68
71
77
79 /**
80 * The public AVVAAPIDeviceContext. See hwcontext_vaapi.h for it.
81 */
83
84 // Surface formats which can be used with this device.
88
90 /**
91 * The public AVVAAPIFramesContext. See hwcontext_vaapi.h for it.
92 */
94
95 // Surface attributes set at create time.
98 // RT format of the underlying surface (Intel driver ignores this anyway).
100 // Whether vaDeriveImage works.
102 // Caches whether VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 is unsupported for
103 // surface imports.
106
108 // Handle to the derived or copied image which is mapped.
110 // The mapping flags actually used.
113
119 } VAAPIFormatDescriptor;
120
121 #define MAP(va, rt, av, swap_uv) { \
122 VA_FOURCC_ ## va, \
123 VA_RT_FORMAT_ ## rt, \
124 AV_PIX_FMT_ ## av, \
125 swap_uv, \
126 }
127 // The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
128 // plane swap cases. The frame handling below tries to hide these.
130 MAP(NV12, YUV420, NV12, 0),
131 #ifdef VA_FOURCC_I420
132 MAP(I420, YUV420, YUV420P, 0),
133 #endif
134 MAP(YV12, YUV420, YUV420P, 1),
135 MAP(IYUV, YUV420, YUV420P, 0),
136 MAP(422
H, YUV422, YUV422P, 0),
137 #ifdef VA_FOURCC_YV16
138 MAP(YV16, YUV422, YUV422P, 1),
139 #endif
140 MAP(UYVY, YUV422, UYVY422, 0),
141 MAP(YUY2, YUV422, YUYV422, 0),
142 #ifdef VA_FOURCC_Y210
143 MAP(Y210, YUV422_10, Y210, 0),
144 #endif
145 #ifdef VA_FOURCC_Y212
146 MAP(Y212, YUV422_12, Y212, 0),
147 #endif
148 MAP(411
P, YUV411, YUV411P, 0),
149 MAP(422
V, YUV422, YUV440P, 0),
150 MAP(444
P, YUV444, YUV444P, 0),
151 #ifdef VA_FOURCC_XYUV
152 MAP(XYUV, YUV444, VUYX, 0),
153 #endif
154 MAP(Y800, YUV400, GRAY8, 0),
155 #ifdef VA_FOURCC_P010
156 MAP(P010, YUV420_10BPP, P010, 0),
157 #endif
158 #ifdef VA_FOURCC_P012
159 MAP(P012, YUV420_12, P012, 0),
160 #endif
161 MAP(BGRA, RGB32, BGRA, 0),
162 MAP(BGRX, RGB32, BGR0, 0),
164 MAP(RGBX, RGB32, RGB0, 0),
165 #ifdef VA_FOURCC_ABGR
166 MAP(ABGR, RGB32, ABGR, 0),
167 MAP(XBGR, RGB32, 0BGR, 0),
168 #endif
169 MAP(ARGB, RGB32, ARGB, 0),
170 MAP(XRGB, RGB32, 0
RGB, 0),
171 #ifdef VA_FOURCC_X2R10G10B10
172 MAP(X2R10G10B10, RGB32_10, X2RGB10, 0),
173 #endif
174 #ifdef VA_FOURCC_Y410
175 // libva doesn't include a fourcc for XV30 and the driver only declares
176 // support for Y410, so we must fudge the mapping here.
177 MAP(Y410, YUV444_10, XV30, 0),
178 #endif
179 #ifdef VA_FOURCC_Y412
180 // libva doesn't include a fourcc for XV36 and the driver only declares
181 // support for Y412, so we must fudge the mapping here.
182 MAP(Y412, YUV444_12, XV36, 0),
183 #endif
184 };
185 #undef MAP
186
187 static const VAAPIFormatDescriptor *
189 {
195 }
196
197 static const VAAPIFormatDescriptor *
199 {
205 }
206
208 {
209 const VAAPIFormatDescriptor *
desc;
212 return desc->pix_fmt;
213 else
215 }
216
219 VAImageFormat **image_format)
220 {
222 const VAAPIFormatDescriptor *
desc;
224
226 if (!
desc || !image_format)
228
229 for (
i = 0;
i <
ctx->nb_formats;
i++) {
230 if (
ctx->formats[
i].fourcc ==
desc->fourcc) {
231 *image_format = &
ctx->formats[
i].image_format;
232 return 0;
233 }
234 }
235
238 }
239
241 const void *hwconfig,
243 {
247 VASurfaceAttrib *attr_list =
NULL;
248 VAStatus vas;
251 int err,
i, j, attr_count, pix_fmt_count;
252
255 attr_count = 0;
256 vas = vaQuerySurfaceAttributes(hwctx->
display,
config->config_id,
257 0, &attr_count);
258 if (vas != VA_STATUS_SUCCESS) {
260 "%d (%s).\n", vas, vaErrorStr(vas));
263 }
264
265 attr_list =
av_malloc(attr_count *
sizeof(*attr_list));
266 if (!attr_list) {
269 }
270
271 vas = vaQuerySurfaceAttributes(hwctx->
display,
config->config_id,
272 attr_list, &attr_count);
273 if (vas != VA_STATUS_SUCCESS) {
275 "%d (%s).\n", vas, vaErrorStr(vas));
278 }
279
280 pix_fmt_count = 0;
281 for (
i = 0;
i < attr_count;
i++) {
282 switch (attr_list[
i].
type) {
283 case VASurfaceAttribPixelFormat:
284 fourcc = attr_list[
i].value.value.i;
287 ++pix_fmt_count;
288 } else {
289 // Something unsupported - ignore.
290 }
291 break;
292 case VASurfaceAttribMinWidth:
293 constraints->
min_width = attr_list[
i].value.value.i;
294 break;
295 case VASurfaceAttribMinHeight:
296 constraints->
min_height = attr_list[
i].value.value.i;
297 break;
298 case VASurfaceAttribMaxWidth:
299 constraints->
max_width = attr_list[
i].value.value.i;
300 break;
301 case VASurfaceAttribMaxHeight:
302 constraints->
max_height = attr_list[
i].value.value.i;
303 break;
304 }
305 }
306 if (pix_fmt_count == 0) {
307 // Nothing usable found. Presumably there exists something which
308 // works, so leave the set null to indicate unknown.
310 } else {
316 }
317
318 for (
i = j = 0;
i < attr_count;
i++) {
319 int k;
320
321 if (attr_list[
i].
type != VASurfaceAttribPixelFormat)
322 continue;
323 fourcc = attr_list[
i].value.value.i;
325
327 continue;
328
329 for (k = 0; k < j; k++) {
331 break;
332 }
333
334 if (k == j)
336 }
338 }
339 } else {
340 // No configuration supplied.
341 // Return the full set of image formats known by the implementation.
347 }
348 for (
i = j = 0;
i <
ctx->nb_formats;
i++) {
349 int k;
350
351 for (k = 0; k < j; k++) {
353 break;
354 }
355
356 if (k == j)
358 }
359
361 }
362
367 }
370
371 err = 0;
374 return err;
375 }
376
377 static const struct {
382 #if !VA_CHECK_VERSION(1, 0, 0)
383 // The i965 driver did not conform before version 2.0.
384 {
385 "Intel i965 (Quick Sync)",
386 "i965",
388 },
389 #endif
390 {
391 "Intel iHD",
392 "ubit",
394 },
395 {
396 "VDPAU wrapper",
397 "Splitted-Desktop Systems VDPAU backend for VA-API",
399 },
400 };
401
403 {
406 VAImageFormat *image_list =
NULL;
407 VAStatus vas;
408 const char *vendor_string;
409 int err,
i, image_count;
412
413 image_count = vaMaxNumImageFormats(hwctx->
display);
414 if (image_count <= 0) {
417 }
418 image_list =
av_malloc(image_count *
sizeof(*image_list));
419 if (!image_list) {
422 }
423 vas = vaQueryImageFormats(hwctx->
display, image_list, &image_count);
424 if (vas != VA_STATUS_SUCCESS) {
427 }
428
433 }
435 for (
i = 0;
i < image_count;
i++) {
441 } else {
446 ctx->formats[
ctx->nb_formats].image_format = image_list[
i];
448 }
449 }
450
451 vendor_string = vaQueryVendorString(hwctx->
display);
452 if (vendor_string)
454
458 } else {
459 // Detect the driver in use and set quirk flags if necessary.
461 if (vendor_string) {
463 if (strstr(vendor_string,
466 "as known nonstandard driver \"%s\", setting "
467 "quirks (%#x).\n",
472 break;
473 }
474 }
477 "nonstandard list, using standard behaviour.\n");
478 }
479 } else {
481 "assuming standard behaviour.\n");
482 }
483 }
484
486 return 0;
490 return err;
491 }
492
494 {
496
498 }
499
501 {
504 VASurfaceID surface_id;
505 VAStatus vas;
506
507 surface_id = (VASurfaceID)(uintptr_t)
data;
508
509 vas = vaDestroySurfaces(hwctx->
display, &surface_id, 1);
510 if (vas != VA_STATUS_SUCCESS) {
512 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
513 }
514 }
515
517 {
522 VASurfaceID surface_id;
523 VAStatus vas;
525
529
530 vas = vaCreateSurfaces(hwctx->
display,
ctx->rt_format,
532 &surface_id, 1,
533 ctx->attributes,
ctx->nb_attributes);
534 if (vas != VA_STATUS_SUCCESS) {
536 "%d (%s).\n", vas, vaErrorStr(vas));
538 }
540
545 vaDestroySurfaces(hwctx->
display, &surface_id, 1);
547 }
548
550 // This is a fixed-size pool, so we must still be in the initial
551 // allocation sequence.
555 }
556
558 }
559
561 {
565 const VAAPIFormatDescriptor *
desc;
566 VAImageFormat *expected_format;
568 VASurfaceID test_surface_id;
569 VAImage test_image;
570 VAStatus vas;
572
578 }
579
583 int need_pixel_format = 1;
585 if (avfc->
attributes[
i].type == VASurfaceAttribMemoryType)
586 need_memory_type = 0;
587 if (avfc->
attributes[
i].type == VASurfaceAttribPixelFormat)
588 need_pixel_format = 0;
589 }
592
594 sizeof(*
ctx->attributes));
595 if (!
ctx->attributes) {
598 }
599
602 if (need_memory_type) {
603 ctx->attributes[
i++] = (VASurfaceAttrib) {
604 .type = VASurfaceAttribMemoryType,
605 .
flags = VA_SURFACE_ATTRIB_SETTABLE,
606 .value.type = VAGenericValueTypeInteger,
607 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
608 };
609 }
610 if (need_pixel_format) {
611 ctx->attributes[
i++] = (VASurfaceAttrib) {
612 .type = VASurfaceAttribPixelFormat,
613 .
flags = VA_SURFACE_ATTRIB_SETTABLE,
614 .value.type = VAGenericValueTypeInteger,
615 .value.value.i =
desc->fourcc,
616 };
617 }
619 } else {
621 ctx->nb_attributes = 0;
622 }
623
624 ctx->rt_format =
desc->rt_format;
625
627 // This pool will be usable as a render target, so we need to store
628 // all of the surface IDs somewhere that vaCreateContext() calls
629 // will be able to access them.
636 }
637 } else {
638 // This pool allows dynamic sizing, and will not be usable as a
639 // render target.
642 }
643
651 }
652 }
653
654 // Allocate a single surface to test whether vaDeriveImage() is going
655 // to work for the specific configuration.
658 if (!test_surface) {
660 "user-configured buffer pool.\n");
663 }
664 } else {
666 if (!test_surface) {
668 "internal buffer pool.\n");
671 }
672 }
673 test_surface_id = (VASurfaceID)(uintptr_t)test_surface->
data;
674
675 ctx->derive_works = 0;
676
679 if (err == 0) {
680 vas = vaDeriveImage(hwctx->
display, test_surface_id, &test_image);
681 if (vas == VA_STATUS_SUCCESS) {
682 if (expected_format->fourcc == test_image.format.fourcc) {
684 ctx->derive_works = 1;
685 } else {
687 "derived image format %08x does not match "
688 "expected format %08x.\n",
689 expected_format->fourcc, test_image.format.fourcc);
690 }
691 vaDestroyImage(hwctx->
display, test_image.image_id);
692 } else {
694 "deriving image does not work: "
695 "%d (%s).\n", vas, vaErrorStr(vas));
696 }
697 } else {
699 "image format is not supported.\n");
700 }
701
703 return 0;
704
709 return err;
710 }
711
713 {
716
719 }
720
722 {
726
731
732 return 0;
733 }
734
738 {
741 int i, k, sw_format_available;
742
743 sw_format_available = 0;
744 for (
i = 0;
i <
ctx->nb_formats;
i++) {
746 sw_format_available = 1;
747 }
748
752
753 if (sw_format_available) {
755 k = 1;
756 } else {
757 k = 0;
758 }
759 for (
i = 0;
i <
ctx->nb_formats;
i++) {
761 continue;
764 }
766
768 return 0;
769 }
770
773 {
776 VASurfaceID surface_id;
777 VAStatus vas;
778
779 surface_id = (VASurfaceID)(uintptr_t)hwmap->
source->
data[3];
781
782 vas = vaUnmapBuffer(hwctx->
display,
map->image.buf);
783 if (vas != VA_STATUS_SUCCESS) {
785 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
786 }
787
790 vas = vaPutImage(hwctx->
display, surface_id,
map->image.image_id,
793 if (vas != VA_STATUS_SUCCESS) {
795 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
796 }
797 }
798
799 vas = vaDestroyImage(hwctx->
display,
map->image.image_id);
800 if (vas != VA_STATUS_SUCCESS) {
802 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
803 }
804
806 }
807
810 {
813 VASurfaceID surface_id;
814 const VAAPIFormatDescriptor *
desc;
815 VAImageFormat *image_format;
817 VAStatus vas;
818 void *address =
NULL;
820 #if VA_CHECK_VERSION(1, 21, 0)
821 uint32_t vaflags = 0;
822 #endif
823
824 surface_id = (VASurfaceID)(uintptr_t)
src->data[3];
826
828 // Requested direct mapping but it is not possible.
830 }
834 // Requested direct mapping but the formats do not match.
836 }
837
839 if (err < 0) {
840 // Requested format is not a valid output format.
841 return err;
842 }
843
848 map->image.image_id = VA_INVALID_ID;
849
850 vas = vaSyncSurface(hwctx->
display, surface_id);
851 if (vas != VA_STATUS_SUCCESS) {
853 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
856 }
857
858 // The memory which we map using derive need not be connected to the CPU
859 // in a way conducive to fast access. On Gen7-Gen9 Intel graphics, the
860 // memory is mappable but not cached, so normal memcpy()-like access is
861 // very slow to read it (but writing is ok). It is possible to read much
862 // faster with a copy routine which is aware of the limitation, but we
863 // assume for now that the user is not aware of that and would therefore
864 // prefer not to be given direct-mapped memory if they request read access.
867 vas = vaDeriveImage(hwctx->
display, surface_id, &
map->image);
868 if (vas != VA_STATUS_SUCCESS) {
870 "surface %#x: %d (%s).\n",
871 surface_id, vas, vaErrorStr(vas));
874 }
875 if (
map->image.format.fourcc != image_format->fourcc) {
877 "is in wrong format: expected %#08x, got %#08x.\n",
878 surface_id, image_format->fourcc,
map->image.format.fourcc);
881 }
883 } else {
884 vas = vaCreateImage(hwctx->
display, image_format,
886 if (vas != VA_STATUS_SUCCESS) {
888 "surface %#x: %d (%s).\n",
889 surface_id, vas, vaErrorStr(vas));
892 }
894 vas = vaGetImage(hwctx->
display, surface_id, 0, 0,
896 if (vas != VA_STATUS_SUCCESS) {
898 "surface %#x: %d (%s).\n",
899 surface_id, vas, vaErrorStr(vas));
902 }
903 }
904 }
905
906 #if VA_CHECK_VERSION(1, 21, 0)
908 vaflags |= VA_MAPBUFFER_FLAG_READ;
910 vaflags |= VA_MAPBUFFER_FLAG_WRITE;
911 // On drivers not implementing vaMapBuffer2 libva calls vaMapBuffer instead.
912 vas = vaMapBuffer2(hwctx->
display,
map->image.buf, &address, vaflags);
913 #else
914 vas = vaMapBuffer(hwctx->
display,
map->image.buf, &address);
915 #endif
916 if (vas != VA_STATUS_SUCCESS) {
918 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
921 }
922
925 if (err < 0)
927
929 dst->height =
src->height;
930
931 for (
i = 0;
i <
map->image.num_planes;
i++) {
932 dst->data[
i] = (uint8_t*)address +
map->image.offsets[
i];
933 dst->linesize[
i] =
map->image.pitches[
i];
934 }
935
937 if (
desc &&
desc->chroma_planes_swapped) {
938 // Chroma planes are YVU rather than YUV, so swap them.
940 }
941
942 return 0;
943
946 if (address)
947 vaUnmapBuffer(hwctx->
display,
map->image.buf);
948 if (
map->image.image_id != VA_INVALID_ID)
949 vaDestroyImage(hwctx->
display,
map->image.image_id);
951 }
952 return err;
953 }
954
957 {
959 int err;
960
963
967 map->format =
dst->format;
968
970 if (err)
972
974 map->height =
dst->height;
975
977 if (err)
979
980 err = 0;
983 return err;
984 }
985
988 {
990 int err;
991
994
998 map->format =
src->format;
999
1001 if (err)
1003
1005 map->height =
src->height;
1006
1008 if (err)
1010
1011 err = 0;
1014 return err;
1015 }
1016
1019 {
1020 int err;
1021
1023 if (err)
1024 return err;
1025
1027 if (err)
1028 return err;
1029
1030 return 0;
1031 }
1032
1033 #if CONFIG_LIBDRM
1034
1035 #define DRM_MAP(va, layers, ...) { \
1036 VA_FOURCC_ ## va, \
1037 layers, \
1038 { __VA_ARGS__ } \
1039 }
1040 static const struct {
1041 uint32_t va_fourcc;
1042 int nb_layer_formats;
1044 } vaapi_drm_format_map[] = {
1045 #ifdef DRM_FORMAT_R8
1046 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_RG88),
1047 DRM_MAP(NV12, 2, DRM_FORMAT_R8, DRM_FORMAT_GR88),
1048 #endif
1049 DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
1050 #if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
1051 DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
1052 #endif
1053 #if defined(VA_FOURCC_P012) && defined(DRM_FORMAT_R16)
1054 DRM_MAP(P012, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
1055 #endif
1056 DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
1057 DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
1058 DRM_MAP(
RGBA, 1, DRM_FORMAT_ABGR8888),
1059 DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
1060 #ifdef VA_FOURCC_ABGR
1061 DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
1062 DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
1063 #endif
1064 DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
1065 DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
1066 #if defined(VA_FOURCC_XYUV) && defined(DRM_FORMAT_XYUV8888)
1067 DRM_MAP(XYUV, 1, DRM_FORMAT_XYUV8888),
1068 #endif
1069 #if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU2101010)
1070 DRM_MAP(Y410, 1, DRM_FORMAT_XVYU2101010),
1071 #endif
1072 #if defined(VA_FOURCC_Y412) && defined(DRM_FORMAT_XVYU12_16161616)
1073 DRM_MAP(Y412, 1, DRM_FORMAT_XVYU12_16161616),
1074 #endif
1075 #if defined(VA_FOURCC_X2R10G10B10) && defined(DRM_FORMAT_XRGB2101010)
1076 DRM_MAP(X2R10G10B10, 1, DRM_FORMAT_XRGB2101010),
1077 #endif
1078 };
1079 #undef DRM_MAP
1080
1083 {
1085
1086 VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->
priv;
1087
1089
1090 vaDestroySurfaces(dst_dev->
display, &surface_id, 1);
1091 }
1092
1095 {
1096 #if VA_CHECK_VERSION(1, 1, 0)
1098 int use_prime2;
1099 #else
1100 int k;
1101 #endif
1106 const VAAPIFormatDescriptor *format_desc;
1107 VASurfaceID surface_id;
1108 VAStatus vas = VA_STATUS_SUCCESS;
1109 uint32_t va_fourcc;
1111
1112 #if !VA_CHECK_VERSION(1, 1, 0)
1113 unsigned long buffer_handle;
1114 VASurfaceAttribExternalBuffers buffer_desc;
1115 VASurfaceAttrib attrs[2] = {
1116 {
1117 .type = VASurfaceAttribMemoryType,
1118 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1119 .value.type = VAGenericValueTypeInteger,
1120 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1121 },
1122 {
1123 .type = VASurfaceAttribExternalBufferDescriptor,
1124 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1125 .value.type = VAGenericValueTypePointer,
1126 .value.value.p = &buffer_desc,
1127 }
1128 };
1129 #endif
1130
1132
1133 if (
desc->nb_objects != 1) {
1135 "made from a single DRM object.\n");
1137 }
1138
1139 va_fourcc = 0;
1141 if (
desc->nb_layers != vaapi_drm_format_map[
i].nb_layer_formats)
1142 continue;
1143 for (j = 0; j <
desc->nb_layers; j++) {
1144 if (
desc->layers[j].format !=
1145 vaapi_drm_format_map[
i].layer_formats[j])
1146 break;
1147 }
1148 if (j !=
desc->nb_layers)
1149 continue;
1150 va_fourcc = vaapi_drm_format_map[
i].va_fourcc;
1151 break;
1152 }
1153 if (!va_fourcc) {
1155 "by VAAPI.\n");
1157 }
1158
1160 "%08x.\n",
desc->objects[0].fd, va_fourcc);
1161
1164
1165 #if VA_CHECK_VERSION(1, 1, 0)
1168 if (use_prime2) {
1169 VADRMPRIMESurfaceDescriptor prime_desc;
1170 VASurfaceAttrib prime_attrs[2] = {
1171 {
1172 .type = VASurfaceAttribMemoryType,
1173 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1174 .value.type = VAGenericValueTypeInteger,
1175 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1176 },
1177 {
1178 .type = VASurfaceAttribExternalBufferDescriptor,
1179 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1180 .value.type = VAGenericValueTypePointer,
1181 .value.value.p = &prime_desc,
1182 }
1183 };
1184 prime_desc.fourcc = va_fourcc;
1185 prime_desc.width = src_fc->
width;
1186 prime_desc.height = src_fc->
height;
1187 prime_desc.num_objects =
desc->nb_objects;
1188 for (
i = 0;
i <
desc->nb_objects; ++
i) {
1189 prime_desc.objects[
i].fd =
desc->objects[
i].fd;
1190 prime_desc.objects[
i].size =
desc->objects[
i].size;
1191 prime_desc.objects[
i].drm_format_modifier =
1192 desc->objects[
i].format_modifier;
1193 }
1194
1195 prime_desc.num_layers =
desc->nb_layers;
1196 for (
i = 0;
i <
desc->nb_layers; ++
i) {
1197 prime_desc.layers[
i].drm_format =
desc->layers[
i].format;
1198 prime_desc.layers[
i].num_planes =
desc->layers[
i].nb_planes;
1199 for (j = 0; j <
desc->layers[
i].nb_planes; ++j) {
1200 prime_desc.layers[
i].object_index[j] =
1201 desc->layers[
i].planes[j].object_index;
1202 prime_desc.layers[
i].offset[j] =
desc->layers[
i].planes[j].offset;
1203 prime_desc.layers[
i].pitch[j] =
desc->layers[
i].planes[j].pitch;
1204 }
1205
1206 if (format_desc->chroma_planes_swapped &&
1207 desc->layers[
i].nb_planes == 3) {
1208 FFSWAP(uint32_t, prime_desc.layers[
i].pitch[1],
1209 prime_desc.layers[
i].pitch[2]);
1210 FFSWAP(uint32_t, prime_desc.layers[
i].offset[1],
1211 prime_desc.layers[
i].offset[2]);
1212 }
1213 }
1214
1215 /*
1216 * We can query for PRIME_2 support with vaQuerySurfaceAttributes, but that
1217 * that needs the config_id which we don't have here . Both Intel and
1218 * Gallium seem to do the correct error checks, so lets just try the
1219 * PRIME_2 import first.
1220 */
1221 vas = vaCreateSurfaces(dst_dev->
display, format_desc->rt_format,
1222 src->width,
src->height, &surface_id, 1,
1224 if (vas != VA_STATUS_SUCCESS)
1226 }
1227
1228 if (!use_prime2 || vas != VA_STATUS_SUCCESS) {
1229 int k;
1230 uintptr_t buffer_handle;
1231 VASurfaceAttribExternalBuffers buffer_desc;
1232 VASurfaceAttrib buffer_attrs[2] = {
1233 {
1234 .type = VASurfaceAttribMemoryType,
1235 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1236 .value.type = VAGenericValueTypeInteger,
1237 .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1238 },
1239 {
1240 .type = VASurfaceAttribExternalBufferDescriptor,
1241 .flags = VA_SURFACE_ATTRIB_SETTABLE,
1242 .value.type = VAGenericValueTypePointer,
1243 .value.value.p = &buffer_desc,
1244 }
1245 };
1246
1247 buffer_handle =
desc->objects[0].fd;
1248 buffer_desc.pixel_format = va_fourcc;
1249 buffer_desc.width = src_fc->
width;
1250 buffer_desc.height = src_fc->
height;
1251 buffer_desc.data_size =
desc->objects[0].size;
1252 buffer_desc.buffers = &buffer_handle;
1253 buffer_desc.num_buffers = 1;
1254 buffer_desc.flags = 0;
1255
1256 k = 0;
1257 for (
i = 0;
i <
desc->nb_layers;
i++) {
1258 for (j = 0; j <
desc->layers[
i].nb_planes; j++) {
1259 buffer_desc.pitches[k] =
desc->layers[
i].planes[j].pitch;
1260 buffer_desc.offsets[k] =
desc->layers[
i].planes[j].offset;
1261 ++k;
1262 }
1263 }
1264 buffer_desc.num_planes = k;
1265
1266 if (format_desc->chroma_planes_swapped &&
1267 buffer_desc.num_planes == 3) {
1268 FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1269 FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1270 }
1271
1272 vas = vaCreateSurfaces(dst_dev->
display, format_desc->rt_format,
1274 &surface_id, 1,
1276 }
1277 #else
1278 buffer_handle =
desc->objects[0].fd;
1279 buffer_desc.pixel_format = va_fourcc;
1280 buffer_desc.width = src_fc->
width;
1281 buffer_desc.height = src_fc->
height;
1282 buffer_desc.data_size =
desc->objects[0].size;
1283 buffer_desc.buffers = &buffer_handle;
1284 buffer_desc.num_buffers = 1;
1285 buffer_desc.flags = 0;
1286
1287 k = 0;
1288 for (
i = 0;
i <
desc->nb_layers;
i++) {
1289 for (j = 0; j <
desc->layers[
i].nb_planes; j++) {
1290 buffer_desc.pitches[k] =
desc->layers[
i].planes[j].pitch;
1291 buffer_desc.offsets[k] =
desc->layers[
i].planes[j].offset;
1292 ++k;
1293 }
1294 }
1295 buffer_desc.num_planes = k;
1296
1297 if (format_desc->chroma_planes_swapped &&
1298 buffer_desc.num_planes == 3) {
1299 FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1300 FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1301 }
1302
1303 vas = vaCreateSurfaces(dst_dev->
display, format_desc->rt_format,
1305 &surface_id, 1,
1307 #endif
1308 if (vas != VA_STATUS_SUCCESS) {
1310 "object: %d (%s).\n", vas, vaErrorStr(vas));
1312 }
1314
1316 &vaapi_unmap_from_drm,
1317 (void*)(uintptr_t)surface_id);
1318 if (err < 0)
1319 return err;
1320
1322 dst->height =
src->height;
1323 dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
1324
1326 "surface %#x.\n",
desc->objects[0].fd, surface_id);
1327
1328 return 0;
1329 }
1330
1331 #if VA_CHECK_VERSION(1, 1, 0)
1334 {
1337
1340
1342 }
1343
1346 {
1348 VASurfaceID surface_id;
1349 VAStatus vas;
1350 VADRMPRIMESurfaceDescriptor va_desc;
1352 uint32_t export_flags;
1354
1355 surface_id = (VASurfaceID)(uintptr_t)
src->data[3];
1356
1357 export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1359 export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1360
1361 vas = vaSyncSurface(hwctx->
display, surface_id);
1362 if (vas != VA_STATUS_SUCCESS) {
1364 "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
1366 }
1367 }
1368
1370 export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1371
1372 vas = vaExportSurfaceHandle(hwctx->
display, surface_id,
1373 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1374 export_flags, &va_desc);
1375 if (vas != VA_STATUS_SUCCESS) {
1376 if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1379 "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1381 }
1382
1384 if (!drm_desc) {
1387 }
1388
1389 // By some bizarre coincidence, these structures are very similar...
1391 for (
i = 0;
i < va_desc.num_objects;
i++) {
1395 va_desc.objects[
i].drm_format_modifier;
1396 }
1397 drm_desc->
nb_layers = va_desc.num_layers;
1398 for (
i = 0;
i < va_desc.num_layers;
i++) {
1401 for (j = 0; j < va_desc.layers[
i].num_planes; j++) {
1403 va_desc.layers[
i].object_index[j];
1405 va_desc.layers[
i].offset[j];
1407 va_desc.layers[
i].pitch[j];
1408 }
1409 }
1410
1412 &vaapi_unmap_to_drm_esh, drm_desc);
1413 if (err < 0)
1415
1417 dst->height =
src->height;
1418 dst->data[0] = (uint8_t*)drm_desc;
1419
1420 return 0;
1421
1423 for (
i = 0;
i < va_desc.num_objects;
i++)
1424 close(va_desc.objects[
i].fd);
1426 return err;
1427 }
1428 #endif
1429
1430 #if VA_CHECK_VERSION(0, 36, 0)
1431 typedef struct VAAPIDRMImageBufferMapping {
1432 VAImage image;
1433 VABufferInfo buffer_info;
1434
1436 } VAAPIDRMImageBufferMapping;
1437
1440 {
1442 VAAPIDRMImageBufferMapping *mapping = hwmap->
priv;
1443 VASurfaceID surface_id;
1444 VAStatus vas;
1445
1446 surface_id = (VASurfaceID)(uintptr_t)hwmap->
source->
data[3];
1448 surface_id);
1449
1450 // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1451 // so we shouldn't close them separately.
1452
1453 vas = vaReleaseBufferHandle(hwctx->
display, mapping->image.buf);
1454 if (vas != VA_STATUS_SUCCESS) {
1456 "handle of image %#x (derived from surface %#x): "
1457 "%d (%s).\n", mapping->image.buf, surface_id,
1458 vas, vaErrorStr(vas));
1459 }
1460
1461 vas = vaDestroyImage(hwctx->
display, mapping->image.image_id);
1462 if (vas != VA_STATUS_SUCCESS) {
1464 "derived from surface %#x: %d (%s).\n",
1465 surface_id, vas, vaErrorStr(vas));
1466 }
1467
1469 }
1470
1473 {
1475 VAAPIDRMImageBufferMapping *mapping =
NULL;
1476 VASurfaceID surface_id;
1477 VAStatus vas;
1479
1480 surface_id = (VASurfaceID)(uintptr_t)
src->data[3];
1482 surface_id);
1483
1485 if (!mapping)
1487
1488 vas = vaDeriveImage(hwctx->
display, surface_id,
1489 &mapping->image);
1490 if (vas != VA_STATUS_SUCCESS) {
1492 "surface %#x: %d (%s).\n",
1493 surface_id, vas, vaErrorStr(vas));
1496 }
1497
1499 if (vaapi_drm_format_map[
i].va_fourcc ==
1500 mapping->image.format.fourcc)
1501 break;
1502 }
1505 "VAAPI format %#x.\n", mapping->image.format.fourcc);
1507 goto fail_derived;
1508 }
1509
1510 mapping->buffer_info.mem_type =
1511 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1512
1513 mapping->drm_desc.nb_layers =
1514 vaapi_drm_format_map[
i].nb_layer_formats;
1515 if (mapping->drm_desc.nb_layers > 1) {
1516 if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1518 "expected format: got %d planes, but expected %d.\n",
1519 mapping->image.num_planes, mapping->drm_desc.nb_layers);
1521 goto fail_derived;
1522 }
1523
1524 for(
p = 0;
p < mapping->drm_desc.nb_layers;
p++) {
1526 .format = vaapi_drm_format_map[
i].layer_formats[
p],
1527 .nb_planes = 1,
1528 .planes[0] = {
1529 .object_index = 0,
1530 .offset = mapping->image.offsets[
p],
1531 .pitch = mapping->image.pitches[
p],
1532 },
1533 };
1534 }
1535 } else {
1536 mapping->drm_desc.layers[0].format =
1537 vaapi_drm_format_map[
i].layer_formats[0];
1538 mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1539 for (
p = 0;
p < mapping->image.num_planes;
p++) {
1541 .object_index = 0,
1542 .offset = mapping->image.offsets[
p],
1543 .pitch = mapping->image.pitches[
p],
1544 };
1545 }
1546 }
1547
1548 vas = vaAcquireBufferHandle(hwctx->
display, mapping->image.buf,
1549 &mapping->buffer_info);
1550 if (vas != VA_STATUS_SUCCESS) {
1552 "handle from image %#x (derived from surface %#x): "
1553 "%d (%s).\n", mapping->image.buf, surface_id,
1554 vas, vaErrorStr(vas));
1556 goto fail_derived;
1557 }
1558
1560 mapping->buffer_info.handle);
1561
1562 mapping->drm_desc.nb_objects = 1;
1564 .fd = mapping->buffer_info.handle,
1565 .size = mapping->image.data_size,
1566 // There is no way to get the format modifier with this API.
1568 };
1569
1571 dst,
src, &vaapi_unmap_to_drm_abh,
1572 mapping);
1573 if (err < 0)
1574 goto fail_mapped;
1575
1576 dst->data[0] = (uint8_t*)&mapping->drm_desc;
1578 dst->height =
src->height;
1579
1580 return 0;
1581
1582 fail_mapped:
1583 vaReleaseBufferHandle(hwctx->
display, mapping->image.buf);
1584 fail_derived:
1585 vaDestroyImage(hwctx->
display, mapping->image.image_id);
1588 return err;
1589 }
1590 #endif
1591
1594 {
1595 #if VA_CHECK_VERSION(1, 1, 0)
1596 int err;
1597 err = vaapi_map_to_drm_esh(hwfc,
dst,
src,
flags);
1599 return err;
1600 #endif
1601 #if VA_CHECK_VERSION(0, 36, 0)
1602 return vaapi_map_to_drm_abh(hwfc,
dst,
src,
flags);
1603 #endif
1605 }
1606
1607 #endif /* CONFIG_LIBDRM */
1608
1611 {
1612 switch (
src->format) {
1613 #if CONFIG_LIBDRM
1616 #endif
1617 default:
1619 }
1620 }
1621
1624 {
1625 switch (
dst->format) {
1626 #if CONFIG_LIBDRM
1629 #endif
1630 default:
1632 }
1633 }
1634
1636 {
1639
1642
1643 #if HAVE_VAAPI_X11
1644 if (priv->x11_display)
1645 XCloseDisplay(priv->x11_display);
1646 #endif
1647
1650
1652 }
1653
1654 #if CONFIG_VAAPI_1
1655 static void vaapi_device_log_error(
void *
context,
const char *
message)
1656 {
1658
1660 }
1661
1662 static void vaapi_device_log_info(
void *
context,
const char *
message)
1663 {
1665
1667 }
1668 #endif
1669
1671 VADisplay display)
1672 {
1674 int major, minor;
1675 VAStatus vas;
1676
1677 #if CONFIG_VAAPI_1
1678 vaSetErrorCallback(display, &vaapi_device_log_error,
ctx);
1679 vaSetInfoCallback (display, &vaapi_device_log_info,
ctx);
1680 #endif
1681
1683
1684 vas = vaInitialize(display, &major, &minor);
1685 if (vas != VA_STATUS_SUCCESS) {
1687 "connection: %d (%s).\n", vas, vaErrorStr(vas));
1689 }
1691 "version %d.%d\n", major, minor);
1692
1693 return 0;
1694 }
1695
1698 {
1700 VADisplay display =
NULL;
1702 int try_drm, try_x11, try_win32, try_all;
1703
1705 if (!priv)
1707
1709
1710 ctx->user_opaque = priv;
1712
1714 if (ent) {
1715 try_all = try_drm = try_x11 = try_win32 = 0;
1716 if (!strcmp(ent->
value,
"drm")) {
1717 try_drm = 1;
1718 }
else if (!strcmp(ent->
value,
"x11")) {
1719 try_x11 = 1;
1720 }
else if (!strcmp(ent->
value,
"win32")) {
1721 try_win32 = 1;
1722 } else {
1726 }
1727 } else {
1728 try_all = 1;
1729 try_drm = HAVE_VAAPI_DRM;
1730 try_x11 = HAVE_VAAPI_X11;
1731 try_win32 = HAVE_VAAPI_WIN32;
1732 }
1733
1734 #if HAVE_VAAPI_DRM
1735 while (!display && try_drm) {
1736 // If the device is specified, try to open it as a DRM device node.
1737 // If not, look for a usable render node, possibly restricted to those
1738 // using a specified kernel driver.
1740 if (device) {
1741 priv->
drm_fd = open(device, O_RDWR);
1743 av_log(
ctx, loglevel,
"Failed to open %s as "
1744 "DRM device node.\n", device);
1745 break;
1746 }
1747 } else {
1748 char path[64];
1749 int n, max_devices = 8;
1750 #if CONFIG_LIBDRM
1756 #endif
1757 for (n = 0; n < max_devices; n++) {
1759 "/dev/dri/renderD%d", 128 + n);
1760 priv->
drm_fd = open(path, O_RDWR);
1762 if (errno == ENOENT) {
1763 if (n != max_devices - 1) {
1765 "No render device %s, try next device for "
1766 "DRM render node.\n", path);
1767 continue;
1768 }
1769
1771 "for DRM render node.\n");
1772 } else
1774 "DRM render node for device %d.\n", n);
1775 break;
1776 }
1777 #if CONFIG_LIBDRM
1781 "Failed to get DRM version for device %d.\n", n);
1784 continue;
1785 }
1786 if (kernel_driver) {
1787 if (strcmp(kernel_driver->
value,
info->name)) {
1789 "with non-matching kernel driver (%s).\n",
1791 drmFreeVersion(
info);
1794 continue;
1795 }
1797 "DRM render node for device %d, "
1798 "with matching kernel driver (%s).\n",
1800 drmFreeVersion(
info);
1801 break;
1802 // drmGetVersion() ensures |info->name| is 0-terminated.
1803 }
else if (!strcmp(
info->name,
"vgem")) {
1805 "Skipping vgem node for device %d.\n", n);
1806 drmFreeVersion(
info);
1809 continue;
1810 } else if (vendor_id) {
1811 drmDevicePtr device;
1812 char drm_vendor[8];
1813 if (drmGetDevice(priv->
drm_fd, &device)) {
1815 "Failed to get DRM device info for device %d.\n", n);
1818 continue;
1819 }
1820
1821 snprintf(drm_vendor,
sizeof(drm_vendor),
"0x%x", device->deviceinfo.pci->vendor_id);
1822 if (strcmp(vendor_id->
value, drm_vendor)) {
1824 "with non-matching vendor id (%s).\n",
1825 n, vendor_id->
value);
1826 drmFreeDevice(&device);
1829 continue;
1830 }
1832 "DRM render node for device %d, "
1833 "with matching vendor id (%s).\n",
1834 n, vendor_id->
value);
1835 drmFreeDevice(&device);
1836 break;
1837 }
1838 drmFreeVersion(
info);
1839 #endif
1841 "DRM render node for device %d.\n", n);
1842 break;
1843 }
1844 if (n >= max_devices)
1845 break;
1846 }
1847
1848 display = vaGetDisplayDRM(priv->
drm_fd);
1849 if (!display) {
1851 "from DRM device %s.\n", device);
1853 }
1854 break;
1855 }
1856 #endif
1857
1858 #if HAVE_VAAPI_X11
1859 if (!display && try_x11) {
1860 // Try to open the device as an X11 display.
1861 priv->x11_display = XOpenDisplay(device);
1862 if (!priv->x11_display) {
1864 "%s.\n", XDisplayName(device));
1865 } else {
1866 display = vaGetDisplay(priv->x11_display);
1867 if (!display) {
1869 "from X11 display %s.\n", XDisplayName(device));
1871 }
1872
1874 "X11 display %s.\n", XDisplayName(device));
1875 }
1876 }
1877 #endif
1878
1879 #if HAVE_VAAPI_WIN32
1880 if (!display && try_win32) {
1881 // Try to create a display from the specified device, if any.
1882 if (!device) {
1883 display = vaGetDisplayWin32(
NULL);
1884 } else {
1885 IDXGIFactory2 *pDXGIFactory =
NULL;
1886 IDXGIAdapter *pAdapter =
NULL;
1887 #if !HAVE_UWP
1888 HANDLE dxgi = dlopen("dxgi.dll", 0);
1889 if (!dxgi) {
1892 }
1895 if (!pfnCreateDXGIFactory) {
1897 dlclose(dxgi);
1899 }
1900 #else
1901 // In UWP (which lacks LoadLibrary), CreateDXGIFactory isn't
1902 // available, only CreateDXGIFactory1
1905 #endif
1906 if (SUCCEEDED(pfnCreateDXGIFactory(&IID_IDXGIFactory2,
1907 (void **)&pDXGIFactory))) {
1908 int adapter = atoi(device);
1909 if (SUCCEEDED(IDXGIFactory2_EnumAdapters(pDXGIFactory,
1910 adapter,
1911 &pAdapter))) {
1912 DXGI_ADAPTER_DESC
desc;
1913 if (SUCCEEDED(IDXGIAdapter2_GetDesc(pAdapter, &
desc))) {
1915 "Using device %04x:%04x (%ls) - LUID %lu %ld.\n",
1917 desc.AdapterLuid.LowPart,
1918 desc.AdapterLuid.HighPart);
1919 display = vaGetDisplayWin32(&
desc.AdapterLuid);
1920 }
1921 IDXGIAdapter_Release(pAdapter);
1922 }
1923 IDXGIFactory2_Release(pDXGIFactory);
1924 }
1925 #if !HAVE_UWP
1926 dlclose(dxgi);
1927 #endif
1928 }
1929
1930 if (!display) {
1932 "from Win32 display.\n");
1934 }
1935
1937 "Win32 display.\n");
1938 }
1939 #endif
1940
1941 if (!display) {
1942 if (device)
1944 "device %s.\n", device);
1945 else
1947 "any default device.\n");
1949 }
1950
1952 if (ent) {
1953 #if VA_CHECK_VERSION(0, 38, 0)
1954 VAStatus vas;
1955 vas = vaSetDriverName(display, ent->
value);
1956 if (vas != VA_STATUS_SUCCESS) {
1958 "%s: %d (%s).\n", ent->
value, vas, vaErrorStr(vas));
1959 vaTerminate(display);
1961 }
1962 #else
1964 "supported with this VAAPI version.\n");
1965 #endif
1966 }
1967
1969 }
1970
1974 {
1975 #if HAVE_VAAPI_DRM
1978 VADisplay *display;
1980 int fd;
1981
1982 if (src_hwctx->
fd < 0) {
1984 "device to derive a VA display from.\n");
1986 }
1987
1988 #if CONFIG_LIBDRM
1989 {
1990 int node_type = drmGetNodeTypeFromFd(src_hwctx->
fd);
1991 char *render_node;
1992 if (node_type < 0) {
1994 "to refer to a DRM device.\n");
1996 }
1997 if (node_type == DRM_NODE_RENDER) {
1999 } else {
2000 render_node = drmGetRenderDeviceNameFromFd(src_hwctx->
fd);
2001 if (!render_node) {
2003 "because the device does not have an "
2004 "associated render node.\n");
2006 } else {
2007 fd = open(render_node, O_RDWR);
2008 if (fd < 0) {
2010 "because the associated render node "
2011 "could not be opened.\n");
2013 } else {
2015 "in place of non-render DRM device.\n",
2016 render_node);
2017 }
2018 free(render_node);
2019 }
2020 }
2021 }
2022 #else
2024 #endif
2025
2027 if (!priv) {
2028 if (fd != src_hwctx->
fd) {
2029 // The fd was opened in this function.
2031 }
2033 }
2034
2035 if (fd == src_hwctx->
fd) {
2036 // The fd is inherited from the source context and we are holding
2037 // a reference to that, we don't want to close it from here.
2039 } else {
2041 }
2042
2043 ctx->user_opaque = priv;
2045
2046 display = vaGetDisplayDRM(fd);
2047 if (!display) {
2049 "DRM device.\n");
2051 }
2052
2054 }
2055 #endif
2057 }
2058
2061 .name = "VAAPI",
2062
2066
2080
2084 },
2085 };