summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Hervey <bilboed@bilboed.com>2014-12-03 14:47:05 +0100
committerEdward Hervey <bilboed@bilboed.com>2014-12-03 14:47:05 +0100
commitd2d21279c31138f53c73a6789bcfc9ac71190507 (patch)
tree3fc2c97faa1a16f2f6455dd3bf8e34f1942e8606
parentaa89278adeead49f6cf1101b640dba8b3c97ba27 (diff)
pushfilesrc: Add TIME SEGMENT capabilitypushfile
Adds a new set of properties to make pushfilesrc output a TIME SEGMENT (instead of the filesrc BYTE SEGMENT). When time-segment is set to True the following will happen: * Seeks are refused (data starts from the beginning of the file) * The BYTE segment will be replaced by a TIME segment with the values specified in the various properties * The first outgoing buffer will have a timestamp set on it (by default it has a value of GST_CLOCK_TIME_NONE)
-rw-r--r--gst/debugutils/gstpushfilesrc.c221
-rw-r--r--gst/debugutils/gstpushfilesrc.h8
2 files changed, 228 insertions, 1 deletions
diff --git a/gst/debugutils/gstpushfilesrc.c b/gst/debugutils/gstpushfilesrc.c
index 435d18515..35de3a575 100644
--- a/gst/debugutils/gstpushfilesrc.c
+++ b/gst/debugutils/gstpushfilesrc.c
@@ -48,6 +48,30 @@
GST_DEBUG_CATEGORY_STATIC (pushfilesrc_debug);
#define GST_CAT_DEFAULT pushfilesrc_debug
+enum
+{
+ PROP_0,
+ PROP_LOCATION,
+ PROP_TIME_SEGMENT,
+ PROP_STREAM_TIME,
+ PROP_START_TIME,
+ PROP_INITIAL_TIMESTAMP,
+ PROP_RATE,
+ PROP_APPLIED_RATE
+};
+
+#define DEFAULT_TIME_SEGMENT FALSE
+#define DEFAULT_STREAM_TIME 0
+#define DEFAULT_START_TIME 0
+#define DEFAULT_INITIAL_TIMESTAMP GST_CLOCK_TIME_NONE
+#define DEFAULT_RATE 1.0
+#define DEFAULT_APPLIED_RATE 1.0
+
+static void gst_push_file_src_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_push_file_src_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
@@ -91,6 +115,42 @@ gst_push_file_src_class_init (GstPushFileSrcClass * g_class)
"pushfilesrc element");
gobject_class->dispose = gst_push_file_src_dispose;
+ gobject_class->set_property = gst_push_file_src_set_property;
+ gobject_class->get_property = gst_push_file_src_get_property;
+
+ g_object_class_install_property (gobject_class, PROP_LOCATION,
+ g_param_spec_string ("location", "File Location",
+ "Location of the file to read", NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
+ GST_PARAM_MUTABLE_READY));
+
+ g_object_class_install_property (gobject_class, PROP_TIME_SEGMENT,
+ g_param_spec_boolean ("time-segment", "Time Segment",
+ "Emit TIME SEGMENTS", DEFAULT_TIME_SEGMENT, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_STREAM_TIME,
+ g_param_spec_int64 ("stream-time", "Stream Time",
+ "Initial Stream Time (if time-segment TRUE)", 0, G_MAXINT64,
+ DEFAULT_STREAM_TIME, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_START_TIME,
+ g_param_spec_int64 ("start-time", "Start Time",
+ "Initial Start Time (if time-segment TRUE)", 0, G_MAXINT64,
+ DEFAULT_START_TIME, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_INITIAL_TIMESTAMP,
+ g_param_spec_uint64 ("initial-timestamp", "Initial Timestamp",
+ "Initial Buffer Timestamp (if time-segment TRUE)", 0, G_MAXUINT64,
+ DEFAULT_INITIAL_TIMESTAMP, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_RATE,
+ g_param_spec_double ("rate", "Rate", "Rate to use in TIME SEGMENT",
+ G_MINDOUBLE, G_MAXDOUBLE, DEFAULT_RATE, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_APPLIED_RATE,
+ g_param_spec_double ("applied-rate", "Applied Rate",
+ "Applied rate to use in TIME SEGMENT", G_MINDOUBLE, G_MAXDOUBLE,
+ DEFAULT_APPLIED_RATE, G_PARAM_READWRITE));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&srctemplate));
@@ -101,15 +161,157 @@ gst_push_file_src_class_init (GstPushFileSrcClass * g_class)
"Tim-Philipp Müller <tim centricular net>");
}
+static void
+gst_push_file_src_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstPushFileSrc *src = (GstPushFileSrc *) object;
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ g_object_set_property (G_OBJECT (src->filesrc), "location", value);
+ break;
+ case PROP_TIME_SEGMENT:
+ src->time_segment = g_value_get_boolean (value);
+ break;
+ case PROP_STREAM_TIME:
+ src->stream_time = g_value_get_int64 (value);
+ break;
+ case PROP_START_TIME:
+ src->start_time = g_value_get_int64 (value);
+ break;
+ case PROP_INITIAL_TIMESTAMP:
+ src->initial_timestamp = g_value_get_uint64 (value);
+ break;
+ case PROP_RATE:
+ src->rate = g_value_get_double (value);
+ break;
+ case PROP_APPLIED_RATE:
+ src->applied_rate = g_value_get_double (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_push_file_src_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstPushFileSrc *src = (GstPushFileSrc *) object;
+
+ switch (prop_id) {
+ case PROP_LOCATION:
+ g_object_get_property (G_OBJECT (src->filesrc), "location", value);
+ break;
+ case PROP_TIME_SEGMENT:
+ g_value_set_boolean (value, src->time_segment);
+ break;
+ case PROP_STREAM_TIME:
+ g_value_set_int64 (value, src->stream_time);
+ break;
+ case PROP_START_TIME:
+ g_value_set_int64 (value, src->start_time);
+ break;
+ case PROP_INITIAL_TIMESTAMP:
+ g_value_set_uint64 (value, src->initial_timestamp);
+ break;
+ case PROP_RATE:
+ g_value_set_double (value, src->rate);
+ break;
+ case PROP_APPLIED_RATE:
+ g_value_set_double (value, src->applied_rate);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GstPadProbeReturn
+gst_push_file_src_ghostpad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
+ GstPushFileSrc * src)
+{
+ GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER (info);
+
+ if (src->time_segment && !src->seen_first_buffer) {
+ GST_BUFFER_TIMESTAMP (buffer) = src->initial_timestamp;
+ src->seen_first_buffer = TRUE;
+ }
+ return GST_PAD_PROBE_OK;
+}
+
+static GstPadProbeReturn
+gst_push_file_src_ghostpad_event_probe (GstPad * pad, GstPadProbeInfo * info,
+ GstPushFileSrc * src)
+{
+ GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEGMENT:
+ {
+ if (src->time_segment) {
+ GstSegment segment;
+ GstEvent *replacement;
+ GST_DEBUG_OBJECT (src, "Replacing outgoing segment with TIME SEGMENT");
+ gst_segment_init (&segment, GST_FORMAT_TIME);
+ segment.start = src->start_time;
+ segment.time = src->stream_time;
+ segment.rate = src->rate;
+ segment.applied_rate = src->applied_rate;
+ replacement = gst_event_new_segment (&segment);
+ gst_event_unref (event);
+ GST_PAD_PROBE_INFO_DATA (info) = replacement;
+ }
+ }
+ default:
+ break;
+ }
+ return GST_PAD_PROBE_OK;
+}
+
+static gboolean
+gst_push_file_src_ghostpad_event (GstPad * pad, GstObject * parent,
+ GstEvent * event)
+{
+ GstPushFileSrc *src = (GstPushFileSrc *) parent;
+ gboolean ret;
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_SEEK:
+ if (src->time_segment) {
+ /* When working in time we don't allow seeks */
+ GST_DEBUG_OBJECT (src, "Refusing seek event in TIME mode");
+ gst_event_unref (event);
+ ret = FALSE;
+ break;
+ }
+ /* PASSTHROUGH */
+ default:
+ ret = gst_pad_event_default (pad, parent, event);
+ break;
+ }
+
+ return ret;
+}
+
static gboolean
gst_push_file_src_ghostpad_query (GstPad * pad, GstObject * parent,
GstQuery * query)
{
+ GstPushFileSrc *src = (GstPushFileSrc *) parent;
gboolean res;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_SCHEDULING:
- gst_query_set_scheduling (query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
+ /* When working in time we don't allow seeks */
+ if (src->time_segment)
+ gst_query_set_scheduling (query, GST_SCHEDULING_FLAG_SEQUENTIAL, 1, -1,
+ 0);
+ else
+ gst_query_set_scheduling (query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1,
+ 0);
gst_query_add_scheduling_mode (query, GST_PAD_MODE_PUSH);
res = TRUE;
break;
@@ -123,6 +325,14 @@ gst_push_file_src_ghostpad_query (GstPad * pad, GstObject * parent,
static void
gst_push_file_src_init (GstPushFileSrc * src)
{
+ src->time_segment = DEFAULT_TIME_SEGMENT;
+ src->stream_time = DEFAULT_STREAM_TIME;
+ src->start_time = DEFAULT_START_TIME;
+ src->initial_timestamp = DEFAULT_INITIAL_TIMESTAMP;
+ src->rate = DEFAULT_RATE;
+ src->applied_rate = DEFAULT_APPLIED_RATE;
+ src->seen_first_buffer = FALSE;
+
src->filesrc = gst_element_factory_make ("filesrc", "real-filesrc");
if (src->filesrc) {
GstPad *pad;
@@ -135,6 +345,15 @@ gst_push_file_src_init (GstPushFileSrc * src)
* this and watch core bugginess (some pad stays in flushing state) */
gst_pad_set_query_function (src->srcpad,
GST_DEBUG_FUNCPTR (gst_push_file_src_ghostpad_query));
+ gst_pad_set_event_function (src->srcpad,
+ GST_DEBUG_FUNCPTR (gst_push_file_src_ghostpad_event));
+ /* Add outgoing event probe to replace segment and buffer timestamp */
+ gst_pad_add_probe (src->srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
+ (GstPadProbeCallback) gst_push_file_src_ghostpad_event_probe,
+ src, NULL);
+ gst_pad_add_probe (src->srcpad, GST_PAD_PROBE_TYPE_BUFFER,
+ (GstPadProbeCallback) gst_push_file_src_ghostpad_buffer_probe,
+ src, NULL);
gst_element_add_pad (GST_ELEMENT (src), src->srcpad);
gst_object_unref (pad);
}
diff --git a/gst/debugutils/gstpushfilesrc.h b/gst/debugutils/gstpushfilesrc.h
index 6013cc878..482ae13cf 100644
--- a/gst/debugutils/gstpushfilesrc.h
+++ b/gst/debugutils/gstpushfilesrc.h
@@ -43,6 +43,14 @@ struct _GstPushFileSrc
/*< private > */
GstElement *filesrc;
GstPad *srcpad;
+
+ gboolean time_segment;
+ gboolean seen_first_buffer;
+ gint64 stream_time;
+ gint64 start_time;
+ guint64 initial_timestamp;
+ gdouble rate;
+ gdouble applied_rate;
};
struct _GstPushFileSrcClass