Example #1
0
static GSList *
get_chunk (GstAdapter * adapter, int offset, int *skip)
{
  GSList *g;

#if 1
  if (skip)
    *skip = 0;
#endif

  g_return_val_if_fail (offset >= 0, NULL);
  g_return_val_if_fail (offset < adapter->size, NULL);

  offset += adapter->skip;
  g = adapter->buflist;
  while (g) {
    if (offset < GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data))) {
      if (skip)
        *skip = offset;
      return g;
    }
    offset -= GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data));
    g = g->next;
  }

  g_assert_not_reached ();
}
Example #2
0
/* For reverse playback we use a technique that can be used for
 * any keyframe based video codec.
 *
 * Input:
 *  Buffer decoding order:  7  8  9  4  5  6  1  2  3  EOS
 *  Keyframe flag:                      K        K
 *  Discont flag:           D        D        D
 *
 * - Each Discont marks a discont in the decoding order.
 * - The keyframes mark where we can start decoding.
 *
 * First we prepend incomming buffers to the gather queue, whenever we receive
 * a discont, we flush out the gather queue.
 *
 * The above data will be accumulated in the gather queue like this:
 *
 *   gather queue:  9  8  7
 *                        D
 *
 * Whe buffer 4 is received (with a DISCONT), we flush the gather queue like
 * this:
 *
 *   while (gather)
 *     take head of queue and prepend to decode queue.
 *     if we copied a keyframe, decode the decode queue.
 *
 * After we flushed the gather queue, we add 4 to the (now empty) gather queue.
 * We get the following situation:
 *
 *  gather queue:    4
 *  decode queue:    7  8  9
 *
 * After we received 5 (Keyframe) and 6:
 *
 *  gather queue:    6  5  4
 *  decode queue:    7  8  9
 *
 * When we receive 1 (DISCONT) which triggers a flush of the gather queue:
 *
 *   Copy head of the gather queue (6) to decode queue:
 *
 *    gather queue:    5  4
 *    decode queue:    6  7  8  9
 *
 *   Copy head of the gather queue (5) to decode queue. This is a keyframe so we
 *   can start decoding.
 *
 *    gather queue:    4
 *    decode queue:    5  6  7  8  9
 *
 *   Decode frames in decode queue, store raw decoded data in output queue, we
 *   can take the head of the decode queue and prepend the decoded result in the
 *   output queue:
 *
 *    gather queue:    4
 *    decode queue:    
 *    output queue:    9  8  7  6  5
 *
 *   Now output all the frames in the output queue, picking a frame from the
 *   head of the queue.
 *
 *   Copy head of the gather queue (4) to decode queue, we flushed the gather
 *   queue and can now store input buffer in the gather queue:
 *
 *    gather queue:    1
 *    decode queue:    4
 *
 *  When we receive EOS, the queue looks like:
 *
 *    gather queue:    3  2  1
 *    decode queue:    4
 *
 *  Fill decode queue, first keyframe we copy is 2:
 *
 *    gather queue:    1
 *    decode queue:    2  3  4
 *
 *  Decoded output:
 *
 *    gather queue:    1
 *    decode queue:    
 *    output queue:    4  3  2
 *
 *  Leftover buffer 1 cannot be decoded and must be discarded.
 */
static GstFlowReturn
theora_dec_flush_decode (GstTheoraDec * dec)
{
  GstFlowReturn res = GST_FLOW_OK;

  while (dec->decode) {
    GstBuffer *buf = GST_BUFFER_CAST (dec->decode->data);

    GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT,
        buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));

    /* decode buffer, prepend to output queue */
    res = theora_dec_decode_buffer (dec, buf);

    /* don't need it anymore now */
    gst_buffer_unref (buf);

    dec->decode = g_list_delete_link (dec->decode, dec->decode);
  }
  while (dec->queued) {
    GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data);

    /* iterate ouput queue an push downstream */
    res = gst_pad_push (dec->srcpad, buf);

    dec->queued = g_list_delete_link (dec->queued, dec->queued);
  }

  return res;
}
GstFlowReturn
gst_vdp_output_src_pad_push (GstVdpOutputSrcPad * vdp_pad,
    GstVdpOutputBuffer * output_buf, GError ** error)
{
  GstPad *pad;
  GstBuffer *outbuf;

  g_return_val_if_fail (GST_IS_VDP_OUTPUT_SRC_PAD (vdp_pad), GST_FLOW_ERROR);
  g_return_val_if_fail (GST_IS_VDP_OUTPUT_BUFFER (output_buf), GST_FLOW_ERROR);

  pad = (GstPad *) vdp_pad;

  if (G_UNLIKELY (!GST_PAD_CAPS (pad)))
    return GST_FLOW_NOT_NEGOTIATED;

  switch (vdp_pad->output_format) {
    case GST_VDP_OUTPUT_SRC_PAD_FORMAT_RGB:
    {
      GstFlowReturn ret;
      guint size;

      gst_vdp_output_buffer_calculate_size (output_buf, &size);

      vdp_pad->lock_caps = TRUE;
      ret = gst_pad_alloc_buffer (pad, 0, size, GST_PAD_CAPS (vdp_pad),
          &outbuf);
      vdp_pad->lock_caps = FALSE;

      if (ret != GST_FLOW_OK) {
        gst_buffer_unref (GST_BUFFER_CAST (output_buf));
        return ret;
      }

      if (!gst_vdp_output_buffer_download (output_buf, outbuf, error)) {
        gst_buffer_unref (GST_BUFFER_CAST (output_buf));
        gst_buffer_unref (outbuf);
        return GST_FLOW_ERROR;
      }

      gst_buffer_copy_metadata (outbuf, (const GstBuffer *) output_buf,
          GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS);
      gst_buffer_unref (GST_BUFFER_CAST (output_buf));
      break;
    }
    case GST_VDP_OUTPUT_SRC_PAD_FORMAT_VDPAU:
    {
      outbuf = GST_BUFFER_CAST (output_buf);
      break;
    }

    default:
      g_assert_not_reached ();
      break;
  }

  gst_buffer_set_caps (outbuf, GST_PAD_CAPS (vdp_pad));

  return gst_pad_push (pad, outbuf);
}
static GstMozVideoBuffer*
gst_moz_video_buffer_copy(GstMozVideoBuffer* self)
{
  GstMozVideoBuffer* copy;

  g_return_val_if_fail(GST_IS_MOZ_VIDEO_BUFFER(self), NULL);

  copy = gst_moz_video_buffer_new();

  /* we simply copy everything from our parent */
  GST_BUFFER_DATA(GST_BUFFER_CAST(copy)) =
      (guint8*)g_memdup(GST_BUFFER_DATA(GST_BUFFER_CAST(self)), GST_BUFFER_SIZE(GST_BUFFER_CAST(self)));

  /* make sure it gets freed(even if the parent is subclassed, we return a
     normal buffer) */
  GST_BUFFER_MALLOCDATA(GST_BUFFER_CAST(copy)) = GST_BUFFER_DATA(GST_BUFFER_CAST(copy));
  GST_BUFFER_SIZE(GST_BUFFER_CAST(copy)) = GST_BUFFER_SIZE(GST_BUFFER_CAST(self));

  /* copy metadata */
  gst_buffer_copy_metadata(GST_BUFFER_CAST(copy),
                           GST_BUFFER_CAST(self),
                           (GstBufferCopyFlags)GST_BUFFER_COPY_ALL);
  /* copy videobuffer */
  if(self->data)
    copy->data = (GstMozVideoBufferData*)g_boxed_copy(GST_TYPE_MOZ_VIDEO_BUFFER_DATA, self->data);

  return copy;
}
static void
my_recycle_buffer_finalize (GstMiniObject * mini_object)
{
  GstBuffer *self = GST_BUFFER_CAST (mini_object);

  if (self->pool != NULL) {
    my_buffer_pool_add (self->pool, GST_BUFFER_CAST (self));
    g_usleep (G_USEC_PER_SEC / 100);
  } else {
    GST_MINI_OBJECT_CLASS (my_recycle_buffer_parent_class)->finalize
        (mini_object);
  }
}
Example #6
0
static VdpBitstreamBuffer *
gst_vdp_h264_dec_create_bitstream_buffers (GstVdpH264Dec * h264_dec,
    GstH264Frame * h264_frame, guint * n_bufs)
{
  VdpBitstreamBuffer *bufs;

  if (h264_dec->packetized) {
    guint i;

    bufs = g_new (VdpBitstreamBuffer, h264_frame->slices->len * 2);
    *n_bufs = h264_frame->slices->len * 2;

    for (i = 0; i < h264_frame->slices->len; i++) {
      static const guint8 start_code[] = { 0x00, 0x00, 0x01 };
      guint idx;
      GstBuffer *buf;

      idx = i * 2;
      bufs[idx].bitstream = start_code;
      bufs[idx].bitstream_bytes = 3;
      bufs[idx].struct_version = VDP_BITSTREAM_BUFFER_VERSION;

      idx = idx + 1;
      buf = GST_BUFFER_CAST (g_ptr_array_index (h264_frame->slices, i));
      bufs[idx].bitstream = GST_BUFFER_DATA (buf) + h264_dec->nal_length_size;
      bufs[idx].bitstream_bytes = GST_BUFFER_SIZE (buf) -
          h264_dec->nal_length_size;
      bufs[idx].struct_version = VDP_BITSTREAM_BUFFER_VERSION;
    }
  }

  else {
    guint i;

    bufs = g_new (VdpBitstreamBuffer, h264_frame->slices->len);
    *n_bufs = h264_frame->slices->len;

    for (i = 0; i < h264_frame->slices->len; i++) {
      GstBuffer *buf;

      buf = GST_BUFFER_CAST (g_ptr_array_index (h264_frame->slices, i));
      bufs[i].bitstream = GST_BUFFER_DATA (buf);
      bufs[i].bitstream_bytes = GST_BUFFER_SIZE (buf);
      bufs[i].struct_version = VDP_BITSTREAM_BUFFER_VERSION;
    }
  }

  return bufs;
}
Example #7
0
/**
 * gst_buffer_list_iterator_next:
 * @it: a #GstBufferListIterator
 *
 * Returns the next buffer in the list iterated with @it. If the iterator is at
 * the end of a group, NULL will be returned. This function may be called
 * repeatedly to iterate through the current group.
 *
 * The caller will not get a new ref to the returned #GstBuffer and must not
 * unref it.
 *
 * Returns: the next buffer in the current group of the buffer list, or NULL
 *
 * Since: 0.10.24
 */
GstBuffer *
gst_buffer_list_iterator_next (GstBufferListIterator * it)
{
  GstBuffer *buffer;

  g_return_val_if_fail (it != NULL, NULL);

  while (it->next != NULL && it->next->data != GROUP_START &&
      it->next->data == STOLEN) {
    it->next = g_list_next (it->next);
  }

  if (it->next == NULL || it->next->data == GROUP_START) {
    goto no_buffer;
  }

  buffer = GST_BUFFER_CAST (it->next->data);

  it->last_returned = it->next;
  it->next = g_list_next (it->next);

  return buffer;

no_buffer:
  {
    it->last_returned = NULL;
    return NULL;
  }
}
Example #8
0
static GstFlowReturn
theora_dec_chain_reverse (GstTheoraDec * dec, gboolean discont, GstBuffer * buf)
{
  GstFlowReturn res = GST_FLOW_OK;

  /* if we have a discont, move buffers to the decode list */
  if (G_UNLIKELY (discont)) {
    GST_DEBUG_OBJECT (dec, "received discont,gathering buffers");
    while (dec->gather) {
      GstBuffer *gbuf;
      guint8 *data;

      gbuf = GST_BUFFER_CAST (dec->gather->data);
      /* remove from the gather list */
      dec->gather = g_list_delete_link (dec->gather, dec->gather);
      /* copy to decode queue */
      dec->decode = g_list_prepend (dec->decode, gbuf);

      /* if we copied a keyframe, flush and decode the decode queue */
      data = GST_BUFFER_DATA (gbuf);
      if ((data[0] & 0x40) == 0) {
        GST_DEBUG_OBJECT (dec, "copied keyframe");
        res = theora_dec_flush_decode (dec);
      }
    }
  }

  /* add buffer to gather queue */
  GST_DEBUG_OBJECT (dec, "gathering buffer %p, size %u", buf,
      GST_BUFFER_SIZE (buf));
  dec->gather = g_list_prepend (dec->gather, buf);

  return res;
}
Example #9
0
static GstFlowReturn
gst_funnel_sink_chain_object (GstPad * pad, GstFunnel * funnel,
    gboolean is_list, GstMiniObject * obj)
{
  GstFlowReturn res;

  GST_DEBUG_OBJECT (pad, "received %" GST_PTR_FORMAT, obj);

  GST_PAD_STREAM_LOCK (funnel->srcpad);

  if ((funnel->last_sinkpad == NULL)
      || ((funnel->forward_sticky_events_mode !=
              GST_FUNNEL_FORWARD_STICKY_EVENTS_MODE_NEVER)
          && (funnel->last_sinkpad != pad))) {

    GST_DEBUG_OBJECT (pad, "Forwarding sticky events");
    gst_pad_sticky_events_foreach (pad, forward_events_on_stream_changed,
        funnel);

    gst_object_replace ((GstObject **) & funnel->last_sinkpad,
        GST_OBJECT (pad));
  }

  if (is_list)
    res = gst_pad_push_list (funnel->srcpad, GST_BUFFER_LIST_CAST (obj));
  else
    res = gst_pad_push (funnel->srcpad, GST_BUFFER_CAST (obj));

  GST_PAD_STREAM_UNLOCK (funnel->srcpad);

  GST_LOG_OBJECT (pad, "handled buffer%s %s", (is_list ? "list" : ""),
      gst_flow_get_name (res));

  return res;
}
Example #10
0
static GstFlowReturn
vorbis_dec_chain_reverse (GstVorbisDec * vd, gboolean discont, GstBuffer * buf)
{
  GstFlowReturn result = GST_FLOW_OK;

  /* if we have a discont, move buffers to the decode list */
  if (G_UNLIKELY (discont)) {
    GST_DEBUG_OBJECT (vd, "received discont");
    while (vd->gather) {
      GstBuffer *gbuf;

      gbuf = GST_BUFFER_CAST (vd->gather->data);
      /* remove from the gather list */
      vd->gather = g_list_delete_link (vd->gather, vd->gather);
      /* copy to decode queue */
      vd->decode = g_list_prepend (vd->decode, gbuf);
    }
    /* flush and decode the decode queue */
    result = vorbis_dec_flush_decode (vd);
  }

  if (G_LIKELY (buf)) {
    GST_DEBUG_OBJECT (vd,
        "gathering buffer %p of size %u, time %" GST_TIME_FORMAT
        ", dur %" GST_TIME_FORMAT, buf, GST_BUFFER_SIZE (buf),
        GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
        GST_TIME_ARGS (GST_BUFFER_DURATION (buf)));

    /* add buffer to gather queue */
    vd->gather = g_list_prepend (vd->gather, buf);
  }

  return result;
}
Example #11
0
/**
 * rtp_jitter_buffer_insert:
 * @jbuf: an #RTPJitterBuffer
 * @buf: a buffer
 * @time: a running_time when this buffer was received in nanoseconds
 * @clock_rate: the clock-rate of the payload of @buf
 * @max_delay: the maximum lateness of @buf
 * @tail: TRUE when the tail element changed.
 *
 * Inserts @buf into the packet queue of @jbuf. The sequence number of the
 * packet will be used to sort the packets. This function takes ownerhip of
 * @buf when the function returns %TRUE.
 * @buf should have writable metadata when calling this function.
 *
 * Returns: %FALSE if a packet with the same number already existed.
 */
gboolean
rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf,
    GstClockTime time, guint32 clock_rate, GstClockTime max_delay,
    gboolean * tail)
{
  GList *list;
  guint32 rtptime;
  guint16 seqnum;

  g_return_val_if_fail (jbuf != NULL, FALSE);
  g_return_val_if_fail (buf != NULL, FALSE);

  seqnum = gst_rtp_buffer_get_seq (buf);

  /* loop the list to skip strictly smaller seqnum buffers */
  for (list = jbuf->packets->head; list; list = g_list_next (list)) {
    guint16 qseq;
    gint gap;

    qseq = gst_rtp_buffer_get_seq (GST_BUFFER_CAST (list->data));

    /* compare the new seqnum to the one in the buffer */
    gap = gst_rtp_buffer_compare_seqnum (seqnum, qseq);

    /* we hit a packet with the same seqnum, notify a duplicate */
    if (G_UNLIKELY (gap == 0))
      goto duplicate;

    /* seqnum > qseq, we can stop looking */
    if (G_LIKELY (gap < 0))
      break;
  }

  /* do skew calculation by measuring the difference between rtptime and the
   * receive time, this function will retimestamp @buf with the skew corrected
   * running time. */
  rtptime = gst_rtp_buffer_get_timestamp (buf);
  time = calculate_skew (jbuf, rtptime, time, clock_rate, max_delay);
  GST_BUFFER_TIMESTAMP (buf) = time;

  /* It's more likely that the packet was inserted in the front of the buffer */
  if (G_LIKELY (list))
    g_queue_insert_before (jbuf->packets, list, buf);
  else
    g_queue_push_tail (jbuf->packets, buf);

  /* tail was changed when we did not find a previous packet, we set the return
   * flag when requested. */
  if (G_LIKELY (tail))
    *tail = (list == NULL);

  return TRUE;

  /* ERRORS */
duplicate:
  {
    GST_WARNING ("duplicate packet %d found", (gint) seqnum);
    return FALSE;
  }
}
Example #12
0
gboolean
shmdata_base_reader_reset_time (GstPad *pad,
                                GstMiniObject * mini_obj,
                                gpointer user_data)
{

    shmdata_base_reader_t *context = (shmdata_base_reader_t *) user_data;
    if (GST_IS_EVENT (mini_obj))
    {
        //g_debug ("EVENT %s", GST_EVENT_TYPE_NAME (GST_EVENT_CAST(mini_obj)));
    }
    else if (GST_IS_BUFFER (mini_obj))
    {
        GstBuffer *buffer = GST_BUFFER_CAST (mini_obj);
        /* g_debug ("shmdata writer data frame (%p), data size %d, timestamp %llu, caps %s", */
        /* 	       GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer), */
        /* 	       GST_TIME_AS_MSECONDS (GST_BUFFER_TIMESTAMP (buffer)), */
        /* 	       gst_caps_to_string (GST_BUFFER_CAPS (buffer))); */
        if (context->timereset_)
        {
            context->timeshift_ = GST_BUFFER_TIMESTAMP (buffer);
            context->timereset_ = FALSE;
        }
        GST_BUFFER_TIMESTAMP (buffer) =
            GST_BUFFER_TIMESTAMP (buffer) - context->timeshift_;
    }
    else if (GST_IS_MESSAGE (mini_obj))
    {
    }

    return TRUE;
}
Example #13
0
static GstFlowReturn
vorbis_parse_drain_queue (GstVorbisParse * parse, gint64 granulepos)
{
    GstFlowReturn ret = GST_FLOW_OK;
    GList *walk;
    gint64 cur = granulepos;
    gint64 gp;

    for (walk = parse->buffer_queue->head; walk; walk = walk->next)
        cur -= GST_BUFFER_OFFSET (walk->data);

    if (parse->prev_granulepos != -1)
        cur = MAX (cur, parse->prev_granulepos);

    while (!g_queue_is_empty (parse->buffer_queue)) {
        GstBuffer *buf;

        buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));

        cur += GST_BUFFER_OFFSET (buf);
        gp = CLAMP (cur, 0, granulepos);

        ret = vorbis_parse_push_buffer (parse, buf, gp);

        if (ret != GST_FLOW_OK)
            goto done;
    }

    parse->prev_granulepos = granulepos;

done:
    return ret;
}
Example #14
0
static gboolean
gst_vdp_sink_stop (GstBaseSink * bsink)
{
  VdpSink *vdp_sink = GST_VDP_SINK (bsink);

  vdp_sink->running = FALSE;
  /* Wait for our event thread to finish before we clean up our stuff. */
  if (vdp_sink->event_thread)
    g_thread_join (vdp_sink->event_thread);

  if (vdp_sink->cur_image) {
    gst_buffer_unref (GST_BUFFER_CAST (vdp_sink->cur_image));
    vdp_sink->cur_image = NULL;
  }

  g_mutex_lock (vdp_sink->flow_lock);
  if (vdp_sink->window) {
    gst_vdp_sink_window_destroy (vdp_sink, vdp_sink->window);
    vdp_sink->window = NULL;
  }
  g_mutex_unlock (vdp_sink->flow_lock);

  gst_vdp_device_clear (vdp_sink);

  return TRUE;
}
Example #15
0
static GstFlowReturn
vorbis_parse_drain_queue_prematurely (GstVorbisParse * parse)
{
    GstFlowReturn ret = GST_FLOW_OK;
    gint64 granulepos = MAX (parse->prev_granulepos, 0);

    /* got an EOS event, make sure to push out any buffers that were in the queue
     * -- won't normally be the case, but this catches the
     * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous
     * stream. */

    /* if we got EOS before any buffers came, go ahead and push the other events
     * first */
    vorbis_parse_drain_event_queue (parse);

    while (!g_queue_is_empty (parse->buffer_queue)) {
        GstBuffer *buf;

        buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));

        granulepos += GST_BUFFER_OFFSET (buf);
        ret = vorbis_parse_push_buffer (parse, buf, granulepos);

        if (ret != GST_FLOW_OK)
            goto done;
    }

    parse->prev_granulepos = granulepos;

done:
    return ret;
}
Example #16
0
/*
 * Input:
 *  Buffer decoding order:  7  8  9  4  5  6  3  1  2  EOS
 *  Discont flag:           D        D        D  D
 *
 * - Each Discont marks a discont in the decoding order.
 *
 * for vorbis, each buffer is a keyframe when we have the previous
 * buffer. This means that to decode buffer 7, we need buffer 6, which
 * arrives out of order.
 *
 * we first gather buffers in the gather queue until we get a DISCONT. We
 * prepend each incomming buffer so that they are in reversed order.
 *
 *    gather queue:    9  8  7
 *    decode queue:
 *    output queue:
 *
 * When a DISCONT is received (buffer 4), we move the gather queue to the
 * decode queue. This is simply done be taking the head of the gather queue
 * and prepending it to the decode queue. This yields:
 *
 *    gather queue:
 *    decode queue:    7  8  9
 *    output queue:
 *
 * Then we decode each buffer in the decode queue in order and put the output
 * buffer in the output queue. The first buffer (7) will not produce any output
 * because it needs the previous buffer (6) which did not arrive yet. This
 * yields:
 *
 *    gather queue:
 *    decode queue:    7  8  9
 *    output queue:    9  8
 *
 * Then we remove the consumed buffers from the decode queue. Buffer 7 is not
 * completely consumed, we need to keep it around for when we receive buffer
 * 6. This yields:
 *
 *    gather queue:
 *    decode queue:    7
 *    output queue:    9  8
 *
 * Then we accumulate more buffers:
 *
 *    gather queue:    6  5  4
 *    decode queue:    7
 *    output queue:
 *
 * prepending to the decode queue on DISCONT yields:
 *
 *    gather queue:
 *    decode queue:    4  5  6  7
 *    output queue:
 *
 * after decoding and keeping buffer 4:
 *
 *    gather queue:
 *    decode queue:    4
 *    output queue:    7  6  5
 *
 * Etc..
 */
static GstFlowReturn
vorbis_dec_flush_decode (GstVorbisDec * dec)
{
  GstFlowReturn res = GST_FLOW_OK;
  GList *walk;

  walk = dec->decode;

  GST_DEBUG_OBJECT (dec, "flushing buffers to decoder");

  while (walk) {
    GList *next;
    GstBuffer *buf = GST_BUFFER_CAST (walk->data);

    GST_DEBUG_OBJECT (dec, "decoding buffer %p, ts %" GST_TIME_FORMAT,
        buf, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)));

    next = g_list_next (walk);

    /* decode buffer, prepend to output queue */
    res = vorbis_dec_decode_buffer (dec, buf);

    /* if we generated output, we can discard the buffer, else we
     * keep it in the queue */
    if (dec->queued) {
      GST_DEBUG_OBJECT (dec, "decoded buffer to %p", dec->queued->data);
      dec->decode = g_list_delete_link (dec->decode, walk);
      gst_buffer_unref (buf);
    } else {
      GST_DEBUG_OBJECT (dec, "buffer did not decode, keeping");
    }
    walk = next;
  }
  while (dec->queued) {
    GstBuffer *buf = GST_BUFFER_CAST (dec->queued->data);
    GstClockTime timestamp, duration;

    timestamp = GST_BUFFER_TIMESTAMP (buf);
    duration = GST_BUFFER_DURATION (buf);

    vorbis_do_timestamps (dec, buf, TRUE, timestamp, duration);
    res = vorbis_dec_push_forward (dec, buf);

    dec->queued = g_list_delete_link (dec->queued, dec->queued);
  }
  return res;
}
Example #17
0
GstCaps *
gst_type_find_helper_get_range (GstObject * obj,
    GstTypeFindHelperGetRangeFunction func, guint64 size,
    GstTypeFindProbability * prob)
{
  GstTypeFindHelper helper;
  GstTypeFind find;
  GSList *walk;
  GList *l, *type_list;
  GstCaps *result = NULL;

  g_return_val_if_fail (GST_IS_OBJECT (obj), NULL);
  g_return_val_if_fail (func != NULL, NULL);

  helper.buffers = NULL;
  helper.size = size;
  helper.last_offset = 0;
  helper.func = func;
  helper.best_probability = 0;
  helper.caps = NULL;
  helper.obj = obj;

  find.data = &helper;
  find.peek = helper_find_peek;
  find.suggest = helper_find_suggest;

  if (size == 0 || size == (guint64) - 1) {
    find.get_length = NULL;
  } else {
    find.get_length = helper_find_get_length;
  }

  /* FIXME: we need to keep this list within the registry */
  type_list = gst_type_find_factory_get_list ();
  type_list = g_list_sort (type_list, type_find_factory_rank_cmp);

  for (l = type_list; l; l = l->next) {
    helper.factory = GST_TYPE_FIND_FACTORY (l->data);
    gst_type_find_factory_call_function (helper.factory, &find);
    if (helper.best_probability >= GST_TYPE_FIND_MAXIMUM)
      break;
  }
  gst_plugin_feature_list_free (type_list);

  for (walk = helper.buffers; walk; walk = walk->next)
    gst_buffer_unref (GST_BUFFER_CAST (walk->data));
  g_slist_free (helper.buffers);

  if (helper.best_probability > 0)
    result = helper.caps;

  if (prob)
    *prob = helper.best_probability;

  GST_LOG_OBJECT (obj, "Returning %" GST_PTR_FORMAT " (probability = %u)",
      result, (guint) helper.best_probability);

  return result;
}
Example #18
0
static gboolean
handle_queued_objects (APP_STATE_T * state)
{
    GstMiniObject *object = NULL;

    g_mutex_lock (&state->queue_lock);
    if (state->flushing) {
        g_cond_broadcast (&state->cond);
        goto beach;
    } else if (g_async_queue_length (state->queue) == 0) {
        goto beach;
    }

    if ((object = g_async_queue_try_pop (state->queue))) {
        if (GST_IS_BUFFER (object)) {
            GstBuffer *buffer = GST_BUFFER_CAST (object);
            update_image (state, buffer);
            render_scene (state);
            gst_buffer_unref (buffer);
            if (!SYNC_BUFFERS) {
                object = NULL;
            }
        } else if (GST_IS_QUERY (object)) {
            GstQuery *query = GST_QUERY_CAST (object);
            GstStructure *s = (GstStructure *) gst_query_get_structure (query);

            if (gst_structure_has_name (s, "not-used")) {
                g_assert_not_reached ();
            } else {
                g_assert_not_reached ();
            }
        } else if (GST_IS_EVENT (object)) {
            GstEvent *event = GST_EVENT_CAST (object);
            g_print ("\nevent %p %s\n", event,
                     gst_event_type_get_name (GST_EVENT_TYPE (event)));

            switch (GST_EVENT_TYPE (event)) {
            case GST_EVENT_EOS:
                flush_internal (state);
                break;
            default:
                break;
            }
            gst_event_unref (event);
            object = NULL;
        }
    }

    if (object) {
        state->popped_obj = object;
        g_cond_broadcast (&state->cond);
    }

beach:
    g_mutex_unlock (&state->queue_lock);

    return FALSE;
}
Example #19
0
static GstFlowReturn
theora_parse_drain_queue (GstTheoraParse * parse, gint64 granulepos)
{
  GstFlowReturn ret = GST_FLOW_OK;
  gint64 keyframe, prev_frame, frame;

  parse_granulepos (parse, granulepos, &keyframe, &frame);

  GST_DEBUG ("draining queue of length %d",
      g_queue_get_length (parse->buffer_queue));

  GST_LOG_OBJECT (parse, "gp %" G_GINT64_FORMAT ", kf %" G_GINT64_FORMAT
      ", frame %" G_GINT64_FORMAT, granulepos, keyframe, frame);

  prev_frame = frame - g_queue_get_length (parse->buffer_queue);

  GST_LOG_OBJECT (parse,
      "new prev %" G_GINT64_FORMAT ", prev %" G_GINT64_FORMAT, prev_frame,
      parse->prev_frame);

  if (prev_frame < parse->prev_frame) {
    GST_WARNING ("jumped %" G_GINT64_FORMAT
        " frames backwards! not sure what to do here",
        parse->prev_frame - prev_frame);
    parse->prev_frame = prev_frame;
  } else if (prev_frame > parse->prev_frame) {
    GST_INFO ("discontinuity detected (%" G_GINT64_FORMAT
        " frames)", prev_frame - parse->prev_frame);
    if (keyframe <= prev_frame && keyframe > parse->prev_keyframe)
      parse->prev_keyframe = keyframe;
    parse->prev_frame = prev_frame;
  }

  while (!g_queue_is_empty (parse->buffer_queue)) {
    GstBuffer *buf;

    parse->prev_frame++;
    g_assert (parse->prev_frame >= 0);

    buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));

    if (is_keyframe (buf))
      /* we have a keyframe */
      parse->prev_keyframe = parse->prev_frame;
    else
      GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT;

    ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe,
        parse->prev_frame);

    if (ret != GST_FLOW_OK)
      goto done;
  }

done:
  return ret;
}
Example #20
0
static gboolean
scan_slow (GstAdapter * adapter, GSList * g, int skip, guint32 pattern,
    guint32 mask)
{
  guint8 tmp[4];
  int j;

  pattern &= mask;
  for (j = 0; j < 4; j++) {
    tmp[j] = ((guint8 *) GST_BUFFER_DATA (GST_BUFFER_CAST (g->data)))[skip];
    skip++;
    if (skip >= GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data))) {
      g = g->next;
      skip = 0;
    }
  }

  return ((GST_READ_UINT32_BE (tmp) & mask) == pattern);
}
Example #21
0
static GstBuffer *
my_recycle_buffer_new (MyBufferPool * pool)
{
  MyRecycleBuffer *buf;

  buf = MY_RECYCLE_BUFFER (gst_mini_object_new (MY_TYPE_RECYCLE_BUFFER));
  buf->pool = pool;

  return GST_BUFFER_CAST (buf);
}
static GstBuffer *
my_recycle_buffer_new (MyBufferPool * pool)
{
  GstBuffer *buf;

  buf = gst_buffer_new ();

  //buf->pool = pool;

  return GST_BUFFER_CAST (buf);
}
Example #23
0
static GstFlowReturn
gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
{
  GstGLImageSink *glimage_sink = NULL;
  GstGLBuffer *gl_buffer = NULL;

  glimage_sink = GST_GLIMAGE_SINK (bsink);

  GST_INFO ("buffer size: %d", GST_BUFFER_SIZE (buf));

  //is gl
  if (glimage_sink->is_gl) {
    //increment gl buffer ref before storage
    gl_buffer = GST_GL_BUFFER (gst_buffer_ref (buf));
  }
  //is not gl
  else {
    //blocking call
    gl_buffer = gst_gl_buffer_new (glimage_sink->display,
        glimage_sink->width, glimage_sink->height);

    //blocking call
    gst_gl_display_do_upload (glimage_sink->display, gl_buffer->texture,
        glimage_sink->width, glimage_sink->height, GST_BUFFER_DATA (buf));

    //gl_buffer is created in this block, so the gl buffer is already referenced
  }

  if (glimage_sink->window_id != glimage_sink->new_window_id) {
    glimage_sink->window_id = glimage_sink->new_window_id;
    gst_gl_display_set_window_id (glimage_sink->display,
        glimage_sink->window_id);
  }
  //the buffer is cleared when an other comes in
  if (glimage_sink->stored_buffer) {
    gst_buffer_unref (GST_BUFFER_CAST (glimage_sink->stored_buffer));
    glimage_sink->stored_buffer = NULL;
  }
  //store current buffer
  glimage_sink->stored_buffer = gl_buffer;

  //redisplay opengl scene
  if (gl_buffer->texture &&
      gst_gl_display_redisplay (glimage_sink->display,
          gl_buffer->texture, gl_buffer->width, gl_buffer->height,
          glimage_sink->window_width, glimage_sink->window_height,
          glimage_sink->keep_aspect_ratio))
    return GST_FLOW_OK;
  else {
    GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND,
        GST_GL_DISPLAY_ERR_MSG (glimage_sink->display), (NULL));
    return GST_FLOW_ERROR;
  }
}
Example #24
0
int
gst_adapter_masked_scan_uint32_compat (GstAdapter * adapter, guint32 mask,
    guint32 pattern, guint offset, guint n)
{
  GSList *g;
  int j;
  int k;
  int skip;
  int m;

  g_return_val_if_fail (n >= 0, -1);
  g_return_val_if_fail (offset >= 0, -1);
  g_return_val_if_fail (offset + n + 4 <= adapter->size, -1);

  g = get_chunk (adapter, offset, &skip);
  j = 0;
  while (j < n) {
    m = MIN (GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data)) - skip - 4, 0);
    if (m > 0) {
      k = scan_fast (GST_BUFFER_DATA (GST_BUFFER_CAST (g->data)) + skip,
          pattern, mask, m);
      if (k < m) {
        return offset + j + k;
      }
      j += m;
      skip += m;
    } else {
      if (scan_slow (adapter, g, skip, pattern, mask)) {
        return offset + j;
      }
      j++;
      skip++;
    }
    if (skip >= GST_BUFFER_SIZE (GST_BUFFER_CAST (g->data))) {
      g = g->next;
      skip = 0;
    }
  }

  return -1;
}
Example #25
0
static gboolean
gst_gl_deinterlace_filter (GstGLFilter * filter, GstGLBuffer * inbuf,
    GstGLBuffer * outbuf)
{
  GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);

  //blocking call, use a FBO
  gst_gl_display_use_fbo (filter->display, filter->width, filter->height,
      filter->fbo, filter->depthbuffer, outbuf->texture,
      gst_gl_deinterlace_callback, inbuf->width, inbuf->height,
      inbuf->texture, 0, filter->width, 0, filter->height,
      GST_GL_DISPLAY_PROJECTION_ORTHO2D, (gpointer) deinterlace_filter);

  if (deinterlace_filter->gl_buffer_prev)
    gst_buffer_unref (GST_BUFFER_CAST (deinterlace_filter->gl_buffer_prev));

  deinterlace_filter->gl_buffer_prev =
      GST_GL_BUFFER (gst_buffer_ref (GST_BUFFER_CAST (inbuf)));

  return TRUE;
}
Example #26
0
static void
gst_gl_deinterlace_reset (GstGLFilter * filter)
{
  GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter);

  if (deinterlace_filter->gl_buffer_prev) {
    gst_buffer_unref (GST_BUFFER_CAST (deinterlace_filter->gl_buffer_prev));
    deinterlace_filter->gl_buffer_prev = NULL;
  }
  //blocking call, wait the opengl thread has destroyed the shader
  gst_gl_display_del_shader (filter->display, deinterlace_filter->shader);
}
void QGstXvImageBufferPool::doAlloc()
{
    //should be always called from the main thread with m_poolMutex locked
    //Q_ASSERT(QThread::currentThread() == thread());

    XSync(QX11Info::display(), false);

    QGstXvImageBuffer *xvBuffer = (QGstXvImageBuffer *)gst_mini_object_new(QGstXvImageBuffer::get_type());

    quint64 portId = m_format.property("portId").toULongLong();
    int xvFormatId = m_format.property("xvFormatId").toInt();

    xvBuffer->xvImage = XvShmCreateImage(
            QX11Info::display(),
            portId,
            xvFormatId,
            0,
            m_format.frameWidth(),
            m_format.frameHeight(),
            &xvBuffer->shmInfo
            );

    if (!xvBuffer->xvImage) {
        qWarning() << "QGstXvImageBufferPool: XvShmCreateImage failed";
        return;
    }

    XSync(QX11Info::display(), false);

    xvBuffer->shmInfo.shmid = shmget(IPC_PRIVATE, xvBuffer->xvImage->data_size, IPC_CREAT | 0777);
    xvBuffer->shmInfo.shmaddr = xvBuffer->xvImage->data = (char*)shmat(xvBuffer->shmInfo.shmid, 0, 0);
    xvBuffer->shmInfo.readOnly = False;

    if (!XShmAttach(QX11Info::display(), &xvBuffer->shmInfo)) {
        qWarning() << "QGstXvImageBufferPool: XShmAttach failed";
        return;
    }

    XSync(QX11Info::display(), false);

    shmctl (xvBuffer->shmInfo.shmid, IPC_RMID, NULL);

    xvBuffer->pool = this;
    GST_MINI_OBJECT_CAST(xvBuffer)->flags = 0;
    gst_buffer_set_caps(GST_BUFFER_CAST(xvBuffer), m_caps);
    GST_BUFFER_DATA(xvBuffer) = (uchar*)xvBuffer->xvImage->data;
    GST_BUFFER_SIZE(xvBuffer) = xvBuffer->xvImage->data_size;

    m_allBuffers.append(xvBuffer);
    m_pool.append(xvBuffer);

    XSync(QX11Info::display(), false);
}
Example #28
0
static GstFlowReturn
theora_parse_drain_queue_prematurely (GstTheoraParse * parse)
{
  GstFlowReturn ret = GST_FLOW_OK;

  /* got an EOS event, make sure to push out any buffers that were in the queue
   * -- won't normally be the case, but this catches the
   * didn't-get-a-granulepos-on-the-last-packet case. Assuming a continuous
   * stream. */

  GST_DEBUG_OBJECT (parse, "got EOS, draining queue");

  /* if we get an eos before pushing the streamheaders, drain our events before
   * eos */
  theora_parse_drain_event_queue (parse);

  while (!g_queue_is_empty (parse->buffer_queue)) {
    GstBuffer *buf;

    buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));

    parse->prev_frame++;

    if (is_keyframe (buf))
      /* we have a keyframe */
      parse->prev_keyframe = parse->prev_frame;
    else
      GST_BUFFER_FLAGS (buf) |= GST_BUFFER_FLAG_DELTA_UNIT;

    if (parse->prev_keyframe < 0) {
      if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) {
        parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf),
            &parse->prev_keyframe, NULL);
      } else {
        /* No previous keyframe known; can't extract one from this frame. That
         * means we can't do any valid output for this frame, just continue to
         * the next frame.
         */
        gst_buffer_unref (buf);
        continue;
      }
    }

    ret = theora_parse_push_buffer (parse, buf, parse->prev_keyframe,
        parse->prev_frame);

    if (ret != GST_FLOW_OK)
      goto done;
  }

done:
  return ret;
}
Example #29
0
static gboolean
on_video_sink_data_flow (GstPad * pad, GstMiniObject * mini_obj,
    gpointer user_data)
{
  GstFPSDisplaySink *self = GST_FPS_DISPLAY_SINK (user_data);

#if 0
  if (GST_IS_BUFFER (mini_obj)) {
    GstBuffer *buf = GST_BUFFER_CAST (mini_obj);

    if (GST_CLOCK_TIME_IS_VALID (self->next_ts)) {
      if (GST_BUFFER_TIMESTAMP (buf) <= self->next_ts) {
        self->frames_rendered++;
      } else {
        GST_WARNING_OBJECT (self, "dropping frame : ts %" GST_TIME_FORMAT
            " < expected_ts %" GST_TIME_FORMAT,
            GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)),
            GST_TIME_ARGS (self->next_ts));
        self->frames_dropped++;
      }
    } else {
      self->frames_rendered++;
    }
  } else
#endif
  if (GST_IS_EVENT (mini_obj)) {
    GstEvent *ev = GST_EVENT_CAST (mini_obj);

    if (GST_EVENT_TYPE (ev) == GST_EVENT_QOS) {
      GstClockTimeDiff diff;
      GstClockTime ts;

      gst_event_parse_qos (ev, NULL, &diff, &ts);
      if (diff <= 0.0) {
        g_atomic_int_inc (&self->frames_rendered);
      } else {
        g_atomic_int_inc (&self->frames_dropped);
      }

      ts = gst_util_get_timestamp ();
      if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (self->start_ts))) {
        self->interval_ts = self->last_ts = self->start_ts = ts;
      }
      if (GST_CLOCK_DIFF (self->interval_ts, ts) > self->fps_update_interval) {
        display_current_fps (self);
        self->interval_ts = ts;
      }
    }
  }
  return TRUE;
}
Example #30
0
static void
theora_parse_clear_queue (GstTheoraParse * parse)
{
  while (parse->buffer_queue->length) {
    GstBuffer *buf;

    buf = GST_BUFFER_CAST (g_queue_pop_head (parse->buffer_queue));
    gst_buffer_unref (buf);
  }
  while (parse->event_queue->length) {
    GstEvent *event;

    event = GST_EVENT_CAST (g_queue_pop_head (parse->event_queue));
    gst_event_unref (event);
  }
}