Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
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;
  }
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
/* encodes frame according to info in xframe;
   - buf is input buffer, can be NULL if dummy
   - buf is disposed of prior to exit
   - resulting buffer is returned, NULL if no encoder output or error
*/
static inline GstBuffer *
gst_xvidenc_encode (GstXvidEnc * xvidenc, GstBuffer * buf,
    xvid_enc_frame_t xframe)
{
  GstBuffer *outbuf;
  gint ret;

  /* compressed frame should fit in the rough size of an uncompressed one */
  outbuf = gst_buffer_new_and_alloc (gst_xvid_image_get_size (xvidenc->csp,
          xvidenc->width, xvidenc->height));

  xframe.bitstream = (void *) GST_BUFFER_DATA (outbuf);
  xframe.length = GST_BUFFER_SIZE (outbuf);

  /* now provide input image data where-abouts, if needed */
  if (buf)
    gst_xvid_image_fill (&xframe.input, GST_BUFFER_DATA (buf), xvidenc->csp,
        xvidenc->width, xvidenc->height);

  GST_DEBUG_OBJECT (xvidenc, "encoding frame into buffer of size %d",
      GST_BUFFER_SIZE (outbuf));
  ret = xvid_encore (xvidenc->handle, XVID_ENC_ENCODE, &xframe, NULL);

  if (ret < 0) {
    /* things can be nasty if we are trying to flush, so don't signal error then */
    if (buf) {
      GST_ELEMENT_WARNING (xvidenc, LIBRARY, ENCODE, (NULL),
          ("Error encoding xvid frame: %s (%d)", gst_xvid_error (ret), ret));
      gst_buffer_unref (buf);
    }
    gst_buffer_unref (outbuf);
    return NULL;
  } else if (ret > 0) {         /* make sub-buffer */
    GstBuffer *sub;

    GST_DEBUG_OBJECT (xvidenc, "xvid produced output of size %d", ret);
    sub = gst_buffer_create_sub (outbuf, 0, ret);

    /* parent no longer needed, will go away with child buffer */
    gst_buffer_unref (outbuf);
    outbuf = sub;
  } else {                      /* encoder did not yet produce something */
    GST_DEBUG_OBJECT (xvidenc, "xvid produced no output");
    gst_buffer_unref (outbuf);
    g_queue_push_tail (xvidenc->delay, buf);
    return NULL;
  }

  /* finish decoration and return */
  if (!(xframe.out_flags & XVID_KEYFRAME))
    GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT);
  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (xvidenc->srcpad));

  /* now we need the right buf to take timestamps from;
     note that timestamps from a display order input buffer can end up with
     another encode order output buffer, but other than this permutation,
     the overall time progress is tracked,
     and keyframes should have the correct stamp */
  if (!g_queue_is_empty (xvidenc->delay)) {
    if (buf)
      g_queue_push_tail (xvidenc->delay, buf);
    buf = g_queue_pop_head (xvidenc->delay);
  }
  if (buf) {
    GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
    GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buf);
    gst_buffer_unref (buf);
  }

  return outbuf;
}
Ejemplo n.º 6
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;
}