📄 gstbasesrc.c
字号:
gst_segment_set_duration (&src->segment, GST_FORMAT_BYTES, size); /* make sure we don't exceed the configured segment stop * if it was set */ if (src->segment.stop != -1) maxsize = MIN (size, src->segment.stop); else maxsize = size; /* if we are at or past the end, EOS */ if (G_UNLIKELY (offset >= maxsize)) goto unexpected_length; /* else we can clip to the end */ if (G_UNLIKELY (offset + *length >= maxsize)) *length = maxsize - offset; } } /* keep track of current position. segment is in bytes, we checked * that above. */ gst_segment_set_last_stop (&src->segment, GST_FORMAT_BYTES, offset); return TRUE; /* ERRORS */unexpected_length: { return FALSE; }}/* must be called with LIVE_LOCK */static GstFlowReturngst_base_src_get_range (GstBaseSrc * src, guint64 offset, guint length, GstBuffer ** buf){ GstFlowReturn ret; GstBaseSrcClass *bclass; GstClockReturn status; bclass = GST_BASE_SRC_GET_CLASS (src); ret = gst_base_src_wait_playing (src); if (ret != GST_FLOW_OK) goto stopped; if (G_UNLIKELY (!GST_OBJECT_FLAG_IS_SET (src, GST_BASE_SRC_STARTED))) goto not_started; if (G_UNLIKELY (!bclass->create)) goto no_function; if (G_UNLIKELY (!gst_base_src_update_length (src, offset, &length))) goto unexpected_length; /* normally we don't count buffers */ if (G_UNLIKELY (src->num_buffers_left >= 0)) { if (src->num_buffers_left == 0) goto reached_num_buffers; else src->num_buffers_left--; } GST_DEBUG_OBJECT (src, "calling create offset %" G_GUINT64_FORMAT " length %u, time %" G_GINT64_FORMAT, offset, length, src->segment.time); ret = bclass->create (src, offset, length, buf); if (G_UNLIKELY (ret != GST_FLOW_OK)) goto not_ok; /* no timestamp set and we are at offset 0, we can timestamp with 0 */ if (offset == 0 && src->segment.time == 0 && GST_BUFFER_TIMESTAMP (*buf) == -1) GST_BUFFER_TIMESTAMP (*buf) = 0; /* now sync before pushing the buffer */ status = gst_base_src_do_sync (src, *buf); /* waiting for the clock could have made us flushing */ if (src->priv->flushing) goto flushing; switch (status) { case GST_CLOCK_EARLY: /* the buffer is too late. We currently don't drop the buffer. */ GST_DEBUG_OBJECT (src, "buffer too late!, returning anyway"); break; case GST_CLOCK_OK: /* buffer synchronised properly */ GST_DEBUG_OBJECT (src, "buffer ok"); break; case GST_CLOCK_UNSCHEDULED: /* this case is triggered when we were waiting for the clock and * it got unlocked because we did a state change. We return * WRONG_STATE in this case to stop the dataflow also get rid of the * produced buffer. */ GST_DEBUG_OBJECT (src, "clock was unscheduled (%d), returning WRONG_STATE", status); gst_buffer_unref (*buf); *buf = NULL; ret = GST_FLOW_WRONG_STATE; break; default: /* all other result values are unexpected and errors */ GST_ELEMENT_ERROR (src, CORE, CLOCK, (_("Internal clock error.")), ("clock returned unexpected return value %d", status)); gst_buffer_unref (*buf); *buf = NULL; ret = GST_FLOW_ERROR; break; } return ret; /* ERROR */stopped: { GST_DEBUG_OBJECT (src, "wait_playing returned %d (%s)", ret, gst_flow_get_name (ret)); return ret; }not_ok: { GST_DEBUG_OBJECT (src, "create returned %d (%s)", ret, gst_flow_get_name (ret)); return ret; }not_started: { GST_DEBUG_OBJECT (src, "getrange but not started"); return GST_FLOW_WRONG_STATE; }no_function: { GST_DEBUG_OBJECT (src, "no create function"); return GST_FLOW_ERROR; }unexpected_length: { GST_DEBUG_OBJECT (src, "unexpected length %u (offset=%" G_GUINT64_FORMAT ", size=%" G_GINT64_FORMAT ")", length, offset, src->segment.duration); return GST_FLOW_UNEXPECTED; }reached_num_buffers: { GST_DEBUG_OBJECT (src, "sent all buffers"); return GST_FLOW_UNEXPECTED; }flushing: { GST_DEBUG_OBJECT (src, "we are flushing"); gst_buffer_unref (*buf); *buf = NULL; return GST_FLOW_WRONG_STATE; }}static GstFlowReturngst_base_src_pad_get_range (GstPad * pad, guint64 offset, guint length, GstBuffer ** buf){ GstBaseSrc *src; GstFlowReturn res; src = GST_BASE_SRC (gst_pad_get_parent (pad)); GST_LIVE_LOCK (src); if (src->priv->flushing) goto flushing; res = gst_base_src_get_range (src, offset, length, buf);done: GST_LIVE_UNLOCK (src); gst_object_unref (src); return res; /* ERRORS */flushing: { GST_DEBUG_OBJECT (src, "we are flushing"); res = GST_FLOW_WRONG_STATE; goto done; }}static gbooleangst_base_src_default_check_get_range (GstBaseSrc * src){ gboolean res; if (!GST_OBJECT_FLAG_IS_SET (src, GST_BASE_SRC_STARTED)) { GST_LOG_OBJECT (src, "doing start/stop to check get_range support"); if (G_LIKELY (gst_base_src_start (src))) gst_base_src_stop (src); } /* we can operate in getrange mode if the native format is bytes * and we are seekable, this condition is set in the random_access * flag and is set in the _start() method. */ res = src->random_access; return res;}static gbooleangst_base_src_check_get_range (GstBaseSrc * src){ GstBaseSrcClass *bclass; gboolean res; bclass = GST_BASE_SRC_GET_CLASS (src); if (bclass->check_get_range == NULL) goto no_function; res = bclass->check_get_range (src); GST_LOG_OBJECT (src, "%s() returned %d", GST_DEBUG_FUNCPTR_NAME (bclass->check_get_range), (gint) res); return res; /* ERRORS */no_function: { GST_WARNING_OBJECT (src, "no check_get_range function set"); return FALSE; }}static gbooleangst_base_src_pad_check_get_range (GstPad * pad){ GstBaseSrc *src; gboolean res; src = GST_BASE_SRC (gst_pad_get_parent (pad)); res = gst_base_src_check_get_range (src); gst_object_unref (src); return res;}static voidgst_base_src_loop (GstPad * pad){ GstBaseSrc *src; GstBuffer *buf = NULL; GstFlowReturn ret; gint64 position; gboolean eos; eos = FALSE; src = GST_BASE_SRC (gst_pad_get_parent (pad)); GST_LIVE_LOCK (src); if (src->priv->flushing) goto flushing; src->priv->last_sent_eos = FALSE; /* if we operate in bytes, we can calculate an offset */ if (src->segment.format == GST_FORMAT_BYTES) position = src->segment.last_stop; else position = -1; ret = gst_base_src_get_range (src, position, src->blocksize, &buf); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_INFO_OBJECT (src, "pausing after gst_base_src_get_range() = %s", gst_flow_get_name (ret)); GST_LIVE_UNLOCK (src); goto pause; } /* this should not happen */ if (G_UNLIKELY (buf == NULL)) goto null_buffer; /* push events to close/start our segment before we push the buffer. */ if (src->priv->close_segment) { gst_pad_push_event (pad, src->priv->close_segment); src->priv->close_segment = NULL; } if (src->priv->start_segment) { gst_pad_push_event (pad, src->priv->start_segment); src->priv->start_segment = NULL; } /* figure out the new position */ switch (src->segment.format) { case GST_FORMAT_BYTES: position += GST_BUFFER_SIZE (buf); break; case GST_FORMAT_TIME: { GstClockTime start, duration; start = GST_BUFFER_TIMESTAMP (buf); duration = GST_BUFFER_DURATION (buf); if (GST_CLOCK_TIME_IS_VALID (start)) position = start; else position = src->segment.last_stop; if (GST_CLOCK_TIME_IS_VALID (duration)) position += duration; break; } case GST_FORMAT_DEFAULT: position = GST_BUFFER_OFFSET_END (buf); break; default: position = -1; break; } if (position != -1) { if (src->segment.stop != -1) { if (position >= src->segment.stop) { eos = TRUE; position = src->segment.stop; } } gst_segment_set_last_stop (&src->segment, src->segment.format, position); } if (G_UNLIKELY (src->priv->discont)) { buf = gst_buffer_make_metadata_writable (buf); GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT); src->priv->discont = FALSE; } GST_LIVE_UNLOCK (src); ret = gst_pad_push (pad, buf); if (G_UNLIKELY (ret != GST_FLOW_OK)) { GST_INFO_OBJECT (src, "pausing after gst_pad_push() = %s", gst_flow_get_name (ret)); goto pause; } if (eos) { GST_INFO_OBJECT (src, "pausing after EOS"); ret = GST_FLOW_UNEXPECTED; goto pause; }done: gst_object_unref (src); return; /* special cases */flushing: { GST_DEBUG_OBJECT (src, "we are flushing"); GST_LIVE_UNLOCK (src); ret = GST_FLOW_WRONG_STATE; goto pause; }pause: { const gchar *reason = gst_flow_get_name (ret); GST_DEBUG_OBJECT (src, "pausing task, reason %s", reason); src->data.ABI.running = FALSE; gst_pad_pause_task (pad); if (GST_FLOW_IS_FATAL (ret) || ret == GST_FLOW_NOT_LINKED) { if (ret == GST_FLOW_UNEXPECTED) { /* perform EOS logic */ if (src->segment.flags & GST_SEEK_FLAG_SEGMENT) { gst_element_post_message (GST_ELEMENT_CAST (src), gst_message_new_segment_done (GST_OBJECT_CAST (src), src->segment.format, src->segment.last_stop)); } else { gst_pad_push_event (pad, gst_event_new_eos ()); src->priv->last_sent_eos = TRUE; } } else { /* for fatal errors we post an error message, post the error * first so the app knows about the error first. */ GST_ELEMENT_ERROR (src, STREAM, FAILED, (_("Internal data flow error.")), ("streaming task paused, reason %s (%d)", reason, ret)); gst_pad_push_event (pad, gst_event_new_eos ()); src->priv->last_sent_eos = TRUE; } } goto done; }null_buffer: { GST_ELEMENT_ERROR (src, STREAM, FAILED, (_("Internal data flow error.")), ("element returned NULL buffer")); GST_LIVE_UNLOCK (src); /* we finished the segment on error */ ret = GST_FLOW_ERROR; goto done; }}/* default negotiation code. * * Take intersection between src and sink pads, take first * caps and fixate. */static gbooleangst_base_src_default_negotiate (GstBaseSrc * basesrc){ GstCaps *thiscaps; GstCaps *caps = NULL; GstCaps *peercaps = NULL; gboolean result = FALSE; /* first see what is possible on our source pad */ thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc)); GST_DEBUG_OBJECT (base
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -