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

📄 gstbasesrc.c

📁 GStreamer是一个开源的多媒体框架库。利用它
💻 C
📖 第 1 页 / 共 5 页
字号:
  if (cur_type != GST_SEEK_TYPE_NONE) {    /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */    res =        gst_pad_query_convert (src->srcpad, seek_format, cur, &dest_format,        &cur);    cur_type = GST_SEEK_TYPE_SET;  }  if (res && stop_type != GST_SEEK_TYPE_NONE) {    /* FIXME: Handle seek_cur & seek_end by converting the input segment vals */    res =        gst_pad_query_convert (src->srcpad, seek_format, stop, &dest_format,        &stop);    stop_type = GST_SEEK_TYPE_SET;  }  /* And finally, configure our output segment in the desired format */  gst_segment_set_seek (segment, rate, dest_format, flags, cur_type, cur,      stop_type, stop, &update);  if (!res)    goto no_format;  return res;no_format:  {    GST_DEBUG_OBJECT (src, "undefined format given, seek aborted.");    return FALSE;  }}static gbooleangst_base_src_prepare_seek_segment (GstBaseSrc * src, GstEvent * event,    GstSegment * seeksegment){  GstBaseSrcClass *bclass;  gboolean result = FALSE;  bclass = GST_BASE_SRC_GET_CLASS (src);  if (bclass->prepare_seek_segment)    result = bclass->prepare_seek_segment (src, event, seeksegment);  return result;}/* this code implements the seeking. It is a good example * handling all cases. * * A seek updates the currently configured segment.start * and segment.stop values based on the SEEK_TYPE. If the * segment.start value is updated, a seek to this new position * should be performed. * * The seek can only be executed when we are not currently * streaming any data, to make sure that this is the case, we * acquire the STREAM_LOCK which is taken when we are in the * _loop() function or when a getrange() is called. Normally * we will not receive a seek if we are operating in pull mode * though. * * When we are in the loop() function, we might be in the middle * of pushing a buffer, which might block in a sink. To make sure * that the push gets unblocked we push out a FLUSH_START event. * Our loop function will get a WRONG_STATE return value from * the push and will pause, effectively releasing the STREAM_LOCK. * * For a non-flushing seek, we pause the task, which might eventually * release the STREAM_LOCK. We say eventually because when the sink * blocks on the sample we might wait a very long time until the sink * unblocks the sample. In any case we acquire the STREAM_LOCK and * can continue the seek. A non-flushing seek is normally done in a  * running pipeline to perform seamless playback. * In the case of a non-flushing seek we need to make sure that the * data we output after the seek is continuous with the previous data, * this is because a non-flushing seek does not reset the stream-time * to 0. We do this by closing the currently running segment, ie. sending * a new_segment event with the stop position set to the last processed  * position. * * After updating the segment.start/stop values, we prepare for * streaming again. We push out a FLUSH_STOP to make the peer pad * accept data again and we start our task again. * * A segment seek posts a message on the bus saying that the playback * of the segment started. We store the segment flag internally because * when we reach the segment.stop we have to post a segment.done * instead of EOS when doing a segment seek. *//* FIXME (0.11), we have the unlock gboolean here because most current  * implementations (fdsrc, -base/gst/tcp/, ...) unconditionally unlock, even when * the streaming thread isn't running, resulting in bogus unlocks later when it  * starts. This is fixed by adding unlock_stop, but we should still avoid unlocking * unnecessarily for backwards compatibility. Ergo, the unlock variable stays * until 0.11 */static gbooleangst_base_src_perform_seek (GstBaseSrc * src, GstEvent * event, gboolean unlock){  gboolean res = TRUE;  gdouble rate;  GstFormat seek_format, dest_format;  GstSeekFlags flags;  GstSeekType cur_type, stop_type;  gint64 cur, stop;  gboolean flush;  gboolean update;  gboolean relative_seek = FALSE;  gboolean seekseg_configured = FALSE;  GstSegment seeksegment;  GST_DEBUG_OBJECT (src, "doing seek");  dest_format = src->segment.format;  if (event) {    gst_event_parse_seek (event, &rate, &seek_format, &flags,        &cur_type, &cur, &stop_type, &stop);    relative_seek = SEEK_TYPE_IS_RELATIVE (cur_type) ||        SEEK_TYPE_IS_RELATIVE (stop_type);    if (dest_format != seek_format && !relative_seek) {      /* If we have an ABSOLUTE position (SEEK_SET only), we can convert it       * here before taking the stream lock, otherwise we must convert it later,       * once we have the stream lock and can read the current position */      gst_segment_init (&seeksegment, dest_format);      if (!gst_base_src_prepare_seek_segment (src, event, &seeksegment))        goto prepare_failed;      seekseg_configured = TRUE;    }    flush = flags & GST_SEEK_FLAG_FLUSH;  } else {    flush = FALSE;  }  /* send flush start */  if (flush)    gst_pad_push_event (src->srcpad, gst_event_new_flush_start ());  else    gst_pad_pause_task (src->srcpad);  /* unblock streaming thread */  if (unlock)    gst_base_src_unlock (src);  /* grab streaming lock, this should eventually be possible, either   * because the task is paused or our streaming thread stopped    * because our peer is flushing. */  GST_PAD_STREAM_LOCK (src->srcpad);  if (unlock)    gst_base_src_unlock_stop (src);  /* If we configured the seeksegment above, don't overwrite it now. Otherwise   * copy the current segment info into the temp segment that we can actually   * attempt the seek with. We only update the real segment if the seek suceeds. */  if (!seekseg_configured) {    memcpy (&seeksegment, &src->segment, sizeof (GstSegment));    /* now configure the final seek segment */    if (event) {      if (src->segment.format != seek_format) {        /* OK, here's where we give the subclass a chance to convert the relative         * seek into an absolute one in the processing format. We set up any         * absolute seek above, before taking the stream lock. */        if (!gst_base_src_prepare_seek_segment (src, event, &seeksegment)) {          GST_DEBUG_OBJECT (src, "Preparing the seek failed after flushing. "              "Aborting seek");          res = FALSE;        }      } else {        /* The seek format matches our processing format, no need to ask the         * the subclass to configure the segment. */        gst_segment_set_seek (&seeksegment, rate, seek_format, flags,            cur_type, cur, stop_type, stop, &update);      }    }    /* Else, no seek event passed, so we're just (re)starting the        current segment. */  }  if (res) {    GST_DEBUG_OBJECT (src, "segment configured from %" G_GINT64_FORMAT        " to %" G_GINT64_FORMAT ", position %" G_GINT64_FORMAT,        seeksegment.start, seeksegment.stop, seeksegment.last_stop);    /* do the seek, segment.last_stop contains the new position. */    res = gst_base_src_do_seek (src, &seeksegment);  }  /* and prepare to continue streaming */  if (flush) {    /* send flush stop, peer will accept data and events again. We     * are not yet providing data as we still have the STREAM_LOCK. */    gst_pad_push_event (src->srcpad, gst_event_new_flush_stop ());  } else if (res && src->data.ABI.running) {    /* we are running the current segment and doing a non-flushing seek,      * close the segment first based on the last_stop. */    GST_DEBUG_OBJECT (src, "closing running segment %" G_GINT64_FORMAT        " to %" G_GINT64_FORMAT, src->segment.start, src->segment.last_stop);    /* queue the segment for sending in the stream thread */    if (src->priv->close_segment)      gst_event_unref (src->priv->close_segment);    src->priv->close_segment =        gst_event_new_new_segment_full (TRUE,        src->segment.rate, src->segment.applied_rate, src->segment.format,        src->segment.start, src->segment.last_stop, src->segment.time);  }  /* The subclass must have converted the segment to the processing format    * by now */  if (res && seeksegment.format != dest_format) {    GST_DEBUG_OBJECT (src, "Subclass failed to prepare a seek segment "        "in the correct format. Aborting seek.");    res = FALSE;  }  /* if successfull seek, we update our real segment and push   * out the new segment. */  if (res) {    memcpy (&src->segment, &seeksegment, sizeof (GstSegment));    if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) {      gst_element_post_message (GST_ELEMENT (src),          gst_message_new_segment_start (GST_OBJECT (src),              src->segment.format, src->segment.last_stop));    }    /* for deriving a stop position for the playback segment form the seek     * segment, we must take the duration when the stop is not set */    if ((stop = src->segment.stop) == -1)      stop = src->segment.duration;    GST_DEBUG_OBJECT (src, "Sending newsegment from %" G_GINT64_FORMAT        " to %" G_GINT64_FORMAT, src->segment.start, stop);    /* now replace the old segment so that we send it in the stream thread the     * next time it is scheduled. */    if (src->priv->start_segment)      gst_event_unref (src->priv->start_segment);    src->priv->start_segment =        gst_event_new_new_segment_full (FALSE,        src->segment.rate, src->segment.applied_rate, src->segment.format,        src->segment.last_stop, stop, src->segment.time);  }  src->priv->discont = TRUE;  src->data.ABI.running = TRUE;  /* and restart the task in case it got paused explicitely or by   * the FLUSH_START event we pushed out. */  gst_pad_start_task (src->srcpad, (GstTaskFunction) gst_base_src_loop,      src->srcpad);  /* and release the lock again so we can continue streaming */  GST_PAD_STREAM_UNLOCK (src->srcpad);  return res;  /* ERROR */prepare_failed:  GST_DEBUG_OBJECT (src, "Preparing the seek failed before flushing. "      "Aborting seek");  return FALSE;}static const GstQueryType *gst_base_src_get_query_types (GstElement * element){  static const GstQueryType query_types[] = {    GST_QUERY_DURATION,    GST_QUERY_POSITION,    GST_QUERY_SEEKING,    GST_QUERY_SEGMENT,    GST_QUERY_FORMATS,    GST_QUERY_LATENCY,    GST_QUERY_JITTER,    GST_QUERY_RATE,    GST_QUERY_CONVERT,    0  };  return query_types;}/* all events send to this element directly */static gbooleangst_base_src_send_event (GstElement * element, GstEvent * event){  GstBaseSrc *src;  gboolean result = FALSE;  src = GST_BASE_SRC (element);  switch (GST_EVENT_TYPE (event)) {    case GST_EVENT_FLUSH_START:    case GST_EVENT_FLUSH_STOP:      /* sending random flushes downstream can break stuff,       * especially sync since all segment info will get flushed */      break;    case GST_EVENT_EOS:      /* FIXME, queue EOS and make sure the task or pull function        * perform the EOS actions. */      break;    case GST_EVENT_NEWSEGMENT:      /* sending random NEWSEGMENT downstream can break sync. */      break;    case GST_EVENT_TAG:    case GST_EVENT_BUFFERSIZE:      break;    case GST_EVENT_QOS:      break;    case GST_EVENT_SEEK:    {      gboolean started;      GST_OBJECT_LOCK (src->srcpad);      if (GST_PAD_ACTIVATE_MODE (src->srcpad) == GST_ACTIVATE_PULL)        goto wrong_mode;      started = GST_PAD_ACTIVATE_MODE (src->srcpad) == GST_ACTIVATE_PUSH;      GST_OBJECT_UNLOCK (src->srcpad);      if (started) {        /* when we are running in push mode, we can execute the         * seek right now, we need to unlock. */        result = gst_base_src_perform_seek (src, event, TRUE);      } else {        GstEvent **event_p;        /* else we store the event and execute the seek when we         * get activated */        GST_OBJECT_LOCK (src);        event_p = &src->data.ABI.pending_seek;        gst_event_replace ((GstEvent **) event_p, event);        GST_OBJECT_UNLOCK (src);        /* assume the seek will work */        result = TRUE;      }      break;    }    case GST_EVENT_NAVIGATION:      break;    default:      break;  }done:  gst_event_unref (event);  return result;  /* ERRORS */wrong_mode:  {    GST_DEBUG_OBJECT (src, "cannot perform seek when operating in pull mode");    GST_OBJECT_UNLOCK (src->srcpad);    result = FALSE;    goto done;  }}static gbooleangst_base_src_default_event (GstBaseSrc * src, GstEvent * event){  gboolean result;  switch (GST_EVENT_TYPE (event)) {    case GST_EVENT_SEEK:      /* is normally called when in push mode */      if (!src->seekable)        goto not_seekable;      result = gst_base_src_perform_seek (src, event, TRUE);      break;    case GST_EVENT_FLUSH_START:      /* cancel any blocking getrange, is normally called       * when in pull mode. */      result = gst_base_src_unlock (src);      break;    case GST_EVENT_FLUSH_STOP:      result = gst_base_src_unlock_stop (src);      break;    default:      result = TRUE;      break;  }  return result;  /* ERRORS */not_seekable:  {    GST_DEBUG_OBJECT (src, "is not seekable");    return FALSE;  }}static gbooleangst_base_src_event_handler (GstPad * pad, GstEvent * event){  GstBaseSrc *src;  GstBaseSrcClass *bclass;  gboolean result = FALSE;  src = GST_BASE_SRC (gst_pad_get_parent (pad));  bclass = GST_BASE_SRC_GET_CLASS (src);  if (bclass->event) {    if (!(result = bclass->event (src, event)))      goto subclass_failed;  }done:  gst_event_unref (event);  gst_object_unref (src);  return result;  /* ERRORS */subclass_failed:  {    GST_DEBUG_OBJECT (src, "subclass refused event");    goto done;  }}static voidgst_base_src_set_property (GObject * object, guint prop_id,    const GValue * value, GParamSpec * pspec){  GstBaseSrc *src;  src = GST_BASE_SRC (object);  switch (prop_id) {

⌨️ 快捷键说明

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