Esempio n. 1
0
gint
gst_xvid_image_get_size (gint csp, gint width, gint height)
{
  xvid_image_t dummy_im;

  return gst_xvid_image_fill (&dummy_im, NULL, csp, width, height);
}
Esempio n. 2
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;
  }
}
Esempio n. 3
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;
}