LCOV - code coverage report
Current view: top level - src/libavutil - hwcontext_vaapi.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 457 0.0 %
Date: 2017-01-21 09:32:20 Functions: 0 17 0.0 %

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

Generated by: LCOV version 1.12