diff options
author | Sebastian Dröge <sebastian@centricular.com> | 2019-10-23 16:47:43 +0300 |
---|---|---|
committer | Sebastian Dröge <sebastian@centricular.com> | 2019-10-23 16:48:26 +0300 |
commit | 5a9541caffece8d0c8b570258d897bb20b663bdb (patch) | |
tree | b24a47abf6ceffccc6373163e56838dceecd8bd9 /gst/timecode | |
parent | fc463b9ebcad1317ece1cf00321bd28a8684ac81 (diff) | |
download | gstreamer-plugins-bad-5a9541caffece8d0c8b570258d897bb20b663bdb.tar.gz |
timecodestamper: Add properties to time out cached upstream/LTC timecodes after a while
By default we never time them out and simply continue couting up with
each frame forever.
Diffstat (limited to 'gst/timecode')
-rw-r--r-- | gst/timecode/gsttimecodestamper.c | 88 | ||||
-rw-r--r-- | gst/timecode/gsttimecodestamper.h | 4 |
2 files changed, 82 insertions, 10 deletions
diff --git a/gst/timecode/gsttimecodestamper.c b/gst/timecode/gsttimecodestamper.c index 2f18bd381..42ab547fa 100644 --- a/gst/timecode/gsttimecodestamper.c +++ b/gst/timecode/gsttimecodestamper.c @@ -61,11 +61,13 @@ enum PROP_SOURCE, PROP_SET, PROP_AUTO_RESYNC, + PROP_TIMEOUT, PROP_DROP_FRAME, PROP_POST_MESSAGES, PROP_SET_INTERNAL_TIMECODE, PROP_LTC_DAILY_JAM, PROP_LTC_AUTO_RESYNC, + PROP_LTC_TIMEOUT, PROP_RTC_MAX_DRIFT, PROP_RTC_AUTO_RESYNC, PROP_TIMECODE_OFFSET @@ -74,11 +76,13 @@ enum #define DEFAULT_SOURCE GST_TIME_CODE_STAMPER_SOURCE_INTERNAL #define DEFAULT_SET GST_TIME_CODE_STAMPER_SET_KEEP #define DEFAULT_AUTO_RESYNC TRUE +#define DEFAULT_TIMEOUT GST_CLOCK_TIME_NONE #define DEFAULT_DROP_FRAME FALSE #define DEFAULT_POST_MESSAGES FALSE #define DEFAULT_SET_INTERNAL_TIMECODE NULL #define DEFAULT_LTC_DAILY_JAM NULL #define DEFAULT_LTC_AUTO_RESYNC TRUE +#define DEFAULT_LTC_TIMEOUT GST_CLOCK_TIME_NONE #define DEFAULT_RTC_MAX_DRIFT 250000000 #define DEFAULT_RTC_AUTO_RESYNC TRUE #define DEFAULT_TIMECODE_OFFSET 0 @@ -227,6 +231,12 @@ gst_timecodestamper_class_init (GstTimeCodeStamperClass * klass) "If true resync last known timecode from upstream, otherwise only " "count up from the last known one", DEFAULT_AUTO_RESYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_TIMEOUT, + g_param_spec_uint64 ("timeout", + "Timeout", + "Time out upstream timecode if no new timecode was detected after this time", + 0, G_MAXUINT64, DEFAULT_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_DROP_FRAME, g_param_spec_boolean ("drop-frame", "Drop Frame", "Use drop-frame timecodes for 29.97 and 59.94 FPS", @@ -256,6 +266,11 @@ gst_timecodestamper_class_init (GstTimeCodeStamperClass * klass) "If true the LTC timecode will be automatically resynced if it drifts, " "otherwise it will only be counted up from the last known one", DEFAULT_LTC_AUTO_RESYNC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_LTC_TIMEOUT, + g_param_spec_uint64 ("ltc-timeout", "LTC Timeout", + "Time out LTC timecode if no new timecode was detected after this time", + 0, G_MAXUINT64, DEFAULT_LTC_TIMEOUT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_RTC_MAX_DRIFT, g_param_spec_uint64 ("rtc-max-drift", "RTC Maximum Offset", @@ -304,17 +319,20 @@ gst_timecodestamper_init (GstTimeCodeStamper * timecodestamper) timecodestamper->tc_source = GST_TIME_CODE_STAMPER_SOURCE_INTERNAL; timecodestamper->tc_set = GST_TIME_CODE_STAMPER_SET_KEEP; timecodestamper->tc_auto_resync = DEFAULT_AUTO_RESYNC; + timecodestamper->tc_timeout = DEFAULT_TIMEOUT; timecodestamper->drop_frame = DEFAULT_DROP_FRAME; timecodestamper->post_messages = DEFAULT_POST_MESSAGES; timecodestamper->set_internal_tc = NULL; timecodestamper->ltc_daily_jam = DEFAULT_LTC_DAILY_JAM; timecodestamper->ltc_auto_resync = DEFAULT_LTC_AUTO_RESYNC; + timecodestamper->ltc_timeout = DEFAULT_LTC_TIMEOUT; timecodestamper->rtc_max_drift = DEFAULT_RTC_MAX_DRIFT; timecodestamper->rtc_auto_resync = DEFAULT_RTC_AUTO_RESYNC; timecodestamper->timecode_offset = 0; timecodestamper->internal_tc = NULL; timecodestamper->last_tc = NULL; + timecodestamper->last_tc_running_time = GST_CLOCK_TIME_NONE; timecodestamper->rtc_tc = NULL; #if HAVE_LTC @@ -329,6 +347,7 @@ gst_timecodestamper_init (GstTimeCodeStamper * timecodestamper) timecodestamper->ltc_current_tc = NULL; timecodestamper->ltc_current_tc_running_time = GST_CLOCK_TIME_NONE; timecodestamper->ltc_internal_tc = NULL; + timecodestamper->ltc_internal_running_time = GST_CLOCK_TIME_NONE; timecodestamper->ltc_dec = NULL; timecodestamper->ltc_total = 0; @@ -368,6 +387,7 @@ gst_timecodestamper_dispose (GObject * object) gst_video_time_code_free (timecodestamper->last_tc); timecodestamper->last_tc = NULL; } + timecodestamper->last_tc_running_time = GST_CLOCK_TIME_NONE; if (timecodestamper->rtc_tc != NULL) { gst_video_time_code_free (timecodestamper->rtc_tc); @@ -385,6 +405,7 @@ gst_timecodestamper_dispose (GObject * object) gst_video_time_code_free (timecodestamper->ltc_internal_tc); timecodestamper->ltc_internal_tc = NULL; } + timecodestamper->ltc_internal_running_time = GST_CLOCK_TIME_NONE; if (timecodestamper->ltc_dec) { ltc_decoder_free (timecodestamper->ltc_dec); @@ -419,6 +440,9 @@ gst_timecodestamper_set_property (GObject * object, guint prop_id, case PROP_AUTO_RESYNC: timecodestamper->tc_auto_resync = g_value_get_boolean (value); break; + case PROP_TIMEOUT: + timecodestamper->tc_timeout = g_value_get_uint64 (value); + break; case PROP_DROP_FRAME: timecodestamper->drop_frame = g_value_get_boolean (value); gst_timecodestamper_update_drop_frame (timecodestamper); @@ -468,6 +492,9 @@ gst_timecodestamper_set_property (GObject * object, guint prop_id, case PROP_LTC_AUTO_RESYNC: timecodestamper->ltc_auto_resync = g_value_get_boolean (value); break; + case PROP_LTC_TIMEOUT: + timecodestamper->ltc_timeout = g_value_get_uint64 (value); + break; case PROP_RTC_MAX_DRIFT: timecodestamper->rtc_max_drift = g_value_get_uint64 (value); break; @@ -502,6 +529,9 @@ gst_timecodestamper_get_property (GObject * object, guint prop_id, case PROP_AUTO_RESYNC: g_value_set_boolean (value, timecodestamper->tc_auto_resync); break; + case PROP_TIMEOUT: + g_value_set_uint64 (value, timecodestamper->tc_timeout); + break; case PROP_DROP_FRAME: g_value_set_boolean (value, timecodestamper->drop_frame); break; @@ -517,6 +547,9 @@ gst_timecodestamper_get_property (GObject * object, guint prop_id, case PROP_LTC_AUTO_RESYNC: g_value_set_boolean (value, timecodestamper->ltc_auto_resync); break; + case PROP_LTC_TIMEOUT: + g_value_set_uint64 (value, timecodestamper->ltc_timeout); + break; case PROP_RTC_MAX_DRIFT: g_value_set_uint64 (value, timecodestamper->rtc_max_drift); break; @@ -563,6 +596,7 @@ gst_timecodestamper_stop (GstBaseTransform * trans) gst_video_time_code_free (timecodestamper->last_tc); timecodestamper->last_tc = NULL; } + timecodestamper->last_tc_running_time = GST_CLOCK_TIME_NONE; #if HAVE_LTC g_mutex_lock (&timecodestamper->mutex); gst_audio_info_init (&timecodestamper->ainfo); @@ -575,6 +609,7 @@ gst_timecodestamper_stop (GstBaseTransform * trans) gst_video_time_code_free (timecodestamper->ltc_internal_tc); timecodestamper->ltc_internal_tc = NULL; } + timecodestamper->ltc_internal_running_time = GST_CLOCK_TIME_NONE; if (timecodestamper->ltc_current_tc != NULL) { gst_video_time_code_free (timecodestamper->ltc_current_tc); @@ -915,21 +950,36 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter, if (timecodestamper->last_tc) gst_video_time_code_free (timecodestamper->last_tc); timecodestamper->last_tc = gst_video_time_code_copy (&tc_meta->tc); + timecodestamper->last_tc_running_time = running_time; tc_str = gst_video_time_code_to_string (timecodestamper->last_tc); GST_DEBUG_OBJECT (timecodestamper, "Updated upstream timecode to %s", tc_str); g_free (tc_str); } else { - gchar *tc_str; - if (timecodestamper->last_tc) { - gst_video_time_code_increment_frame (timecodestamper->last_tc); + if (timecodestamper->tc_auto_resync + && timecodestamper->tc_timeout != GST_CLOCK_TIME_NONE + && (running_time + timecodestamper->tc_timeout < + timecodestamper->last_tc_running_time + || running_time >= + timecodestamper->last_tc_running_time + + timecodestamper->tc_timeout)) { + if (timecodestamper->last_tc) + gst_video_time_code_free (timecodestamper->last_tc); + timecodestamper->last_tc = NULL; + timecodestamper->last_tc_running_time = GST_CLOCK_TIME_NONE; + GST_DEBUG_OBJECT (timecodestamper, "Upstream timecode timed out"); + } else { + gchar *tc_str; - tc_str = gst_video_time_code_to_string (timecodestamper->last_tc); - GST_DEBUG_OBJECT (timecodestamper, "Incremented upstream timecode to %s", - tc_str); - g_free (tc_str); + gst_video_time_code_increment_frame (timecodestamper->last_tc); + + tc_str = gst_video_time_code_to_string (timecodestamper->last_tc); + GST_DEBUG_OBJECT (timecodestamper, + "Incremented upstream timecode to %s", tc_str); + g_free (tc_str); + } } else { GST_DEBUG_OBJECT (timecodestamper, "Never saw an upstream timecode"); } @@ -1107,6 +1157,7 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter, if (gst_video_time_code_is_valid (ltc_read_tc_ptr)) { timecodestamper->ltc_internal_tc = gst_video_time_code_copy (ltc_read_tc_ptr); + timecodestamper->ltc_internal_running_time = running_time; updated_internal = TRUE; GST_INFO_OBJECT (timecodestamper, "Resynced internal LTC counter"); } else { @@ -1152,9 +1203,25 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter, } if (timecodestamper->ltc_internal_tc) { - tc_str = gst_video_time_code_to_string (timecodestamper->ltc_internal_tc); - GST_DEBUG_OBJECT (timecodestamper, "Updated LTC timecode to %s", tc_str); - g_free (tc_str); + if (timecodestamper->ltc_auto_resync + && timecodestamper->ltc_timeout != GST_CLOCK_TIME_NONE + && (running_time + timecodestamper->ltc_timeout < + timecodestamper->ltc_internal_running_time + || running_time >= + timecodestamper->ltc_internal_running_time + + timecodestamper->ltc_timeout)) { + if (timecodestamper->ltc_internal_tc) + gst_video_time_code_free (timecodestamper->ltc_internal_tc); + timecodestamper->ltc_internal_tc = NULL; + GST_DEBUG_OBJECT (timecodestamper, "LTC timecode timed out"); + timecodestamper->ltc_internal_running_time = GST_CLOCK_TIME_NONE; + } else { + tc_str = + gst_video_time_code_to_string (timecodestamper->ltc_internal_tc); + GST_DEBUG_OBJECT (timecodestamper, "Updated LTC timecode to %s", + tc_str); + g_free (tc_str); + } } else { GST_DEBUG_OBJECT (timecodestamper, "Have no LTC timecode yet"); } @@ -1341,6 +1408,7 @@ gst_timecodestamper_release_pad (GstElement * element, GstPad * pad) gst_video_time_code_free (timecodestamper->ltc_internal_tc); timecodestamper->ltc_internal_tc = NULL; } + timecodestamper->ltc_internal_running_time = GST_CLOCK_TIME_NONE; if (timecodestamper->ltc_current_tc != NULL) { gst_video_time_code_free (timecodestamper->ltc_current_tc); diff --git a/gst/timecode/gsttimecodestamper.h b/gst/timecode/gsttimecodestamper.h index e3778de4f..be630b117 100644 --- a/gst/timecode/gsttimecodestamper.h +++ b/gst/timecode/gsttimecodestamper.h @@ -78,11 +78,13 @@ struct _GstTimeCodeStamper GstTimeCodeStamperSource tc_source; GstTimeCodeStamperSet tc_set; gboolean tc_auto_resync; + GstClockTime tc_timeout; gboolean drop_frame; gboolean post_messages; GstVideoTimeCode *set_internal_tc; GDateTime *ltc_daily_jam; gboolean ltc_auto_resync; + GstClockTime ltc_timeout; GstClockTime rtc_max_drift; gboolean rtc_auto_resync; gint timecode_offset; @@ -90,6 +92,7 @@ struct _GstTimeCodeStamper /* Timecode tracking, protected by object lock */ GstVideoTimeCode *internal_tc; GstVideoTimeCode *last_tc; + GstClockTime last_tc_running_time; GstVideoTimeCode *rtc_tc; /* Internal state */ @@ -119,6 +122,7 @@ struct _GstTimeCodeStamper /* LTC timecode we last synced to and potentially incremented manually since * then */ GstVideoTimeCode *ltc_internal_tc; + GstClockTime ltc_internal_running_time; /* Protected by mutex above */ LTCDecoder *ltc_dec; |