func: static int vaapi_build_decoder_config(VAAPIDecoderContext *ctx,
  
                                        AVCodecContext *avctx,
  
                                        int fallback_allowed)
  
  {
  
      AVVAAPIDeviceContext *hwctx = ctx->device->hwctx;
  
      AVVAAPIHWConfig *hwconfig = NULL;
  
      AVHWFramesConstraints *constraints = NULL;
  
      VAStatus vas;
  
      int err, i, j;
  
      int loglevel = fallback_allowed ? AV_LOG_VERBOSE : AV_LOG_ERROR;
  
      const AVCodecDescriptor *codec_desc;
  
      const AVPixFmtDescriptor *pix_desc;
  
      enum AVPixelFormat pix_fmt;
  
      VAProfile profile, *profile_list = NULL;
  
      int profile_count, exact_match, alt_profile;
  
  
  
      codec_desc = avcodec_descriptor_get(avctx->codec_id);
  
      if (!codec_desc) {
  
          err = AVERROR(EINVAL);
  
          goto fail;
  
      }
  
  
  
      profile_count = vaMaxNumProfiles(hwctx->display);
  
      profile_list = av_malloc(profile_count * sizeof(VAProfile));
  
      if (!profile_list) {
  
          err = AVERROR(ENOMEM);
  
          goto fail;
  
      }
  
  
  
      vas = vaQueryConfigProfiles(hwctx->display,
  
                                  profile_list, &profile_count);
  
      if (vas != VA_STATUS_SUCCESS) {
  
          av_log(ctx, loglevel, "Failed to query profiles: %d (%s).\n",
  
                 vas, vaErrorStr(vas));
  
          err = AVERROR(EIO);
  
          goto fail;
  
      }
  
  
  
      profile = VAProfileNone;
  
      exact_match = 0;
  
  
  
      for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) {
  
          int profile_match = 0;
  
          if (avctx->codec_id != vaapi_profile_map[i].codec_id)
  
              continue;
  
          if (avctx->profile == vaapi_profile_map[i].codec_profile)
  
              profile_match = 1;
  
          profile = vaapi_profile_map[i].va_profile;
  
          for (j = 0; j < profile_count; j++) {
  
              if (profile == profile_list[j]) {
  
                  exact_match = profile_match;
  
                  break;
  
              }
  
          }
  
          if (j < profile_count) {
  
              if (exact_match)
  
                  break;
  
              alt_profile = vaapi_profile_map[i].codec_profile;
  
          }
  
      }
  
      av_freep(&profile_list);
  
  
  
      if (profile == VAProfileNone) {
  
          av_log(ctx, loglevel, "No VAAPI support for codec %s.\n",
  
                 codec_desc->name);
  
          err = AVERROR(ENOSYS);
  
          goto fail;
  
      }
  
      if (!exact_match) {
  
          if (fallback_allowed || !hwaccel_lax_profile_check) {
  
              av_log(ctx, loglevel, "No VAAPI support for codec %s "
  
                     "profile %d.\n", codec_desc->name, avctx->profile);
  
              if (!fallback_allowed) {
  
                  av_log(ctx, AV_LOG_WARNING, "If you want attempt decoding "
  
                         "anyway with a possibly-incompatible profile, add "
  
                         "the option -hwaccel_lax_profile_check.\n");
  
              }
  
              err = AVERROR(EINVAL);
  
              goto fail;
  
          } else {
  
              av_log(ctx, AV_LOG_WARNING, "No VAAPI support for codec %s "
  
                     "profile %d: trying instead with profile %d.\n",
  
                     codec_desc->name, avctx->profile, alt_profile);
  
              av_log(ctx, AV_LOG_WARNING, "This may fail or give "
  
                     "incorrect results, depending on your hardware.\n");
  
          }
  
      }
  
  
  
      ctx->va_profile = profile;
  
      ctx->va_entrypoint = VAEntrypointVLD;
  
  
  
      vas = vaCreateConfig(hwctx->display, ctx->va_profile,
  
                           ctx->va_entrypoint, 0, 0, &ctx->va_config);
  
      if (vas != VA_STATUS_SUCCESS) {
  
          av_log(ctx, AV_LOG_ERROR, "Failed to create decode pipeline "
  
                 "configuration: %d (%s).\n", vas, vaErrorStr(vas));
  
          err = AVERROR(EIO);
  
          goto fail;
  
      }
  
  
  
      hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref);
  
      if (!hwconfig) {
  
          err = AVERROR(ENOMEM);
  
          goto fail;
  
      }
  
      hwconfig->config_id = ctx->va_config;
  
  
  
      constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref,
  
                                                        hwconfig);
  
      if (!constraints)
  
          goto fail;
  
  
  
      // Decide on the decoder target format.
  
      // If the user specified something with -hwaccel_output_format then
  
      // try to use that to minimise conversions later.
  
      ctx->decode_format = AV_PIX_FMT_NONE;
  
      if (ctx->output_format != AV_PIX_FMT_NONE &&
  
          ctx->output_format != AV_PIX_FMT_VAAPI) {
  
          for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) {
  
              if (constraints->valid_sw_formats[i] == ctx->decode_format) {
  
                  ctx->decode_format = ctx->output_format;
  
                  av_log(ctx, AV_LOG_DEBUG, "Using decode format %s (output "
  
                         "format).\n", av_get_pix_fmt_name(ctx->decode_format));
  
                  break;
  
              }
  
          }
  
      }
  
      // Otherwise, we would like to try to choose something which matches the
  
      // decoder output, but there isn't enough information available here to
  
      // do so.  Assume for now that we are always dealing with YUV 4:2:0, so
  
      // pick a format which does that.
  
      if (ctx->decode_format == AV_PIX_FMT_NONE) {
  
          for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) {
  
              pix_fmt  = constraints->valid_sw_formats[i];
  
              pix_desc = av_pix_fmt_desc_get(pix_fmt);
  
              if (pix_desc->nb_components == 3 &&
  
                  pix_desc->log2_chroma_w == 1 &&
  
                  pix_desc->log2_chroma_h == 1) {
  
                  ctx->decode_format = pix_fmt;
  
                  av_log(ctx, AV_LOG_DEBUG, "Using decode format %s (format "
  
                         "matched).\n", av_get_pix_fmt_name(ctx->decode_format));
  
                  break;
  
              }
  
          }
  
      }
  
      // Otherwise pick the first in the list and hope for the best.
  
      if (ctx->decode_format == AV_PIX_FMT_NONE) {
  
          ctx->decode_format = constraints->valid_sw_formats[0];
  
          av_log(ctx, AV_LOG_DEBUG, "Using decode format %s (first in list).\n",
  
                 av_get_pix_fmt_name(ctx->decode_format));
  
          if (i > 1) {
  
              // There was a choice, and we picked randomly.  Warn the user
  
              // that they might want to choose intelligently instead.
  
              av_log(ctx, AV_LOG_WARNING, "Using randomly chosen decode "
  
                     "format %s.\n", av_get_pix_fmt_name(ctx->decode_format));
  
          }
  
      }
  
  
  
      // Ensure the picture size is supported by the hardware.
  
      ctx->decode_width  = avctx->coded_width;
  
      ctx->decode_height = avctx->coded_height;
  
      if (ctx->decode_width  < constraints->min_width  ||
  
          ctx->decode_height < constraints->min_height ||
  
          ctx->decode_width  > constraints->max_width  ||
  
          ctx->decode_height >constraints->max_height) {
  
          av_log(ctx, AV_LOG_ERROR, "VAAPI hardware does not support image "
  
                 "size %dx%d (constraints: width %d-%d height %d-%d).\n",
  
                 ctx->decode_width, ctx->decode_height,
  
                 constraints->min_width,  constraints->max_width,
  
                 constraints->min_height, constraints->max_height);
  
          err = AVERROR(EINVAL);
  
          goto fail;
  
      }
  
  
  
      av_hwframe_constraints_free(&constraints);
  
      av_freep(&hwconfig);
  
  
  
      // Decide how many reference frames we need.  This might be doable more
  
      // nicely based on the codec and input stream?
  
      ctx->decode_surfaces = DEFAULT_SURFACES;
  
      // For frame-threaded decoding, one additional surfaces is needed for
  
      // each thread.
  
      if (avctx->active_thread_type & FF_THREAD_FRAME)
  
          ctx->decode_surfaces += avctx->thread_count;
  
  
  
      return 0;
  
  
  
  fail:
  
      av_hwframe_constraints_free(&constraints);
  
      av_freep(&hwconfig);
  
      vaDestroyConfig(hwctx->display, ctx->va_config);
  
      av_freep(&profile_list);
  
      return err;
  
  }
  