pushfilesrc: Add TIME SEGMENT capability
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)
This commit is contained in:
parent
f5d26af3c9
commit
0a381b9edd
@ -48,6 +48,30 @@
|
|||||||
GST_DEBUG_CATEGORY_STATIC (pushfilesrc_debug);
|
GST_DEBUG_CATEGORY_STATIC (pushfilesrc_debug);
|
||||||
#define GST_CAT_DEFAULT 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",
|
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||||
GST_PAD_SRC,
|
GST_PAD_SRC,
|
||||||
GST_PAD_ALWAYS,
|
GST_PAD_ALWAYS,
|
||||||
@ -91,6 +115,42 @@ gst_push_file_src_class_init (GstPushFileSrcClass * g_class)
|
|||||||
"pushfilesrc element");
|
"pushfilesrc element");
|
||||||
|
|
||||||
gobject_class->dispose = gst_push_file_src_dispose;
|
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_element_class_add_pad_template (element_class,
|
||||||
gst_static_pad_template_get (&srctemplate));
|
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>");
|
"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
|
static gboolean
|
||||||
gst_push_file_src_ghostpad_query (GstPad * pad, GstObject * parent,
|
gst_push_file_src_ghostpad_query (GstPad * pad, GstObject * parent,
|
||||||
GstQuery * query)
|
GstQuery * query)
|
||||||
{
|
{
|
||||||
|
GstPushFileSrc *src = (GstPushFileSrc *) parent;
|
||||||
gboolean res;
|
gboolean res;
|
||||||
|
|
||||||
switch (GST_QUERY_TYPE (query)) {
|
switch (GST_QUERY_TYPE (query)) {
|
||||||
case GST_QUERY_SCHEDULING:
|
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);
|
gst_query_add_scheduling_mode (query, GST_PAD_MODE_PUSH);
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
break;
|
break;
|
||||||
@ -123,6 +325,14 @@ gst_push_file_src_ghostpad_query (GstPad * pad, GstObject * parent,
|
|||||||
static void
|
static void
|
||||||
gst_push_file_src_init (GstPushFileSrc * src)
|
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");
|
src->filesrc = gst_element_factory_make ("filesrc", "real-filesrc");
|
||||||
if (src->filesrc) {
|
if (src->filesrc) {
|
||||||
GstPad *pad;
|
GstPad *pad;
|
||||||
@ -135,6 +345,15 @@ gst_push_file_src_init (GstPushFileSrc * src)
|
|||||||
* this and watch core bugginess (some pad stays in flushing state) */
|
* this and watch core bugginess (some pad stays in flushing state) */
|
||||||
gst_pad_set_query_function (src->srcpad,
|
gst_pad_set_query_function (src->srcpad,
|
||||||
GST_DEBUG_FUNCPTR (gst_push_file_src_ghostpad_query));
|
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_element_add_pad (GST_ELEMENT (src), src->srcpad);
|
||||||
gst_object_unref (pad);
|
gst_object_unref (pad);
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,14 @@ struct _GstPushFileSrc
|
|||||||
/*< private > */
|
/*< private > */
|
||||||
GstElement *filesrc;
|
GstElement *filesrc;
|
||||||
GstPad *srcpad;
|
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
|
struct _GstPushFileSrcClass
|
||||||
|
Loading…
x
Reference in New Issue
Block a user