⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gstbasesink.c

📁 GStreamer是一个开源的多媒体框架库。利用它
💻 C
📖 第 1 页 / 共 5 页
字号:
  if (format == GST_FORMAT_TIME) {    GST_DEBUG_OBJECT (basesink,        "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "        "format GST_FORMAT_TIME, "        "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT        ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,        update, rate, arate, GST_TIME_ARGS (segment->start),        GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),        GST_TIME_ARGS (segment->accum));  } else {    GST_DEBUG_OBJECT (basesink,        "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "        "format %d, "        "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"        G_GINT64_FORMAT ", accum %" G_GINT64_FORMAT, update, rate, arate,        segment->format, segment->start, segment->stop, segment->time,        segment->accum);  }  GST_OBJECT_UNLOCK (basesink);}/* with PREROLL_LOCK, STREAM_LOCK */static gbooleangst_base_sink_commit_state (GstBaseSink * basesink){  /* commit state and proceed to next pending state */  GstState current, next, pending, post_pending;  gboolean post_paused = FALSE;  gboolean post_async_done = FALSE;  gboolean post_playing = FALSE;  gboolean sync;  /* we are certainly not playing async anymore now */  basesink->playing_async = FALSE;  GST_OBJECT_LOCK (basesink);  current = GST_STATE (basesink);  next = GST_STATE_NEXT (basesink);  pending = GST_STATE_PENDING (basesink);  post_pending = pending;  sync = basesink->sync;  switch (pending) {    case GST_STATE_PLAYING:    {      GstBaseSinkClass *bclass;      GstStateChangeReturn ret;      bclass = GST_BASE_SINK_GET_CLASS (basesink);      GST_DEBUG_OBJECT (basesink, "commiting state to PLAYING");      basesink->need_preroll = FALSE;      post_async_done = TRUE;      basesink->priv->commited = TRUE;      post_playing = TRUE;      /* post PAUSED too when we were READY */      if (current == GST_STATE_READY) {        post_paused = TRUE;      }      /* make sure we notify the subclass of async playing */      if (bclass->async_play) {        ret = bclass->async_play (basesink);        if (ret == GST_STATE_CHANGE_FAILURE)          goto async_failed;      }      break;    }    case GST_STATE_PAUSED:      GST_DEBUG_OBJECT (basesink, "commiting state to PAUSED");      post_paused = TRUE;      post_async_done = TRUE;      basesink->priv->commited = TRUE;      post_pending = GST_STATE_VOID_PENDING;      break;    case GST_STATE_READY:    case GST_STATE_NULL:      goto stopping;    case GST_STATE_VOID_PENDING:      goto nothing_pending;    default:      break;  }  GST_STATE (basesink) = pending;  GST_STATE_NEXT (basesink) = GST_STATE_VOID_PENDING;  GST_STATE_PENDING (basesink) = GST_STATE_VOID_PENDING;  GST_STATE_RETURN (basesink) = GST_STATE_CHANGE_SUCCESS;  GST_OBJECT_UNLOCK (basesink);  if (post_paused) {    gst_element_post_message (GST_ELEMENT_CAST (basesink),        gst_message_new_state_changed (GST_OBJECT_CAST (basesink),            current, next, post_pending));  }  if (post_async_done) {    gst_element_post_message (GST_ELEMENT_CAST (basesink),        gst_message_new_async_done (GST_OBJECT_CAST (basesink)));  }  if (post_playing) {    gst_element_post_message (GST_ELEMENT_CAST (basesink),        gst_message_new_state_changed (GST_OBJECT_CAST (basesink),            next, pending, GST_STATE_VOID_PENDING));  }  GST_STATE_BROADCAST (basesink);  return TRUE;nothing_pending:  {    /* Depending on the state, set our vars. We get in this situation when the     * state change function got a change to update the state vars before the     * streaming thread did. This is fine but we need to make sure that we     * update the need_preroll var since it was TRUE when we got here and might     * become FALSE if we got to PLAYING. */    GST_DEBUG_OBJECT (basesink, "nothing to commit, now in %s",        gst_element_state_get_name (current));    switch (current) {      case GST_STATE_PLAYING:        basesink->need_preroll = FALSE;        break;      case GST_STATE_PAUSED:        basesink->need_preroll = TRUE;        break;      default:        basesink->need_preroll = FALSE;        basesink->flushing = TRUE;        break;    }    GST_OBJECT_UNLOCK (basesink);    return TRUE;  }stopping:  {    /* app is going to READY */    GST_DEBUG_OBJECT (basesink, "stopping");    basesink->need_preroll = FALSE;    basesink->flushing = TRUE;    GST_OBJECT_UNLOCK (basesink);    return FALSE;  }async_failed:  {    GST_DEBUG_OBJECT (basesink, "async commit failed");    GST_STATE_RETURN (basesink) = GST_STATE_CHANGE_FAILURE;    GST_OBJECT_UNLOCK (basesink);    return FALSE;  }}/* with STREAM_LOCK, PREROLL_LOCK * * Returns TRUE if the object needs synchronisation and takes therefore * part in prerolling. * * rsstart/rsstop contain the start/stop in stream time. * rrstart/rrstop contain the start/stop in running time. */static gbooleangst_base_sink_get_sync_times (GstBaseSink * basesink, GstMiniObject * obj,    GstClockTime * rsstart, GstClockTime * rsstop,    GstClockTime * rrstart, GstClockTime * rrstop, gboolean * do_sync){  GstBaseSinkClass *bclass;  GstBuffer *buffer;  GstClockTime start, stop;     /* raw start/stop timestamps */  gint64 cstart, cstop;         /* clipped raw timestamps */  gint64 rstart, rstop;         /* clipped timestamps converted to running time */  GstClockTime sstart, sstop;   /* clipped timestamps converted to stream time */  GstFormat format;  GstSegment *segment;  /* start with nothing */  start = stop = sstart = sstop = rstart = rstop = -1;  if (G_UNLIKELY (GST_IS_EVENT (obj))) {    GstEvent *event = GST_EVENT_CAST (obj);    switch (GST_EVENT_TYPE (event)) {        /* EOS event needs syncing */      case GST_EVENT_EOS:        sstart = sstop = basesink->priv->current_sstop;        rstart = rstop = basesink->priv->eos_rtime;        *do_sync = rstart != -1;        GST_DEBUG_OBJECT (basesink, "sync times for EOS %" GST_TIME_FORMAT,            GST_TIME_ARGS (rstart));        goto done;        /* other events do not need syncing */        /* FIXME, maybe NEWSEGMENT might need synchronisation         * since the POSITION query depends on accumulated times and         * we cannot accumulate the current segment before the previous         * one completed.         */      default:        return FALSE;    }  }  /* else do buffer sync code */  buffer = GST_BUFFER_CAST (obj);  bclass = GST_BASE_SINK_GET_CLASS (basesink);  /* just get the times to see if we need syncing */  if (bclass->get_times)    bclass->get_times (basesink, buffer, &start, &stop);  if (start == -1) {    gst_base_sink_get_times (basesink, buffer, &start, &stop);    *do_sync = FALSE;  } else {    *do_sync = TRUE;  }  GST_DEBUG_OBJECT (basesink, "got times start: %" GST_TIME_FORMAT      ", stop: %" GST_TIME_FORMAT ", do_sync %d", GST_TIME_ARGS (start),      GST_TIME_ARGS (stop), *do_sync);  /* collect segment and format for code clarity */  segment = &basesink->segment;  format = segment->format;  /* no timestamp clipping if we did not * get a TIME segment format */  if (G_UNLIKELY (format != GST_FORMAT_TIME)) {    cstart = start;    cstop = stop;    goto do_times;  }  /* clip */  if (G_UNLIKELY (!gst_segment_clip (segment, GST_FORMAT_TIME,              (gint64) start, (gint64) stop, &cstart, &cstop)))    goto out_of_segment;  if (G_UNLIKELY (start != cstart || stop != cstop)) {    GST_DEBUG_OBJECT (basesink, "clipped to: start %" GST_TIME_FORMAT        ", stop: %" GST_TIME_FORMAT, GST_TIME_ARGS (cstart),        GST_TIME_ARGS (cstop));  }  /* set last stop position */  gst_segment_set_last_stop (segment, GST_FORMAT_TIME, cstop);do_times:  /* this can produce wrong values if we accumulated non-TIME segments. If this happens,   * upstream is behaving very badly */  sstart = gst_segment_to_stream_time (segment, format, cstart);  sstop = gst_segment_to_stream_time (segment, format, cstop);  rstart = gst_segment_to_running_time (segment, format, cstart);  rstop = gst_segment_to_running_time (segment, format, cstop);done:  /* save times */  *rsstart = sstart;  *rsstop = sstop;  *rrstart = rstart;  *rrstop = rstop;  /* buffers and EOS always need syncing and preroll */  return TRUE;  /* special cases */out_of_segment:  {    /* should not happen since we clip them in the chain function already,      * we return FALSE so that we don't try to sync on it. */    GST_ELEMENT_WARNING (basesink, STREAM, FAILED,        (NULL), ("unexpected buffer out of segment found."));    GST_LOG_OBJECT (basesink, "buffer skipped, not in segment");    return FALSE;  }}/* with STREAM_LOCK, PREROLL_LOCK * * Waits for the clock to reach @time. If @time is not valid, no * synchronisation is done and BADTIME is returned.  * If synchronisation is disabled in the element or there is no * clock, no synchronisation is done and BADTIME is returned. * * Else a blocking wait is performed on the clock. We save the ClockID * so we can unlock the entry at any time. While we are blocking, we  * release the PREROLL_LOCK so that other threads can interrupt the entry. * * @time is expressed in running time. */static GstClockReturngst_base_sink_wait_clock (GstBaseSink * basesink, GstClockTime time,    GstClockTimeDiff * jitter){  GstClockID id;  GstClockReturn ret;  GstClock *clock;  if (G_UNLIKELY (!GST_CLOCK_TIME_IS_VALID (time)))    goto invalid_time;  GST_OBJECT_LOCK (basesink);  if (G_UNLIKELY (!basesink->sync))    goto no_sync;  if (G_UNLIKELY ((clock = GST_ELEMENT_CLOCK (basesink)) == NULL))    goto no_clock;  /* add base time and latency */  time += GST_ELEMENT_CAST (basesink)->base_time;  time += basesink->priv->latency;  id = gst_clock_new_single_shot_id (clock, time);  GST_OBJECT_UNLOCK (basesink);  basesink->clock_id = id;  /* release the preroll lock while waiting */  GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);  ret = gst_clock_id_wait (id, jitter);  GST_PAD_PREROLL_LOCK (basesink->sinkpad);  gst_clock_id_unref (id);  basesink->clock_id = NULL;  return ret;  /* no syncing needed */invalid_time:  {    GST_DEBUG_OBJECT (basesink, "time not valid, no sync needed");    return GST_CLOCK_BADTIME;  }no_sync:  {    GST_DEBUG_OBJECT (basesink, "sync disabled");    GST_OBJECT_UNLOCK (basesink);    return GST_CLOCK_BADTIME;  }no_clock:  {    GST_DEBUG_OBJECT (basesink, "no clock, can't sync");    GST_OBJECT_UNLOCK (basesink);    return GST_CLOCK_BADTIME;  }}/** * gst_base_sink_wait_preroll: * @sink: the sink * * If the #GstBaseSinkClass::render method performs its own synchronisation against * the clock it must unblock when going from PLAYING to the PAUSED state and call * this method before continuing to render the remaining data. * * This function will block until a state change to PLAYING happens (in which * case this function returns #GST_FLOW_OK) or the processing must be stopped due * to a state change to READY or a FLUSH event (in which case this function * returns #GST_FLOW_WRONG_STATE). * * Since: 0.10.11 * * Returns: #GST_FLOW_OK if the preroll completed and processing can * continue. Any other return value should be returned from the render vmethod. */GstFlowReturngst_base_sink_wait_preroll (GstBaseSink * sink){  /* block until the state changes, or we get a flush, or something */  GST_DEBUG_OBJECT (sink, "wait for preroll...");  sink->have_preroll = TRUE;  GST_PAD_PREROLL_WAIT (sink->sinkpad);  sink->have_preroll = FALSE;  GST_DEBUG_OBJECT (sink, "preroll done");  if (G_UNLIKELY (sink->flushing))    goto stopping;  GST_DEBUG_OBJECT (sink, "continue after preroll");  return GST_FLOW_OK;  /* ERRORS */stopping:  {    GST_DEBUG_OBJECT (sink, "preroll interrupted");    return GST_FLOW_WRONG_STATE;  }}/* with STREAM_LOCK, PREROLL_LOCK * * Make sure we are in PLAYING and synchronize an object to the clock. * * If we need preroll, we are not in PLAYING. We try to commit the state * if needed and then block if we still are not PLAYING. * * We start waiting on the clock in PLAYING. If we got interrupted, we * immediatly try to re-preroll. * * Some objects do not need synchronisation (most events) and so this function * immediatly returns GST_FLOW_OK. * * for objects that arrive later than max-lateness to be synchronized to the  * clock have the @late boolean set to TRUE. * * This function keeps a running average of the jitter (the diff between the * clock time and the requested sync time). The jitter is negative for * objects that arrive in time and positive for late buffers. * * does not take ownership of obj. */static GstFlowReturngst_base_sink_do_sync (GstBaseSink * basesink, GstPad * pad,    GstMiniObject * obj, gboolean * late){  GstClockTimeDiff jitter;  gboolean syncable;  GstClockReturn status = GST_CLOCK_OK;  GstClockTime sstart, sstop, rstart, rstop;  gboolean do_sync;  sstart = sstop = rstart = rstop = -1;  do_sync = TRUE;  basesink->priv->current_rstart = -1;  /* update timing information for this object */  syncable = gst_base_sink_get_sync_times (basesink, obj,      &sstart, &sstop, &rstart, &rstop, &do_sync);  /* a syncable object needs to participate in preroll and   * clocking. All buffers and EOS are syncable. */  if (G_UNLIKELY (!syncable))    goto not_syncable;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -