From bb840bd116fe43344bda90a881be179e519f8b95 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Tue, 6 Sep 2022 17:25:50 -0400 Subject: [PATCH] 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: --- .../docs/plugins/gst_plugins_cache.json | 14 ++ .../gst/videorate/gstvideorate.c | 181 +++++++++++++----- .../gst/videorate/gstvideorate.h | 1 + .../tests/validate/meson.build | 3 + .../videorate/duplicate_on_eos.validatetest | 21 ++ .../log-videorate-sink-expected | 12 ++ .../log-videorate-src-expected | 98 ++++++++++ .../duplicate_on_eos_disbaled.validatetest | 23 +++ .../log-videorate-sink-expected | 11 ++ .../log-videorate-src-expected | 38 ++++ .../duplicate_on_eos_half_sec.validatetest | 25 +++ .../log-videorate-sink-expected | 11 ++ .../log-videorate-src-expected | 53 +++++ 13 files changed, 442 insertions(+), 49 deletions(-) create mode 100644 subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos.validatetest create mode 100644 subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos/flow-expectations/log-videorate-sink-expected create mode 100644 subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos/flow-expectations/log-videorate-src-expected create mode 100644 subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled.validatetest create mode 100644 subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled/flow-expectations/log-videorate-sink-expected create mode 100644 subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled/flow-expectations/log-videorate-src-expected create mode 100644 subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec.validatetest create mode 100644 subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec/flow-expectations/log-videorate-sink-expected create mode 100644 subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec/flow-expectations/log-videorate-src-expected diff --git a/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json b/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json index 8828acea98..27d27c8e2c 100644 --- a/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json +++ b/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json @@ -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, diff --git a/subprojects/gst-plugins-base/gst/videorate/gstvideorate.c b/subprojects/gst-plugins-base/gst/videorate/gstvideorate.c index 2fdd6d3130..c347b94438 100644 --- a/subprojects/gst-plugins-base/gst/videorate/gstvideorate.c +++ b/subprojects/gst-plugins-base/gst/videorate/gstvideorate.c @@ -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; diff --git a/subprojects/gst-plugins-base/gst/videorate/gstvideorate.h b/subprojects/gst-plugins-base/gst/videorate/gstvideorate.h index 1dfd866752..02d26e39d7 100644 --- a/subprojects/gst-plugins-base/gst/videorate/gstvideorate.h +++ b/subprojects/gst-plugins-base/gst/videorate/gstvideorate.h @@ -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; diff --git a/subprojects/gst-plugins-base/tests/validate/meson.build b/subprojects/gst-plugins-base/tests/validate/meson.build index f055ffd2d8..abcd16edbf 100644 --- a/subprojects/gst-plugins-base/tests/validate/meson.build +++ b/subprojects/gst-plugins-base/tests/validate/meson.build @@ -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', diff --git a/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos.validatetest b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos.validatetest new file mode 100644 index 0000000000..8162596bcd --- /dev/null +++ b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos.validatetest @@ -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 diff --git a/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos/flow-expectations/log-videorate-sink-expected b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos/flow-expectations/log-videorate-sink-expected new file mode 100644 index 0000000000..edaf641966 --- /dev/null +++ b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos/flow-expectations/log-videorate-sink-expected @@ -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) diff --git a/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos/flow-expectations/log-videorate-src-expected b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos/flow-expectations/log-videorate-src-expected new file mode 100644 index 0000000000..58a15c0a34 --- /dev/null +++ b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos/flow-expectations/log-videorate-src-expected @@ -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) diff --git a/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled.validatetest b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled.validatetest new file mode 100644 index 0000000000..8549da49f8 --- /dev/null +++ b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled.validatetest @@ -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 + + diff --git a/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled/flow-expectations/log-videorate-sink-expected b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled/flow-expectations/log-videorate-sink-expected new file mode 100644 index 0000000000..7ecb4e927d --- /dev/null +++ b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled/flow-expectations/log-videorate-sink-expected @@ -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) diff --git a/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled/flow-expectations/log-videorate-src-expected b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled/flow-expectations/log-videorate-src-expected new file mode 100644 index 0000000000..c25ae88a21 --- /dev/null +++ b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_disbaled/flow-expectations/log-videorate-src-expected @@ -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) diff --git a/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec.validatetest b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec.validatetest new file mode 100644 index 0000000000..3d9ce96293 --- /dev/null +++ b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec.validatetest @@ -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 + + + diff --git a/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec/flow-expectations/log-videorate-sink-expected b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec/flow-expectations/log-videorate-sink-expected new file mode 100644 index 0000000000..7ecb4e927d --- /dev/null +++ b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec/flow-expectations/log-videorate-sink-expected @@ -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) diff --git a/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec/flow-expectations/log-videorate-src-expected b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec/flow-expectations/log-videorate-src-expected new file mode 100644 index 0000000000..32eb33c399 --- /dev/null +++ b/subprojects/gst-plugins-base/tests/validate/videorate/duplicate_on_eos_half_sec/flow-expectations/log-videorate-src-expected @@ -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)