1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * This file is part of FFmpeg.
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
5cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
6cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
7cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
8cabdff1aSopenharmony_ci *
9cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
10cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
11cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12cabdff1aSopenharmony_ci * Lesser General Public License for more details.
13cabdff1aSopenharmony_ci *
14cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
15cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
16cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17cabdff1aSopenharmony_ci */
18cabdff1aSopenharmony_ci
19cabdff1aSopenharmony_ci#include "config.h"
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#if HAVE_VAAPI_X11
22cabdff1aSopenharmony_ci#   include <va/va_x11.h>
23cabdff1aSopenharmony_ci#endif
24cabdff1aSopenharmony_ci#if HAVE_VAAPI_DRM
25cabdff1aSopenharmony_ci#   include <va/va_drm.h>
26cabdff1aSopenharmony_ci#endif
27cabdff1aSopenharmony_ci
28cabdff1aSopenharmony_ci#if CONFIG_LIBDRM
29cabdff1aSopenharmony_ci#   include <va/va_drmcommon.h>
30cabdff1aSopenharmony_ci#   include <xf86drm.h>
31cabdff1aSopenharmony_ci#   include <drm_fourcc.h>
32cabdff1aSopenharmony_ci#   ifndef DRM_FORMAT_MOD_INVALID
33cabdff1aSopenharmony_ci#       define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
34cabdff1aSopenharmony_ci#   endif
35cabdff1aSopenharmony_ci#endif
36cabdff1aSopenharmony_ci
37cabdff1aSopenharmony_ci#include <fcntl.h>
38cabdff1aSopenharmony_ci#if HAVE_UNISTD_H
39cabdff1aSopenharmony_ci#   include <unistd.h>
40cabdff1aSopenharmony_ci#endif
41cabdff1aSopenharmony_ci
42cabdff1aSopenharmony_ci
43cabdff1aSopenharmony_ci#include "avassert.h"
44cabdff1aSopenharmony_ci#include "buffer.h"
45cabdff1aSopenharmony_ci#include "common.h"
46cabdff1aSopenharmony_ci#include "hwcontext.h"
47cabdff1aSopenharmony_ci#include "hwcontext_drm.h"
48cabdff1aSopenharmony_ci#include "hwcontext_internal.h"
49cabdff1aSopenharmony_ci#include "hwcontext_vaapi.h"
50cabdff1aSopenharmony_ci#include "mem.h"
51cabdff1aSopenharmony_ci#include "pixdesc.h"
52cabdff1aSopenharmony_ci#include "pixfmt.h"
53cabdff1aSopenharmony_ci
54cabdff1aSopenharmony_ci
55cabdff1aSopenharmony_citypedef struct VAAPIDevicePriv {
56cabdff1aSopenharmony_ci#if HAVE_VAAPI_X11
57cabdff1aSopenharmony_ci    Display *x11_display;
58cabdff1aSopenharmony_ci#endif
59cabdff1aSopenharmony_ci
60cabdff1aSopenharmony_ci    int drm_fd;
61cabdff1aSopenharmony_ci} VAAPIDevicePriv;
62cabdff1aSopenharmony_ci
63cabdff1aSopenharmony_citypedef struct VAAPISurfaceFormat {
64cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt;
65cabdff1aSopenharmony_ci    VAImageFormat image_format;
66cabdff1aSopenharmony_ci} VAAPISurfaceFormat;
67cabdff1aSopenharmony_ci
68cabdff1aSopenharmony_citypedef struct VAAPIDeviceContext {
69cabdff1aSopenharmony_ci    // Surface formats which can be used with this device.
70cabdff1aSopenharmony_ci    VAAPISurfaceFormat *formats;
71cabdff1aSopenharmony_ci    int              nb_formats;
72cabdff1aSopenharmony_ci} VAAPIDeviceContext;
73cabdff1aSopenharmony_ci
74cabdff1aSopenharmony_citypedef struct VAAPIFramesContext {
75cabdff1aSopenharmony_ci    // Surface attributes set at create time.
76cabdff1aSopenharmony_ci    VASurfaceAttrib *attributes;
77cabdff1aSopenharmony_ci    int           nb_attributes;
78cabdff1aSopenharmony_ci    // RT format of the underlying surface (Intel driver ignores this anyway).
79cabdff1aSopenharmony_ci    unsigned int rt_format;
80cabdff1aSopenharmony_ci    // Whether vaDeriveImage works.
81cabdff1aSopenharmony_ci    int derive_works;
82cabdff1aSopenharmony_ci    // Caches whether VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 is unsupported for
83cabdff1aSopenharmony_ci    // surface imports.
84cabdff1aSopenharmony_ci    int prime_2_import_unsupported;
85cabdff1aSopenharmony_ci} VAAPIFramesContext;
86cabdff1aSopenharmony_ci
87cabdff1aSopenharmony_citypedef struct VAAPIMapping {
88cabdff1aSopenharmony_ci    // Handle to the derived or copied image which is mapped.
89cabdff1aSopenharmony_ci    VAImage image;
90cabdff1aSopenharmony_ci    // The mapping flags actually used.
91cabdff1aSopenharmony_ci    int flags;
92cabdff1aSopenharmony_ci} VAAPIMapping;
93cabdff1aSopenharmony_ci
94cabdff1aSopenharmony_citypedef struct VAAPIFormat {
95cabdff1aSopenharmony_ci    unsigned int fourcc;
96cabdff1aSopenharmony_ci    unsigned int rt_format;
97cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt;
98cabdff1aSopenharmony_ci    int chroma_planes_swapped;
99cabdff1aSopenharmony_ci} VAAPIFormatDescriptor;
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_ci#define MAP(va, rt, av, swap_uv) { \
102cabdff1aSopenharmony_ci        VA_FOURCC_ ## va, \
103cabdff1aSopenharmony_ci        VA_RT_FORMAT_ ## rt, \
104cabdff1aSopenharmony_ci        AV_PIX_FMT_ ## av, \
105cabdff1aSopenharmony_ci        swap_uv, \
106cabdff1aSopenharmony_ci    }
107cabdff1aSopenharmony_ci// The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V
108cabdff1aSopenharmony_ci// plane swap cases.  The frame handling below tries to hide these.
109cabdff1aSopenharmony_cistatic const VAAPIFormatDescriptor vaapi_format_map[] = {
110cabdff1aSopenharmony_ci    MAP(NV12, YUV420,  NV12,    0),
111cabdff1aSopenharmony_ci#ifdef VA_FOURCC_I420
112cabdff1aSopenharmony_ci    MAP(I420, YUV420,  YUV420P, 0),
113cabdff1aSopenharmony_ci#endif
114cabdff1aSopenharmony_ci    MAP(YV12, YUV420,  YUV420P, 1),
115cabdff1aSopenharmony_ci    MAP(IYUV, YUV420,  YUV420P, 0),
116cabdff1aSopenharmony_ci    MAP(422H, YUV422,  YUV422P, 0),
117cabdff1aSopenharmony_ci#ifdef VA_FOURCC_YV16
118cabdff1aSopenharmony_ci    MAP(YV16, YUV422,  YUV422P, 1),
119cabdff1aSopenharmony_ci#endif
120cabdff1aSopenharmony_ci    MAP(UYVY, YUV422,  UYVY422, 0),
121cabdff1aSopenharmony_ci    MAP(YUY2, YUV422,  YUYV422, 0),
122cabdff1aSopenharmony_ci#ifdef VA_FOURCC_Y210
123cabdff1aSopenharmony_ci    MAP(Y210, YUV422_10,  Y210, 0),
124cabdff1aSopenharmony_ci#endif
125cabdff1aSopenharmony_ci    MAP(411P, YUV411,  YUV411P, 0),
126cabdff1aSopenharmony_ci    MAP(422V, YUV422,  YUV440P, 0),
127cabdff1aSopenharmony_ci    MAP(444P, YUV444,  YUV444P, 0),
128cabdff1aSopenharmony_ci    MAP(Y800, YUV400,  GRAY8,   0),
129cabdff1aSopenharmony_ci#ifdef VA_FOURCC_P010
130cabdff1aSopenharmony_ci    MAP(P010, YUV420_10BPP, P010, 0),
131cabdff1aSopenharmony_ci#endif
132cabdff1aSopenharmony_ci    MAP(BGRA, RGB32,   BGRA, 0),
133cabdff1aSopenharmony_ci    MAP(BGRX, RGB32,   BGR0, 0),
134cabdff1aSopenharmony_ci    MAP(RGBA, RGB32,   RGBA, 0),
135cabdff1aSopenharmony_ci    MAP(RGBX, RGB32,   RGB0, 0),
136cabdff1aSopenharmony_ci#ifdef VA_FOURCC_ABGR
137cabdff1aSopenharmony_ci    MAP(ABGR, RGB32,   ABGR, 0),
138cabdff1aSopenharmony_ci    MAP(XBGR, RGB32,   0BGR, 0),
139cabdff1aSopenharmony_ci#endif
140cabdff1aSopenharmony_ci    MAP(ARGB, RGB32,   ARGB, 0),
141cabdff1aSopenharmony_ci    MAP(XRGB, RGB32,   0RGB, 0),
142cabdff1aSopenharmony_ci#ifdef VA_FOURCC_X2R10G10B10
143cabdff1aSopenharmony_ci    MAP(X2R10G10B10, RGB32_10, X2RGB10, 0),
144cabdff1aSopenharmony_ci#endif
145cabdff1aSopenharmony_ci};
146cabdff1aSopenharmony_ci#undef MAP
147cabdff1aSopenharmony_ci
148cabdff1aSopenharmony_cistatic const VAAPIFormatDescriptor *
149cabdff1aSopenharmony_ci    vaapi_format_from_fourcc(unsigned int fourcc)
150cabdff1aSopenharmony_ci{
151cabdff1aSopenharmony_ci    int i;
152cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
153cabdff1aSopenharmony_ci        if (vaapi_format_map[i].fourcc == fourcc)
154cabdff1aSopenharmony_ci            return &vaapi_format_map[i];
155cabdff1aSopenharmony_ci    return NULL;
156cabdff1aSopenharmony_ci}
157cabdff1aSopenharmony_ci
158cabdff1aSopenharmony_cistatic const VAAPIFormatDescriptor *
159cabdff1aSopenharmony_ci    vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt)
160cabdff1aSopenharmony_ci{
161cabdff1aSopenharmony_ci    int i;
162cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++)
163cabdff1aSopenharmony_ci        if (vaapi_format_map[i].pix_fmt == pix_fmt)
164cabdff1aSopenharmony_ci            return &vaapi_format_map[i];
165cabdff1aSopenharmony_ci    return NULL;
166cabdff1aSopenharmony_ci}
167cabdff1aSopenharmony_ci
168cabdff1aSopenharmony_cistatic enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc)
169cabdff1aSopenharmony_ci{
170cabdff1aSopenharmony_ci    const VAAPIFormatDescriptor *desc;
171cabdff1aSopenharmony_ci    desc = vaapi_format_from_fourcc(fourcc);
172cabdff1aSopenharmony_ci    if (desc)
173cabdff1aSopenharmony_ci        return desc->pix_fmt;
174cabdff1aSopenharmony_ci    else
175cabdff1aSopenharmony_ci        return AV_PIX_FMT_NONE;
176cabdff1aSopenharmony_ci}
177cabdff1aSopenharmony_ci
178cabdff1aSopenharmony_cistatic int vaapi_get_image_format(AVHWDeviceContext *hwdev,
179cabdff1aSopenharmony_ci                                  enum AVPixelFormat pix_fmt,
180cabdff1aSopenharmony_ci                                  VAImageFormat **image_format)
181cabdff1aSopenharmony_ci{
182cabdff1aSopenharmony_ci    VAAPIDeviceContext *ctx = hwdev->internal->priv;
183cabdff1aSopenharmony_ci    int i;
184cabdff1aSopenharmony_ci
185cabdff1aSopenharmony_ci    for (i = 0; i < ctx->nb_formats; i++) {
186cabdff1aSopenharmony_ci        if (ctx->formats[i].pix_fmt == pix_fmt) {
187cabdff1aSopenharmony_ci            if (image_format)
188cabdff1aSopenharmony_ci                *image_format = &ctx->formats[i].image_format;
189cabdff1aSopenharmony_ci            return 0;
190cabdff1aSopenharmony_ci        }
191cabdff1aSopenharmony_ci    }
192cabdff1aSopenharmony_ci    return AVERROR(EINVAL);
193cabdff1aSopenharmony_ci}
194cabdff1aSopenharmony_ci
195cabdff1aSopenharmony_cistatic int vaapi_frames_get_constraints(AVHWDeviceContext *hwdev,
196cabdff1aSopenharmony_ci                                        const void *hwconfig,
197cabdff1aSopenharmony_ci                                        AVHWFramesConstraints *constraints)
198cabdff1aSopenharmony_ci{
199cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
200cabdff1aSopenharmony_ci    const AVVAAPIHWConfig *config = hwconfig;
201cabdff1aSopenharmony_ci    VAAPIDeviceContext *ctx = hwdev->internal->priv;
202cabdff1aSopenharmony_ci    VASurfaceAttrib *attr_list = NULL;
203cabdff1aSopenharmony_ci    VAStatus vas;
204cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt;
205cabdff1aSopenharmony_ci    unsigned int fourcc;
206cabdff1aSopenharmony_ci    int err, i, j, attr_count, pix_fmt_count;
207cabdff1aSopenharmony_ci
208cabdff1aSopenharmony_ci    if (config &&
209cabdff1aSopenharmony_ci        !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
210cabdff1aSopenharmony_ci        attr_count = 0;
211cabdff1aSopenharmony_ci        vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
212cabdff1aSopenharmony_ci                                       0, &attr_count);
213cabdff1aSopenharmony_ci        if (vas != VA_STATUS_SUCCESS) {
214cabdff1aSopenharmony_ci            av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
215cabdff1aSopenharmony_ci                   "%d (%s).\n", vas, vaErrorStr(vas));
216cabdff1aSopenharmony_ci            err = AVERROR(ENOSYS);
217cabdff1aSopenharmony_ci            goto fail;
218cabdff1aSopenharmony_ci        }
219cabdff1aSopenharmony_ci
220cabdff1aSopenharmony_ci        attr_list = av_malloc(attr_count * sizeof(*attr_list));
221cabdff1aSopenharmony_ci        if (!attr_list) {
222cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
223cabdff1aSopenharmony_ci            goto fail;
224cabdff1aSopenharmony_ci        }
225cabdff1aSopenharmony_ci
226cabdff1aSopenharmony_ci        vas = vaQuerySurfaceAttributes(hwctx->display, config->config_id,
227cabdff1aSopenharmony_ci                                       attr_list, &attr_count);
228cabdff1aSopenharmony_ci        if (vas != VA_STATUS_SUCCESS) {
229cabdff1aSopenharmony_ci            av_log(hwdev, AV_LOG_ERROR, "Failed to query surface attributes: "
230cabdff1aSopenharmony_ci                   "%d (%s).\n", vas, vaErrorStr(vas));
231cabdff1aSopenharmony_ci            err = AVERROR(ENOSYS);
232cabdff1aSopenharmony_ci            goto fail;
233cabdff1aSopenharmony_ci        }
234cabdff1aSopenharmony_ci
235cabdff1aSopenharmony_ci        pix_fmt_count = 0;
236cabdff1aSopenharmony_ci        for (i = 0; i < attr_count; i++) {
237cabdff1aSopenharmony_ci            switch (attr_list[i].type) {
238cabdff1aSopenharmony_ci            case VASurfaceAttribPixelFormat:
239cabdff1aSopenharmony_ci                fourcc = attr_list[i].value.value.i;
240cabdff1aSopenharmony_ci                pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
241cabdff1aSopenharmony_ci                if (pix_fmt != AV_PIX_FMT_NONE) {
242cabdff1aSopenharmony_ci                    ++pix_fmt_count;
243cabdff1aSopenharmony_ci                } else {
244cabdff1aSopenharmony_ci                    // Something unsupported - ignore.
245cabdff1aSopenharmony_ci                }
246cabdff1aSopenharmony_ci                break;
247cabdff1aSopenharmony_ci            case VASurfaceAttribMinWidth:
248cabdff1aSopenharmony_ci                constraints->min_width  = attr_list[i].value.value.i;
249cabdff1aSopenharmony_ci                break;
250cabdff1aSopenharmony_ci            case VASurfaceAttribMinHeight:
251cabdff1aSopenharmony_ci                constraints->min_height = attr_list[i].value.value.i;
252cabdff1aSopenharmony_ci                break;
253cabdff1aSopenharmony_ci            case VASurfaceAttribMaxWidth:
254cabdff1aSopenharmony_ci                constraints->max_width  = attr_list[i].value.value.i;
255cabdff1aSopenharmony_ci                break;
256cabdff1aSopenharmony_ci            case VASurfaceAttribMaxHeight:
257cabdff1aSopenharmony_ci                constraints->max_height = attr_list[i].value.value.i;
258cabdff1aSopenharmony_ci                break;
259cabdff1aSopenharmony_ci            }
260cabdff1aSopenharmony_ci        }
261cabdff1aSopenharmony_ci        if (pix_fmt_count == 0) {
262cabdff1aSopenharmony_ci            // Nothing usable found.  Presumably there exists something which
263cabdff1aSopenharmony_ci            // works, so leave the set null to indicate unknown.
264cabdff1aSopenharmony_ci            constraints->valid_sw_formats = NULL;
265cabdff1aSopenharmony_ci        } else {
266cabdff1aSopenharmony_ci            constraints->valid_sw_formats = av_malloc_array(pix_fmt_count + 1,
267cabdff1aSopenharmony_ci                                                            sizeof(pix_fmt));
268cabdff1aSopenharmony_ci            if (!constraints->valid_sw_formats) {
269cabdff1aSopenharmony_ci                err = AVERROR(ENOMEM);
270cabdff1aSopenharmony_ci                goto fail;
271cabdff1aSopenharmony_ci            }
272cabdff1aSopenharmony_ci
273cabdff1aSopenharmony_ci            for (i = j = 0; i < attr_count; i++) {
274cabdff1aSopenharmony_ci                int k;
275cabdff1aSopenharmony_ci
276cabdff1aSopenharmony_ci                if (attr_list[i].type != VASurfaceAttribPixelFormat)
277cabdff1aSopenharmony_ci                    continue;
278cabdff1aSopenharmony_ci                fourcc = attr_list[i].value.value.i;
279cabdff1aSopenharmony_ci                pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
280cabdff1aSopenharmony_ci
281cabdff1aSopenharmony_ci                if (pix_fmt == AV_PIX_FMT_NONE)
282cabdff1aSopenharmony_ci                    continue;
283cabdff1aSopenharmony_ci
284cabdff1aSopenharmony_ci                for (k = 0; k < j; k++) {
285cabdff1aSopenharmony_ci                    if (constraints->valid_sw_formats[k] == pix_fmt)
286cabdff1aSopenharmony_ci                        break;
287cabdff1aSopenharmony_ci                }
288cabdff1aSopenharmony_ci
289cabdff1aSopenharmony_ci                if (k == j)
290cabdff1aSopenharmony_ci                    constraints->valid_sw_formats[j++] = pix_fmt;
291cabdff1aSopenharmony_ci            }
292cabdff1aSopenharmony_ci            constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
293cabdff1aSopenharmony_ci        }
294cabdff1aSopenharmony_ci    } else {
295cabdff1aSopenharmony_ci        // No configuration supplied.
296cabdff1aSopenharmony_ci        // Return the full set of image formats known by the implementation.
297cabdff1aSopenharmony_ci        constraints->valid_sw_formats = av_malloc_array(ctx->nb_formats + 1,
298cabdff1aSopenharmony_ci                                                        sizeof(pix_fmt));
299cabdff1aSopenharmony_ci        if (!constraints->valid_sw_formats) {
300cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
301cabdff1aSopenharmony_ci            goto fail;
302cabdff1aSopenharmony_ci        }
303cabdff1aSopenharmony_ci        for (i = j = 0; i < ctx->nb_formats; i++) {
304cabdff1aSopenharmony_ci            int k;
305cabdff1aSopenharmony_ci
306cabdff1aSopenharmony_ci            for (k = 0; k < j; k++) {
307cabdff1aSopenharmony_ci                if (constraints->valid_sw_formats[k] == ctx->formats[i].pix_fmt)
308cabdff1aSopenharmony_ci                    break;
309cabdff1aSopenharmony_ci            }
310cabdff1aSopenharmony_ci
311cabdff1aSopenharmony_ci            if (k == j)
312cabdff1aSopenharmony_ci                constraints->valid_sw_formats[j++] = ctx->formats[i].pix_fmt;
313cabdff1aSopenharmony_ci        }
314cabdff1aSopenharmony_ci
315cabdff1aSopenharmony_ci        constraints->valid_sw_formats[j] = AV_PIX_FMT_NONE;
316cabdff1aSopenharmony_ci    }
317cabdff1aSopenharmony_ci
318cabdff1aSopenharmony_ci    constraints->valid_hw_formats = av_malloc_array(2, sizeof(pix_fmt));
319cabdff1aSopenharmony_ci    if (!constraints->valid_hw_formats) {
320cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
321cabdff1aSopenharmony_ci        goto fail;
322cabdff1aSopenharmony_ci    }
323cabdff1aSopenharmony_ci    constraints->valid_hw_formats[0] = AV_PIX_FMT_VAAPI;
324cabdff1aSopenharmony_ci    constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
325cabdff1aSopenharmony_ci
326cabdff1aSopenharmony_ci    err = 0;
327cabdff1aSopenharmony_cifail:
328cabdff1aSopenharmony_ci    av_freep(&attr_list);
329cabdff1aSopenharmony_ci    return err;
330cabdff1aSopenharmony_ci}
331cabdff1aSopenharmony_ci
332cabdff1aSopenharmony_cistatic const struct {
333cabdff1aSopenharmony_ci    const char *friendly_name;
334cabdff1aSopenharmony_ci    const char *match_string;
335cabdff1aSopenharmony_ci    unsigned int quirks;
336cabdff1aSopenharmony_ci} vaapi_driver_quirks_table[] = {
337cabdff1aSopenharmony_ci#if !VA_CHECK_VERSION(1, 0, 0)
338cabdff1aSopenharmony_ci    // The i965 driver did not conform before version 2.0.
339cabdff1aSopenharmony_ci    {
340cabdff1aSopenharmony_ci        "Intel i965 (Quick Sync)",
341cabdff1aSopenharmony_ci        "i965",
342cabdff1aSopenharmony_ci        AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS,
343cabdff1aSopenharmony_ci    },
344cabdff1aSopenharmony_ci#endif
345cabdff1aSopenharmony_ci    {
346cabdff1aSopenharmony_ci        "Intel iHD",
347cabdff1aSopenharmony_ci        "ubit",
348cabdff1aSopenharmony_ci        AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE,
349cabdff1aSopenharmony_ci    },
350cabdff1aSopenharmony_ci    {
351cabdff1aSopenharmony_ci        "VDPAU wrapper",
352cabdff1aSopenharmony_ci        "Splitted-Desktop Systems VDPAU backend for VA-API",
353cabdff1aSopenharmony_ci        AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES,
354cabdff1aSopenharmony_ci    },
355cabdff1aSopenharmony_ci};
356cabdff1aSopenharmony_ci
357cabdff1aSopenharmony_cistatic int vaapi_device_init(AVHWDeviceContext *hwdev)
358cabdff1aSopenharmony_ci{
359cabdff1aSopenharmony_ci    VAAPIDeviceContext *ctx = hwdev->internal->priv;
360cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwdev->hwctx;
361cabdff1aSopenharmony_ci    VAImageFormat *image_list = NULL;
362cabdff1aSopenharmony_ci    VAStatus vas;
363cabdff1aSopenharmony_ci    const char *vendor_string;
364cabdff1aSopenharmony_ci    int err, i, image_count;
365cabdff1aSopenharmony_ci    enum AVPixelFormat pix_fmt;
366cabdff1aSopenharmony_ci    unsigned int fourcc;
367cabdff1aSopenharmony_ci
368cabdff1aSopenharmony_ci    image_count = vaMaxNumImageFormats(hwctx->display);
369cabdff1aSopenharmony_ci    if (image_count <= 0) {
370cabdff1aSopenharmony_ci        err = AVERROR(EIO);
371cabdff1aSopenharmony_ci        goto fail;
372cabdff1aSopenharmony_ci    }
373cabdff1aSopenharmony_ci    image_list = av_malloc(image_count * sizeof(*image_list));
374cabdff1aSopenharmony_ci    if (!image_list) {
375cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
376cabdff1aSopenharmony_ci        goto fail;
377cabdff1aSopenharmony_ci    }
378cabdff1aSopenharmony_ci    vas = vaQueryImageFormats(hwctx->display, image_list, &image_count);
379cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
380cabdff1aSopenharmony_ci        err = AVERROR(EIO);
381cabdff1aSopenharmony_ci        goto fail;
382cabdff1aSopenharmony_ci    }
383cabdff1aSopenharmony_ci
384cabdff1aSopenharmony_ci    ctx->formats  = av_malloc(image_count * sizeof(*ctx->formats));
385cabdff1aSopenharmony_ci    if (!ctx->formats) {
386cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
387cabdff1aSopenharmony_ci        goto fail;
388cabdff1aSopenharmony_ci    }
389cabdff1aSopenharmony_ci    ctx->nb_formats = 0;
390cabdff1aSopenharmony_ci    for (i = 0; i < image_count; i++) {
391cabdff1aSopenharmony_ci        fourcc  = image_list[i].fourcc;
392cabdff1aSopenharmony_ci        pix_fmt = vaapi_pix_fmt_from_fourcc(fourcc);
393cabdff1aSopenharmony_ci        if (pix_fmt == AV_PIX_FMT_NONE) {
394cabdff1aSopenharmony_ci            av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> unknown.\n",
395cabdff1aSopenharmony_ci                   fourcc);
396cabdff1aSopenharmony_ci        } else {
397cabdff1aSopenharmony_ci            av_log(hwdev, AV_LOG_DEBUG, "Format %#x -> %s.\n",
398cabdff1aSopenharmony_ci                   fourcc, av_get_pix_fmt_name(pix_fmt));
399cabdff1aSopenharmony_ci            ctx->formats[ctx->nb_formats].pix_fmt      = pix_fmt;
400cabdff1aSopenharmony_ci            ctx->formats[ctx->nb_formats].image_format = image_list[i];
401cabdff1aSopenharmony_ci            ++ctx->nb_formats;
402cabdff1aSopenharmony_ci        }
403cabdff1aSopenharmony_ci    }
404cabdff1aSopenharmony_ci
405cabdff1aSopenharmony_ci    vendor_string = vaQueryVendorString(hwctx->display);
406cabdff1aSopenharmony_ci    if (vendor_string)
407cabdff1aSopenharmony_ci        av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string);
408cabdff1aSopenharmony_ci
409cabdff1aSopenharmony_ci    if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) {
410cabdff1aSopenharmony_ci        av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n",
411cabdff1aSopenharmony_ci               hwctx->driver_quirks);
412cabdff1aSopenharmony_ci    } else {
413cabdff1aSopenharmony_ci        // Detect the driver in use and set quirk flags if necessary.
414cabdff1aSopenharmony_ci        hwctx->driver_quirks = 0;
415cabdff1aSopenharmony_ci        if (vendor_string) {
416cabdff1aSopenharmony_ci            for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) {
417cabdff1aSopenharmony_ci                if (strstr(vendor_string,
418cabdff1aSopenharmony_ci                           vaapi_driver_quirks_table[i].match_string)) {
419cabdff1aSopenharmony_ci                    av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string "
420cabdff1aSopenharmony_ci                           "as known nonstandard driver \"%s\", setting "
421cabdff1aSopenharmony_ci                           "quirks (%#x).\n",
422cabdff1aSopenharmony_ci                           vaapi_driver_quirks_table[i].friendly_name,
423cabdff1aSopenharmony_ci                           vaapi_driver_quirks_table[i].quirks);
424cabdff1aSopenharmony_ci                    hwctx->driver_quirks |=
425cabdff1aSopenharmony_ci                        vaapi_driver_quirks_table[i].quirks;
426cabdff1aSopenharmony_ci                    break;
427cabdff1aSopenharmony_ci                }
428cabdff1aSopenharmony_ci            }
429cabdff1aSopenharmony_ci            if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) {
430cabdff1aSopenharmony_ci                av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known "
431cabdff1aSopenharmony_ci                       "nonstandard list, using standard behaviour.\n");
432cabdff1aSopenharmony_ci            }
433cabdff1aSopenharmony_ci        } else {
434cabdff1aSopenharmony_ci            av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, "
435cabdff1aSopenharmony_ci                   "assuming standard behaviour.\n");
436cabdff1aSopenharmony_ci        }
437cabdff1aSopenharmony_ci    }
438cabdff1aSopenharmony_ci
439cabdff1aSopenharmony_ci    av_free(image_list);
440cabdff1aSopenharmony_ci    return 0;
441cabdff1aSopenharmony_cifail:
442cabdff1aSopenharmony_ci    av_freep(&ctx->formats);
443cabdff1aSopenharmony_ci    av_free(image_list);
444cabdff1aSopenharmony_ci    return err;
445cabdff1aSopenharmony_ci}
446cabdff1aSopenharmony_ci
447cabdff1aSopenharmony_cistatic void vaapi_device_uninit(AVHWDeviceContext *hwdev)
448cabdff1aSopenharmony_ci{
449cabdff1aSopenharmony_ci    VAAPIDeviceContext *ctx = hwdev->internal->priv;
450cabdff1aSopenharmony_ci
451cabdff1aSopenharmony_ci    av_freep(&ctx->formats);
452cabdff1aSopenharmony_ci}
453cabdff1aSopenharmony_ci
454cabdff1aSopenharmony_cistatic void vaapi_buffer_free(void *opaque, uint8_t *data)
455cabdff1aSopenharmony_ci{
456cabdff1aSopenharmony_ci    AVHWFramesContext     *hwfc = opaque;
457cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
458cabdff1aSopenharmony_ci    VASurfaceID surface_id;
459cabdff1aSopenharmony_ci    VAStatus vas;
460cabdff1aSopenharmony_ci
461cabdff1aSopenharmony_ci    surface_id = (VASurfaceID)(uintptr_t)data;
462cabdff1aSopenharmony_ci
463cabdff1aSopenharmony_ci    vas = vaDestroySurfaces(hwctx->display, &surface_id, 1);
464cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
465cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to destroy surface %#x: "
466cabdff1aSopenharmony_ci               "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
467cabdff1aSopenharmony_ci    }
468cabdff1aSopenharmony_ci}
469cabdff1aSopenharmony_ci
470cabdff1aSopenharmony_cistatic AVBufferRef *vaapi_pool_alloc(void *opaque, size_t size)
471cabdff1aSopenharmony_ci{
472cabdff1aSopenharmony_ci    AVHWFramesContext     *hwfc = opaque;
473cabdff1aSopenharmony_ci    VAAPIFramesContext     *ctx = hwfc->internal->priv;
474cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
475cabdff1aSopenharmony_ci    AVVAAPIFramesContext  *avfc = hwfc->hwctx;
476cabdff1aSopenharmony_ci    VASurfaceID surface_id;
477cabdff1aSopenharmony_ci    VAStatus vas;
478cabdff1aSopenharmony_ci    AVBufferRef *ref;
479cabdff1aSopenharmony_ci
480cabdff1aSopenharmony_ci    if (hwfc->initial_pool_size > 0 &&
481cabdff1aSopenharmony_ci        avfc->nb_surfaces >= hwfc->initial_pool_size)
482cabdff1aSopenharmony_ci        return NULL;
483cabdff1aSopenharmony_ci
484cabdff1aSopenharmony_ci    vas = vaCreateSurfaces(hwctx->display, ctx->rt_format,
485cabdff1aSopenharmony_ci                           hwfc->width, hwfc->height,
486cabdff1aSopenharmony_ci                           &surface_id, 1,
487cabdff1aSopenharmony_ci                           ctx->attributes, ctx->nb_attributes);
488cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
489cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to create surface: "
490cabdff1aSopenharmony_ci               "%d (%s).\n", vas, vaErrorStr(vas));
491cabdff1aSopenharmony_ci        return NULL;
492cabdff1aSopenharmony_ci    }
493cabdff1aSopenharmony_ci    av_log(hwfc, AV_LOG_DEBUG, "Created surface %#x.\n", surface_id);
494cabdff1aSopenharmony_ci
495cabdff1aSopenharmony_ci    ref = av_buffer_create((uint8_t*)(uintptr_t)surface_id,
496cabdff1aSopenharmony_ci                           sizeof(surface_id), &vaapi_buffer_free,
497cabdff1aSopenharmony_ci                           hwfc, AV_BUFFER_FLAG_READONLY);
498cabdff1aSopenharmony_ci    if (!ref) {
499cabdff1aSopenharmony_ci        vaDestroySurfaces(hwctx->display, &surface_id, 1);
500cabdff1aSopenharmony_ci        return NULL;
501cabdff1aSopenharmony_ci    }
502cabdff1aSopenharmony_ci
503cabdff1aSopenharmony_ci    if (hwfc->initial_pool_size > 0) {
504cabdff1aSopenharmony_ci        // This is a fixed-size pool, so we must still be in the initial
505cabdff1aSopenharmony_ci        // allocation sequence.
506cabdff1aSopenharmony_ci        av_assert0(avfc->nb_surfaces < hwfc->initial_pool_size);
507cabdff1aSopenharmony_ci        avfc->surface_ids[avfc->nb_surfaces] = surface_id;
508cabdff1aSopenharmony_ci        ++avfc->nb_surfaces;
509cabdff1aSopenharmony_ci    }
510cabdff1aSopenharmony_ci
511cabdff1aSopenharmony_ci    return ref;
512cabdff1aSopenharmony_ci}
513cabdff1aSopenharmony_ci
514cabdff1aSopenharmony_cistatic int vaapi_frames_init(AVHWFramesContext *hwfc)
515cabdff1aSopenharmony_ci{
516cabdff1aSopenharmony_ci    AVVAAPIFramesContext  *avfc = hwfc->hwctx;
517cabdff1aSopenharmony_ci    VAAPIFramesContext     *ctx = hwfc->internal->priv;
518cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
519cabdff1aSopenharmony_ci    const VAAPIFormatDescriptor *desc;
520cabdff1aSopenharmony_ci    VAImageFormat *expected_format;
521cabdff1aSopenharmony_ci    AVBufferRef *test_surface = NULL;
522cabdff1aSopenharmony_ci    VASurfaceID test_surface_id;
523cabdff1aSopenharmony_ci    VAImage test_image;
524cabdff1aSopenharmony_ci    VAStatus vas;
525cabdff1aSopenharmony_ci    int err, i;
526cabdff1aSopenharmony_ci
527cabdff1aSopenharmony_ci    desc = vaapi_format_from_pix_fmt(hwfc->sw_format);
528cabdff1aSopenharmony_ci    if (!desc) {
529cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n",
530cabdff1aSopenharmony_ci               av_get_pix_fmt_name(hwfc->sw_format));
531cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
532cabdff1aSopenharmony_ci    }
533cabdff1aSopenharmony_ci
534cabdff1aSopenharmony_ci    if (!hwfc->pool) {
535cabdff1aSopenharmony_ci        if (!(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES)) {
536cabdff1aSopenharmony_ci            int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE);
537cabdff1aSopenharmony_ci            int need_pixel_format = 1;
538cabdff1aSopenharmony_ci            for (i = 0; i < avfc->nb_attributes; i++) {
539cabdff1aSopenharmony_ci                if (avfc->attributes[i].type == VASurfaceAttribMemoryType)
540cabdff1aSopenharmony_ci                    need_memory_type  = 0;
541cabdff1aSopenharmony_ci                if (avfc->attributes[i].type == VASurfaceAttribPixelFormat)
542cabdff1aSopenharmony_ci                    need_pixel_format = 0;
543cabdff1aSopenharmony_ci            }
544cabdff1aSopenharmony_ci            ctx->nb_attributes =
545cabdff1aSopenharmony_ci                avfc->nb_attributes + need_memory_type + need_pixel_format;
546cabdff1aSopenharmony_ci
547cabdff1aSopenharmony_ci            ctx->attributes = av_malloc(ctx->nb_attributes *
548cabdff1aSopenharmony_ci                                        sizeof(*ctx->attributes));
549cabdff1aSopenharmony_ci            if (!ctx->attributes) {
550cabdff1aSopenharmony_ci                err = AVERROR(ENOMEM);
551cabdff1aSopenharmony_ci                goto fail;
552cabdff1aSopenharmony_ci            }
553cabdff1aSopenharmony_ci
554cabdff1aSopenharmony_ci            for (i = 0; i < avfc->nb_attributes; i++)
555cabdff1aSopenharmony_ci                ctx->attributes[i] = avfc->attributes[i];
556cabdff1aSopenharmony_ci            if (need_memory_type) {
557cabdff1aSopenharmony_ci                ctx->attributes[i++] = (VASurfaceAttrib) {
558cabdff1aSopenharmony_ci                    .type          = VASurfaceAttribMemoryType,
559cabdff1aSopenharmony_ci                    .flags         = VA_SURFACE_ATTRIB_SETTABLE,
560cabdff1aSopenharmony_ci                    .value.type    = VAGenericValueTypeInteger,
561cabdff1aSopenharmony_ci                    .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA,
562cabdff1aSopenharmony_ci                };
563cabdff1aSopenharmony_ci            }
564cabdff1aSopenharmony_ci            if (need_pixel_format) {
565cabdff1aSopenharmony_ci                ctx->attributes[i++] = (VASurfaceAttrib) {
566cabdff1aSopenharmony_ci                    .type          = VASurfaceAttribPixelFormat,
567cabdff1aSopenharmony_ci                    .flags         = VA_SURFACE_ATTRIB_SETTABLE,
568cabdff1aSopenharmony_ci                    .value.type    = VAGenericValueTypeInteger,
569cabdff1aSopenharmony_ci                    .value.value.i = desc->fourcc,
570cabdff1aSopenharmony_ci                };
571cabdff1aSopenharmony_ci            }
572cabdff1aSopenharmony_ci            av_assert0(i == ctx->nb_attributes);
573cabdff1aSopenharmony_ci        } else {
574cabdff1aSopenharmony_ci            ctx->attributes = NULL;
575cabdff1aSopenharmony_ci            ctx->nb_attributes = 0;
576cabdff1aSopenharmony_ci        }
577cabdff1aSopenharmony_ci
578cabdff1aSopenharmony_ci        ctx->rt_format = desc->rt_format;
579cabdff1aSopenharmony_ci
580cabdff1aSopenharmony_ci        if (hwfc->initial_pool_size > 0) {
581cabdff1aSopenharmony_ci            // This pool will be usable as a render target, so we need to store
582cabdff1aSopenharmony_ci            // all of the surface IDs somewhere that vaCreateContext() calls
583cabdff1aSopenharmony_ci            // will be able to access them.
584cabdff1aSopenharmony_ci            avfc->nb_surfaces = 0;
585cabdff1aSopenharmony_ci            avfc->surface_ids = av_malloc(hwfc->initial_pool_size *
586cabdff1aSopenharmony_ci                                          sizeof(*avfc->surface_ids));
587cabdff1aSopenharmony_ci            if (!avfc->surface_ids) {
588cabdff1aSopenharmony_ci                err = AVERROR(ENOMEM);
589cabdff1aSopenharmony_ci                goto fail;
590cabdff1aSopenharmony_ci            }
591cabdff1aSopenharmony_ci        } else {
592cabdff1aSopenharmony_ci            // This pool allows dynamic sizing, and will not be usable as a
593cabdff1aSopenharmony_ci            // render target.
594cabdff1aSopenharmony_ci            avfc->nb_surfaces = 0;
595cabdff1aSopenharmony_ci            avfc->surface_ids = NULL;
596cabdff1aSopenharmony_ci        }
597cabdff1aSopenharmony_ci
598cabdff1aSopenharmony_ci        hwfc->internal->pool_internal =
599cabdff1aSopenharmony_ci            av_buffer_pool_init2(sizeof(VASurfaceID), hwfc,
600cabdff1aSopenharmony_ci                                 &vaapi_pool_alloc, NULL);
601cabdff1aSopenharmony_ci        if (!hwfc->internal->pool_internal) {
602cabdff1aSopenharmony_ci            av_log(hwfc, AV_LOG_ERROR, "Failed to create VAAPI surface pool.\n");
603cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
604cabdff1aSopenharmony_ci            goto fail;
605cabdff1aSopenharmony_ci        }
606cabdff1aSopenharmony_ci    }
607cabdff1aSopenharmony_ci
608cabdff1aSopenharmony_ci    // Allocate a single surface to test whether vaDeriveImage() is going
609cabdff1aSopenharmony_ci    // to work for the specific configuration.
610cabdff1aSopenharmony_ci    if (hwfc->pool) {
611cabdff1aSopenharmony_ci        test_surface = av_buffer_pool_get(hwfc->pool);
612cabdff1aSopenharmony_ci        if (!test_surface) {
613cabdff1aSopenharmony_ci            av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
614cabdff1aSopenharmony_ci                   "user-configured buffer pool.\n");
615cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
616cabdff1aSopenharmony_ci            goto fail;
617cabdff1aSopenharmony_ci        }
618cabdff1aSopenharmony_ci    } else {
619cabdff1aSopenharmony_ci        test_surface = av_buffer_pool_get(hwfc->internal->pool_internal);
620cabdff1aSopenharmony_ci        if (!test_surface) {
621cabdff1aSopenharmony_ci            av_log(hwfc, AV_LOG_ERROR, "Unable to allocate a surface from "
622cabdff1aSopenharmony_ci                   "internal buffer pool.\n");
623cabdff1aSopenharmony_ci            err = AVERROR(ENOMEM);
624cabdff1aSopenharmony_ci            goto fail;
625cabdff1aSopenharmony_ci        }
626cabdff1aSopenharmony_ci    }
627cabdff1aSopenharmony_ci    test_surface_id = (VASurfaceID)(uintptr_t)test_surface->data;
628cabdff1aSopenharmony_ci
629cabdff1aSopenharmony_ci    ctx->derive_works = 0;
630cabdff1aSopenharmony_ci
631cabdff1aSopenharmony_ci    err = vaapi_get_image_format(hwfc->device_ctx,
632cabdff1aSopenharmony_ci                                 hwfc->sw_format, &expected_format);
633cabdff1aSopenharmony_ci    if (err == 0) {
634cabdff1aSopenharmony_ci        vas = vaDeriveImage(hwctx->display, test_surface_id, &test_image);
635cabdff1aSopenharmony_ci        if (vas == VA_STATUS_SUCCESS) {
636cabdff1aSopenharmony_ci            if (expected_format->fourcc == test_image.format.fourcc) {
637cabdff1aSopenharmony_ci                av_log(hwfc, AV_LOG_DEBUG, "Direct mapping possible.\n");
638cabdff1aSopenharmony_ci                ctx->derive_works = 1;
639cabdff1aSopenharmony_ci            } else {
640cabdff1aSopenharmony_ci                av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
641cabdff1aSopenharmony_ci                       "derived image format %08x does not match "
642cabdff1aSopenharmony_ci                       "expected format %08x.\n",
643cabdff1aSopenharmony_ci                       expected_format->fourcc, test_image.format.fourcc);
644cabdff1aSopenharmony_ci            }
645cabdff1aSopenharmony_ci            vaDestroyImage(hwctx->display, test_image.image_id);
646cabdff1aSopenharmony_ci        } else {
647cabdff1aSopenharmony_ci            av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
648cabdff1aSopenharmony_ci                   "deriving image does not work: "
649cabdff1aSopenharmony_ci                   "%d (%s).\n", vas, vaErrorStr(vas));
650cabdff1aSopenharmony_ci        }
651cabdff1aSopenharmony_ci    } else {
652cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_DEBUG, "Direct mapping disabled: "
653cabdff1aSopenharmony_ci               "image format is not supported.\n");
654cabdff1aSopenharmony_ci    }
655cabdff1aSopenharmony_ci
656cabdff1aSopenharmony_ci    av_buffer_unref(&test_surface);
657cabdff1aSopenharmony_ci    return 0;
658cabdff1aSopenharmony_ci
659cabdff1aSopenharmony_cifail:
660cabdff1aSopenharmony_ci    av_buffer_unref(&test_surface);
661cabdff1aSopenharmony_ci    av_freep(&avfc->surface_ids);
662cabdff1aSopenharmony_ci    av_freep(&ctx->attributes);
663cabdff1aSopenharmony_ci    return err;
664cabdff1aSopenharmony_ci}
665cabdff1aSopenharmony_ci
666cabdff1aSopenharmony_cistatic void vaapi_frames_uninit(AVHWFramesContext *hwfc)
667cabdff1aSopenharmony_ci{
668cabdff1aSopenharmony_ci    AVVAAPIFramesContext *avfc = hwfc->hwctx;
669cabdff1aSopenharmony_ci    VAAPIFramesContext    *ctx = hwfc->internal->priv;
670cabdff1aSopenharmony_ci
671cabdff1aSopenharmony_ci    av_freep(&avfc->surface_ids);
672cabdff1aSopenharmony_ci    av_freep(&ctx->attributes);
673cabdff1aSopenharmony_ci}
674cabdff1aSopenharmony_ci
675cabdff1aSopenharmony_cistatic int vaapi_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame)
676cabdff1aSopenharmony_ci{
677cabdff1aSopenharmony_ci    frame->buf[0] = av_buffer_pool_get(hwfc->pool);
678cabdff1aSopenharmony_ci    if (!frame->buf[0])
679cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
680cabdff1aSopenharmony_ci
681cabdff1aSopenharmony_ci    frame->data[3] = frame->buf[0]->data;
682cabdff1aSopenharmony_ci    frame->format  = AV_PIX_FMT_VAAPI;
683cabdff1aSopenharmony_ci    frame->width   = hwfc->width;
684cabdff1aSopenharmony_ci    frame->height  = hwfc->height;
685cabdff1aSopenharmony_ci
686cabdff1aSopenharmony_ci    return 0;
687cabdff1aSopenharmony_ci}
688cabdff1aSopenharmony_ci
689cabdff1aSopenharmony_cistatic int vaapi_transfer_get_formats(AVHWFramesContext *hwfc,
690cabdff1aSopenharmony_ci                                      enum AVHWFrameTransferDirection dir,
691cabdff1aSopenharmony_ci                                      enum AVPixelFormat **formats)
692cabdff1aSopenharmony_ci{
693cabdff1aSopenharmony_ci    VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv;
694cabdff1aSopenharmony_ci    enum AVPixelFormat *pix_fmts;
695cabdff1aSopenharmony_ci    int i, k, sw_format_available;
696cabdff1aSopenharmony_ci
697cabdff1aSopenharmony_ci    sw_format_available = 0;
698cabdff1aSopenharmony_ci    for (i = 0; i < ctx->nb_formats; i++) {
699cabdff1aSopenharmony_ci        if (ctx->formats[i].pix_fmt == hwfc->sw_format)
700cabdff1aSopenharmony_ci            sw_format_available = 1;
701cabdff1aSopenharmony_ci    }
702cabdff1aSopenharmony_ci
703cabdff1aSopenharmony_ci    pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts));
704cabdff1aSopenharmony_ci    if (!pix_fmts)
705cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
706cabdff1aSopenharmony_ci
707cabdff1aSopenharmony_ci    if (sw_format_available) {
708cabdff1aSopenharmony_ci        pix_fmts[0] = hwfc->sw_format;
709cabdff1aSopenharmony_ci        k = 1;
710cabdff1aSopenharmony_ci    } else {
711cabdff1aSopenharmony_ci        k = 0;
712cabdff1aSopenharmony_ci    }
713cabdff1aSopenharmony_ci    for (i = 0; i < ctx->nb_formats; i++) {
714cabdff1aSopenharmony_ci        if (ctx->formats[i].pix_fmt == hwfc->sw_format)
715cabdff1aSopenharmony_ci            continue;
716cabdff1aSopenharmony_ci        av_assert0(k < ctx->nb_formats);
717cabdff1aSopenharmony_ci        pix_fmts[k++] = ctx->formats[i].pix_fmt;
718cabdff1aSopenharmony_ci    }
719cabdff1aSopenharmony_ci    pix_fmts[k] = AV_PIX_FMT_NONE;
720cabdff1aSopenharmony_ci
721cabdff1aSopenharmony_ci    *formats = pix_fmts;
722cabdff1aSopenharmony_ci    return 0;
723cabdff1aSopenharmony_ci}
724cabdff1aSopenharmony_ci
725cabdff1aSopenharmony_cistatic void vaapi_unmap_frame(AVHWFramesContext *hwfc,
726cabdff1aSopenharmony_ci                              HWMapDescriptor *hwmap)
727cabdff1aSopenharmony_ci{
728cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
729cabdff1aSopenharmony_ci    VAAPIMapping           *map = hwmap->priv;
730cabdff1aSopenharmony_ci    VASurfaceID surface_id;
731cabdff1aSopenharmony_ci    VAStatus vas;
732cabdff1aSopenharmony_ci
733cabdff1aSopenharmony_ci    surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
734cabdff1aSopenharmony_ci    av_log(hwfc, AV_LOG_DEBUG, "Unmap surface %#x.\n", surface_id);
735cabdff1aSopenharmony_ci
736cabdff1aSopenharmony_ci    vas = vaUnmapBuffer(hwctx->display, map->image.buf);
737cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
738cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to unmap image from surface "
739cabdff1aSopenharmony_ci               "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
740cabdff1aSopenharmony_ci    }
741cabdff1aSopenharmony_ci
742cabdff1aSopenharmony_ci    if ((map->flags & AV_HWFRAME_MAP_WRITE) &&
743cabdff1aSopenharmony_ci        !(map->flags & AV_HWFRAME_MAP_DIRECT)) {
744cabdff1aSopenharmony_ci        vas = vaPutImage(hwctx->display, surface_id, map->image.image_id,
745cabdff1aSopenharmony_ci                         0, 0, hwfc->width, hwfc->height,
746cabdff1aSopenharmony_ci                         0, 0, hwfc->width, hwfc->height);
747cabdff1aSopenharmony_ci        if (vas != VA_STATUS_SUCCESS) {
748cabdff1aSopenharmony_ci            av_log(hwfc, AV_LOG_ERROR, "Failed to write image to surface "
749cabdff1aSopenharmony_ci                   "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
750cabdff1aSopenharmony_ci        }
751cabdff1aSopenharmony_ci    }
752cabdff1aSopenharmony_ci
753cabdff1aSopenharmony_ci    vas = vaDestroyImage(hwctx->display, map->image.image_id);
754cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
755cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image from surface "
756cabdff1aSopenharmony_ci               "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
757cabdff1aSopenharmony_ci    }
758cabdff1aSopenharmony_ci
759cabdff1aSopenharmony_ci    av_free(map);
760cabdff1aSopenharmony_ci}
761cabdff1aSopenharmony_ci
762cabdff1aSopenharmony_cistatic int vaapi_map_frame(AVHWFramesContext *hwfc,
763cabdff1aSopenharmony_ci                           AVFrame *dst, const AVFrame *src, int flags)
764cabdff1aSopenharmony_ci{
765cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
766cabdff1aSopenharmony_ci    VAAPIFramesContext *ctx = hwfc->internal->priv;
767cabdff1aSopenharmony_ci    VASurfaceID surface_id;
768cabdff1aSopenharmony_ci    const VAAPIFormatDescriptor *desc;
769cabdff1aSopenharmony_ci    VAImageFormat *image_format;
770cabdff1aSopenharmony_ci    VAAPIMapping *map;
771cabdff1aSopenharmony_ci    VAStatus vas;
772cabdff1aSopenharmony_ci    void *address = NULL;
773cabdff1aSopenharmony_ci    int err, i;
774cabdff1aSopenharmony_ci
775cabdff1aSopenharmony_ci    surface_id = (VASurfaceID)(uintptr_t)src->data[3];
776cabdff1aSopenharmony_ci    av_log(hwfc, AV_LOG_DEBUG, "Map surface %#x.\n", surface_id);
777cabdff1aSopenharmony_ci
778cabdff1aSopenharmony_ci    if (!ctx->derive_works && (flags & AV_HWFRAME_MAP_DIRECT)) {
779cabdff1aSopenharmony_ci        // Requested direct mapping but it is not possible.
780cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
781cabdff1aSopenharmony_ci    }
782cabdff1aSopenharmony_ci    if (dst->format == AV_PIX_FMT_NONE)
783cabdff1aSopenharmony_ci        dst->format = hwfc->sw_format;
784cabdff1aSopenharmony_ci    if (dst->format != hwfc->sw_format && (flags & AV_HWFRAME_MAP_DIRECT)) {
785cabdff1aSopenharmony_ci        // Requested direct mapping but the formats do not match.
786cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
787cabdff1aSopenharmony_ci    }
788cabdff1aSopenharmony_ci
789cabdff1aSopenharmony_ci    err = vaapi_get_image_format(hwfc->device_ctx, dst->format, &image_format);
790cabdff1aSopenharmony_ci    if (err < 0) {
791cabdff1aSopenharmony_ci        // Requested format is not a valid output format.
792cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
793cabdff1aSopenharmony_ci    }
794cabdff1aSopenharmony_ci
795cabdff1aSopenharmony_ci    map = av_malloc(sizeof(*map));
796cabdff1aSopenharmony_ci    if (!map)
797cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
798cabdff1aSopenharmony_ci    map->flags = flags;
799cabdff1aSopenharmony_ci    map->image.image_id = VA_INVALID_ID;
800cabdff1aSopenharmony_ci
801cabdff1aSopenharmony_ci    vas = vaSyncSurface(hwctx->display, surface_id);
802cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
803cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to sync surface "
804cabdff1aSopenharmony_ci               "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
805cabdff1aSopenharmony_ci        err = AVERROR(EIO);
806cabdff1aSopenharmony_ci        goto fail;
807cabdff1aSopenharmony_ci    }
808cabdff1aSopenharmony_ci
809cabdff1aSopenharmony_ci    // The memory which we map using derive need not be connected to the CPU
810cabdff1aSopenharmony_ci    // in a way conducive to fast access.  On Gen7-Gen9 Intel graphics, the
811cabdff1aSopenharmony_ci    // memory is mappable but not cached, so normal memcpy()-like access is
812cabdff1aSopenharmony_ci    // very slow to read it (but writing is ok).  It is possible to read much
813cabdff1aSopenharmony_ci    // faster with a copy routine which is aware of the limitation, but we
814cabdff1aSopenharmony_ci    // assume for now that the user is not aware of that and would therefore
815cabdff1aSopenharmony_ci    // prefer not to be given direct-mapped memory if they request read access.
816cabdff1aSopenharmony_ci    if (ctx->derive_works && dst->format == hwfc->sw_format &&
817cabdff1aSopenharmony_ci        ((flags & AV_HWFRAME_MAP_DIRECT) || !(flags & AV_HWFRAME_MAP_READ))) {
818cabdff1aSopenharmony_ci        vas = vaDeriveImage(hwctx->display, surface_id, &map->image);
819cabdff1aSopenharmony_ci        if (vas != VA_STATUS_SUCCESS) {
820cabdff1aSopenharmony_ci            av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
821cabdff1aSopenharmony_ci                   "surface %#x: %d (%s).\n",
822cabdff1aSopenharmony_ci                   surface_id, vas, vaErrorStr(vas));
823cabdff1aSopenharmony_ci            err = AVERROR(EIO);
824cabdff1aSopenharmony_ci            goto fail;
825cabdff1aSopenharmony_ci        }
826cabdff1aSopenharmony_ci        if (map->image.format.fourcc != image_format->fourcc) {
827cabdff1aSopenharmony_ci            av_log(hwfc, AV_LOG_ERROR, "Derive image of surface %#x "
828cabdff1aSopenharmony_ci                   "is in wrong format: expected %#08x, got %#08x.\n",
829cabdff1aSopenharmony_ci                   surface_id, image_format->fourcc, map->image.format.fourcc);
830cabdff1aSopenharmony_ci            err = AVERROR(EIO);
831cabdff1aSopenharmony_ci            goto fail;
832cabdff1aSopenharmony_ci        }
833cabdff1aSopenharmony_ci        map->flags |= AV_HWFRAME_MAP_DIRECT;
834cabdff1aSopenharmony_ci    } else {
835cabdff1aSopenharmony_ci        vas = vaCreateImage(hwctx->display, image_format,
836cabdff1aSopenharmony_ci                            hwfc->width, hwfc->height, &map->image);
837cabdff1aSopenharmony_ci        if (vas != VA_STATUS_SUCCESS) {
838cabdff1aSopenharmony_ci            av_log(hwfc, AV_LOG_ERROR, "Failed to create image for "
839cabdff1aSopenharmony_ci                   "surface %#x: %d (%s).\n",
840cabdff1aSopenharmony_ci                   surface_id, vas, vaErrorStr(vas));
841cabdff1aSopenharmony_ci            err = AVERROR(EIO);
842cabdff1aSopenharmony_ci            goto fail;
843cabdff1aSopenharmony_ci        }
844cabdff1aSopenharmony_ci        if (!(flags & AV_HWFRAME_MAP_OVERWRITE)) {
845cabdff1aSopenharmony_ci            vas = vaGetImage(hwctx->display, surface_id, 0, 0,
846cabdff1aSopenharmony_ci                             hwfc->width, hwfc->height, map->image.image_id);
847cabdff1aSopenharmony_ci            if (vas != VA_STATUS_SUCCESS) {
848cabdff1aSopenharmony_ci                av_log(hwfc, AV_LOG_ERROR, "Failed to read image from "
849cabdff1aSopenharmony_ci                       "surface %#x: %d (%s).\n",
850cabdff1aSopenharmony_ci                       surface_id, vas, vaErrorStr(vas));
851cabdff1aSopenharmony_ci                err = AVERROR(EIO);
852cabdff1aSopenharmony_ci                goto fail;
853cabdff1aSopenharmony_ci            }
854cabdff1aSopenharmony_ci        }
855cabdff1aSopenharmony_ci    }
856cabdff1aSopenharmony_ci
857cabdff1aSopenharmony_ci    vas = vaMapBuffer(hwctx->display, map->image.buf, &address);
858cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
859cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to map image from surface "
860cabdff1aSopenharmony_ci               "%#x: %d (%s).\n", surface_id, vas, vaErrorStr(vas));
861cabdff1aSopenharmony_ci        err = AVERROR(EIO);
862cabdff1aSopenharmony_ci        goto fail;
863cabdff1aSopenharmony_ci    }
864cabdff1aSopenharmony_ci
865cabdff1aSopenharmony_ci    err = ff_hwframe_map_create(src->hw_frames_ctx,
866cabdff1aSopenharmony_ci                                dst, src, &vaapi_unmap_frame, map);
867cabdff1aSopenharmony_ci    if (err < 0)
868cabdff1aSopenharmony_ci        goto fail;
869cabdff1aSopenharmony_ci
870cabdff1aSopenharmony_ci    dst->width  = src->width;
871cabdff1aSopenharmony_ci    dst->height = src->height;
872cabdff1aSopenharmony_ci
873cabdff1aSopenharmony_ci    for (i = 0; i < map->image.num_planes; i++) {
874cabdff1aSopenharmony_ci        dst->data[i] = (uint8_t*)address + map->image.offsets[i];
875cabdff1aSopenharmony_ci        dst->linesize[i] = map->image.pitches[i];
876cabdff1aSopenharmony_ci    }
877cabdff1aSopenharmony_ci
878cabdff1aSopenharmony_ci    desc = vaapi_format_from_fourcc(map->image.format.fourcc);
879cabdff1aSopenharmony_ci    if (desc && desc->chroma_planes_swapped) {
880cabdff1aSopenharmony_ci        // Chroma planes are YVU rather than YUV, so swap them.
881cabdff1aSopenharmony_ci        FFSWAP(uint8_t*, dst->data[1], dst->data[2]);
882cabdff1aSopenharmony_ci    }
883cabdff1aSopenharmony_ci
884cabdff1aSopenharmony_ci    return 0;
885cabdff1aSopenharmony_ci
886cabdff1aSopenharmony_cifail:
887cabdff1aSopenharmony_ci    if (map) {
888cabdff1aSopenharmony_ci        if (address)
889cabdff1aSopenharmony_ci            vaUnmapBuffer(hwctx->display, map->image.buf);
890cabdff1aSopenharmony_ci        if (map->image.image_id != VA_INVALID_ID)
891cabdff1aSopenharmony_ci            vaDestroyImage(hwctx->display, map->image.image_id);
892cabdff1aSopenharmony_ci        av_free(map);
893cabdff1aSopenharmony_ci    }
894cabdff1aSopenharmony_ci    return err;
895cabdff1aSopenharmony_ci}
896cabdff1aSopenharmony_ci
897cabdff1aSopenharmony_cistatic int vaapi_transfer_data_from(AVHWFramesContext *hwfc,
898cabdff1aSopenharmony_ci                                    AVFrame *dst, const AVFrame *src)
899cabdff1aSopenharmony_ci{
900cabdff1aSopenharmony_ci    AVFrame *map;
901cabdff1aSopenharmony_ci    int err;
902cabdff1aSopenharmony_ci
903cabdff1aSopenharmony_ci    if (dst->width > hwfc->width || dst->height > hwfc->height)
904cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
905cabdff1aSopenharmony_ci
906cabdff1aSopenharmony_ci    map = av_frame_alloc();
907cabdff1aSopenharmony_ci    if (!map)
908cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
909cabdff1aSopenharmony_ci    map->format = dst->format;
910cabdff1aSopenharmony_ci
911cabdff1aSopenharmony_ci    err = vaapi_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
912cabdff1aSopenharmony_ci    if (err)
913cabdff1aSopenharmony_ci        goto fail;
914cabdff1aSopenharmony_ci
915cabdff1aSopenharmony_ci    map->width  = dst->width;
916cabdff1aSopenharmony_ci    map->height = dst->height;
917cabdff1aSopenharmony_ci
918cabdff1aSopenharmony_ci    err = av_frame_copy(dst, map);
919cabdff1aSopenharmony_ci    if (err)
920cabdff1aSopenharmony_ci        goto fail;
921cabdff1aSopenharmony_ci
922cabdff1aSopenharmony_ci    err = 0;
923cabdff1aSopenharmony_cifail:
924cabdff1aSopenharmony_ci    av_frame_free(&map);
925cabdff1aSopenharmony_ci    return err;
926cabdff1aSopenharmony_ci}
927cabdff1aSopenharmony_ci
928cabdff1aSopenharmony_cistatic int vaapi_transfer_data_to(AVHWFramesContext *hwfc,
929cabdff1aSopenharmony_ci                                  AVFrame *dst, const AVFrame *src)
930cabdff1aSopenharmony_ci{
931cabdff1aSopenharmony_ci    AVFrame *map;
932cabdff1aSopenharmony_ci    int err;
933cabdff1aSopenharmony_ci
934cabdff1aSopenharmony_ci    if (src->width > hwfc->width || src->height > hwfc->height)
935cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
936cabdff1aSopenharmony_ci
937cabdff1aSopenharmony_ci    map = av_frame_alloc();
938cabdff1aSopenharmony_ci    if (!map)
939cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
940cabdff1aSopenharmony_ci    map->format = src->format;
941cabdff1aSopenharmony_ci
942cabdff1aSopenharmony_ci    err = vaapi_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
943cabdff1aSopenharmony_ci    if (err)
944cabdff1aSopenharmony_ci        goto fail;
945cabdff1aSopenharmony_ci
946cabdff1aSopenharmony_ci    map->width  = src->width;
947cabdff1aSopenharmony_ci    map->height = src->height;
948cabdff1aSopenharmony_ci
949cabdff1aSopenharmony_ci    err = av_frame_copy(map, src);
950cabdff1aSopenharmony_ci    if (err)
951cabdff1aSopenharmony_ci        goto fail;
952cabdff1aSopenharmony_ci
953cabdff1aSopenharmony_ci    err = 0;
954cabdff1aSopenharmony_cifail:
955cabdff1aSopenharmony_ci    av_frame_free(&map);
956cabdff1aSopenharmony_ci    return err;
957cabdff1aSopenharmony_ci}
958cabdff1aSopenharmony_ci
959cabdff1aSopenharmony_cistatic int vaapi_map_to_memory(AVHWFramesContext *hwfc, AVFrame *dst,
960cabdff1aSopenharmony_ci                               const AVFrame *src, int flags)
961cabdff1aSopenharmony_ci{
962cabdff1aSopenharmony_ci    int err;
963cabdff1aSopenharmony_ci
964cabdff1aSopenharmony_ci    if (dst->format != AV_PIX_FMT_NONE) {
965cabdff1aSopenharmony_ci        err = vaapi_get_image_format(hwfc->device_ctx, dst->format, NULL);
966cabdff1aSopenharmony_ci        if (err < 0)
967cabdff1aSopenharmony_ci            return AVERROR(ENOSYS);
968cabdff1aSopenharmony_ci    }
969cabdff1aSopenharmony_ci
970cabdff1aSopenharmony_ci    err = vaapi_map_frame(hwfc, dst, src, flags);
971cabdff1aSopenharmony_ci    if (err)
972cabdff1aSopenharmony_ci        return err;
973cabdff1aSopenharmony_ci
974cabdff1aSopenharmony_ci    err = av_frame_copy_props(dst, src);
975cabdff1aSopenharmony_ci    if (err)
976cabdff1aSopenharmony_ci        return err;
977cabdff1aSopenharmony_ci
978cabdff1aSopenharmony_ci    return 0;
979cabdff1aSopenharmony_ci}
980cabdff1aSopenharmony_ci
981cabdff1aSopenharmony_ci#if CONFIG_LIBDRM
982cabdff1aSopenharmony_ci
983cabdff1aSopenharmony_ci#define DRM_MAP(va, layers, ...) { \
984cabdff1aSopenharmony_ci        VA_FOURCC_ ## va, \
985cabdff1aSopenharmony_ci        layers, \
986cabdff1aSopenharmony_ci        { __VA_ARGS__ } \
987cabdff1aSopenharmony_ci    }
988cabdff1aSopenharmony_cistatic const struct {
989cabdff1aSopenharmony_ci    uint32_t va_fourcc;
990cabdff1aSopenharmony_ci    int   nb_layer_formats;
991cabdff1aSopenharmony_ci    uint32_t layer_formats[AV_DRM_MAX_PLANES];
992cabdff1aSopenharmony_ci} vaapi_drm_format_map[] = {
993cabdff1aSopenharmony_ci#ifdef DRM_FORMAT_R8
994cabdff1aSopenharmony_ci    DRM_MAP(NV12, 2, DRM_FORMAT_R8,  DRM_FORMAT_RG88),
995cabdff1aSopenharmony_ci    DRM_MAP(NV12, 2, DRM_FORMAT_R8,  DRM_FORMAT_GR88),
996cabdff1aSopenharmony_ci#endif
997cabdff1aSopenharmony_ci    DRM_MAP(NV12, 1, DRM_FORMAT_NV12),
998cabdff1aSopenharmony_ci#if defined(VA_FOURCC_P010) && defined(DRM_FORMAT_R16)
999cabdff1aSopenharmony_ci    DRM_MAP(P010, 2, DRM_FORMAT_R16, DRM_FORMAT_RG1616),
1000cabdff1aSopenharmony_ci#endif
1001cabdff1aSopenharmony_ci    DRM_MAP(BGRA, 1, DRM_FORMAT_ARGB8888),
1002cabdff1aSopenharmony_ci    DRM_MAP(BGRX, 1, DRM_FORMAT_XRGB8888),
1003cabdff1aSopenharmony_ci    DRM_MAP(RGBA, 1, DRM_FORMAT_ABGR8888),
1004cabdff1aSopenharmony_ci    DRM_MAP(RGBX, 1, DRM_FORMAT_XBGR8888),
1005cabdff1aSopenharmony_ci#ifdef VA_FOURCC_ABGR
1006cabdff1aSopenharmony_ci    DRM_MAP(ABGR, 1, DRM_FORMAT_RGBA8888),
1007cabdff1aSopenharmony_ci    DRM_MAP(XBGR, 1, DRM_FORMAT_RGBX8888),
1008cabdff1aSopenharmony_ci#endif
1009cabdff1aSopenharmony_ci    DRM_MAP(ARGB, 1, DRM_FORMAT_BGRA8888),
1010cabdff1aSopenharmony_ci    DRM_MAP(XRGB, 1, DRM_FORMAT_BGRX8888),
1011cabdff1aSopenharmony_ci};
1012cabdff1aSopenharmony_ci#undef DRM_MAP
1013cabdff1aSopenharmony_ci
1014cabdff1aSopenharmony_cistatic void vaapi_unmap_from_drm(AVHWFramesContext *dst_fc,
1015cabdff1aSopenharmony_ci                                 HWMapDescriptor *hwmap)
1016cabdff1aSopenharmony_ci{
1017cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx;
1018cabdff1aSopenharmony_ci
1019cabdff1aSopenharmony_ci    VASurfaceID surface_id = (VASurfaceID)(uintptr_t)hwmap->priv;
1020cabdff1aSopenharmony_ci
1021cabdff1aSopenharmony_ci    av_log(dst_fc, AV_LOG_DEBUG, "Destroy surface %#x.\n", surface_id);
1022cabdff1aSopenharmony_ci
1023cabdff1aSopenharmony_ci    vaDestroySurfaces(dst_dev->display, &surface_id, 1);
1024cabdff1aSopenharmony_ci}
1025cabdff1aSopenharmony_ci
1026cabdff1aSopenharmony_cistatic int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst,
1027cabdff1aSopenharmony_ci                              const AVFrame *src, int flags)
1028cabdff1aSopenharmony_ci{
1029cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(1, 1, 0)
1030cabdff1aSopenharmony_ci    VAAPIFramesContext     *src_vafc = src_fc->internal->priv;
1031cabdff1aSopenharmony_ci    int use_prime2;
1032cabdff1aSopenharmony_ci#else
1033cabdff1aSopenharmony_ci    int k;
1034cabdff1aSopenharmony_ci#endif
1035cabdff1aSopenharmony_ci    AVHWFramesContext      *dst_fc =
1036cabdff1aSopenharmony_ci        (AVHWFramesContext*)dst->hw_frames_ctx->data;
1037cabdff1aSopenharmony_ci    AVVAAPIDeviceContext  *dst_dev = dst_fc->device_ctx->hwctx;
1038cabdff1aSopenharmony_ci    const AVDRMFrameDescriptor *desc;
1039cabdff1aSopenharmony_ci    const VAAPIFormatDescriptor *format_desc;
1040cabdff1aSopenharmony_ci    VASurfaceID surface_id;
1041cabdff1aSopenharmony_ci    VAStatus vas = VA_STATUS_SUCCESS;
1042cabdff1aSopenharmony_ci    uint32_t va_fourcc;
1043cabdff1aSopenharmony_ci    int err, i, j;
1044cabdff1aSopenharmony_ci
1045cabdff1aSopenharmony_ci#if !VA_CHECK_VERSION(1, 1, 0)
1046cabdff1aSopenharmony_ci    unsigned long buffer_handle;
1047cabdff1aSopenharmony_ci    VASurfaceAttribExternalBuffers buffer_desc;
1048cabdff1aSopenharmony_ci    VASurfaceAttrib attrs[2] = {
1049cabdff1aSopenharmony_ci        {
1050cabdff1aSopenharmony_ci            .type  = VASurfaceAttribMemoryType,
1051cabdff1aSopenharmony_ci            .flags = VA_SURFACE_ATTRIB_SETTABLE,
1052cabdff1aSopenharmony_ci            .value.type    = VAGenericValueTypeInteger,
1053cabdff1aSopenharmony_ci            .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1054cabdff1aSopenharmony_ci        },
1055cabdff1aSopenharmony_ci        {
1056cabdff1aSopenharmony_ci            .type  = VASurfaceAttribExternalBufferDescriptor,
1057cabdff1aSopenharmony_ci            .flags = VA_SURFACE_ATTRIB_SETTABLE,
1058cabdff1aSopenharmony_ci            .value.type    = VAGenericValueTypePointer,
1059cabdff1aSopenharmony_ci            .value.value.p = &buffer_desc,
1060cabdff1aSopenharmony_ci        }
1061cabdff1aSopenharmony_ci    };
1062cabdff1aSopenharmony_ci#endif
1063cabdff1aSopenharmony_ci
1064cabdff1aSopenharmony_ci    desc = (AVDRMFrameDescriptor*)src->data[0];
1065cabdff1aSopenharmony_ci
1066cabdff1aSopenharmony_ci    if (desc->nb_objects != 1) {
1067cabdff1aSopenharmony_ci        av_log(dst_fc, AV_LOG_ERROR, "VAAPI can only map frames "
1068cabdff1aSopenharmony_ci               "made from a single DRM object.\n");
1069cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
1070cabdff1aSopenharmony_ci    }
1071cabdff1aSopenharmony_ci
1072cabdff1aSopenharmony_ci    va_fourcc = 0;
1073cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1074cabdff1aSopenharmony_ci        if (desc->nb_layers != vaapi_drm_format_map[i].nb_layer_formats)
1075cabdff1aSopenharmony_ci            continue;
1076cabdff1aSopenharmony_ci        for (j = 0; j < desc->nb_layers; j++) {
1077cabdff1aSopenharmony_ci            if (desc->layers[j].format !=
1078cabdff1aSopenharmony_ci                vaapi_drm_format_map[i].layer_formats[j])
1079cabdff1aSopenharmony_ci                break;
1080cabdff1aSopenharmony_ci        }
1081cabdff1aSopenharmony_ci        if (j != desc->nb_layers)
1082cabdff1aSopenharmony_ci            continue;
1083cabdff1aSopenharmony_ci        va_fourcc = vaapi_drm_format_map[i].va_fourcc;
1084cabdff1aSopenharmony_ci        break;
1085cabdff1aSopenharmony_ci    }
1086cabdff1aSopenharmony_ci    if (!va_fourcc) {
1087cabdff1aSopenharmony_ci        av_log(dst_fc, AV_LOG_ERROR, "DRM format not supported "
1088cabdff1aSopenharmony_ci               "by VAAPI.\n");
1089cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
1090cabdff1aSopenharmony_ci    }
1091cabdff1aSopenharmony_ci
1092cabdff1aSopenharmony_ci    av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as "
1093cabdff1aSopenharmony_ci           "%08x.\n", desc->objects[0].fd, va_fourcc);
1094cabdff1aSopenharmony_ci
1095cabdff1aSopenharmony_ci    format_desc = vaapi_format_from_fourcc(va_fourcc);
1096cabdff1aSopenharmony_ci    av_assert0(format_desc);
1097cabdff1aSopenharmony_ci
1098cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(1, 1, 0)
1099cabdff1aSopenharmony_ci    use_prime2 = !src_vafc->prime_2_import_unsupported &&
1100cabdff1aSopenharmony_ci                 desc->objects[0].format_modifier != DRM_FORMAT_MOD_INVALID;
1101cabdff1aSopenharmony_ci    if (use_prime2) {
1102cabdff1aSopenharmony_ci        VADRMPRIMESurfaceDescriptor prime_desc;
1103cabdff1aSopenharmony_ci        VASurfaceAttrib prime_attrs[2] = {
1104cabdff1aSopenharmony_ci            {
1105cabdff1aSopenharmony_ci                .type  = VASurfaceAttribMemoryType,
1106cabdff1aSopenharmony_ci                .flags = VA_SURFACE_ATTRIB_SETTABLE,
1107cabdff1aSopenharmony_ci                .value.type    = VAGenericValueTypeInteger,
1108cabdff1aSopenharmony_ci                .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1109cabdff1aSopenharmony_ci            },
1110cabdff1aSopenharmony_ci            {
1111cabdff1aSopenharmony_ci                .type  = VASurfaceAttribExternalBufferDescriptor,
1112cabdff1aSopenharmony_ci                .flags = VA_SURFACE_ATTRIB_SETTABLE,
1113cabdff1aSopenharmony_ci                .value.type    = VAGenericValueTypePointer,
1114cabdff1aSopenharmony_ci                .value.value.p = &prime_desc,
1115cabdff1aSopenharmony_ci            }
1116cabdff1aSopenharmony_ci        };
1117cabdff1aSopenharmony_ci        prime_desc.fourcc = va_fourcc;
1118cabdff1aSopenharmony_ci        prime_desc.width = src_fc->width;
1119cabdff1aSopenharmony_ci        prime_desc.height = src_fc->height;
1120cabdff1aSopenharmony_ci        prime_desc.num_objects = desc->nb_objects;
1121cabdff1aSopenharmony_ci        for (i = 0; i < desc->nb_objects; ++i) {
1122cabdff1aSopenharmony_ci            prime_desc.objects[i].fd = desc->objects[i].fd;
1123cabdff1aSopenharmony_ci            prime_desc.objects[i].size = desc->objects[i].size;
1124cabdff1aSopenharmony_ci            prime_desc.objects[i].drm_format_modifier =
1125cabdff1aSopenharmony_ci                    desc->objects[i].format_modifier;
1126cabdff1aSopenharmony_ci        }
1127cabdff1aSopenharmony_ci
1128cabdff1aSopenharmony_ci        prime_desc.num_layers = desc->nb_layers;
1129cabdff1aSopenharmony_ci        for (i = 0; i < desc->nb_layers; ++i) {
1130cabdff1aSopenharmony_ci            prime_desc.layers[i].drm_format = desc->layers[i].format;
1131cabdff1aSopenharmony_ci            prime_desc.layers[i].num_planes = desc->layers[i].nb_planes;
1132cabdff1aSopenharmony_ci            for (j = 0; j < desc->layers[i].nb_planes; ++j) {
1133cabdff1aSopenharmony_ci                prime_desc.layers[i].object_index[j] =
1134cabdff1aSopenharmony_ci                        desc->layers[i].planes[j].object_index;
1135cabdff1aSopenharmony_ci                prime_desc.layers[i].offset[j] = desc->layers[i].planes[j].offset;
1136cabdff1aSopenharmony_ci                prime_desc.layers[i].pitch[j] = desc->layers[i].planes[j].pitch;
1137cabdff1aSopenharmony_ci            }
1138cabdff1aSopenharmony_ci
1139cabdff1aSopenharmony_ci            if (format_desc->chroma_planes_swapped &&
1140cabdff1aSopenharmony_ci                desc->layers[i].nb_planes == 3) {
1141cabdff1aSopenharmony_ci                FFSWAP(uint32_t, prime_desc.layers[i].pitch[1],
1142cabdff1aSopenharmony_ci                    prime_desc.layers[i].pitch[2]);
1143cabdff1aSopenharmony_ci                FFSWAP(uint32_t, prime_desc.layers[i].offset[1],
1144cabdff1aSopenharmony_ci                    prime_desc.layers[i].offset[2]);
1145cabdff1aSopenharmony_ci            }
1146cabdff1aSopenharmony_ci        }
1147cabdff1aSopenharmony_ci
1148cabdff1aSopenharmony_ci        /*
1149cabdff1aSopenharmony_ci         * We can query for PRIME_2 support with vaQuerySurfaceAttributes, but that
1150cabdff1aSopenharmony_ci         * that needs the config_id which we don't have here . Both Intel and
1151cabdff1aSopenharmony_ci         * Gallium seem to do the correct error checks, so lets just try the
1152cabdff1aSopenharmony_ci         * PRIME_2 import first.
1153cabdff1aSopenharmony_ci         */
1154cabdff1aSopenharmony_ci        vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1155cabdff1aSopenharmony_ci                               src->width, src->height, &surface_id, 1,
1156cabdff1aSopenharmony_ci                               prime_attrs, FF_ARRAY_ELEMS(prime_attrs));
1157cabdff1aSopenharmony_ci        if (vas != VA_STATUS_SUCCESS)
1158cabdff1aSopenharmony_ci            src_vafc->prime_2_import_unsupported = 1;
1159cabdff1aSopenharmony_ci    }
1160cabdff1aSopenharmony_ci
1161cabdff1aSopenharmony_ci    if (!use_prime2 || vas != VA_STATUS_SUCCESS) {
1162cabdff1aSopenharmony_ci        int k;
1163cabdff1aSopenharmony_ci        unsigned long buffer_handle;
1164cabdff1aSopenharmony_ci        VASurfaceAttribExternalBuffers buffer_desc;
1165cabdff1aSopenharmony_ci        VASurfaceAttrib buffer_attrs[2] = {
1166cabdff1aSopenharmony_ci            {
1167cabdff1aSopenharmony_ci                .type  = VASurfaceAttribMemoryType,
1168cabdff1aSopenharmony_ci                .flags = VA_SURFACE_ATTRIB_SETTABLE,
1169cabdff1aSopenharmony_ci                .value.type    = VAGenericValueTypeInteger,
1170cabdff1aSopenharmony_ci                .value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
1171cabdff1aSopenharmony_ci            },
1172cabdff1aSopenharmony_ci            {
1173cabdff1aSopenharmony_ci                .type  = VASurfaceAttribExternalBufferDescriptor,
1174cabdff1aSopenharmony_ci                .flags = VA_SURFACE_ATTRIB_SETTABLE,
1175cabdff1aSopenharmony_ci                .value.type    = VAGenericValueTypePointer,
1176cabdff1aSopenharmony_ci                .value.value.p = &buffer_desc,
1177cabdff1aSopenharmony_ci            }
1178cabdff1aSopenharmony_ci        };
1179cabdff1aSopenharmony_ci
1180cabdff1aSopenharmony_ci        buffer_handle = desc->objects[0].fd;
1181cabdff1aSopenharmony_ci        buffer_desc.pixel_format = va_fourcc;
1182cabdff1aSopenharmony_ci        buffer_desc.width        = src_fc->width;
1183cabdff1aSopenharmony_ci        buffer_desc.height       = src_fc->height;
1184cabdff1aSopenharmony_ci        buffer_desc.data_size    = desc->objects[0].size;
1185cabdff1aSopenharmony_ci        buffer_desc.buffers      = &buffer_handle;
1186cabdff1aSopenharmony_ci        buffer_desc.num_buffers  = 1;
1187cabdff1aSopenharmony_ci        buffer_desc.flags        = 0;
1188cabdff1aSopenharmony_ci
1189cabdff1aSopenharmony_ci        k = 0;
1190cabdff1aSopenharmony_ci        for (i = 0; i < desc->nb_layers; i++) {
1191cabdff1aSopenharmony_ci            for (j = 0; j < desc->layers[i].nb_planes; j++) {
1192cabdff1aSopenharmony_ci                buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1193cabdff1aSopenharmony_ci                buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1194cabdff1aSopenharmony_ci                ++k;
1195cabdff1aSopenharmony_ci            }
1196cabdff1aSopenharmony_ci        }
1197cabdff1aSopenharmony_ci        buffer_desc.num_planes = k;
1198cabdff1aSopenharmony_ci
1199cabdff1aSopenharmony_ci        if (format_desc->chroma_planes_swapped &&
1200cabdff1aSopenharmony_ci            buffer_desc.num_planes == 3) {
1201cabdff1aSopenharmony_ci            FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1202cabdff1aSopenharmony_ci            FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1203cabdff1aSopenharmony_ci        }
1204cabdff1aSopenharmony_ci
1205cabdff1aSopenharmony_ci        vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1206cabdff1aSopenharmony_ci                               src->width, src->height,
1207cabdff1aSopenharmony_ci                               &surface_id, 1,
1208cabdff1aSopenharmony_ci                               buffer_attrs, FF_ARRAY_ELEMS(buffer_attrs));
1209cabdff1aSopenharmony_ci    }
1210cabdff1aSopenharmony_ci#else
1211cabdff1aSopenharmony_ci    buffer_handle = desc->objects[0].fd;
1212cabdff1aSopenharmony_ci    buffer_desc.pixel_format = va_fourcc;
1213cabdff1aSopenharmony_ci    buffer_desc.width        = src_fc->width;
1214cabdff1aSopenharmony_ci    buffer_desc.height       = src_fc->height;
1215cabdff1aSopenharmony_ci    buffer_desc.data_size    = desc->objects[0].size;
1216cabdff1aSopenharmony_ci    buffer_desc.buffers      = &buffer_handle;
1217cabdff1aSopenharmony_ci    buffer_desc.num_buffers  = 1;
1218cabdff1aSopenharmony_ci    buffer_desc.flags        = 0;
1219cabdff1aSopenharmony_ci
1220cabdff1aSopenharmony_ci    k = 0;
1221cabdff1aSopenharmony_ci    for (i = 0; i < desc->nb_layers; i++) {
1222cabdff1aSopenharmony_ci        for (j = 0; j < desc->layers[i].nb_planes; j++) {
1223cabdff1aSopenharmony_ci            buffer_desc.pitches[k] = desc->layers[i].planes[j].pitch;
1224cabdff1aSopenharmony_ci            buffer_desc.offsets[k] = desc->layers[i].planes[j].offset;
1225cabdff1aSopenharmony_ci            ++k;
1226cabdff1aSopenharmony_ci        }
1227cabdff1aSopenharmony_ci    }
1228cabdff1aSopenharmony_ci    buffer_desc.num_planes = k;
1229cabdff1aSopenharmony_ci
1230cabdff1aSopenharmony_ci    if (format_desc->chroma_planes_swapped &&
1231cabdff1aSopenharmony_ci        buffer_desc.num_planes == 3) {
1232cabdff1aSopenharmony_ci        FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]);
1233cabdff1aSopenharmony_ci        FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]);
1234cabdff1aSopenharmony_ci    }
1235cabdff1aSopenharmony_ci
1236cabdff1aSopenharmony_ci    vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format,
1237cabdff1aSopenharmony_ci                           src->width, src->height,
1238cabdff1aSopenharmony_ci                           &surface_id, 1,
1239cabdff1aSopenharmony_ci                           attrs, FF_ARRAY_ELEMS(attrs));
1240cabdff1aSopenharmony_ci#endif
1241cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
1242cabdff1aSopenharmony_ci        av_log(dst_fc, AV_LOG_ERROR, "Failed to create surface from DRM "
1243cabdff1aSopenharmony_ci               "object: %d (%s).\n", vas, vaErrorStr(vas));
1244cabdff1aSopenharmony_ci        return AVERROR(EIO);
1245cabdff1aSopenharmony_ci    }
1246cabdff1aSopenharmony_ci    av_log(dst_fc, AV_LOG_DEBUG, "Create surface %#x.\n", surface_id);
1247cabdff1aSopenharmony_ci
1248cabdff1aSopenharmony_ci    err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src,
1249cabdff1aSopenharmony_ci                                &vaapi_unmap_from_drm,
1250cabdff1aSopenharmony_ci                                (void*)(uintptr_t)surface_id);
1251cabdff1aSopenharmony_ci    if (err < 0)
1252cabdff1aSopenharmony_ci        return err;
1253cabdff1aSopenharmony_ci
1254cabdff1aSopenharmony_ci    dst->width   = src->width;
1255cabdff1aSopenharmony_ci    dst->height  = src->height;
1256cabdff1aSopenharmony_ci    dst->data[3] = (uint8_t*)(uintptr_t)surface_id;
1257cabdff1aSopenharmony_ci
1258cabdff1aSopenharmony_ci    av_log(dst_fc, AV_LOG_DEBUG, "Mapped DRM object %d to "
1259cabdff1aSopenharmony_ci           "surface %#x.\n", desc->objects[0].fd, surface_id);
1260cabdff1aSopenharmony_ci
1261cabdff1aSopenharmony_ci    return 0;
1262cabdff1aSopenharmony_ci}
1263cabdff1aSopenharmony_ci
1264cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(1, 1, 0)
1265cabdff1aSopenharmony_cistatic void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc,
1266cabdff1aSopenharmony_ci                                   HWMapDescriptor *hwmap)
1267cabdff1aSopenharmony_ci{
1268cabdff1aSopenharmony_ci    AVDRMFrameDescriptor *drm_desc = hwmap->priv;
1269cabdff1aSopenharmony_ci    int i;
1270cabdff1aSopenharmony_ci
1271cabdff1aSopenharmony_ci    for (i = 0; i < drm_desc->nb_objects; i++)
1272cabdff1aSopenharmony_ci        close(drm_desc->objects[i].fd);
1273cabdff1aSopenharmony_ci
1274cabdff1aSopenharmony_ci    av_freep(&drm_desc);
1275cabdff1aSopenharmony_ci}
1276cabdff1aSopenharmony_ci
1277cabdff1aSopenharmony_cistatic int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst,
1278cabdff1aSopenharmony_ci                                const AVFrame *src, int flags)
1279cabdff1aSopenharmony_ci{
1280cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1281cabdff1aSopenharmony_ci    VASurfaceID surface_id;
1282cabdff1aSopenharmony_ci    VAStatus vas;
1283cabdff1aSopenharmony_ci    VADRMPRIMESurfaceDescriptor va_desc;
1284cabdff1aSopenharmony_ci    AVDRMFrameDescriptor *drm_desc = NULL;
1285cabdff1aSopenharmony_ci    uint32_t export_flags;
1286cabdff1aSopenharmony_ci    int err, i, j;
1287cabdff1aSopenharmony_ci
1288cabdff1aSopenharmony_ci    surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1289cabdff1aSopenharmony_ci
1290cabdff1aSopenharmony_ci    export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS;
1291cabdff1aSopenharmony_ci    if (flags & AV_HWFRAME_MAP_READ)
1292cabdff1aSopenharmony_ci        export_flags |= VA_EXPORT_SURFACE_READ_ONLY;
1293cabdff1aSopenharmony_ci    if (flags & AV_HWFRAME_MAP_WRITE)
1294cabdff1aSopenharmony_ci        export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY;
1295cabdff1aSopenharmony_ci
1296cabdff1aSopenharmony_ci    vas = vaExportSurfaceHandle(hwctx->display, surface_id,
1297cabdff1aSopenharmony_ci                                VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
1298cabdff1aSopenharmony_ci                                export_flags, &va_desc);
1299cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
1300cabdff1aSopenharmony_ci        if (vas == VA_STATUS_ERROR_UNIMPLEMENTED)
1301cabdff1aSopenharmony_ci            return AVERROR(ENOSYS);
1302cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to export surface %#x: "
1303cabdff1aSopenharmony_ci               "%d (%s).\n", surface_id, vas, vaErrorStr(vas));
1304cabdff1aSopenharmony_ci        return AVERROR(EIO);
1305cabdff1aSopenharmony_ci    }
1306cabdff1aSopenharmony_ci
1307cabdff1aSopenharmony_ci    drm_desc = av_mallocz(sizeof(*drm_desc));
1308cabdff1aSopenharmony_ci    if (!drm_desc) {
1309cabdff1aSopenharmony_ci        err = AVERROR(ENOMEM);
1310cabdff1aSopenharmony_ci        goto fail;
1311cabdff1aSopenharmony_ci    }
1312cabdff1aSopenharmony_ci
1313cabdff1aSopenharmony_ci    // By some bizarre coincidence, these structures are very similar...
1314cabdff1aSopenharmony_ci    drm_desc->nb_objects = va_desc.num_objects;
1315cabdff1aSopenharmony_ci    for (i = 0; i < va_desc.num_objects; i++) {
1316cabdff1aSopenharmony_ci        drm_desc->objects[i].fd   = va_desc.objects[i].fd;
1317cabdff1aSopenharmony_ci        drm_desc->objects[i].size = va_desc.objects[i].size;
1318cabdff1aSopenharmony_ci        drm_desc->objects[i].format_modifier =
1319cabdff1aSopenharmony_ci            va_desc.objects[i].drm_format_modifier;
1320cabdff1aSopenharmony_ci    }
1321cabdff1aSopenharmony_ci    drm_desc->nb_layers = va_desc.num_layers;
1322cabdff1aSopenharmony_ci    for (i = 0; i < va_desc.num_layers; i++) {
1323cabdff1aSopenharmony_ci        drm_desc->layers[i].format    = va_desc.layers[i].drm_format;
1324cabdff1aSopenharmony_ci        drm_desc->layers[i].nb_planes = va_desc.layers[i].num_planes;
1325cabdff1aSopenharmony_ci        for (j = 0; j < va_desc.layers[i].num_planes; j++) {
1326cabdff1aSopenharmony_ci            drm_desc->layers[i].planes[j].object_index =
1327cabdff1aSopenharmony_ci                va_desc.layers[i].object_index[j];
1328cabdff1aSopenharmony_ci            drm_desc->layers[i].planes[j].offset =
1329cabdff1aSopenharmony_ci                va_desc.layers[i].offset[j];
1330cabdff1aSopenharmony_ci            drm_desc->layers[i].planes[j].pitch =
1331cabdff1aSopenharmony_ci                va_desc.layers[i].pitch[j];
1332cabdff1aSopenharmony_ci        }
1333cabdff1aSopenharmony_ci    }
1334cabdff1aSopenharmony_ci
1335cabdff1aSopenharmony_ci    err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src,
1336cabdff1aSopenharmony_ci                                &vaapi_unmap_to_drm_esh, drm_desc);
1337cabdff1aSopenharmony_ci    if (err < 0)
1338cabdff1aSopenharmony_ci        goto fail;
1339cabdff1aSopenharmony_ci
1340cabdff1aSopenharmony_ci    dst->width   = src->width;
1341cabdff1aSopenharmony_ci    dst->height  = src->height;
1342cabdff1aSopenharmony_ci    dst->data[0] = (uint8_t*)drm_desc;
1343cabdff1aSopenharmony_ci
1344cabdff1aSopenharmony_ci    return 0;
1345cabdff1aSopenharmony_ci
1346cabdff1aSopenharmony_cifail:
1347cabdff1aSopenharmony_ci    for (i = 0; i < va_desc.num_objects; i++)
1348cabdff1aSopenharmony_ci        close(va_desc.objects[i].fd);
1349cabdff1aSopenharmony_ci    av_freep(&drm_desc);
1350cabdff1aSopenharmony_ci    return err;
1351cabdff1aSopenharmony_ci}
1352cabdff1aSopenharmony_ci#endif
1353cabdff1aSopenharmony_ci
1354cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(0, 36, 0)
1355cabdff1aSopenharmony_citypedef struct VAAPIDRMImageBufferMapping {
1356cabdff1aSopenharmony_ci    VAImage      image;
1357cabdff1aSopenharmony_ci    VABufferInfo buffer_info;
1358cabdff1aSopenharmony_ci
1359cabdff1aSopenharmony_ci    AVDRMFrameDescriptor drm_desc;
1360cabdff1aSopenharmony_ci} VAAPIDRMImageBufferMapping;
1361cabdff1aSopenharmony_ci
1362cabdff1aSopenharmony_cistatic void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc,
1363cabdff1aSopenharmony_ci                                  HWMapDescriptor *hwmap)
1364cabdff1aSopenharmony_ci{
1365cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1366cabdff1aSopenharmony_ci    VAAPIDRMImageBufferMapping *mapping = hwmap->priv;
1367cabdff1aSopenharmony_ci    VASurfaceID surface_id;
1368cabdff1aSopenharmony_ci    VAStatus vas;
1369cabdff1aSopenharmony_ci
1370cabdff1aSopenharmony_ci    surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3];
1371cabdff1aSopenharmony_ci    av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n",
1372cabdff1aSopenharmony_ci           surface_id);
1373cabdff1aSopenharmony_ci
1374cabdff1aSopenharmony_ci    // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(),
1375cabdff1aSopenharmony_ci    // so we shouldn't close them separately.
1376cabdff1aSopenharmony_ci
1377cabdff1aSopenharmony_ci    vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1378cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
1379cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer "
1380cabdff1aSopenharmony_ci               "handle of image %#x (derived from surface %#x): "
1381cabdff1aSopenharmony_ci               "%d (%s).\n", mapping->image.buf, surface_id,
1382cabdff1aSopenharmony_ci               vas, vaErrorStr(vas));
1383cabdff1aSopenharmony_ci    }
1384cabdff1aSopenharmony_ci
1385cabdff1aSopenharmony_ci    vas = vaDestroyImage(hwctx->display, mapping->image.image_id);
1386cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
1387cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image "
1388cabdff1aSopenharmony_ci               "derived from surface %#x: %d (%s).\n",
1389cabdff1aSopenharmony_ci               surface_id, vas, vaErrorStr(vas));
1390cabdff1aSopenharmony_ci    }
1391cabdff1aSopenharmony_ci
1392cabdff1aSopenharmony_ci    av_free(mapping);
1393cabdff1aSopenharmony_ci}
1394cabdff1aSopenharmony_ci
1395cabdff1aSopenharmony_cistatic int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst,
1396cabdff1aSopenharmony_ci                                const AVFrame *src, int flags)
1397cabdff1aSopenharmony_ci{
1398cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx;
1399cabdff1aSopenharmony_ci    VAAPIDRMImageBufferMapping *mapping = NULL;
1400cabdff1aSopenharmony_ci    VASurfaceID surface_id;
1401cabdff1aSopenharmony_ci    VAStatus vas;
1402cabdff1aSopenharmony_ci    int err, i, p;
1403cabdff1aSopenharmony_ci
1404cabdff1aSopenharmony_ci    surface_id = (VASurfaceID)(uintptr_t)src->data[3];
1405cabdff1aSopenharmony_ci    av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n",
1406cabdff1aSopenharmony_ci           surface_id);
1407cabdff1aSopenharmony_ci
1408cabdff1aSopenharmony_ci    mapping = av_mallocz(sizeof(*mapping));
1409cabdff1aSopenharmony_ci    if (!mapping)
1410cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
1411cabdff1aSopenharmony_ci
1412cabdff1aSopenharmony_ci    vas = vaDeriveImage(hwctx->display, surface_id,
1413cabdff1aSopenharmony_ci                        &mapping->image);
1414cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
1415cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from "
1416cabdff1aSopenharmony_ci               "surface %#x: %d (%s).\n",
1417cabdff1aSopenharmony_ci               surface_id, vas, vaErrorStr(vas));
1418cabdff1aSopenharmony_ci        err = AVERROR(EIO);
1419cabdff1aSopenharmony_ci        goto fail;
1420cabdff1aSopenharmony_ci    }
1421cabdff1aSopenharmony_ci
1422cabdff1aSopenharmony_ci    for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) {
1423cabdff1aSopenharmony_ci        if (vaapi_drm_format_map[i].va_fourcc ==
1424cabdff1aSopenharmony_ci            mapping->image.format.fourcc)
1425cabdff1aSopenharmony_ci            break;
1426cabdff1aSopenharmony_ci    }
1427cabdff1aSopenharmony_ci    if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) {
1428cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for "
1429cabdff1aSopenharmony_ci               "VAAPI format %#x.\n", mapping->image.format.fourcc);
1430cabdff1aSopenharmony_ci        err = AVERROR(EINVAL);
1431cabdff1aSopenharmony_ci        goto fail_derived;
1432cabdff1aSopenharmony_ci    }
1433cabdff1aSopenharmony_ci
1434cabdff1aSopenharmony_ci    mapping->buffer_info.mem_type =
1435cabdff1aSopenharmony_ci        VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
1436cabdff1aSopenharmony_ci
1437cabdff1aSopenharmony_ci    mapping->drm_desc.nb_layers =
1438cabdff1aSopenharmony_ci        vaapi_drm_format_map[i].nb_layer_formats;
1439cabdff1aSopenharmony_ci    if (mapping->drm_desc.nb_layers > 1) {
1440cabdff1aSopenharmony_ci        if (mapping->drm_desc.nb_layers != mapping->image.num_planes) {
1441cabdff1aSopenharmony_ci            av_log(hwfc, AV_LOG_ERROR, "Image properties do not match "
1442cabdff1aSopenharmony_ci                   "expected format: got %d planes, but expected %d.\n",
1443cabdff1aSopenharmony_ci                   mapping->image.num_planes, mapping->drm_desc.nb_layers);
1444cabdff1aSopenharmony_ci            err = AVERROR(EINVAL);
1445cabdff1aSopenharmony_ci            goto fail_derived;
1446cabdff1aSopenharmony_ci        }
1447cabdff1aSopenharmony_ci
1448cabdff1aSopenharmony_ci        for(p = 0; p < mapping->drm_desc.nb_layers; p++) {
1449cabdff1aSopenharmony_ci            mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) {
1450cabdff1aSopenharmony_ci                .format    = vaapi_drm_format_map[i].layer_formats[p],
1451cabdff1aSopenharmony_ci                .nb_planes = 1,
1452cabdff1aSopenharmony_ci                .planes[0] = {
1453cabdff1aSopenharmony_ci                    .object_index = 0,
1454cabdff1aSopenharmony_ci                    .offset       = mapping->image.offsets[p],
1455cabdff1aSopenharmony_ci                    .pitch        = mapping->image.pitches[p],
1456cabdff1aSopenharmony_ci                },
1457cabdff1aSopenharmony_ci            };
1458cabdff1aSopenharmony_ci        }
1459cabdff1aSopenharmony_ci    } else {
1460cabdff1aSopenharmony_ci        mapping->drm_desc.layers[0].format =
1461cabdff1aSopenharmony_ci            vaapi_drm_format_map[i].layer_formats[0];
1462cabdff1aSopenharmony_ci        mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes;
1463cabdff1aSopenharmony_ci        for (p = 0; p < mapping->image.num_planes; p++) {
1464cabdff1aSopenharmony_ci            mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) {
1465cabdff1aSopenharmony_ci                .object_index = 0,
1466cabdff1aSopenharmony_ci                .offset       = mapping->image.offsets[p],
1467cabdff1aSopenharmony_ci                .pitch        = mapping->image.pitches[p],
1468cabdff1aSopenharmony_ci            };
1469cabdff1aSopenharmony_ci        }
1470cabdff1aSopenharmony_ci    }
1471cabdff1aSopenharmony_ci
1472cabdff1aSopenharmony_ci    vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf,
1473cabdff1aSopenharmony_ci                                &mapping->buffer_info);
1474cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
1475cabdff1aSopenharmony_ci        av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer "
1476cabdff1aSopenharmony_ci               "handle from image %#x (derived from surface %#x): "
1477cabdff1aSopenharmony_ci               "%d (%s).\n", mapping->image.buf, surface_id,
1478cabdff1aSopenharmony_ci               vas, vaErrorStr(vas));
1479cabdff1aSopenharmony_ci        err = AVERROR(EIO);
1480cabdff1aSopenharmony_ci        goto fail_derived;
1481cabdff1aSopenharmony_ci    }
1482cabdff1aSopenharmony_ci
1483cabdff1aSopenharmony_ci    av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n",
1484cabdff1aSopenharmony_ci           mapping->buffer_info.handle);
1485cabdff1aSopenharmony_ci
1486cabdff1aSopenharmony_ci    mapping->drm_desc.nb_objects = 1;
1487cabdff1aSopenharmony_ci    mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) {
1488cabdff1aSopenharmony_ci        .fd   = mapping->buffer_info.handle,
1489cabdff1aSopenharmony_ci        .size = mapping->image.data_size,
1490cabdff1aSopenharmony_ci        // There is no way to get the format modifier with this API.
1491cabdff1aSopenharmony_ci        .format_modifier = DRM_FORMAT_MOD_INVALID,
1492cabdff1aSopenharmony_ci    };
1493cabdff1aSopenharmony_ci
1494cabdff1aSopenharmony_ci    err = ff_hwframe_map_create(src->hw_frames_ctx,
1495cabdff1aSopenharmony_ci                                dst, src, &vaapi_unmap_to_drm_abh,
1496cabdff1aSopenharmony_ci                                mapping);
1497cabdff1aSopenharmony_ci    if (err < 0)
1498cabdff1aSopenharmony_ci        goto fail_mapped;
1499cabdff1aSopenharmony_ci
1500cabdff1aSopenharmony_ci    dst->data[0] = (uint8_t*)&mapping->drm_desc;
1501cabdff1aSopenharmony_ci    dst->width   = src->width;
1502cabdff1aSopenharmony_ci    dst->height  = src->height;
1503cabdff1aSopenharmony_ci
1504cabdff1aSopenharmony_ci    return 0;
1505cabdff1aSopenharmony_ci
1506cabdff1aSopenharmony_cifail_mapped:
1507cabdff1aSopenharmony_ci    vaReleaseBufferHandle(hwctx->display, mapping->image.buf);
1508cabdff1aSopenharmony_cifail_derived:
1509cabdff1aSopenharmony_ci    vaDestroyImage(hwctx->display, mapping->image.image_id);
1510cabdff1aSopenharmony_cifail:
1511cabdff1aSopenharmony_ci    av_freep(&mapping);
1512cabdff1aSopenharmony_ci    return err;
1513cabdff1aSopenharmony_ci}
1514cabdff1aSopenharmony_ci#endif
1515cabdff1aSopenharmony_ci
1516cabdff1aSopenharmony_cistatic int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst,
1517cabdff1aSopenharmony_ci                            const AVFrame *src, int flags)
1518cabdff1aSopenharmony_ci{
1519cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(1, 1, 0)
1520cabdff1aSopenharmony_ci    int err;
1521cabdff1aSopenharmony_ci    err = vaapi_map_to_drm_esh(hwfc, dst, src, flags);
1522cabdff1aSopenharmony_ci    if (err != AVERROR(ENOSYS))
1523cabdff1aSopenharmony_ci        return err;
1524cabdff1aSopenharmony_ci#endif
1525cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(0, 36, 0)
1526cabdff1aSopenharmony_ci    return vaapi_map_to_drm_abh(hwfc, dst, src, flags);
1527cabdff1aSopenharmony_ci#endif
1528cabdff1aSopenharmony_ci    return AVERROR(ENOSYS);
1529cabdff1aSopenharmony_ci}
1530cabdff1aSopenharmony_ci
1531cabdff1aSopenharmony_ci#endif /* CONFIG_LIBDRM */
1532cabdff1aSopenharmony_ci
1533cabdff1aSopenharmony_cistatic int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst,
1534cabdff1aSopenharmony_ci                        const AVFrame *src, int flags)
1535cabdff1aSopenharmony_ci{
1536cabdff1aSopenharmony_ci    switch (src->format) {
1537cabdff1aSopenharmony_ci#if CONFIG_LIBDRM
1538cabdff1aSopenharmony_ci    case AV_PIX_FMT_DRM_PRIME:
1539cabdff1aSopenharmony_ci        return vaapi_map_from_drm(hwfc, dst, src, flags);
1540cabdff1aSopenharmony_ci#endif
1541cabdff1aSopenharmony_ci    default:
1542cabdff1aSopenharmony_ci        return AVERROR(ENOSYS);
1543cabdff1aSopenharmony_ci    }
1544cabdff1aSopenharmony_ci}
1545cabdff1aSopenharmony_ci
1546cabdff1aSopenharmony_cistatic int vaapi_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
1547cabdff1aSopenharmony_ci                          const AVFrame *src, int flags)
1548cabdff1aSopenharmony_ci{
1549cabdff1aSopenharmony_ci    switch (dst->format) {
1550cabdff1aSopenharmony_ci#if CONFIG_LIBDRM
1551cabdff1aSopenharmony_ci    case AV_PIX_FMT_DRM_PRIME:
1552cabdff1aSopenharmony_ci        return vaapi_map_to_drm(hwfc, dst, src, flags);
1553cabdff1aSopenharmony_ci#endif
1554cabdff1aSopenharmony_ci    default:
1555cabdff1aSopenharmony_ci        return vaapi_map_to_memory(hwfc, dst, src, flags);
1556cabdff1aSopenharmony_ci    }
1557cabdff1aSopenharmony_ci}
1558cabdff1aSopenharmony_ci
1559cabdff1aSopenharmony_cistatic void vaapi_device_free(AVHWDeviceContext *ctx)
1560cabdff1aSopenharmony_ci{
1561cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1562cabdff1aSopenharmony_ci    VAAPIDevicePriv      *priv  = ctx->user_opaque;
1563cabdff1aSopenharmony_ci
1564cabdff1aSopenharmony_ci    if (hwctx->display)
1565cabdff1aSopenharmony_ci        vaTerminate(hwctx->display);
1566cabdff1aSopenharmony_ci
1567cabdff1aSopenharmony_ci#if HAVE_VAAPI_X11
1568cabdff1aSopenharmony_ci    if (priv->x11_display)
1569cabdff1aSopenharmony_ci        XCloseDisplay(priv->x11_display);
1570cabdff1aSopenharmony_ci#endif
1571cabdff1aSopenharmony_ci
1572cabdff1aSopenharmony_ci    if (priv->drm_fd >= 0)
1573cabdff1aSopenharmony_ci        close(priv->drm_fd);
1574cabdff1aSopenharmony_ci
1575cabdff1aSopenharmony_ci    av_freep(&priv);
1576cabdff1aSopenharmony_ci}
1577cabdff1aSopenharmony_ci
1578cabdff1aSopenharmony_ci#if CONFIG_VAAPI_1
1579cabdff1aSopenharmony_cistatic void vaapi_device_log_error(void *context, const char *message)
1580cabdff1aSopenharmony_ci{
1581cabdff1aSopenharmony_ci    AVHWDeviceContext *ctx = context;
1582cabdff1aSopenharmony_ci
1583cabdff1aSopenharmony_ci    av_log(ctx, AV_LOG_ERROR, "libva: %s", message);
1584cabdff1aSopenharmony_ci}
1585cabdff1aSopenharmony_ci
1586cabdff1aSopenharmony_cistatic void vaapi_device_log_info(void *context, const char *message)
1587cabdff1aSopenharmony_ci{
1588cabdff1aSopenharmony_ci    AVHWDeviceContext *ctx = context;
1589cabdff1aSopenharmony_ci
1590cabdff1aSopenharmony_ci    av_log(ctx, AV_LOG_VERBOSE, "libva: %s", message);
1591cabdff1aSopenharmony_ci}
1592cabdff1aSopenharmony_ci#endif
1593cabdff1aSopenharmony_ci
1594cabdff1aSopenharmony_cistatic int vaapi_device_connect(AVHWDeviceContext *ctx,
1595cabdff1aSopenharmony_ci                                VADisplay display)
1596cabdff1aSopenharmony_ci{
1597cabdff1aSopenharmony_ci    AVVAAPIDeviceContext *hwctx = ctx->hwctx;
1598cabdff1aSopenharmony_ci    int major, minor;
1599cabdff1aSopenharmony_ci    VAStatus vas;
1600cabdff1aSopenharmony_ci
1601cabdff1aSopenharmony_ci#if CONFIG_VAAPI_1
1602cabdff1aSopenharmony_ci    vaSetErrorCallback(display, &vaapi_device_log_error, ctx);
1603cabdff1aSopenharmony_ci    vaSetInfoCallback (display, &vaapi_device_log_info,  ctx);
1604cabdff1aSopenharmony_ci#endif
1605cabdff1aSopenharmony_ci
1606cabdff1aSopenharmony_ci    hwctx->display = display;
1607cabdff1aSopenharmony_ci
1608cabdff1aSopenharmony_ci    vas = vaInitialize(display, &major, &minor);
1609cabdff1aSopenharmony_ci    if (vas != VA_STATUS_SUCCESS) {
1610cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI "
1611cabdff1aSopenharmony_ci               "connection: %d (%s).\n", vas, vaErrorStr(vas));
1612cabdff1aSopenharmony_ci        return AVERROR(EIO);
1613cabdff1aSopenharmony_ci    }
1614cabdff1aSopenharmony_ci    av_log(ctx, AV_LOG_VERBOSE, "Initialised VAAPI connection: "
1615cabdff1aSopenharmony_ci           "version %d.%d\n", major, minor);
1616cabdff1aSopenharmony_ci
1617cabdff1aSopenharmony_ci    return 0;
1618cabdff1aSopenharmony_ci}
1619cabdff1aSopenharmony_ci
1620cabdff1aSopenharmony_cistatic int vaapi_device_create(AVHWDeviceContext *ctx, const char *device,
1621cabdff1aSopenharmony_ci                               AVDictionary *opts, int flags)
1622cabdff1aSopenharmony_ci{
1623cabdff1aSopenharmony_ci    VAAPIDevicePriv *priv;
1624cabdff1aSopenharmony_ci    VADisplay display = NULL;
1625cabdff1aSopenharmony_ci    const AVDictionaryEntry *ent;
1626cabdff1aSopenharmony_ci    int try_drm, try_x11, try_all;
1627cabdff1aSopenharmony_ci
1628cabdff1aSopenharmony_ci    priv = av_mallocz(sizeof(*priv));
1629cabdff1aSopenharmony_ci    if (!priv)
1630cabdff1aSopenharmony_ci        return AVERROR(ENOMEM);
1631cabdff1aSopenharmony_ci
1632cabdff1aSopenharmony_ci    priv->drm_fd = -1;
1633cabdff1aSopenharmony_ci
1634cabdff1aSopenharmony_ci    ctx->user_opaque = priv;
1635cabdff1aSopenharmony_ci    ctx->free        = vaapi_device_free;
1636cabdff1aSopenharmony_ci
1637cabdff1aSopenharmony_ci    ent = av_dict_get(opts, "connection_type", NULL, 0);
1638cabdff1aSopenharmony_ci    if (ent) {
1639cabdff1aSopenharmony_ci        try_all = try_drm = try_x11 = 0;
1640cabdff1aSopenharmony_ci        if (!strcmp(ent->value, "drm")) {
1641cabdff1aSopenharmony_ci            try_drm = 1;
1642cabdff1aSopenharmony_ci        } else if (!strcmp(ent->value, "x11")) {
1643cabdff1aSopenharmony_ci            try_x11 = 1;
1644cabdff1aSopenharmony_ci        } else {
1645cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n",
1646cabdff1aSopenharmony_ci                   ent->value);
1647cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
1648cabdff1aSopenharmony_ci        }
1649cabdff1aSopenharmony_ci    } else {
1650cabdff1aSopenharmony_ci        try_all = 1;
1651cabdff1aSopenharmony_ci        try_drm = HAVE_VAAPI_DRM;
1652cabdff1aSopenharmony_ci        try_x11 = HAVE_VAAPI_X11;
1653cabdff1aSopenharmony_ci    }
1654cabdff1aSopenharmony_ci
1655cabdff1aSopenharmony_ci#if HAVE_VAAPI_DRM
1656cabdff1aSopenharmony_ci    while (!display && try_drm) {
1657cabdff1aSopenharmony_ci        // If the device is specified, try to open it as a DRM device node.
1658cabdff1aSopenharmony_ci        // If not, look for a usable render node, possibly restricted to those
1659cabdff1aSopenharmony_ci        // using a specified kernel driver.
1660cabdff1aSopenharmony_ci        int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR;
1661cabdff1aSopenharmony_ci        if (device) {
1662cabdff1aSopenharmony_ci            priv->drm_fd = open(device, O_RDWR);
1663cabdff1aSopenharmony_ci            if (priv->drm_fd < 0) {
1664cabdff1aSopenharmony_ci                av_log(ctx, loglevel, "Failed to open %s as "
1665cabdff1aSopenharmony_ci                       "DRM device node.\n", device);
1666cabdff1aSopenharmony_ci                break;
1667cabdff1aSopenharmony_ci            }
1668cabdff1aSopenharmony_ci        } else {
1669cabdff1aSopenharmony_ci            char path[64];
1670cabdff1aSopenharmony_ci            int n, max_devices = 8;
1671cabdff1aSopenharmony_ci#if CONFIG_LIBDRM
1672cabdff1aSopenharmony_ci            const AVDictionaryEntry *kernel_driver;
1673cabdff1aSopenharmony_ci            kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0);
1674cabdff1aSopenharmony_ci#endif
1675cabdff1aSopenharmony_ci            for (n = 0; n < max_devices; n++) {
1676cabdff1aSopenharmony_ci                snprintf(path, sizeof(path),
1677cabdff1aSopenharmony_ci                         "/dev/dri/renderD%d", 128 + n);
1678cabdff1aSopenharmony_ci                priv->drm_fd = open(path, O_RDWR);
1679cabdff1aSopenharmony_ci                if (priv->drm_fd < 0) {
1680cabdff1aSopenharmony_ci                    av_log(ctx, AV_LOG_VERBOSE, "Cannot open "
1681cabdff1aSopenharmony_ci                           "DRM render node for device %d.\n", n);
1682cabdff1aSopenharmony_ci                    break;
1683cabdff1aSopenharmony_ci                }
1684cabdff1aSopenharmony_ci#if CONFIG_LIBDRM
1685cabdff1aSopenharmony_ci                if (kernel_driver) {
1686cabdff1aSopenharmony_ci                    drmVersion *info;
1687cabdff1aSopenharmony_ci                    info = drmGetVersion(priv->drm_fd);
1688cabdff1aSopenharmony_ci                    if (strcmp(kernel_driver->value, info->name)) {
1689cabdff1aSopenharmony_ci                        av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d "
1690cabdff1aSopenharmony_ci                               "with non-matching kernel driver (%s).\n",
1691cabdff1aSopenharmony_ci                               n, info->name);
1692cabdff1aSopenharmony_ci                        drmFreeVersion(info);
1693cabdff1aSopenharmony_ci                        close(priv->drm_fd);
1694cabdff1aSopenharmony_ci                        priv->drm_fd = -1;
1695cabdff1aSopenharmony_ci                        continue;
1696cabdff1aSopenharmony_ci                    }
1697cabdff1aSopenharmony_ci                    av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
1698cabdff1aSopenharmony_ci                           "DRM render node for device %d, "
1699cabdff1aSopenharmony_ci                           "with matching kernel driver (%s).\n",
1700cabdff1aSopenharmony_ci                           n, info->name);
1701cabdff1aSopenharmony_ci                    drmFreeVersion(info);
1702cabdff1aSopenharmony_ci                } else
1703cabdff1aSopenharmony_ci#endif
1704cabdff1aSopenharmony_ci                {
1705cabdff1aSopenharmony_ci                    av_log(ctx, AV_LOG_VERBOSE, "Trying to use "
1706cabdff1aSopenharmony_ci                           "DRM render node for device %d.\n", n);
1707cabdff1aSopenharmony_ci                }
1708cabdff1aSopenharmony_ci                break;
1709cabdff1aSopenharmony_ci            }
1710cabdff1aSopenharmony_ci            if (n >= max_devices)
1711cabdff1aSopenharmony_ci                break;
1712cabdff1aSopenharmony_ci        }
1713cabdff1aSopenharmony_ci
1714cabdff1aSopenharmony_ci        display = vaGetDisplayDRM(priv->drm_fd);
1715cabdff1aSopenharmony_ci        if (!display) {
1716cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display "
1717cabdff1aSopenharmony_ci                   "from DRM device %s.\n", device);
1718cabdff1aSopenharmony_ci            return AVERROR_EXTERNAL;
1719cabdff1aSopenharmony_ci        }
1720cabdff1aSopenharmony_ci        break;
1721cabdff1aSopenharmony_ci    }
1722cabdff1aSopenharmony_ci#endif
1723cabdff1aSopenharmony_ci
1724cabdff1aSopenharmony_ci#if HAVE_VAAPI_X11
1725cabdff1aSopenharmony_ci    if (!display && try_x11) {
1726cabdff1aSopenharmony_ci        // Try to open the device as an X11 display.
1727cabdff1aSopenharmony_ci        priv->x11_display = XOpenDisplay(device);
1728cabdff1aSopenharmony_ci        if (!priv->x11_display) {
1729cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_VERBOSE, "Cannot open X11 display "
1730cabdff1aSopenharmony_ci                   "%s.\n", XDisplayName(device));
1731cabdff1aSopenharmony_ci        } else {
1732cabdff1aSopenharmony_ci            display = vaGetDisplay(priv->x11_display);
1733cabdff1aSopenharmony_ci            if (!display) {
1734cabdff1aSopenharmony_ci                av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display "
1735cabdff1aSopenharmony_ci                       "from X11 display %s.\n", XDisplayName(device));
1736cabdff1aSopenharmony_ci                return AVERROR_UNKNOWN;
1737cabdff1aSopenharmony_ci            }
1738cabdff1aSopenharmony_ci
1739cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via "
1740cabdff1aSopenharmony_ci                   "X11 display %s.\n", XDisplayName(device));
1741cabdff1aSopenharmony_ci        }
1742cabdff1aSopenharmony_ci    }
1743cabdff1aSopenharmony_ci#endif
1744cabdff1aSopenharmony_ci
1745cabdff1aSopenharmony_ci    if (!display) {
1746cabdff1aSopenharmony_ci        if (device)
1747cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1748cabdff1aSopenharmony_ci                   "device %s.\n", device);
1749cabdff1aSopenharmony_ci        else
1750cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_ERROR, "No VA display found for "
1751cabdff1aSopenharmony_ci                   "any default device.\n");
1752cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
1753cabdff1aSopenharmony_ci    }
1754cabdff1aSopenharmony_ci
1755cabdff1aSopenharmony_ci    ent = av_dict_get(opts, "driver", NULL, 0);
1756cabdff1aSopenharmony_ci    if (ent) {
1757cabdff1aSopenharmony_ci#if VA_CHECK_VERSION(0, 38, 0)
1758cabdff1aSopenharmony_ci        VAStatus vas;
1759cabdff1aSopenharmony_ci        vas = vaSetDriverName(display, ent->value);
1760cabdff1aSopenharmony_ci        if (vas != VA_STATUS_SUCCESS) {
1761cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to "
1762cabdff1aSopenharmony_ci                   "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas));
1763cabdff1aSopenharmony_ci            vaTerminate(display);
1764cabdff1aSopenharmony_ci            return AVERROR_EXTERNAL;
1765cabdff1aSopenharmony_ci        }
1766cabdff1aSopenharmony_ci#else
1767cabdff1aSopenharmony_ci        av_log(ctx, AV_LOG_WARNING, "Driver name setting is not "
1768cabdff1aSopenharmony_ci               "supported with this VAAPI version.\n");
1769cabdff1aSopenharmony_ci#endif
1770cabdff1aSopenharmony_ci    }
1771cabdff1aSopenharmony_ci
1772cabdff1aSopenharmony_ci    return vaapi_device_connect(ctx, display);
1773cabdff1aSopenharmony_ci}
1774cabdff1aSopenharmony_ci
1775cabdff1aSopenharmony_cistatic int vaapi_device_derive(AVHWDeviceContext *ctx,
1776cabdff1aSopenharmony_ci                               AVHWDeviceContext *src_ctx,
1777cabdff1aSopenharmony_ci                               AVDictionary *opts, int flags)
1778cabdff1aSopenharmony_ci{
1779cabdff1aSopenharmony_ci#if HAVE_VAAPI_DRM
1780cabdff1aSopenharmony_ci    if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) {
1781cabdff1aSopenharmony_ci        AVDRMDeviceContext *src_hwctx = src_ctx->hwctx;
1782cabdff1aSopenharmony_ci        VADisplay *display;
1783cabdff1aSopenharmony_ci        VAAPIDevicePriv *priv;
1784cabdff1aSopenharmony_ci        int fd;
1785cabdff1aSopenharmony_ci
1786cabdff1aSopenharmony_ci        if (src_hwctx->fd < 0) {
1787cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_ERROR, "DRM instance requires an associated "
1788cabdff1aSopenharmony_ci                   "device to derive a VA display from.\n");
1789cabdff1aSopenharmony_ci            return AVERROR(EINVAL);
1790cabdff1aSopenharmony_ci        }
1791cabdff1aSopenharmony_ci
1792cabdff1aSopenharmony_ci#if CONFIG_LIBDRM
1793cabdff1aSopenharmony_ci        {
1794cabdff1aSopenharmony_ci            int node_type = drmGetNodeTypeFromFd(src_hwctx->fd);
1795cabdff1aSopenharmony_ci            char *render_node;
1796cabdff1aSopenharmony_ci            if (node_type < 0) {
1797cabdff1aSopenharmony_ci                av_log(ctx, AV_LOG_ERROR, "DRM instance fd does not appear "
1798cabdff1aSopenharmony_ci                       "to refer to a DRM device.\n");
1799cabdff1aSopenharmony_ci                return AVERROR(EINVAL);
1800cabdff1aSopenharmony_ci            }
1801cabdff1aSopenharmony_ci            if (node_type == DRM_NODE_RENDER) {
1802cabdff1aSopenharmony_ci                fd = src_hwctx->fd;
1803cabdff1aSopenharmony_ci            } else {
1804cabdff1aSopenharmony_ci                render_node = drmGetRenderDeviceNameFromFd(src_hwctx->fd);
1805cabdff1aSopenharmony_ci                if (!render_node) {
1806cabdff1aSopenharmony_ci                    av_log(ctx, AV_LOG_VERBOSE, "Using non-render node "
1807cabdff1aSopenharmony_ci                           "because the device does not have an "
1808cabdff1aSopenharmony_ci                           "associated render node.\n");
1809cabdff1aSopenharmony_ci                    fd = src_hwctx->fd;
1810cabdff1aSopenharmony_ci                } else {
1811cabdff1aSopenharmony_ci                    fd = open(render_node, O_RDWR);
1812cabdff1aSopenharmony_ci                    if (fd < 0) {
1813cabdff1aSopenharmony_ci                        av_log(ctx, AV_LOG_VERBOSE, "Using non-render node "
1814cabdff1aSopenharmony_ci                               "because the associated render node "
1815cabdff1aSopenharmony_ci                               "could not be opened.\n");
1816cabdff1aSopenharmony_ci                        fd = src_hwctx->fd;
1817cabdff1aSopenharmony_ci                    } else {
1818cabdff1aSopenharmony_ci                        av_log(ctx, AV_LOG_VERBOSE, "Using render node %s "
1819cabdff1aSopenharmony_ci                               "in place of non-render DRM device.\n",
1820cabdff1aSopenharmony_ci                               render_node);
1821cabdff1aSopenharmony_ci                    }
1822cabdff1aSopenharmony_ci                    free(render_node);
1823cabdff1aSopenharmony_ci                }
1824cabdff1aSopenharmony_ci            }
1825cabdff1aSopenharmony_ci        }
1826cabdff1aSopenharmony_ci#else
1827cabdff1aSopenharmony_ci        fd = src_hwctx->fd;
1828cabdff1aSopenharmony_ci#endif
1829cabdff1aSopenharmony_ci
1830cabdff1aSopenharmony_ci        priv = av_mallocz(sizeof(*priv));
1831cabdff1aSopenharmony_ci        if (!priv) {
1832cabdff1aSopenharmony_ci            if (fd != src_hwctx->fd) {
1833cabdff1aSopenharmony_ci                // The fd was opened in this function.
1834cabdff1aSopenharmony_ci                close(fd);
1835cabdff1aSopenharmony_ci            }
1836cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
1837cabdff1aSopenharmony_ci        }
1838cabdff1aSopenharmony_ci
1839cabdff1aSopenharmony_ci        if (fd == src_hwctx->fd) {
1840cabdff1aSopenharmony_ci            // The fd is inherited from the source context and we are holding
1841cabdff1aSopenharmony_ci            // a reference to that, we don't want to close it from here.
1842cabdff1aSopenharmony_ci            priv->drm_fd = -1;
1843cabdff1aSopenharmony_ci        } else {
1844cabdff1aSopenharmony_ci            priv->drm_fd = fd;
1845cabdff1aSopenharmony_ci        }
1846cabdff1aSopenharmony_ci
1847cabdff1aSopenharmony_ci        ctx->user_opaque = priv;
1848cabdff1aSopenharmony_ci        ctx->free        = &vaapi_device_free;
1849cabdff1aSopenharmony_ci
1850cabdff1aSopenharmony_ci        display = vaGetDisplayDRM(fd);
1851cabdff1aSopenharmony_ci        if (!display) {
1852cabdff1aSopenharmony_ci            av_log(ctx, AV_LOG_ERROR, "Failed to open a VA display from "
1853cabdff1aSopenharmony_ci                   "DRM device.\n");
1854cabdff1aSopenharmony_ci            return AVERROR(EIO);
1855cabdff1aSopenharmony_ci        }
1856cabdff1aSopenharmony_ci
1857cabdff1aSopenharmony_ci        return vaapi_device_connect(ctx, display);
1858cabdff1aSopenharmony_ci    }
1859cabdff1aSopenharmony_ci#endif
1860cabdff1aSopenharmony_ci    return AVERROR(ENOSYS);
1861cabdff1aSopenharmony_ci}
1862cabdff1aSopenharmony_ci
1863cabdff1aSopenharmony_ciconst HWContextType ff_hwcontext_type_vaapi = {
1864cabdff1aSopenharmony_ci    .type                   = AV_HWDEVICE_TYPE_VAAPI,
1865cabdff1aSopenharmony_ci    .name                   = "VAAPI",
1866cabdff1aSopenharmony_ci
1867cabdff1aSopenharmony_ci    .device_hwctx_size      = sizeof(AVVAAPIDeviceContext),
1868cabdff1aSopenharmony_ci    .device_priv_size       = sizeof(VAAPIDeviceContext),
1869cabdff1aSopenharmony_ci    .device_hwconfig_size   = sizeof(AVVAAPIHWConfig),
1870cabdff1aSopenharmony_ci    .frames_hwctx_size      = sizeof(AVVAAPIFramesContext),
1871cabdff1aSopenharmony_ci    .frames_priv_size       = sizeof(VAAPIFramesContext),
1872cabdff1aSopenharmony_ci
1873cabdff1aSopenharmony_ci    .device_create          = &vaapi_device_create,
1874cabdff1aSopenharmony_ci    .device_derive          = &vaapi_device_derive,
1875cabdff1aSopenharmony_ci    .device_init            = &vaapi_device_init,
1876cabdff1aSopenharmony_ci    .device_uninit          = &vaapi_device_uninit,
1877cabdff1aSopenharmony_ci    .frames_get_constraints = &vaapi_frames_get_constraints,
1878cabdff1aSopenharmony_ci    .frames_init            = &vaapi_frames_init,
1879cabdff1aSopenharmony_ci    .frames_uninit          = &vaapi_frames_uninit,
1880cabdff1aSopenharmony_ci    .frames_get_buffer      = &vaapi_get_buffer,
1881cabdff1aSopenharmony_ci    .transfer_get_formats   = &vaapi_transfer_get_formats,
1882cabdff1aSopenharmony_ci    .transfer_data_to       = &vaapi_transfer_data_to,
1883cabdff1aSopenharmony_ci    .transfer_data_from     = &vaapi_transfer_data_from,
1884cabdff1aSopenharmony_ci    .map_to                 = &vaapi_map_to,
1885cabdff1aSopenharmony_ci    .map_from               = &vaapi_map_from,
1886cabdff1aSopenharmony_ci
1887cabdff1aSopenharmony_ci    .pix_fmts = (const enum AVPixelFormat[]) {
1888cabdff1aSopenharmony_ci        AV_PIX_FMT_VAAPI,
1889cabdff1aSopenharmony_ci        AV_PIX_FMT_NONE
1890cabdff1aSopenharmony_ci    },
1891cabdff1aSopenharmony_ci};
1892