Commit bdbc0693 authored by Wim Taymans's avatar Wim Taymans

Rework GstSegment handling

Improve GstSegment, rename some fields. The idea is to have the GstSegment
structure represent the timing structure of the buffers as they are generated by
the source or demuxer element.
gst_segment_set_seek() -> gst_segment_do_seek()
Rename the NEWSEGMENT event to SEGMENT.
Make parsing of the SEGMENT event into a GstSegment structure.
Pass a GstSegment structure when making a new SEGMENT event. This allows us to
pass the timing info directly to the next element. No accumulation is needed in
the receiving element, all the info is inside the element.
Remove gst_segment_set_newsegment(): This function as used to accumulate
segments received from upstream, which is now not needed anymore because the
segment event contains the complete timing information.
parent ddf2489b
......@@ -434,7 +434,7 @@
<RANGE></RANGE>
<FLAGS>rw</FLAGS>
<NICK>Single Segment</NICK>
<BLURB>Timestamp buffers and eat newsegments so as to appear as one segment.</BLURB>
<BLURB>Timestamp buffers and eat segments so as to appear as one segment.</BLURB>
<DEFAULT>FALSE</DEFAULT>
</ARG>
......
......@@ -123,7 +123,7 @@ static GstEventQuarks event_quarks[] = {
{GST_EVENT_FLUSH_STOP, "flush-stop", 0},
{GST_EVENT_EOS, "eos", 0},
{GST_EVENT_CAPS, "caps", 0},
{GST_EVENT_NEWSEGMENT, "newsegment", 0},
{GST_EVENT_SEGMENT, "segment", 0},
{GST_EVENT_TAG, "tag", 0},
{GST_EVENT_BUFFERSIZE, "buffersize", 0},
{GST_EVENT_SINK_MESSAGE, "sink-message", 0},
......@@ -580,7 +580,7 @@ gst_event_new_eos (void)
* @caps: a #GstCaps
*
* Create a new CAPS event for @caps. The caps event can only travel downstream
* synchronized with the buffer flow and contain the format of the buffers
* synchronized with the buffer flow and contains the format of the buffers
* that will follow after the event.
*
* Returns: (transfer full): the new CAPS event.
......@@ -590,7 +590,8 @@ gst_event_new_caps (GstCaps * caps)
{
GstEvent *event;
g_return_val_if_fail (caps != NULL && gst_caps_is_fixed (caps), NULL);
g_return_val_if_fail (caps != NULL, NULL);
g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
GST_CAT_INFO (GST_CAT_EVENT, "creating caps event %" GST_PTR_FORMAT, caps);
......@@ -625,16 +626,12 @@ gst_event_parse_caps (GstEvent * event, GstCaps ** caps)
}
/**
* gst_event_new_new_segment:
* @update: Whether this segment is an update to a previous one
* @rate: A new rate for playback
* @applied_rate: The rate factor which has already been applied
* @format: The format of the segment values
* @start: The start value of the segment
* @stop: The stop value of the segment
* @time: the time value of the segment
* gst_event_new_segment:
* @segment: a #GstSegment
*
* Allocate a new newsegment event with the given format/values triplets.
* Create a new SEGMENT event for @segment. The segment event can only travel
* downstream synchronized with the buffer flow and contains timing information
* and playback properties for the buffers that will follow.
*
* The newsegment event marks the range of buffers to be processed. All
* data not within the segment range is not to be processed. This can be
......@@ -643,131 +640,90 @@ gst_event_parse_caps (GstEvent * event, GstCaps ** caps)
* values.
*
* The time value of the segment is used in conjunction with the start
* value to convert the buffer timestamps into the stream time. This is
* usually done in sinks to report the current stream_time.
* @time represents the stream_time of a buffer carrying a timestamp of
* value to convert the buffer timestamps into the stream time. This is
* usually done in sinks to report the current stream_time.
* @time represents the stream_time of a buffer carrying a timestamp of
* @start. @time cannot be -1.
*
* @start cannot be -1, @stop can be -1. If there
* is a valid @stop given, it must be greater or equal the @start, including
* is a valid @stop given, it must be greater or equal the @start, including
* when the indicated playback @rate is < 0.
*
* The @applied_rate value provides information about any rate adjustment that
* has already been made to the timestamps and content on the buffers of the
* stream. (@rate * @applied_rate) should always equal the rate that has been
* requested for playback. For example, if an element has an input segment
* with intended playback @rate of 2.0 and applied_rate of 1.0, it can adjust
* incoming timestamps and buffer content by half and output a newsegment event
* has already been made to the timestamps and content on the buffers of the
* stream. (@rate * @applied_rate) should always equal the rate that has been
* requested for playback. For example, if an element has an input segment
* with intended playback @rate of 2.0 and applied_rate of 1.0, it can adjust
* incoming timestamps and buffer content by half and output a newsegment event
* with @rate of 1.0 and @applied_rate of 2.0
*
* After a newsegment event, the buffer stream time is calculated with:
*
* time + (TIMESTAMP(buf) - start) * ABS (rate * applied_rate)
*
* Returns: (transfer full): a new newsegment event.
*
* Since: 0.10.6
* Returns: (transfer full): the new SEGMENT event.
*/
GstEvent *
gst_event_new_new_segment (gboolean update, gdouble rate,
gdouble applied_rate, GstFormat format, gint64 start, gint64 stop,
gint64 time)
gst_event_new_segment (GstSegment * segment)
{
GstEvent *event;
GstStructure *structure;
g_return_val_if_fail (rate != 0.0, NULL);
g_return_val_if_fail (applied_rate != 0.0, NULL);
if (format == GST_FORMAT_TIME) {
GST_CAT_INFO (GST_CAT_EVENT,
"creating newsegment update %d, rate %lf, format GST_FORMAT_TIME, "
"start %" GST_TIME_FORMAT ", stop %" GST_TIME_FORMAT
", time %" GST_TIME_FORMAT,
update, rate, GST_TIME_ARGS (start),
GST_TIME_ARGS (stop), GST_TIME_ARGS (time));
} else {
GST_CAT_INFO (GST_CAT_EVENT,
"creating newsegment update %d, rate %lf, format %s, "
"start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT ", time %"
G_GINT64_FORMAT, update, rate, gst_format_get_name (format), start,
stop, time);
}
g_return_val_if_fail (segment != NULL, NULL);
g_return_val_if_fail (time != -1, NULL);
g_return_val_if_fail (start != -1, NULL);
if (stop != -1)
g_return_val_if_fail (start <= stop, NULL);
GST_CAT_INFO (GST_CAT_EVENT, "creating segment event %" GST_PTR_FORMAT,
segment);
structure = gst_structure_id_new (GST_QUARK (EVENT_NEWSEGMENT),
GST_QUARK (UPDATE), G_TYPE_BOOLEAN, update,
GST_QUARK (RATE), G_TYPE_DOUBLE, rate,
GST_QUARK (APPLIED_RATE), G_TYPE_DOUBLE, applied_rate,
GST_QUARK (FORMAT), GST_TYPE_FORMAT, format,
GST_QUARK (START), G_TYPE_INT64, start,
GST_QUARK (STOP), G_TYPE_INT64, stop,
GST_QUARK (TIME), G_TYPE_INT64, time, NULL);
event = gst_event_new_custom (GST_EVENT_NEWSEGMENT, structure);
event = gst_event_new_custom (GST_EVENT_SEGMENT,
gst_structure_id_new (GST_QUARK (EVENT_SEGMENT),
GST_QUARK (SEGMENT), GST_TYPE_SEGMENT, segment, NULL));
return event;
}
/**
* gst_event_parse_new_segment:
* @event: The event to query
* @update: (out): A pointer to the update flag of the segment
* @rate: (out): A pointer to the rate of the segment
* @applied_rate: (out): A pointer to the applied_rate of the segment
* @format: (out): A pointer to the format of the newsegment values
* @start: (out): A pointer to store the start value in
* @stop: (out): A pointer to store the stop value in
* @time: (out): A pointer to store the time value in
*
* Get the update, rate, applied_rate, format, start, stop and
* time in the newsegment event. See gst_event_new_new_segment()
* for a full description of the newsegment event.
*
* Since: 0.10.6
* gst_event_get_segment:
* @event: The event
*
* Get the segment from @event. The segment remains valid as long as @event remains
* valid.
*
* Returns: the #GstSegment. The segment stays valid for as long as @event is
* valid.
*/
void
gst_event_parse_new_segment (GstEvent * event, gboolean * update,
gdouble * rate, gdouble * applied_rate, GstFormat * format,
gint64 * start, gint64 * stop, gint64 * time)
const GstSegment *
gst_event_get_segment (GstEvent * event)
{
const GstStructure *structure;
GstStructure *structure;
GstSegment *segment;
g_return_if_fail (GST_IS_EVENT (event));
g_return_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT);
g_return_val_if_fail (GST_IS_EVENT (event), NULL);
g_return_val_if_fail (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT, NULL);
structure = GST_EVENT_STRUCTURE (event);
if (G_LIKELY (update))
*update =
g_value_get_boolean (gst_structure_id_get_value (structure,
GST_QUARK (UPDATE)));
if (G_LIKELY (rate))
*rate =
g_value_get_double (gst_structure_id_get_value (structure,
GST_QUARK (RATE)));
if (G_LIKELY (applied_rate))
*applied_rate =
g_value_get_double (gst_structure_id_get_value (structure,
GST_QUARK (APPLIED_RATE)));
if (G_LIKELY (format))
*format =
g_value_get_enum (gst_structure_id_get_value (structure,
GST_QUARK (FORMAT)));
if (G_LIKELY (start))
*start =
g_value_get_int64 (gst_structure_id_get_value (structure,
GST_QUARK (START)));
if (G_LIKELY (stop))
*stop =
g_value_get_int64 (gst_structure_id_get_value (structure,
GST_QUARK (STOP)));
if (G_LIKELY (time))
*time =
g_value_get_int64 (gst_structure_id_get_value (structure,
GST_QUARK (TIME)));
segment = g_value_get_boxed (gst_structure_id_get_value (structure,
GST_QUARK (SEGMENT)));
return segment;
}
/**
* gst_event_parse_segment:
* @event: The event to parse
* @segment: a #GstSegment
*
* Copy the segment values from @event into @segment.
*/
void
gst_event_parse_segment (GstEvent * event, GstSegment * segment)
{
const GstSegment *src;
g_return_if_fail (segment != NULL);
src = gst_event_get_segment (event);
g_return_if_fail (src != NULL);
gst_segment_copy_into (src, segment);
}
/**
......
......@@ -31,6 +31,7 @@
#include <gst/gstclock.h>
#include <gst/gststructure.h>
#include <gst/gsttaglist.h>
#include <gst/gstsegment.h>
G_BEGIN_DECLS
......@@ -107,8 +108,8 @@ typedef enum {
* @GST_EVENT_FLUSH_STOP: Stop a flush operation. This event resets the
* running-time of the pipeline.
* @GST_EVENT_EOS: End-Of-Stream. No more data is to be expected to follow
* without a NEWSEGMENT event.
* @GST_EVENT_NEWSEGMENT: A new media segment follows in the dataflow. The
* without a SEGMENT event.
* @GST_EVENT_SEGMENT: A new media segment follows in the dataflow. The
* segment events contains information for clipping buffers and
* converting buffer timestamps to running-time and
* stream-time.
......@@ -157,11 +158,12 @@ typedef enum {
GST_EVENT_FLUSH_STOP = GST_EVENT_MAKE_TYPE (2, 0, FLAG(BOTH) | FLAG(SERIALIZED)),
/* downstream serialized events */
GST_EVENT_CAPS = GST_EVENT_MAKE_TYPE (5, 1, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_NEWSEGMENT = GST_EVENT_MAKE_TYPE (6, 2, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_SEGMENT = GST_EVENT_MAKE_TYPE (6, 2, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_TAG = GST_EVENT_MAKE_TYPE (7, 3, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_BUFFERSIZE = GST_EVENT_MAKE_TYPE (8, 4, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_SINK_MESSAGE = GST_EVENT_MAKE_TYPE (9, 5, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
GST_EVENT_EOS = GST_EVENT_MAKE_TYPE (10, 6, FLAG(DOWNSTREAM) | FLAG(SERIALIZED) | FLAG(STICKY)),
/* upstream events */
GST_EVENT_QOS = GST_EVENT_MAKE_TYPE (15, 0, FLAG(UPSTREAM)),
GST_EVENT_SEEK = GST_EVENT_MAKE_TYPE (16, 0, FLAG(UPSTREAM)),
......@@ -280,77 +282,6 @@ typedef enum {
#define gst_event_replace(old_event,new_event) \
gst_mini_object_replace ((GstMiniObject **)(old_event), GST_MINI_OBJECT_CAST (new_event))
/**
* GstSeekType:
* @GST_SEEK_TYPE_NONE: no change in position is required
* @GST_SEEK_TYPE_CUR: change relative to currently configured segment. This
* can't be used to seek relative to the current playback position - do a
* position query, calculate the desired position and then do an absolute
* position seek instead if that's what you want to do.
* @GST_SEEK_TYPE_SET: absolute position is requested
* @GST_SEEK_TYPE_END: relative position to duration is requested
*
* The different types of seek events. When constructing a seek event with
* gst_event_new_seek(), a format, a seek method and optional flags are to
* be provided. The seek event is then inserted into the graph with
* gst_pad_send_event() or gst_element_send_event().
*/
typedef enum {
/* one of these */
GST_SEEK_TYPE_NONE = 0,
GST_SEEK_TYPE_CUR = 1,
GST_SEEK_TYPE_SET = 2,
GST_SEEK_TYPE_END = 3
} GstSeekType;
/**
* GstSeekFlags:
* @GST_SEEK_FLAG_NONE: no flag
* @GST_SEEK_FLAG_FLUSH: flush pipeline
* @GST_SEEK_FLAG_ACCURATE: accurate position is requested, this might
* be considerably slower for some formats.
* @GST_SEEK_FLAG_KEY_UNIT: seek to the nearest keyframe. This might be
* faster but less accurate.
* @GST_SEEK_FLAG_SEGMENT: perform a segment seek.
* @GST_SEEK_FLAG_SKIP: when doing fast foward or fast reverse playback, allow
* elements to skip frames instead of generating all
* frames. Since 0.10.22.
*
* Flags to be used with gst_element_seek() or gst_event_new_seek(). All flags
* can be used together.
*
* A non flushing seek might take some time to perform as the currently
* playing data in the pipeline will not be cleared.
*
* An accurate seek might be slower for formats that don't have any indexes
* or timestamp markers in the stream. Specifying this flag might require a
* complete scan of the file in those cases.
*
* When performing a segment seek: after the playback of the segment completes,
* no EOS will be emmited by the element that performed the seek, but a
* #GST_MESSAGE_SEGMENT_DONE message will be posted on the bus by the element.
* When this message is posted, it is possible to send a new seek event to
* continue playback. With this seek method it is possible to perform seemless
* looping or simple linear editing.
*
* When doing fast forward (rate > 1.0) or fast reverse (rate < -1.0) trickmode
* playback, the @GST_SEEK_FLAG_SKIP flag can be used to instruct decoders
* and demuxers to adjust the playback rate by skipping frames. This can improve
* performance and decrease CPU usage because not all frames need to be decoded.
*
* Also see part-seeking.txt in the GStreamer design documentation for more
* details on the meaning of these flags and the behaviour expected of
* elements that handle them.
*/
typedef enum {
GST_SEEK_FLAG_NONE = 0,
GST_SEEK_FLAG_FLUSH = (1 << 0),
GST_SEEK_FLAG_ACCURATE = (1 << 1),
GST_SEEK_FLAG_KEY_UNIT = (1 << 2),
GST_SEEK_FLAG_SEGMENT = (1 << 3),
GST_SEEK_FLAG_SKIP = (1 << 4)
} GstSeekFlags;
/**
* GstQOSType:
* @GST_QOS_TYPE_OVERFLOW: The QoS event type that is produced when downstream
......@@ -477,19 +408,11 @@ GstEvent * gst_event_new_eos (void);
GstEvent * gst_event_new_caps (GstCaps *caps);
void gst_event_parse_caps (GstEvent *event, GstCaps **caps);
/* newsegment events */
GstEvent* gst_event_new_new_segment (gboolean update, gdouble rate,
gdouble applied_rate,
GstFormat format,
gint64 start, gint64 stop,
gint64 time);
void gst_event_parse_new_segment (GstEvent *event,
gboolean *update,
gdouble *rate,
gdouble *applied_rate,
GstFormat *format,
gint64 *start, gint64 *stop,
gint64 *time);
/* segment event */
GstEvent* gst_event_new_segment (GstSegment *segment);
const GstSegment *
gst_event_get_segment (GstEvent *event);
void gst_event_parse_segment (GstEvent *event, GstSegment *segment);
/* tag event */
GstEvent* gst_event_new_tag (GstTagList *taglist);
......@@ -515,6 +438,7 @@ void gst_event_parse_seek (GstEvent *event, gdouble *rate,
GstSeekFlags *flags,
GstSeekType *start_type, gint64 *start,
GstSeekType *stop_type, gint64 *stop);
/* navigation event */
GstEvent* gst_event_new_navigation (GstStructure *structure);
......
......@@ -724,13 +724,11 @@ gst_debug_print_segment (gpointer ptr)
}
case GST_FORMAT_TIME:{
return g_strdup_printf ("time segment start=%" GST_TIME_FORMAT
", stop=%" GST_TIME_FORMAT ", last_stop=%" GST_TIME_FORMAT
", duration=%" GST_TIME_FORMAT ", rate=%f, applied_rate=%f"
", flags=0x%02x, time=%" GST_TIME_FORMAT ", accum=%" GST_TIME_FORMAT,
", stop=%" GST_TIME_FORMAT ", rate=%f, applied_rate=%f"
", flags=0x%02x, time=%" GST_TIME_FORMAT ", base=%" GST_TIME_FORMAT,
GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop),
GST_TIME_ARGS (segment->last_stop), GST_TIME_ARGS (segment->duration),
segment->rate, segment->applied_rate, (guint) segment->flags,
GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->accum));
GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->base));
}
default:{
const gchar *format_name;
......@@ -739,13 +737,11 @@ gst_debug_print_segment (gpointer ptr)
if (G_UNLIKELY (format_name == NULL))
format_name = "(UNKNOWN FORMAT)";
return g_strdup_printf ("%s segment start=%" G_GINT64_FORMAT
", stop=%" G_GINT64_FORMAT ", last_stop=%" G_GINT64_FORMAT
", duration=%" G_GINT64_FORMAT ", rate=%f, applied_rate=%f"
", flags=0x%02x, time=%" GST_TIME_FORMAT ", accum=%" GST_TIME_FORMAT,
format_name, segment->start, segment->stop, segment->last_stop,
segment->duration, segment->rate, segment->applied_rate,
(guint) segment->flags, GST_TIME_ARGS (segment->time),
GST_TIME_ARGS (segment->accum));
", stop=%" G_GINT64_FORMAT ", rate=%f, applied_rate=%f"
", flags=0x%02x, time=%" GST_TIME_FORMAT ", base=%" GST_TIME_FORMAT,
format_name, segment->start, segment->stop, segment->rate,
segment->applied_rate, (guint) segment->flags,
GST_TIME_ARGS (segment->time), GST_TIME_ARGS (segment->base));
}
}
}
......
......@@ -37,7 +37,7 @@ static const gchar *_quark_strings[] = {
"max-latency", "busy", "type", "owner", "update", "applied-rate",
"start", "stop", "minsize", "maxsize", "async", "proportion",
"diff", "timestamp", "flags", "cur-type", "cur", "stop-type",
"latency", "uri", "object", "taglist", "GstEventNewsegment",
"latency", "uri", "object", "taglist", "GstEventSegment",
"GstEventBufferSize", "GstEventQOS", "GstEventSeek", "GstEventLatency",
"GstMessageError", "GstMessageWarning", "GstMessageInfo",
"GstMessageBuffering", "GstMessageState", "GstMessageClockProvide",
......@@ -52,7 +52,9 @@ static const gchar *_quark_strings[] = {
"quality", "processed", "dropped", "buffering-ranges", "GstMessageProgress",
"code", "text", "percent", "timeout", "GstBufferPoolConfig", "caps", "size",
"min-buffers", "max-buffers", "prefix", "postfix", "align", "time",
"GstQueryAllocation", "need-pool", "meta", "pool", "GstEventCaps", "GstEventReconfigure"
"GstQueryAllocation", "need-pool", "meta", "pool", "GstEventCaps",
"GstEventReconfigure",
"segment"
};
GQuark _priv_gst_quark_table[GST_QUARK_MAX];
......
......@@ -80,7 +80,7 @@ typedef enum _GstQuarkId
GST_QUARK_URI = 51,
GST_QUARK_OBJECT = 52,
GST_QUARK_TAGLIST = 53,
GST_QUARK_EVENT_NEWSEGMENT = 54,
GST_QUARK_EVENT_SEGMENT = 54,
GST_QUARK_EVENT_BUFFER_SIZE = 55,
GST_QUARK_EVENT_QOS = 56,
GST_QUARK_EVENT_SEEK = 57,
......@@ -147,8 +147,9 @@ typedef enum _GstQuarkId
GST_QUARK_POOL = 118,
GST_QUARK_EVENT_CAPS = 119,
GST_QUARK_EVENT_RECONFIGURE = 120,
GST_QUARK_SEGMENT = 121,
GST_QUARK_MAX = 121
GST_QUARK_MAX = 122
} GstQuarkId;
extern GQuark _priv_gst_quark_table[GST_QUARK_MAX];
......
This diff is collapsed.
......@@ -23,7 +23,6 @@
#ifndef __GST_SEGMENT_H__
#define __GST_SEGMENT_H__
#include <gst/gstevent.h>
#include <gst/gstformat.h>
G_BEGIN_DECLS
......@@ -32,70 +31,129 @@ G_BEGIN_DECLS
typedef struct _GstSegment GstSegment;
/**
* GstSeekType:
* @GST_SEEK_TYPE_NONE: no change in position is required
* @GST_SEEK_TYPE_CUR: change relative to currently configured segment. This
* can't be used to seek relative to the current playback position - do a
* position query, calculate the desired position and then do an absolute
* position seek instead if that's what you want to do.
* @GST_SEEK_TYPE_SET: absolute position is requested
* @GST_SEEK_TYPE_END: relative position to duration is requested
*
* The different types of seek events. When constructing a seek event with
* gst_event_new_seek() or when doing gst_segment_do_seek ().
*/
typedef enum {
/* one of these */
GST_SEEK_TYPE_NONE = 0,
GST_SEEK_TYPE_CUR = 1,
GST_SEEK_TYPE_SET = 2,
GST_SEEK_TYPE_END = 3
} GstSeekType;
/**
* GstSeekFlags:
* @GST_SEEK_FLAG_NONE: no flag
* @GST_SEEK_FLAG_FLUSH: flush pipeline
* @GST_SEEK_FLAG_ACCURATE: accurate position is requested, this might
* be considerably slower for some formats.
* @GST_SEEK_FLAG_KEY_UNIT: seek to the nearest keyframe. This might be
* faster but less accurate.
* @GST_SEEK_FLAG_SEGMENT: perform a segment seek.
* @GST_SEEK_FLAG_SKIP: when doing fast foward or fast reverse playback, allow
* elements to skip frames instead of generating all
* frames. Since 0.10.22.
*
* Flags to be used with gst_element_seek() or gst_event_new_seek(). All flags
* can be used together.
*
* A non flushing seek might take some time to perform as the currently
* playing data in the pipeline will not be cleared.
*
* An accurate seek might be slower for formats that don't have any indexes
* or timestamp markers in the stream. Specifying this flag might require a
* complete scan of the file in those cases.
*
* When performing a segment seek: after the playback of the segment completes,
* no EOS will be emmited by the element that performed the seek, but a
* #GST_MESSAGE_SEGMENT_DONE message will be posted on the bus by the element.
* When this message is posted, it is possible to send a new seek event to
* continue playback. With this seek method it is possible to perform seemless
* looping or simple linear editing.
*
* When doing fast forward (rate > 1.0) or fast reverse (rate < -1.0) trickmode
* playback, the @GST_SEEK_FLAG_SKIP flag can be used to instruct decoders
* and demuxers to adjust the playback rate by skipping frames. This can improve
* performance and decrease CPU usage because not all frames need to be decoded.
*
* Also see part-seeking.txt in the GStreamer design documentation for more
* details on the meaning of these flags and the behaviour expected of
* elements that handle them.
*/
typedef enum {
GST_SEEK_FLAG_NONE = 0,
GST_SEEK_FLAG_FLUSH = (1 << 0),
GST_SEEK_FLAG_ACCURATE = (1 << 1),
GST_SEEK_FLAG_KEY_UNIT = (1 << 2),
GST_SEEK_FLAG_SEGMENT = (1 << 3),
GST_SEEK_FLAG_SKIP = (1 << 4)
} GstSeekFlags;
/**
* GstSegment:
* @flags: flags for this segment
* @rate: the rate of the segment
* @applied_rate: the already applied rate to the segment
* @format: the format of the segment values
* @flags: flags for this segment
* @base: the base time of the segment
* @start: the start of the segment
* @stop: the stop of the segment
* @time: the stream time of the segment
* @accum: accumulated segment
* @last_stop: last known stop time
* @duration: total duration of segment
*
* A helper structure that holds the configured region of
* interest in a media file.
*/
struct _GstSegment {
/*< public >*/
gdouble rate;
gdouble applied_rate;
GstFormat format;
GstSeekFlags flags;
gint64 start;
gint64 stop;
gint64 time;
gint64 accum;
gint64 last_stop;
gint64 duration;
/*< private >*/
gpointer _gst_reserved[GST_PADDING];
GstSeekFlags flags;
gdouble rate;
gdouble applied_rate;
GstFormat format;
guint64 base;
guint64 start;
guint64 stop;
guint64 time;
guint64 position;
guint64 duration;
};
GType gst_segment_get_type (void);
GstSegment * gst_segment_new (void);
GstSegment * gst_segment_copy (GstSegment *segment);
GstSegment * gst_segment_copy (const GstSegment *segment);
void gst_segment_copy_into (const GstSegment *src, GstSegment *dest);
void gst_segment_free (GstSegment *segment);
void gst_segment_init (GstSegment *segment, GstFormat format);
void gst_segment_set_duration (GstSegment *segment, GstFormat format, gint64 duration);
void gst_segment_set_last_stop (GstSegment *segment, GstFormat format, gint64 position);
void gst_segment_set_seek (GstSegment *segment, gdouble rate,
GstFormat format, GstSeekFlags flags,
GstSeekType start_type, gint64 start,
GstSeekType stop_type, gint64 stop,
gboolean *update);
guint64 gst_segment_to_stream_time (const GstSegment *segment, GstFormat format, guint64 position);
guint64 gst_segment_to_running_time (const GstSegment *segment, GstFormat format, guint64 position);
guint64 gst_segment_to_position (const GstSegment *segment, GstFormat format, guint64 running_time);
void gst_segment_set_newsegment (GstSegment *segment, gboolean update, gdouble rate,
gdouble applied_rate, GstFormat format, gint64 start,
gint64 stop, gint64 time);
gboolean gst_segment_set_running_time (GstSegment *segment, GstFormat format, guint64 running_time);
gint64 gst_segment_to_stream_time (GstSegment *segment, GstFormat format, gint64 position);
gint64 gst_segment_to_running_time (GstSegment *segment, GstFormat format, gint64 position);
gint64 gst_segment_to_position (GstSegment *segment, GstFormat format, gint64 running_time);
gboolean gst_segment_clip (const GstSegment *segment, GstFormat format, guint64 start,
guint64 stop, guint64 *clip_start, guint64 *clip_stop);
gboolean gst_segment_clip (GstSegment *segment, GstFormat format, gint64 start,
gint64 stop, gint64 *clip_start, gint64 *clip_stop);
gboolean gst_segment_set_running_time (GstSegment *segment, GstFormat format, gint64 running_time);
gboolean gst_segment_do_seek (GstSegment * segment, gdouble rate,
GstFormat format, GstSeekFlags flags,
GstSeekType start_type, guint64 start,
GstSeekType stop_type, guint64 stop, gboolean * update);
G_END_DECLS
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -250,7 +250,7 @@ struct _GstBaseTransformPrivate
guint64 processed;
guint64 dropped;
GstClockTime last_stop_out;
GstClockTime position_out;
};
static GstElementClass *parent_class = NULL;
......@@ -1163,13 +1163,13 @@ gst_base_transform_query (GstPad * pad, GstQuery ** query)
ret = TRUE;
if ((pad == trans->sinkpad)
|| (trans->priv->last_stop_out == GST_CLOCK_TIME_NONE)) {
|| (trans->priv->position_out == GST_CLOCK_TIME_NONE)) {
pos =
gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
trans->segment.last_stop);
trans->segment.position);
} else {
pos = gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME,
trans->priv->last_stop_out);
trans->priv->position_out);
}
gst_query_set_position (*query, format, pos);
} else {
......@@ -1515,9 +1515,9 @@ gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
trans->priv->dropped = 0;
GST_OBJECT_UNLOCK (trans);
/* we need new segment info after the flush. */
trans->have_newsegment = FALSE;
trans->have_segment = FALSE;
gst_segment_init (&trans->segment, GST_FORMAT_UNDEFINED);
trans->priv->last_stop_out = GST_CLOCK_TIME_NONE;
trans->priv->position_out = GST_CLOCK_TIME_NONE;
break;
case GST_EVENT_EOS:
break;
......@@ -1533,36 +1533,13 @@ gst_base_transform_sink_eventfunc (GstBaseTransform * trans, GstEvent * event)
forward = FALSE;
break;
}
case GST_EVENT_NEWSEGMENT:
case GST_EVENT_SEGMENT:
{
GstFormat format;
gdouble rate, arate;
gint64 start, stop, time;
gboolean update;
gst_event_parse_new_segment (event, &update, &rate, &arate, &format,
&start, &stop, &time);
trans->have_newsegment = TRUE;
gst_segment_set_newsegment (&trans->segment, update, rate, arate,
format, start, stop, time);
if (format == GST_FORMAT_TIME) {
GST_DEBUG_OBJECT (trans, "received TIME NEW_SEGMENT %" GST_TIME_FORMAT
" -- %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT
", accum %" GST_TIME_FORMAT,
GST_TIME_ARGS (trans->segment.start),
GST_TIME_ARGS (trans->segment.stop),
GST_TIME_ARGS (trans->segment.time),
GST_TIME_ARGS (trans->segment.accum));
} else {
GST_DEBUG_OBJECT (trans, "received NEW_SEGMENT %" G_GINT64_FORMAT
" -- %" G_GINT64_FORMAT ", time %" G_GINT64_FORMAT
", accum %" G_GINT64_FORMAT,
trans->segment.start, trans->segment.stop,
trans->segment.time, trans->segment.accum);
}
gst_event_parse_segment (event, &trans->segment);
trans->have_segment = TRUE;
GST_DEBUG_OBJECT (trans, "received SEGMENT %" GST_SEGMENT_FORMAT,
&trans->segment);
break;
}
default:
......@@ -1896,7 +1873,7 @@ gst_base_transform_chain (GstPad * pad, GstBuffer * buffer)
GstBaseTransform *trans;
GstBaseTransformClass *klass;
GstFlowReturn ret;
GstClockTime last_stop = GST_CLOCK_TIME_NONE;
GstClockTime position = GST_CLOCK_TIME_NONE;
GstClockTime timestamp, duration;