static gboolean
fill_sequence (GstVaapiEncoderVP8 * encoder, GstVaapiEncSequence * sequence)
{
  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
  VAEncSequenceParameterBufferVP8 *const seq_param = sequence->param;

  memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferVP8));

  seq_param->frame_width = GST_VAAPI_ENCODER_WIDTH (encoder);
  seq_param->frame_height = GST_VAAPI_ENCODER_HEIGHT (encoder);

  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR ||
      GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_VBR)
    seq_param->bits_per_second = base_encoder->bitrate * 1000;

  seq_param->intra_period = base_encoder->keyframe_period;

  return TRUE;
}
static gboolean
set_misc_parameters (GstVaapiEncoderMpeg2 * encoder,
    GstVaapiEncPicture * picture)
{
  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
  GstVaapiEncMiscParam *misc = NULL;
  VAEncMiscParameterHRD *hrd;
  VAEncMiscParameterRateControl *rate_control;

  /* add hrd */
  misc = GST_VAAPI_ENC_MISC_PARAM_NEW (HRD, encoder);
  g_assert (misc);
  if (!misc)
    return FALSE;
  gst_vaapi_enc_picture_add_misc_param (picture, misc);
  hrd = misc->data;
  if (base_encoder->bitrate > 0) {
    hrd->initial_buffer_fullness = base_encoder->bitrate * 1000 * 4;
    hrd->buffer_size = base_encoder->bitrate * 1000 * 8;
  } else {
    hrd->initial_buffer_fullness = 0;
    hrd->buffer_size = 0;
  }
  gst_vaapi_codec_object_replace (&misc, NULL);

  /* add ratecontrol */
  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR) {
    misc = GST_VAAPI_ENC_MISC_PARAM_NEW (RateControl, encoder);
    g_assert (misc);
    if (!misc)
      return FALSE;
    gst_vaapi_enc_picture_add_misc_param (picture, misc);
    rate_control = misc->data;
    memset (rate_control, 0, sizeof (VAEncMiscParameterRateControl));
    if (base_encoder->bitrate)
      rate_control->bits_per_second = base_encoder->bitrate * 1000;
    else
      rate_control->bits_per_second = 0;
    rate_control->target_percentage = 70;
    rate_control->window_size = 500;
    rate_control->initial_qp = encoder->cqp;
    rate_control->min_qp = 0;
    rate_control->basic_unit_size = 0;
    gst_vaapi_codec_object_replace (&misc, NULL);
  }
  return TRUE;
}
/* Updates video context */
static gboolean
set_context_info (GstVaapiEncoder * encoder)
{
  GstVaapiContextInfo *const cip = &encoder->context_info;
  GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
  const GstVideoFormat format =
    GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder));
  const GstVaapiEncoderClassData *const cdata =
      GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data;

  cip->usage = GST_VAAPI_CONTEXT_USAGE_ENCODE;
  cip->profile = encoder->profile;
  cip->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
  if (cdata->codec != GST_VAAPI_CODEC_JPEG)
    cip->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
  else
    cip->entrypoint = GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE;
  cip->chroma_type = gst_vaapi_video_format_get_chroma_type (format);
  cip->width = GST_VAAPI_ENCODER_WIDTH (encoder);
  cip->height = GST_VAAPI_ENCODER_HEIGHT (encoder);
  cip->ref_frames = encoder->num_ref_frames;

  if (!cip->chroma_type  && (format != GST_VIDEO_FORMAT_ENCODED))
    goto error_unsupported_format;

  if (cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420 &&
      format != GST_VIDEO_FORMAT_ENCODED) {
    GST_ERROR ("We are only supporting YUV:4:2:0 for encoding,"
        "please try to use vaapipostproc to convert the input format!");
    goto error_unsupported_format;
  }
  
  memset (config, 0, sizeof (*config));
  config->rc_mode = GST_VAAPI_ENCODER_RATE_CONTROL (encoder);
  config->packed_headers = get_packed_headers (encoder);
  return TRUE;

  /* ERRORS */
error_unsupported_format:
  {
    GST_ERROR ("failed to determine chroma type for format %s",
        gst_vaapi_video_format_to_string (format));
    return FALSE;
  }
}
static gboolean
ensure_bitrate (GstVaapiEncoderMpeg2 * encoder)
{
  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);

  /* Default compression: 64 bits per macroblock */
  switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
    case GST_VAAPI_RATECONTROL_CBR:
      if (!base_encoder->bitrate)
        base_encoder->bitrate =
            gst_util_uint64_scale (GST_VAAPI_ENCODER_WIDTH (encoder) *
            GST_VAAPI_ENCODER_HEIGHT (encoder),
            GST_VAAPI_ENCODER_FPS_N (encoder),
            GST_VAAPI_ENCODER_FPS_D (encoder)) / 4 / 1000;
      break;
    default:
      base_encoder->bitrate = 0;
      break;
  }
  return TRUE;
}
static gboolean
ensure_control_rate_params (GstVaapiEncoderVP8 * encoder)
{
  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);

  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
    return TRUE;

  /* RateControl params */
  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->yac_qi;
  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).min_qp = 1;

  /* *INDENT-OFF* */
  /* HRD params */
  GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) {
    .buffer_size = base_encoder->bitrate * 1000 * 2,
    .initial_buffer_fullness = base_encoder->bitrate * 1000,
  };
  /* *INDENT-ON* */

  return TRUE;
}

static gboolean
ensure_misc_params (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture)
{
  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);

  if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture))
    return FALSE;

  if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture))
    return FALSE;

  return TRUE;
}