Exemplo n.º 1
0
/* flush xvid encoder buffers caused by bframe usage;
   not well tested */
static void
gst_xviddec_flush_buffers (GstXvidDec * dec, gboolean send)
{
#if 0
  gint ret;
  GstBuffer *outbuf = NULL;
  xvid_dec_frame_t xframe;
  xvid_dec_stats_t xstats;
#endif

  GST_DEBUG_OBJECT (dec, "flushing buffers with send %d, have_ts %d",
      send, dec->have_ts);

  /* no need to flush if there is no delayed time-stamp */
  if (!dec->have_ts)
    return;

  /* flushing must reset the timestamp keeping */
  dec->have_ts = FALSE;

  /* also no need to flush if no handle */
  if (!dec->handle)
    return;

  /* unlike encoder, decoder does not seem to like flushing, disable for now */
#if 0
  gst_xvid_init_struct (xframe);
  gst_xvid_init_struct (xstats);

  /* init a fake frame to force flushing */
  xframe.bitstream = NULL;
  xframe.length = -1;

  ret = gst_xviddec_decode (dec, xframe, &outbuf, &xstats);
  GST_DEBUG_OBJECT (dec, "received frame when flushing, type %d, size %d",
      xstats.type, ret);

  if (ret > 0 && send) {
    /* we have some valid return frame, give it the delayed timestamp and send */
    GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts;
    GST_BUFFER_DURATION (outbuf) = dec->next_dur;

    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (dec->srcpad));
    gst_pad_push (dec->srcpad, outbuf);
    return;
  }

  if (outbuf)
    gst_buffer_unref (outbuf);
#else
  return;
#endif
}
Exemplo n.º 2
0
gboolean
gst_xvid_init (void)
{
  xvid_gbl_init_t xinit;
  gint ret;
  static gboolean is_init = FALSE;

  /* only init once */
  if (is_init == TRUE) {
    return TRUE;
  }

  /* set up xvid initially (function pointers, CPU flags) */
  gst_xvid_init_struct (xinit);

  if ((ret = xvid_global (NULL, XVID_GBL_INIT, &xinit, NULL)) < 0) {
    g_warning ("Failed to initialize XviD: %s (%d)", gst_xvid_error (ret), ret);
    return FALSE;
  }

  GST_LOG ("Initted XviD version %d.%d.%d (API %d.%d)",
      XVID_VERSION_MAJOR (XVID_VERSION),
      XVID_VERSION_MINOR (XVID_VERSION),
      XVID_VERSION_PATCH (XVID_VERSION),
      XVID_API_MAJOR (XVID_API), XVID_API_MINOR (XVID_API));

  is_init = TRUE;
  return TRUE;
}
Exemplo n.º 3
0
static gboolean
gst_xviddec_setup (GstXvidDec * dec)
{
  xvid_dec_create_t xdec;
  gint ret;

  /* initialise parameters, see xvid documentation */
  gst_xvid_init_struct (xdec);
  /* let the decoder handle this, don't trust the container */
  xdec.width = 0;
  xdec.height = 0;
  xdec.handle = NULL;

  GST_DEBUG_OBJECT (dec, "Initializing xvid decoder with parameters "
      "%dx%d@%d", dec->width, dec->height, dec->csp);

  if ((ret = xvid_decore (NULL, XVID_DEC_CREATE, &xdec, NULL)) < 0) {
    GST_WARNING_OBJECT (dec, "Initializing xvid decoder failed: %s (%d)",
        gst_xvid_error (ret), ret);
    return FALSE;
  }

  dec->handle = xdec.handle;

  return TRUE;
}
Exemplo n.º 4
0
/* flush xvid encoder buffers caused by bframe usage */
static void
gst_xvidenc_flush_buffers (GstXvidEnc * xvidenc, gboolean send)
{
  GstBuffer *outbuf;
  xvid_enc_frame_t xframe;

  /* no need to flush if no handle */
  if (!xvidenc->handle)
    return;

  gst_xvid_init_struct (xframe);

  /* init a fake frame to force flushing */
  xframe.input.csp = XVID_CSP_NULL;
  xframe.input.plane[0] = NULL;
  xframe.input.plane[1] = NULL;
  xframe.input.plane[2] = NULL;
  xframe.input.stride[0] = 0;
  xframe.input.stride[1] = 0;
  xframe.input.stride[2] = 0;
  xframe.quant = 0;

  GST_DEBUG ("flushing buffers with sending %d", send);

  while (!g_queue_is_empty (xvidenc->delay)) {
    outbuf = gst_xvidenc_encode (xvidenc, NULL, xframe);

    if (outbuf) {
      if (send)
        gst_pad_push (xvidenc->srcpad, outbuf);
      else
        gst_buffer_unref (outbuf);
    } else                      /* hm, there should have been something in there */
      break;
  }

  /* our queue should be empty anyway if we did not have to break out ... */
  while (!g_queue_is_empty (xvidenc->delay))
    gst_buffer_unref (g_queue_pop_head (xvidenc->delay));
}
Exemplo n.º 5
0
static GstFlowReturn
gst_xviddec_chain (GstPad * pad, GstBuffer * buf)
{
  GstXvidDec *dec;
  GstBuffer *outbuf = NULL;
  xvid_dec_frame_t xframe;
  xvid_dec_stats_t xstats;
  gint ret;
  guint8 *data, *dupe = NULL;
  guint size;
  GstFlowReturn fret;

  dec = GST_XVIDDEC (GST_OBJECT_PARENT (pad));

  if (!dec->handle)
    goto not_negotiated;

  fret = GST_FLOW_OK;

  GST_LOG_OBJECT (dec, "Received buffer of time %" GST_TIME_FORMAT
      " duration %" GST_TIME_FORMAT ", size %d",
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
      GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_SIZE (buf));

  if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT)) {
    /* FIXME: should we do anything here, like flush the decoder? */
  }

  data = GST_BUFFER_DATA (buf);
  size = GST_BUFFER_SIZE (buf);

  /* xvidcore overreads the input buffer, we need to alloc some extra padding
   * to make things work reliably */
#define EXTRA_PADDING 16
  if (EXTRA_PADDING > 0) {
    dupe = g_malloc (size + EXTRA_PADDING);
    memcpy (dupe, data, size);
    memset (dupe + size, 0, EXTRA_PADDING);
    data = dupe;
  }

  do {                          /* loop needed because xvidcore may return vol information */
    /* decode and so ... */
    gst_xvid_init_struct (xframe);
    xframe.general = XVID_LOWDELAY;
    xframe.bitstream = (void *) data;
    xframe.length = size;

    gst_xvid_init_struct (xstats);

    if (outbuf == NULL) {
      fret = gst_pad_alloc_buffer (dec->srcpad, GST_BUFFER_OFFSET_NONE,
          dec->outbuf_size, GST_PAD_CAPS (dec->srcpad), &outbuf);
      if (fret != GST_FLOW_OK)
        goto done;
    }

    gst_xvid_image_fill (&xframe.output, GST_BUFFER_DATA (outbuf),
        dec->csp, dec->width, dec->height);

    ret = xvid_decore (dec->handle, XVID_DEC_DECODE, &xframe, &xstats);
    if (ret < 0)
      goto decode_error;

    GST_LOG_OBJECT (dec, "xvid produced output, type %d, consumed %d",
        xstats.type, ret);

    if (xstats.type == XVID_TYPE_VOL)
      gst_xviddec_negotiate (dec, &xstats);

    data += ret;
    size -= ret;
  } while (xstats.type <= 0 && size > 0);

  /* 1 byte is frequently left over */
  if (size > 1) {
    GST_WARNING_OBJECT (dec, "decoder did not consume all input");
  }

  /* FIXME, reflow the multiple return exit points */
  if (xstats.type > 0) {        /* some real output was produced */
    if (G_UNLIKELY (dec->waiting_for_key)) {
      if (xstats.type != XVID_TYPE_IVOP)
        goto dropping;

      dec->waiting_for_key = FALSE;
    }
    /* bframes can cause a delay in frames being returned
       non keyframe timestamps can permute a bit between
       encode and display order, but should match for keyframes */
    if (dec->have_ts) {
      GST_BUFFER_TIMESTAMP (outbuf) = dec->next_ts;
      GST_BUFFER_DURATION (outbuf) = dec->next_dur;
      dec->next_ts = GST_BUFFER_TIMESTAMP (buf);
      dec->next_dur = GST_BUFFER_DURATION (buf);
    } else {
      GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
      GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
    }
    gst_buffer_set_caps (outbuf, GST_PAD_CAPS (dec->srcpad));
    GST_LOG_OBJECT (dec, "pushing buffer with pts %" GST_TIME_FORMAT
        " duration %" GST_TIME_FORMAT,
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf)));
    fret = gst_pad_push (dec->srcpad, outbuf);

  } else {                      /* no real output yet, delay in frames being returned */
    if (G_UNLIKELY (dec->have_ts)) {
      GST_WARNING_OBJECT (dec,
          "xvid decoder produced no output, but timestamp %" GST_TIME_FORMAT
          " already queued", GST_TIME_ARGS (dec->next_ts));
    } else {
      dec->have_ts = TRUE;
      dec->next_ts = GST_BUFFER_TIMESTAMP (buf);
      dec->next_dur = GST_BUFFER_DURATION (buf);
    }
    gst_buffer_unref (outbuf);
  }

done:
  g_free (dupe);
  gst_buffer_unref (buf);

  return fret;

  /* ERRORS */
not_negotiated:
  {
    GST_ELEMENT_ERROR (dec, CORE, NEGOTIATION, (NULL),
        ("format wasn't negotiated before chain function"));
    fret = GST_FLOW_NOT_NEGOTIATED;
    goto done;
  }
decode_error:
  {
    /* FIXME: shouldn't error out fatally/properly after N decoding errors? */
    GST_ELEMENT_WARNING (dec, STREAM, DECODE, (NULL),
        ("Error decoding xvid frame: %s (%d)", gst_xvid_error (ret), ret));
    if (outbuf)
      gst_buffer_unref (outbuf);
    goto done;
  }
dropping:
  {
    GST_WARNING_OBJECT (dec, "Dropping non-keyframe (seek/init)");
    if (outbuf)
      gst_buffer_unref (outbuf);
    goto done;
  }
}
Exemplo n.º 6
0
static gboolean
gst_xvidenc_setup (GstXvidEnc * xvidenc)
{
  xvid_enc_create_t xenc;
  xvid_enc_plugin_t xplugin[2];
  gint ret;
  GstCaps *allowed_caps;
  gint profile = -1;

  /* Negotiate profile/level with downstream */
  allowed_caps = gst_pad_get_allowed_caps (xvidenc->srcpad);
  if (allowed_caps && !gst_caps_is_empty (allowed_caps)) {
    const gchar *profile_str, *level_str;

    allowed_caps = gst_caps_make_writable (allowed_caps);
    gst_caps_truncate (allowed_caps);

    profile_str =
        gst_structure_get_string (gst_caps_get_structure (allowed_caps, 0),
        "profile");
    level_str =
        gst_structure_get_string (gst_caps_get_structure (allowed_caps, 0),
        "level");
    if (profile_str) {
      if (g_str_equal (profile_str, "simple")) {
        if (!level_str) {
          profile = XVID_PROFILE_S_L0;
        } else if (g_str_equal (level_str, "0")) {
          profile = XVID_PROFILE_S_L0;
        } else if (g_str_equal (level_str, "1")) {
          profile = XVID_PROFILE_S_L1;
        } else if (g_str_equal (level_str, "2")) {
          profile = XVID_PROFILE_S_L2;
        } else if (g_str_equal (level_str, "3")) {
          profile = XVID_PROFILE_S_L3;
       /* } else if (g_str_equal (level_str, "4a")) {
          profile = XVID_PROFILE_S_L4a;
        } else if (g_str_equal (level_str, "5")) {
          profile = XVID_PROFILE_S_L5;
        } else if (g_str_equal (level_str, "6")) {
          profile = XVID_PROFILE_S_L6;*/
        } else {
          GST_ERROR_OBJECT (xvidenc,
              "Invalid profile/level combination (%s %s)", profile_str,
              level_str);
        }
      } else if (g_str_equal (profile_str, "advanced-real-time-simple")) {
        if (!level_str) {
          profile = XVID_PROFILE_ARTS_L1;
        } else if (g_str_equal (level_str, "1")) {
          profile = XVID_PROFILE_ARTS_L1;
        } else if (g_str_equal (level_str, "2")) {
          profile = XVID_PROFILE_ARTS_L2;
        } else if (g_str_equal (level_str, "3")) {
          profile = XVID_PROFILE_ARTS_L3;
        } else if (g_str_equal (level_str, "4")) {
          profile = XVID_PROFILE_ARTS_L4;
        } else {
          GST_ERROR_OBJECT (xvidenc,
              "Invalid profile/level combination (%s %s)", profile_str,
              level_str);
        }
      } else if (g_str_equal (profile_str, "advanced-simple")) {
        if (!level_str) {
          profile = XVID_PROFILE_AS_L0;
        } else if (g_str_equal (level_str, "0")) {
          profile = XVID_PROFILE_AS_L0;
        } else if (g_str_equal (level_str, "1")) {
          profile = XVID_PROFILE_AS_L1;
        } else if (g_str_equal (level_str, "2")) {
          profile = XVID_PROFILE_AS_L2;
        } else if (g_str_equal (level_str, "3")) {
          profile = XVID_PROFILE_AS_L3;
        } else if (g_str_equal (level_str, "4")) {
          profile = XVID_PROFILE_AS_L4;
        } else {
          GST_ERROR_OBJECT (xvidenc,
              "Invalid profile/level combination (%s %s)", profile_str,
              level_str);
        }
      } else {
        GST_ERROR_OBJECT (xvidenc, "Invalid profile (%s)", profile_str);
      }
    }
  }
  if (allowed_caps)
    gst_caps_unref (allowed_caps);

  if (profile != -1) {
    xvidenc->profile = profile;
    g_object_notify (G_OBJECT (xvidenc), "profile");
  }

  /* see xvid.h for the meaning of all this. */
  gst_xvid_init_struct (xenc);

  xenc.profile = xvidenc->used_profile = xvidenc->profile;
  xenc.width = xvidenc->width;
  xenc.height = xvidenc->height;
  xenc.max_bframes = xvidenc->max_bframes;
  xenc.global = XVID_GLOBAL_PACKED
      | (xvidenc->closed_gop ? XVID_GLOBAL_CLOSED_GOP : 0);

  xenc.bquant_ratio = xvidenc->bquant_ratio;
  xenc.bquant_offset = xvidenc->bquant_offset;

  xenc.fbase = xvidenc->fbase;
  xenc.fincr = xvidenc->fincr;
  xenc.max_key_interval = (xvidenc->max_key_interval < 0) ?
      (-xvidenc->max_key_interval * xenc.fbase /
      xenc.fincr) : xvidenc->max_key_interval;
  xenc.handle = NULL;

  /* quantizer ranges */
  xenc.min_quant[0] = xvidenc->min_iquant;
  xenc.min_quant[1] = xvidenc->min_pquant;
  xenc.min_quant[2] = xvidenc->min_bquant;
  xenc.max_quant[0] = xvidenc->max_iquant;
  xenc.max_quant[1] = xvidenc->max_pquant;
  xenc.max_quant[2] = xvidenc->max_bquant;

  /* cbr, vbr or constant quantizer */
  xenc.num_plugins = 1;
  xenc.plugins = xplugin;
  switch (xvidenc->pass) {
    case XVIDENC_CBR:
    case XVIDENC_QUANT:
    {
      xvid_plugin_single_t xsingle;
      xvid_enc_zone_t xzone;

      gst_xvid_init_struct (xsingle);

      xenc.plugins[0].func = xvid_plugin_single;
      xenc.plugins[0].param = &xsingle;

      xsingle.bitrate = xvidenc->bitrate;
      xsingle.reaction_delay_factor = MAX (0, xvidenc->reaction_delay_factor);
      xsingle.averaging_period = MAX (0, xvidenc->averaging_period);
      xsingle.buffer = MAX (0, xvidenc->buffer);

      if (xvidenc->pass == XVIDENC_CBR)
        break;

      /* set up a const quantizer zone */
      xzone.mode = XVID_ZONE_QUANT;
      xzone.frame = 0;
      xzone.increment = xvidenc->quant;
      xzone.base = 1;
      xenc.zones = &xzone;
      xenc.num_zones++;

      break;
    }
    case XVIDENC_VBR_PASS1:
    {
      xvid_plugin_2pass1_t xpass;

      gst_xvid_init_struct (xpass);

      xenc.plugins[0].func = xvid_plugin_2pass1;
      xenc.plugins[0].param = &xpass;

      xpass.filename = xvidenc->filename;
      break;
    }
    case XVIDENC_VBR_PASS2:
    {
      xvid_plugin_2pass2_t xpass;

      gst_xvid_init_struct (xpass);

      xenc.plugins[0].func = xvid_plugin_2pass2;
      xenc.plugins[0].param = &xpass;

      xpass.bitrate = xvidenc->bitrate;
      xpass.filename = xvidenc->filename;
      xpass.keyframe_boost = xvidenc->keyframe_boost;
      xpass.curve_compression_high = xvidenc->curve_compression_high;
      xpass.curve_compression_low = xvidenc->curve_compression_low;
      xpass.overflow_control_strength =
          MAX (0, xvidenc->overflow_control_strength);
      xpass.max_overflow_improvement =
          MAX (0, xvidenc->max_overflow_improvement);
      xpass.max_overflow_degradation =
          MAX (0, xvidenc->max_overflow_degradation);
      xpass.kfreduction = MAX (0, xvidenc->kfreduction);
      xpass.kfthreshold = MAX (0, xvidenc->kfthreshold);
      xpass.container_frame_overhead =
          MAX (0, xvidenc->container_frame_overhead);
      break;
    }
  }

  if (xvidenc->lumimasking) {
    xenc.plugins[1].func = xvid_plugin_lumimasking;
    xenc.plugins[1].param = NULL;
    xenc.num_plugins++;
  }

  if ((ret = xvid_encore (NULL, XVID_ENC_CREATE, &xenc, NULL)) < 0) {
    GST_DEBUG_OBJECT (xvidenc, "Error setting up xvid encoder: %s (%d)",
        gst_xvid_error (ret), ret);
    return FALSE;
  }

  xvidenc->handle = xenc.handle;

  return TRUE;
}
Exemplo n.º 7
0
static GstFlowReturn
gst_xvidenc_chain (GstPad * pad, GstBuffer * buf)
{
  GstXvidEnc *xvidenc = GST_XVIDENC (GST_PAD_PARENT (pad));
  GstBuffer *outbuf;
  xvid_enc_frame_t xframe;

  const gint motion_presets[] = {
    0, 0, 0, 0,
    XVID_ME_HALFPELREFINE16,
    XVID_ME_HALFPELREFINE16 | XVID_ME_ADVANCEDDIAMOND16,
    XVID_ME_HALFPELREFINE16 | XVID_ME_EXTSEARCH16
        | XVID_ME_HALFPELREFINE8 | XVID_ME_USESQUARES16
  };

  if (!xvidenc->handle) {
    GST_ELEMENT_ERROR (xvidenc, CORE, NEGOTIATION, (NULL),
        ("format wasn't negotiated before chain function"));
    gst_buffer_unref (buf);
    return GST_FLOW_NOT_NEGOTIATED;
  }

  GST_DEBUG_OBJECT (xvidenc,
      "Received buffer of time %" GST_TIME_FORMAT ", size %d",
      GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_SIZE (buf));

  if (xvidenc->xframe_cache)
    memcpy (&xframe, xvidenc->xframe_cache, sizeof (xframe));
  else {                        /* need to build some inital xframe to be cached */
    /* encode and so ... */
    gst_xvid_init_struct (xframe);

    if (xvidenc->par_width == xvidenc->par_height)
      xframe.par = XVID_PAR_11_VGA;
    else {
      xframe.par = XVID_PAR_EXT;
      xframe.par_width = xvidenc->par_width;
      xframe.par_height = xvidenc->par_height;
    }

    /* handle options */
    xframe.vol_flags |= xvidenc->quant_type;
    xframe.vop_flags = XVID_VOP_HALFPEL;
    xframe.motion = motion_presets[xvidenc->motion];

    if (xvidenc->me_chroma) {
      xframe.motion |= XVID_ME_CHROMA_PVOP;
      xframe.motion |= XVID_ME_CHROMA_BVOP;
    }

    if (xvidenc->me_vhq >= 1) {
      xframe.vop_flags |= XVID_VOP_MODEDECISION_RD;
    }
    if (xvidenc->me_vhq >= 2) {
      xframe.motion |= XVID_ME_HALFPELREFINE16_RD;
      xframe.motion |= XVID_ME_QUARTERPELREFINE16_RD;
    }
    if (xvidenc->me_vhq >= 3) {
      xframe.motion |= XVID_ME_HALFPELREFINE8_RD;
      xframe.motion |= XVID_ME_QUARTERPELREFINE8_RD;
      xframe.motion |= XVID_ME_CHECKPREDICTION_RD;
    }
    if (xvidenc->me_vhq >= 4) {
      xframe.motion |= XVID_ME_EXTSEARCH_RD;
    }

    /* no motion estimation, then only intra */
    if (xvidenc->motion == 0) {
      xframe.type = XVID_TYPE_IVOP;
    } else {
      xframe.type = XVID_TYPE_AUTO;
    }

    if (xvidenc->motion > 4) {
      xframe.vop_flags |= XVID_VOP_INTER4V;
    }

    if (xvidenc->me_quarterpel) {
      xframe.vol_flags |= XVID_VOL_QUARTERPEL;
      xframe.motion |= XVID_ME_QUARTERPELREFINE16;
      xframe.motion |= XVID_ME_QUARTERPELREFINE8;
    }

    if (xvidenc->gmc) {
      xframe.vol_flags |= XVID_VOL_GMC;
      xframe.motion |= XVID_ME_GME_REFINE;
    }

    if (xvidenc->interlaced) {
      xframe.vol_flags |= XVID_VOL_INTERLACING;
    }

    if (xvidenc->trellis) {
      xframe.vop_flags |= XVID_VOP_TRELLISQUANT;
    }

    if (xvidenc->hqacpred) {
      xframe.vop_flags |= XVID_VOP_HQACPRED;
    }

    if (xvidenc->greyscale) {
      xframe.vop_flags |= XVID_VOP_GREYSCALE;
    }

    if (xvidenc->cartoon) {
      xframe.vop_flags |= XVID_VOP_CARTOON;
      xframe.motion |= XVID_ME_DETECT_STATIC_MOTION;
    }

    xframe.bframe_threshold = xvidenc->bframe_threshold;
    xframe.input.csp = xvidenc->csp;

    /* save in cache */
    xvidenc->xframe_cache = g_memdup (&xframe, sizeof (xframe));
  }

  outbuf = gst_xvidenc_encode (xvidenc, buf, xframe);

  if (!outbuf)                  /* error or no data yet */
    return GST_FLOW_OK;

  /* go out, multiply! */
  return gst_pad_push (xvidenc->srcpad, outbuf);
}
Exemplo n.º 8
0
static gboolean
gst_xvidenc_setup (GstXvidEnc * xvidenc)
{
  xvid_enc_create_t xenc;
  xvid_enc_plugin_t xplugin[2];
  gint ret;

  /* see xvid.h for the meaning of all this. */
  gst_xvid_init_struct (xenc);

  xenc.profile = xvidenc->profile;
  xenc.width = xvidenc->width;
  xenc.height = xvidenc->height;
  xenc.max_bframes = xvidenc->max_bframes;
  xenc.global = XVID_GLOBAL_PACKED
      | (xvidenc->closed_gop ? XVID_GLOBAL_CLOSED_GOP : 0);

  xenc.bquant_ratio = xvidenc->bquant_ratio;
  xenc.bquant_offset = xvidenc->bquant_offset;

  xenc.fbase = xvidenc->fbase;
  xenc.fincr = xvidenc->fincr;
  xenc.max_key_interval = (xvidenc->max_key_interval < 0) ?
      (-xvidenc->max_key_interval * xenc.fbase /
      xenc.fincr) : xvidenc->max_key_interval;
  xenc.handle = NULL;

  /* quantizer ranges */
  xenc.min_quant[0] = xvidenc->min_iquant;
  xenc.min_quant[1] = xvidenc->min_pquant;
  xenc.min_quant[2] = xvidenc->min_bquant;
  xenc.max_quant[0] = xvidenc->max_iquant;
  xenc.max_quant[1] = xvidenc->max_pquant;
  xenc.max_quant[2] = xvidenc->max_bquant;

  /* cbr, vbr or constant quantizer */
  xenc.num_plugins = 1;
  xenc.plugins = xplugin;
  switch (xvidenc->pass) {
    case XVIDENC_CBR:
    case XVIDENC_QUANT:
    {
      xvid_plugin_single_t xsingle;
      xvid_enc_zone_t xzone;

      gst_xvid_init_struct (xsingle);

      xenc.plugins[0].func = xvid_plugin_single;
      xenc.plugins[0].param = &xsingle;

      xsingle.bitrate = xvidenc->bitrate;
      xsingle.reaction_delay_factor = MAX (0, xvidenc->reaction_delay_factor);
      xsingle.averaging_period = MAX (0, xvidenc->averaging_period);
      xsingle.buffer = MAX (0, xvidenc->buffer);

      if (xvidenc->pass == XVIDENC_CBR)
        break;

      /* set up a const quantizer zone */
      xzone.mode = XVID_ZONE_QUANT;
      xzone.frame = 0;
      xzone.increment = xvidenc->quant;
      xzone.base = 1;
      xenc.zones = &xzone;
      xenc.num_zones++;

      break;
    }
    case XVIDENC_VBR_PASS1:
    {
      xvid_plugin_2pass1_t xpass;

      gst_xvid_init_struct (xpass);

      xenc.plugins[0].func = xvid_plugin_2pass1;
      xenc.plugins[0].param = &xpass;

      xpass.filename = xvidenc->filename;
      break;
    }
    case XVIDENC_VBR_PASS2:
    {
      xvid_plugin_2pass2_t xpass;

      gst_xvid_init_struct (xpass);

      xenc.plugins[0].func = xvid_plugin_2pass2;
      xenc.plugins[0].param = &xpass;

      xpass.bitrate = xvidenc->bitrate;
      xpass.filename = xvidenc->filename;
      xpass.keyframe_boost = xvidenc->keyframe_boost;
      xpass.curve_compression_high = xvidenc->curve_compression_high;
      xpass.curve_compression_low = xvidenc->curve_compression_low;
      xpass.overflow_control_strength =
          MAX (0, xvidenc->overflow_control_strength);
      xpass.max_overflow_improvement =
          MAX (0, xvidenc->max_overflow_improvement);
      xpass.max_overflow_degradation =
          MAX (0, xvidenc->max_overflow_degradation);
      xpass.kfreduction = MAX (0, xvidenc->kfreduction);
      xpass.kfthreshold = MAX (0, xvidenc->kfthreshold);
      xpass.container_frame_overhead =
          MAX (0, xvidenc->container_frame_overhead);
      break;
    }
  }

  if (xvidenc->lumimasking) {
    xenc.plugins[1].func = xvid_plugin_lumimasking;
    xenc.plugins[1].param = NULL;
    xenc.num_plugins++;
  }

  if ((ret = xvid_encore (NULL, XVID_ENC_CREATE, &xenc, NULL)) < 0) {
    GST_DEBUG_OBJECT (xvidenc, "Error setting up xvid encoder: %s (%d)",
        gst_xvid_error (ret), ret);
    return FALSE;
  }

  xvidenc->handle = xenc.handle;

  return TRUE;
}