static gboolean
gst_xviddec_setcaps (GstPad * pad, GstCaps * caps)
{
  GstXvidDec *dec = GST_XVIDDEC (GST_PAD_PARENT (pad));
  GstStructure *structure;
  GstCaps *allowed_caps;
  const GValue *val;

  GST_LOG_OBJECT (dec, "caps %" GST_PTR_FORMAT, caps);

  /* if there's something old around, remove it */
  if (dec->handle) {
    gst_xviddec_unset (dec);
  }

  structure = gst_caps_get_structure (caps, 0);
  gst_structure_get_int (structure, "width", &dec->width);
  gst_structure_get_int (structure, "height", &dec->height);

  /* perhaps some fps info */
  val = gst_structure_get_value (structure, "framerate");
  if ((val != NULL) && GST_VALUE_HOLDS_FRACTION (val)) {
    dec->fps_n = gst_value_get_fraction_numerator (val);
    dec->fps_d = gst_value_get_fraction_denominator (val);
  } else {
    dec->fps_n = -1;
    dec->fps_d = 1;
  }

  /* perhaps some par info */
  val = gst_structure_get_value (structure, "pixel-aspect-ratio");
  if (val != NULL && GST_VALUE_HOLDS_FRACTION (val)) {
    dec->par_n = gst_value_get_fraction_numerator (val);
    dec->par_d = gst_value_get_fraction_denominator (val);
  } else {
    dec->par_n = 1;
    dec->par_d = 1;
  }

  /* we try to find the preferred/accept csp */
  allowed_caps = gst_pad_get_allowed_caps (dec->srcpad);
  if (!allowed_caps) {
    GST_DEBUG_OBJECT (dec, "... but no peer, using template caps");
    /* need to copy because get_allowed_caps returns a ref,
       and get_pad_template_caps doesn't */
    allowed_caps = gst_caps_copy (gst_pad_get_pad_template_caps (dec->srcpad));
  }
  GST_LOG_OBJECT (dec, "allowed source caps %" GST_PTR_FORMAT, allowed_caps);

  /* pick the first one ... */
  structure = gst_caps_get_structure (allowed_caps, 0);
  val = gst_structure_get_value (structure, "format");
  if (val != NULL && G_VALUE_TYPE (val) == GST_TYPE_LIST) {
    GValue temp = { 0, };
    gst_value_init_and_copy (&temp, gst_value_list_get_value (val, 0));
    gst_structure_set_value (structure, "format", &temp);
    g_value_unset (&temp);
  }

  /* ... and use its info to get the csp */
  dec->csp = gst_xvid_structure_to_csp (structure);
  if (dec->csp == -1) {
    GST_WARNING_OBJECT (dec, "failed to decide on colorspace, using I420");
    dec->csp = XVID_CSP_I420;
  }

  dec->outbuf_size =
      gst_xvid_image_get_size (dec->csp, dec->width, dec->height);

  GST_LOG_OBJECT (dec, "csp=%d, outbuf_size=%d", dec->csp, dec->outbuf_size);

  gst_caps_unref (allowed_caps);

  /* now set up xvid ... */
  if (!gst_xviddec_setup (dec)) {
    GST_ELEMENT_ERROR (GST_ELEMENT (dec), LIBRARY, INIT, (NULL), (NULL));
    return FALSE;
  }

  return gst_xviddec_negotiate (dec, NULL);
}
Beispiel #2
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;
}