From da35ed69164ba8c8599d337b00ba54074215f7e7 Mon Sep 17 00:00:00 2001 From: Matthew Waters Date: Tue, 12 Mar 2024 14:25:31 +1100 Subject: [PATCH] cccombiner: add support for timing out captions without EOS Part-of: --- .../docs/plugins/gst_plugins_cache.json | 14 ++++ .../ext/closedcaption/gstcccombiner.c | 76 ++++++++++++++++--- .../ext/closedcaption/gstcccombiner.h | 2 + 3 files changed, 80 insertions(+), 12 deletions(-) diff --git a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json index 069ed5b9e3..a9039ba964 100644 --- a/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json +++ b/subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json @@ -7872,6 +7872,20 @@ "readable": true, "type": "gboolean", "writable": true + }, + "schedule-timeout": { + "blurb": "How long after not receiving caption data on the caption pad to continue adding (padding) caption data on output buffers", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "18446744073709551615", + "max": "18446744073709551615", + "min": "0", + "mutable": "playing", + "readable": true, + "type": "guint64", + "writable": true } }, "rank": "none" diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c b/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c index 58e836c555..ca604bcf7c 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c +++ b/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.c @@ -65,6 +65,7 @@ enum PROP_MAX_SCHEDULED, PROP_CEA608_PADDING_STRATEGY, PROP_CEA608_VALID_PADDING_TIMEOUT, + PROP_SCHEDULE_TIMEOUT, }; #define DEFAULT_MAX_SCHEDULED 30 @@ -72,6 +73,7 @@ enum #define DEFAULT_OUTPUT_PADDING TRUE #define DEFAULT_CEA608_PADDING_STRATEGY CC_BUFFER_CEA608_PADDING_STRATEGY_VALID #define DEFAULT_CEA608_VALID_PADDING_TIMEOUT GST_CLOCK_TIME_NONE +#define DEFAULT_SCHEDULE_TIMEOUT GST_CLOCK_TIME_NONE typedef struct { @@ -277,25 +279,24 @@ schedule_caption (GstCCCombiner * self, GstBuffer * caption_buf, const GstVideoTimeCode * tc) { GstMapInfo map; - GstClockTime pts, duration; + GstClockTime pts, duration, running_time; + GstAggregatorPad *caption_pad; pts = GST_BUFFER_PTS (caption_buf); duration = GST_BUFFER_DURATION (caption_buf); - if (self->current_scheduled + 1 >= self->max_scheduled) { - GstClockTime stream_time, running_time; - GstAggregatorPad *caption_pad; + caption_pad = + GST_AGGREGATOR_PAD_CAST (gst_element_get_static_pad (GST_ELEMENT_CAST + (self), "caption")); + running_time = + gst_segment_to_running_time (&caption_pad->segment, GST_FORMAT_TIME, pts); - caption_pad = - GST_AGGREGATOR_PAD_CAST (gst_element_get_static_pad (GST_ELEMENT_CAST - (self), "caption")); + if (self->current_scheduled + 1 >= self->max_scheduled) { + GstClockTime stream_time; GST_WARNING_OBJECT (self, "scheduled queue runs too long, discarding stored"); - running_time = - gst_segment_to_running_time (&caption_pad->segment, GST_FORMAT_TIME, - pts); stream_time = gst_segment_to_stream_time (&caption_pad->segment, GST_FORMAT_TIME, pts); @@ -306,10 +307,12 @@ schedule_caption (GstCCCombiner * self, GstBuffer * caption_buf, cc_buffer_discard (self->cc_buffer); self->current_scheduled = 0; - - gst_clear_object (&caption_pad); } + self->last_caption_ts = running_time; + + gst_clear_object (&caption_pad); + gst_buffer_map (caption_buf, &map, GST_MAP_READ); switch (self->caption_type) { @@ -346,6 +349,24 @@ dequeue_caption (GstCCCombiner * self, GstVideoTimeCode * tc, gboolean drain) if (drain && cc_buffer_is_empty (self->cc_buffer)) return; + if (self->prop_schedule_timeout != GST_CLOCK_TIME_NONE) { + if (self->last_caption_ts == GST_CLOCK_TIME_NONE) { + return; + } + + if (self->current_video_running_time > self->last_caption_ts + && self->current_video_running_time - self->last_caption_ts + > self->prop_schedule_timeout) { + GST_LOG_OBJECT (self, "Not outputting caption as last caption buffer ts %" + GST_TIME_FORMAT " is more than the schedule timeout %" GST_TIME_FORMAT + " from the current output time %" GST_TIME_FORMAT, + GST_TIME_ARGS (self->last_caption_ts), + GST_TIME_ARGS (self->prop_schedule_timeout), + GST_TIME_ARGS (self->current_video_running_time)); + return; + } + } + caption_data.caption_type = self->caption_type; switch (self->caption_type) { case GST_VIDEO_CAPTION_TYPE_CEA708_CDP: @@ -859,6 +880,11 @@ gst_cc_combiner_sink_event (GstAggregator * aggregator, } break; } + case GST_EVENT_STREAM_START:{ + if (strcmp (GST_OBJECT_NAME (agg_pad), "caption") == 0) { + self->last_caption_ts = GST_CLOCK_TIME_NONE; + } + } default: break; } @@ -1138,6 +1164,9 @@ gst_cc_combiner_set_property (GObject * object, guint prop_id, cc_buffer_set_cea608_valid_timeout (self->cc_buffer, self->prop_cea608_valid_padding_timeout); break; + case PROP_SCHEDULE_TIMEOUT: + self->prop_schedule_timeout = g_value_get_uint64 (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1166,6 +1195,9 @@ gst_cc_combiner_get_property (GObject * object, guint prop_id, GValue * value, case PROP_CEA608_VALID_PADDING_TIMEOUT: g_value_set_uint64 (value, self->prop_cea608_valid_padding_timeout); break; + case PROP_SCHEDULE_TIMEOUT: + g_value_set_uint64 (value, self->prop_schedule_timeout); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1294,6 +1326,24 @@ gst_cc_combiner_class_init (GstCCCombinerClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_PLAYING)); + /** + * GstCCCombiner:schedule-timeout: + * + * Timeout to apply when the caption pad is EOS and schedule=true. On + * reaching the timeout, no caption data will be placed on the outgoing + * buffers until receiving a new stream. + * + * Since: 1.26 + */ + g_object_class_install_property (G_OBJECT_CLASS (klass), + PROP_SCHEDULE_TIMEOUT, + g_param_spec_uint64 ("schedule-timeout", + "Schedule Timeout", + "How long after not receiving caption data on the caption pad to continue adding (padding) caption data on output buffers", + 0, G_MAXUINT64, DEFAULT_SCHEDULE_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | + GST_PARAM_MUTABLE_PLAYING)); + gst_element_class_add_static_pad_template_with_gtype (gstelement_class, &sinktemplate, GST_TYPE_AGGREGATOR_PAD); gst_element_class_add_static_pad_template_with_gtype (gstelement_class, @@ -1347,8 +1397,10 @@ gst_cc_combiner_init (GstCCCombiner * self) self->prop_cea608_padding_strategy = DEFAULT_CEA608_PADDING_STRATEGY; self->prop_cea608_valid_padding_timeout = DEFAULT_CEA608_VALID_PADDING_TIMEOUT; + self->prop_schedule_timeout = DEFAULT_SCHEDULE_TIMEOUT; self->cdp_hdr_sequence_cntr = 0; self->cdp_fps_entry = &null_fps_entry; + self->last_caption_ts = GST_CLOCK_TIME_NONE; self->cc_buffer = cc_buffer_new (); cc_buffer_set_max_buffer_time (self->cc_buffer, GST_CLOCK_TIME_NONE); diff --git a/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.h b/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.h index ed3e44f271..eaa9daa5f4 100644 --- a/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.h +++ b/subprojects/gst-plugins-bad/ext/closedcaption/gstcccombiner.h @@ -61,11 +61,13 @@ struct _GstCCCombiner gboolean prop_output_padding; CCBufferCea608PaddingStrategy prop_cea608_padding_strategy; GstClockTime prop_cea608_valid_padding_timeout; + GstClockTime prop_schedule_timeout; gboolean schedule; guint max_scheduled; gboolean output_padding; guint current_scheduled; + GstClockTime last_caption_ts; CCBuffer *cc_buffer; guint16 cdp_hdr_sequence_cntr;