videorate: Add a max-closing-segment-duplication-duration property

This allows users to let videorate fully fill the segments when received
EOS or on new segment, removing an arbitrary limit of 25 duplicates which
might not be what the user wants (for example on low FPS stream in GES,
that sometimes leaded to broken behavior)

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3000>
This commit is contained in:
Thibault Saunier 2022-09-06 17:25:50 -04:00 committed by GStreamer Marge Bot
parent 515e1b55ee
commit bb840bd116
13 changed files with 442 additions and 49 deletions

View file

@ -14153,6 +14153,20 @@
"type": "guint64",
"writable": false
},
"max-closing-segment-duplication-duration": {
"blurb": "Maximum duration of duplicated buffers to close current segment",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "1000000000",
"max": "18446744073709551615",
"min": "0",
"mutable": "null",
"readable": true,
"type": "guint64",
"writable": true
},
"max-duplication-time": {
"blurb": "Do not duplicate frames if the gap exceeds this period (in ns) (0 = disabled)",
"conditionally-available": false,

View file

@ -100,6 +100,7 @@ enum
#define DEFAULT_MAX_RATE G_MAXINT
#define DEFAULT_RATE 1.0
#define DEFAULT_MAX_DUPLICATION_TIME 0
#define DEFAULT_MAX_CLOSING_SEGMENT_DUPLICATION_DURATION GST_SECOND
enum
{
@ -115,7 +116,8 @@ enum
PROP_AVERAGE_PERIOD,
PROP_MAX_RATE,
PROP_RATE,
PROP_MAX_DUPLICATION_TIME
PROP_MAX_DUPLICATION_TIME,
PROP_MAX_CLOSING_SEGMENT_DUPLICATION_DURATION
};
static GstStaticPadTemplate gst_video_rate_src_template =
@ -295,6 +297,27 @@ gst_video_rate_class_init (GstVideoRateClass * klass)
0, G_MAXUINT64, DEFAULT_MAX_DUPLICATION_TIME,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstVideoRate:max-closing-segment-duplication-duration:
*
* Limits the maximum duration for which the last buffer is duplicated when
* finalizing a segment or on EOS. When receiving an EOS event or a new
* segment, videorate duplicates the last frame to close the configured
* segment (copying the last buffer until its #GstSegment.stop time (or
* #GstSegment.start time for reverse playback) is reached), this property
* ensures that it won't push buffers covering a duration longer than
* specified.
*
* Since: 1.22
*/
g_object_class_install_property (object_class,
PROP_MAX_CLOSING_SEGMENT_DUPLICATION_DURATION,
g_param_spec_uint64 ("max-closing-segment-duplication-duration",
"Maximum closing segment duplication duration",
"Maximum duration of duplicated buffers to close current segment", 0,
G_MAXUINT64, DEFAULT_MAX_CLOSING_SEGMENT_DUPLICATION_DURATION,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_static_metadata (element_class,
"Video rate adjuster", "Filter/Effect/Video",
"Drops/duplicates/adjusts timestamps on video frames to make a perfect stream",
@ -637,6 +660,8 @@ gst_video_rate_init (GstVideoRate * videorate)
videorate->rate = DEFAULT_RATE;
videorate->pending_rate = DEFAULT_RATE;
videorate->max_duplication_time = DEFAULT_MAX_DUPLICATION_TIME;
videorate->max_closing_segment_duplication_duration =
DEFAULT_MAX_CLOSING_SEGMENT_DUPLICATION_DURATION;
videorate->from_rate_numerator = 0;
videorate->from_rate_denominator = 0;
@ -782,7 +807,90 @@ gst_video_rate_notify_duplicate (GstVideoRate * videorate)
g_object_notify_by_pspec ((GObject *) videorate, pspec_duplicate);
}
#define MAGIC_LIMIT 25
static gboolean
gst_video_rate_check_duplicate_to_close_segment (GstVideoRate * videorate,
GstClockTime last_input_ts, gboolean is_first)
{
GstClockTime next_stream_time = videorate->next_ts - videorate->segment.base;
GstClockTime max_closing_segment_duplication_duration =
videorate->max_closing_segment_duplication_duration;
if (!GST_CLOCK_TIME_IS_VALID (videorate->next_ts))
return FALSE;
if (videorate->segment.rate > 0.0) {
if (!GST_CLOCK_TIME_IS_VALID (videorate->segment.stop)) {
/* Ensure that if no 'stop' is set, we push the last frame anyway */
return is_first;
}
if (next_stream_time >= videorate->segment.stop)
return FALSE;
if (GST_CLOCK_TIME_IS_VALID (max_closing_segment_duplication_duration)) {
if (last_input_ts > videorate->next_ts)
return TRUE;
return (videorate->next_ts - last_input_ts <
max_closing_segment_duplication_duration);
}
return TRUE;
}
/* Reverse playback */
if (!GST_CLOCK_TIME_IS_VALID (videorate->segment.start)) {
/* Ensure that if no 'start' is set, we push the last frame anyway */
return is_first;
}
if (next_stream_time < videorate->segment.start)
return FALSE;
if (GST_CLOCK_TIME_IS_VALID (max_closing_segment_duplication_duration)) {
if (last_input_ts < videorate->next_ts)
return TRUE;
return (last_input_ts - videorate->next_ts <
max_closing_segment_duplication_duration);
}
return TRUE;
}
static gint
gst_video_rate_duplicate_to_close_segment (GstVideoRate * videorate)
{
gint count = 0;
GstFlowReturn res;
GstClockTime last_input_ts = videorate->prev_ts;
if (videorate->drop_only)
return count;
if (!videorate->prevbuf) {
GST_INFO_OBJECT (videorate, "got EOS before any buffer was received");
return count;
}
res = GST_FLOW_OK;
/* fill up to the end of current segment */
while (res == GST_FLOW_OK
&& gst_video_rate_check_duplicate_to_close_segment (videorate,
last_input_ts, count < 1)) {
res =
gst_video_rate_flush_prev (videorate, count > 0, GST_CLOCK_TIME_NONE,
FALSE);
count++;
}
return count;
}
static gboolean
gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
{
@ -804,30 +912,8 @@ gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
/* close up the previous segment, if appropriate */
if (videorate->prevbuf) {
gint count = 0;
GstFlowReturn res;
res = GST_FLOW_OK;
/* fill up to the end of current segment,
* or only send out the stored buffer if there is no specific stop.
* regardless, prevent going loopy in strange cases */
while (res == GST_FLOW_OK && count <= MAGIC_LIMIT
&& !videorate->drop_only
&& ((videorate->segment.rate > 0.0
&& GST_CLOCK_TIME_IS_VALID (videorate->segment.stop)
&& GST_CLOCK_TIME_IS_VALID (videorate->next_ts)
&& videorate->next_ts - videorate->segment.base <
videorate->segment.stop) || (videorate->segment.rate < 0.0
&& GST_CLOCK_TIME_IS_VALID (videorate->segment.start)
&& GST_CLOCK_TIME_IS_VALID (videorate->next_ts)
&& videorate->next_ts - videorate->segment.base >=
videorate->segment.start)
|| count < 1)) {
res =
gst_video_rate_flush_prev (videorate, count > 0,
GST_CLOCK_TIME_NONE, FALSE);
count++;
}
/* fill up to the end of current segment */
gint count = gst_video_rate_duplicate_to_close_segment (videorate);
if (count > 1) {
videorate->dup += count - 1;
if (!videorate->silent)
@ -871,34 +957,23 @@ gst_video_rate_sink_event (GstBaseTransform * trans, GstEvent * event)
/* If the segment has a stop position, fill the segment */
if (GST_CLOCK_TIME_IS_VALID (videorate->segment.stop)) {
/* fill up to the end of current segment,
* or only send out the stored buffer if there is no specific stop.
* regardless, prevent going loopy in strange cases */
while (res == GST_FLOW_OK && count <= MAGIC_LIMIT
&& !videorate->drop_only
&& ((videorate->segment.rate > 0.0
&& GST_CLOCK_TIME_IS_VALID (videorate->segment.stop)
&& GST_CLOCK_TIME_IS_VALID (videorate->next_ts)
&& videorate->next_ts - videorate->segment.base <
videorate->segment.stop) || (videorate->segment.rate < 0.0
&& GST_CLOCK_TIME_IS_VALID (videorate->segment.start)
&& GST_CLOCK_TIME_IS_VALID (videorate->next_ts)
&& videorate->next_ts - videorate->segment.base >=
videorate->segment.start)
)) {
res = gst_video_rate_flush_prev (videorate, count > 0,
GST_CLOCK_TIME_NONE, FALSE);
count++;
}
/* fill up to the end of current segment */
count = gst_video_rate_duplicate_to_close_segment (videorate);
} else if (!videorate->drop_only && videorate->prevbuf) {
/* Output at least one frame but if the buffer duration is valid, output
* enough frames to use the complete buffer duration */
if (GST_BUFFER_DURATION_IS_VALID (videorate->prevbuf)) {
GstClockTime end_ts =
videorate->next_ts + GST_BUFFER_DURATION (videorate->prevbuf);
GstClockTime end_ts, duration =
GST_BUFFER_DURATION (videorate->prevbuf);
while (res == GST_FLOW_OK && count <= MAGIC_LIMIT &&
((videorate->segment.rate > 0.0
if (GST_CLOCK_TIME_IS_VALID
(videorate->max_closing_segment_duplication_duration))
duration =
MIN (videorate->max_closing_segment_duplication_duration,
duration);
end_ts = videorate->next_ts + duration;
while (res == GST_FLOW_OK && ((videorate->segment.rate > 0.0
&& GST_CLOCK_TIME_IS_VALID (videorate->segment.stop)
&& GST_CLOCK_TIME_IS_VALID (videorate->next_ts)
&& videorate->next_ts - videorate->segment.base < end_ts)
@ -1839,6 +1914,10 @@ gst_video_rate_set_property (GObject * object,
case PROP_MAX_DUPLICATION_TIME:
videorate->max_duplication_time = g_value_get_uint64 (value);
break;
case PROP_MAX_CLOSING_SEGMENT_DUPLICATION_DURATION:
videorate->max_closing_segment_duplication_duration =
g_value_get_uint64 (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1901,6 +1980,10 @@ gst_video_rate_get_property (GObject * object,
case PROP_MAX_DUPLICATION_TIME:
g_value_set_uint64 (value, videorate->max_duplication_time);
break;
case PROP_MAX_CLOSING_SEGMENT_DUPLICATION_DURATION:
g_value_set_uint64 (value,
videorate->max_closing_segment_duplication_duration);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -58,6 +58,7 @@ struct _GstVideoRate
gboolean force_variable_rate;
gboolean updating_caps;
guint64 max_duplication_time;
guint64 max_closing_segment_duplication_duration;
/* segment handling */
GstSegment segment;

View file

@ -17,6 +17,9 @@ tests = [
'videorate/rate_0_5_with_decoder',
'videorate/rate_2_0',
'videorate/rate_2_0_with_decoder',
'videorate/duplicate_on_eos',
'videorate/duplicate_on_eos_disbaled',
'videorate/duplicate_on_eos_half_sec',
'compositor/renogotiate_failing_unsupported_src_format',
'giosrc/read-growing-file',
'encodebin/set-encoder-properties',

View file

@ -0,0 +1,21 @@
meta,
args = {
"videotestsrc pattern=ball animation-mode=frames ! video/x-raw,format=I420,framerate=1/1,width=320,height=240 ! videorate name=videorate ! video/x-raw,framerate=30/1 ! fakesink sync=true qos=true",
},
configs = {
"$(validateflow), pad=videorate:sink, buffers-checksum=as-id, ignored-event-types={ tag }",
"$(validateflow), pad=videorate:src, buffers-checksum=as-id, ignored-event-types={ tag }",
},
handles-states=true,
ignore-eos=true
pause
seek, flags=flush+accurate, start=0, stop=3.0
play
crank-clock, repeat=91
wait, message-type=eos
# Last buffer is duplicated until the full segment is filled
check-position, expected-position=3.0
stop

View file

@ -0,0 +1,12 @@
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
event caps: video/x-raw, format=(string)I420, framerate=(fraction)1/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:01.000000000, flags=discont
buffer: content-id=1, pts=0:00:01.000000000, dur=0:00:01.000000000
event flush-start: (no structure)
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:03.000000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:01.000000000, flags=discont
buffer: content-id=1, pts=0:00:01.000000000, dur=0:00:01.000000000
buffer: content-id=2, pts=0:00:02.000000000, dur=0:00:01.000000000
event eos: (no structure)

View file

@ -0,0 +1,98 @@
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
event caps: video/x-raw, format=(string)I420, framerate=(fraction)30/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont
event flush-start: (no structure)
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:03.000000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont
buffer: content-id=0, pts=0:00:00.033333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.066666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.100000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.133333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.166666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.200000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.233333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.266666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.300000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.333333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.366666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.400000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.433333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.466666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.500000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.533333333, dur=0:00:00.033333333
buffer: content-id=1, pts=0:00:00.566666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.600000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.633333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.666666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.700000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.733333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.766666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.800000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.833333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.866666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.900000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.933333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.966666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.000000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.033333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.066666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.100000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.133333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.166666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.200000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.233333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.266666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.300000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.333333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.366666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.400000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.433333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.466666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.500000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:01.533333333, dur=0:00:00.033333333
buffer: content-id=2, pts=0:00:01.566666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:01.600000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:01.633333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:01.666666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:01.700000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:01.733333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:01.766666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:01.800000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:01.833333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:01.866666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:01.900000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:01.933333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:01.966666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.000000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.033333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.066666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.100000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.133333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.166666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.200000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.233333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.266666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.300000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.333333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.366666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.400000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.433333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.466666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.500000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.533333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.566666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.600000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.633333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.666666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.700000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.733333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.766666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.800000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.833333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.866666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=2, pts=0:00:02.900000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.933333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=2, pts=0:00:02.966666666, dur=0:00:00.033333334, flags=gap
event eos: (no structure)

View file

@ -0,0 +1,23 @@
meta,
args = {
"videotestsrc pattern=ball animation-mode=frames ! video/x-raw,format=I420,framerate=1/1,width=320,height=240 ! videorate max-closing-segment-duplication-duration=0 name=videorate ! video/x-raw,framerate=30/1 ! fakesink sync=true qos=true",
},
configs = {
"$(validateflow), pad=videorate:sink, buffers-checksum=as-id, ignored-event-types={ tag }",
"$(validateflow), pad=videorate:src, buffers-checksum=as-id, ignored-event-types={ tag }",
},
handles-states=true,
ignore-eos=true
pause
seek, flags=flush+accurate, start=0, stop=2.0
play
crank-clock, repeat=31
wait, message-type=eos
# Second buffer won't be duplicated as we disabled on on EOS
check-position, expected-position=1.0
stop

View file

@ -0,0 +1,11 @@
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
event caps: video/x-raw, format=(string)I420, framerate=(fraction)1/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:01.000000000, flags=discont
buffer: content-id=1, pts=0:00:01.000000000, dur=0:00:01.000000000
event flush-start: (no structure)
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:02.000000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:01.000000000, flags=discont
buffer: content-id=1, pts=0:00:01.000000000, dur=0:00:01.000000000
event eos: (no structure)

View file

@ -0,0 +1,38 @@
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
event caps: video/x-raw, format=(string)I420, framerate=(fraction)30/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont
event flush-start: (no structure)
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:02.000000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont
buffer: content-id=0, pts=0:00:00.033333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.066666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.100000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.133333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.166666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.200000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.233333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.266666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.300000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.333333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.366666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.400000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.433333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.466666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.500000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.533333333, dur=0:00:00.033333333
buffer: content-id=1, pts=0:00:00.566666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.600000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.633333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.666666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.700000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.733333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.766666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.800000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.833333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.866666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.900000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.933333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.966666666, dur=0:00:00.033333334, flags=gap
event eos: (no structure)

View file

@ -0,0 +1,25 @@
meta,
args = {
"videotestsrc pattern=ball animation-mode=frames ! video/x-raw,format=I420,framerate=1/1,width=320,height=240 ! videorate max-closing-segment-duplication-duration=500000000 name=videorate ! video/x-raw,framerate=30/1 ! fakesink sync=true qos=true",
},
configs = {
"$(validateflow), pad=videorate:sink, buffers-checksum=as-id, ignored-event-types={ tag }",
"$(validateflow), pad=videorate:src, buffers-checksum=as-id, ignored-event-types={ tag }",
},
handles-states=true,
ignore-eos=true
pause
seek, flags=flush+accurate, start=0, stop=2.0
play
crank-clock, repeat=46
wait, message-type=eos
# At most 0.5 second can be output after EOS, meaning that after the second
# buffer (which starts at 1) videorate will duplicate the frame for 0.5 secs
check-position, expected-position=1.5
stop

View file

@ -0,0 +1,11 @@
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
event caps: video/x-raw, format=(string)I420, framerate=(fraction)1/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:01.000000000, flags=discont
buffer: content-id=1, pts=0:00:01.000000000, dur=0:00:01.000000000
event flush-start: (no structure)
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:02.000000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:01.000000000, flags=discont
buffer: content-id=1, pts=0:00:01.000000000, dur=0:00:01.000000000
event eos: (no structure)

View file

@ -0,0 +1,53 @@
event stream-start: GstEventStreamStart, flags=(GstStreamFlags)GST_STREAM_FLAG_NONE, group-id=(uint)1;
event caps: video/x-raw, format=(string)I420, framerate=(fraction)30/1, height=(int)240, interlace-mode=(string)progressive, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, width=(int)320;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=none, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont
event flush-start: (no structure)
event flush-stop: GstEventFlushStop, reset-time=(boolean)true;
event segment: format=TIME, start=0:00:00.000000000, offset=0:00:00.000000000, stop=0:00:02.000000000, flags=0x01, time=0:00:00.000000000, base=0:00:00.000000000, position=0:00:00.000000000
buffer: content-id=0, pts=0:00:00.000000000, dur=0:00:00.033333333, flags=discont
buffer: content-id=0, pts=0:00:00.033333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.066666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.100000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.133333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.166666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.200000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.233333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.266666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.300000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.333333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.366666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.400000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.433333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=0, pts=0:00:00.466666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=0, pts=0:00:00.500000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.533333333, dur=0:00:00.033333333
buffer: content-id=1, pts=0:00:00.566666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.600000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.633333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.666666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.700000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.733333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.766666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.800000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.833333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.866666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:00.900000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.933333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:00.966666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.000000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.033333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.066666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.100000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.133333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.166666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.200000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.233333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.266666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.300000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.333333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.366666666, dur=0:00:00.033333334, flags=gap
buffer: content-id=1, pts=0:00:01.400000000, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.433333333, dur=0:00:00.033333333, flags=gap
buffer: content-id=1, pts=0:00:01.466666666, dur=0:00:00.033333334, flags=gap
event eos: (no structure)