📄 gstbasesrc.c
字号:
* especially sync since all segment info will get flushed */ break; /* downstream serialized events */ 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: /* sending tags could be useful, FIXME insert in dataflow */ break; case GST_EVENT_BUFFERSIZE: /* does not seem to make much sense currently */ break; /* upstream events */ case GST_EVENT_QOS: /* elements should override send_event and do something */ 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: /* could make sense for elements that do something with navigation events * but then they would need to override the send_event function */ break; case GST_EVENT_LATENCY: /* does not seem to make sense currently */ break; /* custom events */ case GST_EVENT_CUSTOM_UPSTREAM: /* override send_event if you want this */ break; case GST_EVENT_CUSTOM_DOWNSTREAM: case GST_EVENT_CUSTOM_BOTH: /* FIXME, insert event in the dataflow */ break; case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: case GST_EVENT_CUSTOM_BOTH_OOB: /* insert a random custom event into the pipeline */ GST_DEBUG_OBJECT (src, "pushing custom OOB event downstream"); result = gst_pad_push_event (src->srcpad, event); /* we gave away the ref to the event in the push */ event = NULL; break; default: break; }done: /* if we still have a ref to the event, unref it now */ if (event) 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_set_flushing (src, TRUE, FALSE, TRUE, NULL); break; case GST_EVENT_FLUSH_STOP: result = gst_base_src_set_flushing (src, FALSE, TRUE, TRUE, NULL); 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) { case PROP_BLOCKSIZE: src->blocksize = g_value_get_ulong (value); break; case PROP_NUM_BUFFERS: src->num_buffers = g_value_get_int (value); break; case PROP_TYPEFIND: src->data.ABI.typefind = g_value_get_boolean (value); break; case PROP_DO_TIMESTAMP: src->priv->do_timestamp = g_value_get_boolean (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; }}static voidgst_base_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec){ GstBaseSrc *src; src = GST_BASE_SRC (object); switch (prop_id) { case PROP_BLOCKSIZE: g_value_set_ulong (value, src->blocksize); break; case PROP_NUM_BUFFERS: g_value_set_int (value, src->num_buffers); break; case PROP_TYPEFIND: g_value_set_boolean (value, src->data.ABI.typefind); break; case PROP_DO_TIMESTAMP: g_value_set_boolean (value, src->priv->do_timestamp); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; }}/* with STREAM_LOCK and LOCK */static GstClockReturngst_base_src_wait (GstBaseSrc * basesrc, GstClock * clock, GstClockTime time){ GstClockReturn ret; GstClockID id; id = gst_clock_new_single_shot_id (clock, time); basesrc->clock_id = id; /* release the live lock while waiting */ GST_LIVE_UNLOCK (basesrc); ret = gst_clock_id_wait (id, NULL); GST_LIVE_LOCK (basesrc); gst_clock_id_unref (id); basesrc->clock_id = NULL; return ret;}/* perform synchronisation on a buffer. * with STREAM_LOCK. */static GstClockReturngst_base_src_do_sync (GstBaseSrc * basesrc, GstBuffer * buffer){ GstClockReturn result; GstClockTime start, end; GstBaseSrcClass *bclass; GstClockTime base_time; GstClock *clock; GstClockTime now = GST_CLOCK_TIME_NONE, timestamp; gboolean do_timestamp, first, pseudo_live; bclass = GST_BASE_SRC_GET_CLASS (basesrc); start = end = -1; if (bclass->get_times) bclass->get_times (basesrc, buffer, &start, &end); /* get buffer timestamp */ timestamp = GST_BUFFER_TIMESTAMP (buffer); /* grab the lock to prepare for clocking and calculate the startup * latency. */ GST_OBJECT_LOCK (basesrc); /* if we are asked to sync against the clock we are a pseudo live element */ pseudo_live = (start != -1 && basesrc->is_live); /* check for the first buffer */ first = (basesrc->priv->latency == -1); if (timestamp != -1 && pseudo_live) { GstClockTime latency; /* we have a timestamp and a sync time, latency is the diff */ if (timestamp <= start) latency = start - timestamp; else latency = 0; if (first) { GST_DEBUG_OBJECT (basesrc, "pseudo_live with latency %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); /* first time we calculate latency, just configure */ basesrc->priv->latency = latency; } else { if (basesrc->priv->latency != latency) { /* we have a new latency, FIXME post latency message */ basesrc->priv->latency = latency; GST_DEBUG_OBJECT (basesrc, "latency changed to %" GST_TIME_FORMAT, GST_TIME_ARGS (latency)); } } } else if (first) { GST_DEBUG_OBJECT (basesrc, "no latency needed, live %d, sync %d", basesrc->is_live, start != -1); basesrc->priv->latency = 0; } /* get clock, if no clock, we can't sync or do timestamps */ if ((clock = GST_ELEMENT_CLOCK (basesrc)) == NULL) goto no_clock; base_time = GST_ELEMENT_CAST (basesrc)->base_time; do_timestamp = basesrc->priv->do_timestamp; /* first buffer, calculate the timestamp offset */ if (first) { GstClockTime running_time; now = gst_clock_get_time (clock); running_time = now - base_time; GST_LOG_OBJECT (basesrc, "startup timestamp: %" GST_TIME_FORMAT ", running_time %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp), GST_TIME_ARGS (running_time)); if (pseudo_live && timestamp != -1) { /* live source and we need to sync, add startup latency to all timestamps * to get the real running_time. Live sources should always timestamp * according to the current running time. */ basesrc->priv->ts_offset = GST_CLOCK_DIFF (timestamp, running_time); GST_LOG_OBJECT (basesrc, "live with sync, ts_offset %" GST_TIME_FORMAT, GST_TIME_ARGS (basesrc->priv->ts_offset)); } else { basesrc->priv->ts_offset = 0; GST_LOG_OBJECT (basesrc, "no timestamp offset needed"); } if (!GST_CLOCK_TIME_IS_VALID (timestamp)) { if (do_timestamp) timestamp = running_time; else timestamp = 0; GST_BUFFER_TIMESTAMP (buffer) = timestamp; GST_LOG_OBJECT (basesrc, "created timestamp: %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); } /* add the timestamp offset we need for sync */ timestamp += basesrc->priv->ts_offset; } else { /* not the first buffer, the timestamp is the diff between the clock and * base_time */ if (do_timestamp && !GST_CLOCK_TIME_IS_VALID (timestamp)) { now = gst_clock_get_time (clock); GST_BUFFER_TIMESTAMP (buffer) = now - base_time; GST_LOG_OBJECT (basesrc, "created timestamp: %" GST_TIME_FORMAT, GST_TIME_ARGS (now - base_time)); } } /* if we don't have a buffer timestamp, we don't sync */ if (!GST_CLOCK_TIME_IS_VALID (start)) goto no_sync; if (basesrc->is_live && GST_CLOCK_TIME_IS_VALID (timestamp)) { /* for pseudo live sources, add our ts_offset to the timestamp */ GST_BUFFER_TIMESTAMP (buffer) += basesrc->priv->ts_offset; start += basesrc->priv->ts_offset; } GST_LOG_OBJECT (basesrc, "waiting for clock, base time %" GST_TIME_FORMAT ", stream_start %" GST_TIME_FORMAT, GST_TIME_ARGS (base_time), GST_TIME_ARGS (start)); GST_OBJECT_UNLOCK (basesrc); result = gst_base_src_wait (basesrc, clock, start + base_time); GST_LOG_OBJECT (basesrc, "clock entry done: %d", result); return result; /* special cases */no_clock: { GST_DEBUG_OBJECT (basesrc, "we have no clock"); GST_OBJECT_UNLOCK (basesrc); return GST_CLOCK_OK; }no_sync: { GST_DEBUG_OBJECT (basesrc, "no sync needed"); GST_OBJECT_UNLOCK (basesrc); return GST_CLOCK_OK; }}static gbooleangst_base_src_update_length (GstBaseSrc * src, guint64 offset, guint * length){ guint64 size, maxsize; GstBaseSrcClass *bclass; bclass = GST_BASE_SRC_GET_CLASS (src); /* only operate if we are working with bytes */ if (src->segment.format != GST_FORMAT_BYTES) return TRUE; /* get total file size */ size = (guint64) src->segment.duration; /* the max amount of bytes to read is the total size or * up to the segment.stop if present. */ if (src->segment.stop != -1) maxsize = MIN (size, src->segment.stop); else maxsize = size; GST_DEBUG_OBJECT (src, "reading offset %" G_GUINT64_FORMAT ", length %u, size %" G_GINT64_FORMAT ", segment.stop %" G_GINT64_FORMAT ", maxsize %" G_GINT64_FORMAT, offset, *length, size, src->segment.stop, maxsize); /* check size if we have one */ if (maxsize != -1) { /* if we run past the end, check if the file became bigger and * retry. */ if (G_UNLIKELY (offset + *length >= maxsize)) { /* see if length of the file changed */ if (bclass->get_size) if (!bclass->get_size (src, &size)) size = -1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -