[FFmpeg-devel] [PATCH 08/13] ffmpeg: Use codec hardware config to configure hwaccels

Philip Langdale philipl at overt.org
Wed Nov 22 06:28:13 EET 2017


On Sat, 18 Nov 2017 18:47:08 +0000
Mark Thompson <sw at jkqxz.net> wrote:

> Removes specific support for all hwaccels supported by the generic
> code (DXVA2, D3D11VA, NVDEC, VAAPI, VDPAU and videotoolbox).
> ---
>  fftools/ffmpeg.c     |  77 +++++++++++-----
>  fftools/ffmpeg.h     |  10 +--
>  fftools/ffmpeg_hw.c  | 244
> +++++++++++++++++++++++++++++++++++----------------
> fftools/ffmpeg_opt.c |  55 ++++++------ 4 files changed, 250
> insertions(+), 136 deletions(-)
> 
> diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c
> index babd85f7bc..acff815e74 100644
> --- a/fftools/ffmpeg.c
> +++ b/fftools/ffmpeg.c
> @@ -2782,45 +2782,77 @@ fail:
>      av_freep(&avc);
>  }
>  
> -static const HWAccel *get_hwaccel(enum AVPixelFormat pix_fmt, enum
> HWAccelID selected_hwaccel_id) -{
> -    int i;
> -    for (i = 0; hwaccels[i].name; i++)
> -        if (hwaccels[i].pix_fmt == pix_fmt &&
> -            (!selected_hwaccel_id || selected_hwaccel_id ==
> HWACCEL_AUTO || hwaccels[i].id == selected_hwaccel_id))
> -            return &hwaccels[i];
> -    return NULL;
> -}
> -
>  static enum AVPixelFormat get_format(AVCodecContext *s, const enum
> AVPixelFormat *pix_fmts) {
>      InputStream *ist = s->opaque;
>      const enum AVPixelFormat *p;
>      int ret;
>  
> -    for (p = pix_fmts; *p != -1; p++) {
> +    for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) {
>          const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p);
> -        const HWAccel *hwaccel;
> +        const AVCodecHWConfig  *config = NULL;
> +        int i;
>  
>          if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL))
>              break;
>  
> -        hwaccel = get_hwaccel(*p, ist->hwaccel_id);
> -        if (!hwaccel ||
> -            (ist->active_hwaccel_id && ist->active_hwaccel_id !=
> hwaccel->id) ||
> -            (ist->hwaccel_id != HWACCEL_AUTO && ist->hwaccel_id !=
> hwaccel->id))
> -            continue;
> +        if (ist->hwaccel_id == HWACCEL_GENERIC ||
> +            ist->hwaccel_id == HWACCEL_AUTO) {
> +            for (i = 0;; i++) {
> +                config = avcodec_get_hw_config(s->codec, i);
> +                if (!config)
> +                    break;
> +                if (!(config->methods &
> +                      AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
> +                    continue;

Just to be explicit, only METHOD_HW_DEVICE_CTX hwaccels can be
generically initialized, so that's why you exclude any other method?

> +                if (config->pix_fmt == *p)
> +                    break;
> +            }
> +        }
> +        if (config) {
> +            if (config->device_type != ist->hwaccel_device_type) {
> +                // Different hwaccel offered, ignore.
> +                continue;
> +            }
>  
> -        ret = hwaccel->init(s);
> -        if (ret < 0) {
> -            if (ist->hwaccel_id == hwaccel->id) {
> +            ret = hwaccel_decode_init(s);
> +            if (ret < 0) {
> +                if (ist->hwaccel_id == HWACCEL_GENERIC) {
> +                    av_log(NULL, AV_LOG_FATAL,
> +                           "%s hwaccel requested for input stream
> #%d:%d, "
> +                           "but cannot be initialized.\n",
> +
> av_hwdevice_get_type_name(config->device_type),
> +                           ist->file_index, ist->st->index);
> +                    return AV_PIX_FMT_NONE;
> +                }
> +                continue;
> +            }
> +        } else {
> +            const HWAccel *hwaccel = NULL;
> +            int i;
> +            for (i = 0; hwaccels[i].name; i++) {
> +                if (hwaccels[i].pix_fmt == *p) {
> +                    hwaccel = &hwaccels[i];
> +                    break;

This can also overrun the NULL terminator right? Or are we lucky
because 'name' is at offset zero inside the struct and there's no
dereference taking place.

I see this pattern has been used previously so it obviously works out.

> +                }
> +            }
> +            if (!hwaccel) {
> +                // No hwaccel supporting this pixfmt.
> +                continue;
> +            }
> +            if (hwaccel->id != ist->hwaccel_id) {
> +                // Does not match requested hwaccel.
> +                continue;
> +            }
> +
> +            ret = hwaccel->init(s);
> +            if (ret < 0) {
>                  av_log(NULL, AV_LOG_FATAL,
>                         "%s hwaccel requested for input stream
> #%d:%d, " "but cannot be initialized.\n", hwaccel->name,
>                         ist->file_index, ist->st->index);
>                  return AV_PIX_FMT_NONE;
>              }
> -            continue;
>          }
>  
>          if (ist->hw_frames_ctx) {
> @@ -2829,8 +2861,7 @@ static enum AVPixelFormat
> get_format(AVCodecContext *s, const enum AVPixelFormat return
> AV_PIX_FMT_NONE; }
>  
> -        ist->active_hwaccel_id = hwaccel->id;
> -        ist->hwaccel_pix_fmt   = *p;
> +        ist->hwaccel_pix_fmt = *p;
>          break;
>      }
>  
> diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h
> index e0977e1bf1..8bb5bae862 100644
> --- a/fftools/ffmpeg.h
> +++ b/fftools/ffmpeg.h
> @@ -61,14 +61,9 @@
>  enum HWAccelID {
>      HWACCEL_NONE = 0,
>      HWACCEL_AUTO,
> -    HWACCEL_VDPAU,
> -    HWACCEL_DXVA2,
> -    HWACCEL_VIDEOTOOLBOX,
> +    HWACCEL_GENERIC,
>      HWACCEL_QSV,
> -    HWACCEL_VAAPI,
>      HWACCEL_CUVID,
> -    HWACCEL_D3D11VA,
> -    HWACCEL_NVDEC,
>  };
>  
>  typedef struct HWAccel {
> @@ -76,7 +71,6 @@ typedef struct HWAccel {
>      int (*init)(AVCodecContext *s);
>      enum HWAccelID id;
>      enum AVPixelFormat pix_fmt;
> -    enum AVHWDeviceType device_type;
>  } HWAccel;
>  
>  typedef struct HWDevice {
> @@ -370,11 +364,11 @@ typedef struct InputStream {
>  
>      /* hwaccel options */
>      enum HWAccelID hwaccel_id;
> +    enum AVHWDeviceType hwaccel_device_type;
>      char  *hwaccel_device;
>      enum AVPixelFormat hwaccel_output_format;
>  
>      /* hwaccel context */
> -    enum HWAccelID active_hwaccel_id;
>      void  *hwaccel_ctx;
>      void (*hwaccel_uninit)(AVCodecContext *s);
>      int  (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame,
> int flags); diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c
> index a4d1cada59..2ec1813854 100644
> --- a/fftools/ffmpeg_hw.c
> +++ b/fftools/ffmpeg_hw.c
> @@ -64,6 +64,31 @@ static HWDevice *hw_device_add(void)
>      return hw_devices[nb_hw_devices++];
>  }
>  
> +static char *hw_device_default_name(enum AVHWDeviceType type)
> +{
> +    // Make an automatic name of the form "type%d".  We arbitrarily
> +    // limit at 1000 anonymous devices of the same type - there is
> +    // probably something else very wrong if you get to this limit.
> +    const char *type_name = av_hwdevice_get_type_name(type);
> +    char *name;
> +    size_t index_pos;
> +    int index, index_limit = 1000;
> +    index_pos = strlen(type_name);
> +    name = av_malloc(index_pos + 4);
> +    if (!name)
> +        return NULL;
> +    for (index = 0; index < index_limit; index++) {
> +        snprintf(name, index_pos + 4, "%s%d", type_name, index);
> +        if (!hw_device_get_by_name(name))
> +            break;
> +    }
> +    if (index >= index_limit) {
> +        av_freep(&name);
> +        return NULL;
> +    }
> +    return name;
> +}
> +
>  int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
>  {
>      // "type=name:device,key=value,key2=value2"
> @@ -111,27 +136,11 @@ int hw_device_init_from_string(const char *arg,
> HWDevice **dev_out) 
>          p += 1 + k;
>      } else {
> -        // Give the device an automatic name of the form "type%d".
> -        // We arbitrarily limit at 1000 anonymous devices of the same
> -        // type - there is probably something else very wrong if you
> -        // get to this limit.
> -        size_t index_pos;
> -        int index, index_limit = 1000;
> -        index_pos = strlen(type_name);
> -        name = av_malloc(index_pos + 4);
> +        name = hw_device_default_name(type);
>          if (!name) {
>              err = AVERROR(ENOMEM);
>              goto fail;
>          }
> -        for (index = 0; index < index_limit; index++) {
> -            snprintf(name, index_pos + 4, "%s%d", type_name, index);
> -            if (!hw_device_get_by_name(name))
> -                break;
> -        }
> -        if (index >= index_limit) {
> -            errmsg = "too many devices";
> -            goto invalid;
> -        }
>      }
>  
>      if (!*p) {
> @@ -214,6 +223,49 @@ fail:
>      goto done;
>  }
>  
> +static int hw_device_init_from_type(enum AVHWDeviceType type,
> +                                    const char *device,
> +                                    HWDevice **dev_out)
> +{
> +    AVBufferRef *device_ref = NULL;
> +    HWDevice *dev;
> +    char *name;
> +    int err;
> +
> +    name = hw_device_default_name(type);
> +    if (!name) {
> +        err = AVERROR(ENOMEM);
> +        goto fail;
> +    }
> +
> +    err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
> +    if (err < 0) {
> +        av_log(NULL, AV_LOG_ERROR,
> +               "Device creation failed: %d.\n", err);
> +        goto fail;
> +    }
> +
> +    dev = hw_device_add();
> +    if (!dev) {
> +        err = AVERROR(ENOMEM);
> +        goto fail;
> +    }
> +
> +    dev->name = name;
> +    dev->type = type;
> +    dev->device_ref = device_ref;
> +
> +    if (dev_out)
> +        *dev_out = dev;
> +
> +    return 0;
> +
> +fail:
> +    av_freep(&name);
> +    av_buffer_unref(&device_ref);
> +    return err;
> +}
> +
>  void hw_device_free_all(void)
>  {
>      int i;
> @@ -226,80 +278,130 @@ void hw_device_free_all(void)
>      nb_hw_devices = 0;
>  }
>  
> -static enum AVHWDeviceType hw_device_match_type_by_hwaccel(enum
> HWAccelID hwaccel_id) +static HWDevice
> *hw_device_match_by_codec(const AVCodec *codec) {
> +    const AVCodecHWConfig *config;
> +    HWDevice *dev;
>      int i;
> -    if (hwaccel_id == HWACCEL_NONE)
> -        return AV_HWDEVICE_TYPE_NONE;
> -    for (i = 0; hwaccels[i].name; i++) {
> -        if (hwaccels[i].id == hwaccel_id)
> -            return hwaccels[i].device_type;
> +    for (i = 0;; i++) {
> +        config = avcodec_get_hw_config(codec, i);
> +        if (!config)
> +            return NULL;
> +        if (!(config->methods &
> AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX))
> +            continue;
> +        dev = hw_device_get_by_type(config->device_type);
> +        if (dev)
> +            return dev;
>      }
> -    return AV_HWDEVICE_TYPE_NONE;
> -}
> -
> -static enum AVHWDeviceType hw_device_match_type_in_name(const char
> *codec_name) -{
> -    const char *type_name;
> -    enum AVHWDeviceType type;
> -    for (type = av_hwdevice_iterate_types(AV_HWDEVICE_TYPE_NONE);
> -         type != AV_HWDEVICE_TYPE_NONE;
> -         type = av_hwdevice_iterate_types(type)) {
> -        type_name = av_hwdevice_get_type_name(type);
> -        if (strstr(codec_name, type_name))
> -            return type;
> -    }
> -    return AV_HWDEVICE_TYPE_NONE;
>  }
>  
>  int hw_device_setup_for_decode(InputStream *ist)
>  {
> +    const AVCodecHWConfig *config;
>      enum AVHWDeviceType type;
> -    HWDevice *dev;
> -    int err;
> +    HWDevice *dev = NULL;
> +    int err, auto_device = 0;
>  
>      if (ist->hwaccel_device) {
>          dev = hw_device_get_by_name(ist->hwaccel_device);
>          if (!dev) {
> -            char *tmp;
> -            type = hw_device_match_type_by_hwaccel(ist->hwaccel_id);
> -            if (type == AV_HWDEVICE_TYPE_NONE) {
> -                // No match - this isn't necessarily invalid, though,
> -                // because an explicit device might not be needed or
> -                // the hwaccel setup could be handled elsewhere.
> +            if (ist->hwaccel_id == HWACCEL_AUTO) {
> +                auto_device = 1;
> +            } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
> +                type = ist->hwaccel_device_type;
> +                err = hw_device_init_from_type(type,
> ist->hwaccel_device,
> +                                               &dev);
> +            } else {
> +                // This will be dealt with by API-specific
> initialisation
> +                // (using hwaccel_device), so nothing further needed
> here. return 0;
>              }
> -            tmp = av_asprintf("%s:%s",
> av_hwdevice_get_type_name(type),
> -                              ist->hwaccel_device);
> -            if (!tmp)
> -                return AVERROR(ENOMEM);
> -            err = hw_device_init_from_string(tmp, &dev);
> -            av_free(tmp);
> -            if (err < 0)
> -                return err;
> +        } else {
> +            if (ist->hwaccel_id == HWACCEL_AUTO) {
> +                ist->hwaccel_device_type = dev->type;
> +            } else if (ist->hwaccel_device_type != dev->type) {
> +                av_log(ist->dec_ctx, AV_LOG_ERROR, "Invalid hwaccel
> device "
> +                       "specified for decoder: device %s of type %s
> is not "
> +                       "usable with hwaccel %s.\n", dev->name,
> +                       av_hwdevice_get_type_name(dev->type),
> +
> av_hwdevice_get_type_name(ist->hwaccel_device_type));
> +                return AVERROR(EINVAL);
> +            }
>          }
>      } else {
> -        if (ist->hwaccel_id != HWACCEL_NONE)
> -            type = hw_device_match_type_by_hwaccel(ist->hwaccel_id);
> -        else
> -            type = hw_device_match_type_in_name(ist->dec->name);
> -        if (type != AV_HWDEVICE_TYPE_NONE) {
> +        if (ist->hwaccel_id == HWACCEL_AUTO) {
> +            auto_device = 1;
> +        } else if (ist->hwaccel_id == HWACCEL_GENERIC) {
> +            type = ist->hwaccel_device_type;
>              dev = hw_device_get_by_type(type);
> +            if (!dev)
> +                err = hw_device_init_from_type(type, NULL, &dev);
> +        } else {
> +            dev = hw_device_match_by_codec(ist->dec);
>              if (!dev) {
> -
> hw_device_init_from_string(av_hwdevice_get_type_name(type),
> +                // No device for this codec, but not using generic
> hwaccel
> +                // and therefore may well not need one - ignore.
> +                return 0;
> +            }
> +        }
> +    }
> +
> +    if (auto_device) {
> +        int i;
> +        if (!avcodec_get_hw_config(ist->dec, 0)) {
> +            // Decoder does not support any hardware devices.
> +            return 0;
> +        }
> +        for (i = 0; !dev; i++) {
> +            config = avcodec_get_hw_config(ist->dec, i);
> +            if (!config)
> +                break;
> +            type = config->device_type;
> +            dev = hw_device_get_by_type(type);
> +            if (dev) {
> +                av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
> +                       "hwaccel type %s with existing device %s.\n",
> +                       av_hwdevice_get_type_name(type), dev->name);
> +            }
> +        }
> +        for (i = 0; !dev; i++) {
> +            config = avcodec_get_hw_config(ist->dec, i);
> +            if (!config)
> +                break;
> +            type = config->device_type;
> +            // Try to make a new device of this type.
> +            err = hw_device_init_from_type(type, ist->hwaccel_device,
>                                             &dev);
> +            if (err < 0) {
> +                // Can't make a device of this type.
> +                continue;
> +            }
> +            if (ist->hwaccel_device) {
> +                av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
> +                       "hwaccel type %s with new device created "
> +                       "from %s.\n", av_hwdevice_get_type_name(type),
> +                       ist->hwaccel_device);
> +            } else {
> +                av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto "
> +                       "hwaccel type %s with new default device.\n",
> +                       av_hwdevice_get_type_name(type));
>              }
> +        }
> +        if (dev) {
> +            ist->hwaccel_device_type = type;
>          } else {
> -            // No device required.
> +            av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel "
> +                   "disabled: no device found.\n");
> +            ist->hwaccel_id = HWACCEL_NONE;
>              return 0;
>          }
>      }
>  
>      if (!dev) {
> -        av_log(ist->dec_ctx, AV_LOG_WARNING, "No device available "
> -               "for decoder (device type %s for codec %s).\n",
> +        av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available "
> +               "for decoder: device type %s needed for codec %s.\n",
>                 av_hwdevice_get_type_name(type), ist->dec->name);
> -        return 0;
> +        return err;
>      }
>  
>      ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
> @@ -311,24 +413,16 @@ int hw_device_setup_for_decode(InputStream *ist)
>  
>  int hw_device_setup_for_encode(OutputStream *ost)
>  {
> -    enum AVHWDeviceType type;
>      HWDevice *dev;
>  
> -    type = hw_device_match_type_in_name(ost->enc->name);
> -    if (type != AV_HWDEVICE_TYPE_NONE) {
> -        dev = hw_device_get_by_type(type);
> -        if (!dev) {
> -            av_log(ost->enc_ctx, AV_LOG_WARNING, "No device
> available "
> -                   "for encoder (device type %s for codec %s).\n",
> -                   av_hwdevice_get_type_name(type), ost->enc->name);
> -            return 0;
> -        }
> +    dev = hw_device_match_by_codec(ost->enc);
> +    if (dev) {
>          ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref);
>          if (!ost->enc_ctx->hw_device_ctx)
>              return AVERROR(ENOMEM);
>          return 0;
>      } else {
> -        // No device required.
> +        // No device required, or no device available.
>          return 0;
>      }
>  }
> diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c
> index 47d384166c..8ccd123c03 100644
> --- a/fftools/ffmpeg_opt.c
> +++ b/fftools/ffmpeg_opt.c
> @@ -66,37 +66,11 @@
>  }
>  
>  const HWAccel hwaccels[] = {
> -#if HAVE_VDPAU_X11
> -    { "vdpau", hwaccel_decode_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU,
> -      AV_HWDEVICE_TYPE_VDPAU },
> -#endif
> -#if CONFIG_D3D11VA
> -    { "d3d11va", hwaccel_decode_init, HWACCEL_D3D11VA,
> AV_PIX_FMT_D3D11,
> -      AV_HWDEVICE_TYPE_D3D11VA },
> -#endif
> -#if CONFIG_DXVA2
> -    { "dxva2", hwaccel_decode_init, HWACCEL_DXVA2,
> AV_PIX_FMT_DXVA2_VLD,
> -      AV_HWDEVICE_TYPE_DXVA2 },
> -#endif
> -#if CONFIG_VIDEOTOOLBOX
> -    { "videotoolbox",   videotoolbox_init,   HWACCEL_VIDEOTOOLBOX,
> AV_PIX_FMT_VIDEOTOOLBOX,
> -      AV_HWDEVICE_TYPE_NONE },
> -#endif
>  #if CONFIG_LIBMFX
> -    { "qsv",   qsv_init,   HWACCEL_QSV,   AV_PIX_FMT_QSV,
> -      AV_HWDEVICE_TYPE_NONE },
> -#endif
> -#if CONFIG_VAAPI
> -    { "vaapi", hwaccel_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI,
> -      AV_HWDEVICE_TYPE_VAAPI },
> -#endif
> -#if CONFIG_NVDEC
> -    { "nvdec", hwaccel_decode_init, HWACCEL_NVDEC, AV_PIX_FMT_CUDA,
> -       AV_HWDEVICE_TYPE_CUDA },
> +    { "qsv",   qsv_init,   HWACCEL_QSV,   AV_PIX_FMT_QSV },
>  #endif
>  #if CONFIG_CUVID
> -    { "cuvid", cuvid_init, HWACCEL_CUVID, AV_PIX_FMT_CUDA,
> -      AV_HWDEVICE_TYPE_NONE },
> +    { "cuvid", cuvid_init, HWACCEL_CUVID, AV_PIX_FMT_CUDA },
>  #endif
>      { 0 },
>  };
> @@ -194,12 +168,15 @@ static void init_options(OptionsContext *o)
>  
>  static int show_hwaccels(void *optctx, const char *opt, const char
> *arg) {
> +    enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE;
>      int i;
>  
>      printf("Hardware acceleration methods:\n");
> -    for (i = 0; hwaccels[i].name; i++) {
> +    while ((type = av_hwdevice_iterate_types(type)) !=
> +           AV_HWDEVICE_TYPE_NONE)
> +        printf("%s\n", av_hwdevice_get_type_name(type));
> +    for (i = 0; hwaccels[i].name; i++)
>          printf("%s\n", hwaccels[i].name);
> -    }
>      printf("\n");
>      return 0;
>  }
> @@ -819,11 +796,16 @@ static void add_input_streams(OptionsContext
> *o, AVFormatContext *ic) 
>              MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
>              if (hwaccel) {
> +                // The NVDEC hwaccels use a CUDA device, so remap
> the name here.
> +                if (!strcmp(hwaccel, "nvdec"))
> +                    hwaccel = "cuda";
> +

This is a bit unfortunate. Can't we get the device type by matching
names from ist->dec->hw_configs[i]->hwaccel and then using
hw_configs[i]->device_type? That's admittedly clunky, of course.

>                  if (!strcmp(hwaccel, "none"))
>                      ist->hwaccel_id = HWACCEL_NONE;
>                  else if (!strcmp(hwaccel, "auto"))
>                      ist->hwaccel_id = HWACCEL_AUTO;
>                  else {
> +                    enum AVHWDeviceType type;
>                      int i;
>                      for (i = 0; hwaccels[i].name; i++) {
>                          if (!strcmp(hwaccels[i].name, hwaccel)) {
> @@ -833,9 +815,22 @@ static void add_input_streams(OptionsContext *o,
> AVFormatContext *ic) }
>  
>                      if (!ist->hwaccel_id) {
> +                        type =
> av_hwdevice_find_type_by_name(hwaccel);
> +                        if (type != AV_HWDEVICE_TYPE_NONE) {
> +                            ist->hwaccel_id = HWACCEL_GENERIC;
> +                            ist->hwaccel_device_type = type;
> +                        }
> +                    }
> +
> +                    if (!ist->hwaccel_id) {
>                          av_log(NULL, AV_LOG_FATAL, "Unrecognized
> hwaccel: %s.\n", hwaccel);
>                          av_log(NULL, AV_LOG_FATAL, "Supported
> hwaccels: ");
> +                        type = AV_HWDEVICE_TYPE_NONE;
> +                        while ((type =
> av_hwdevice_iterate_types(type)) !=
> +                               AV_HWDEVICE_TYPE_NONE)
> +                            av_log(NULL, AV_LOG_FATAL, "%s ",
> +                                   av_hwdevice_get_type_name(type));
>                          for (i = 0; hwaccels[i].name; i++)
>                              av_log(NULL, AV_LOG_FATAL, "%s ",
> hwaccels[i].name); av_log(NULL, AV_LOG_FATAL, "\n");


Rest is LGTM.

--phil


More information about the ffmpeg-devel mailing list