From a0423ee20f166c3fa0fffc90700fcfbfa3e19530 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Fri, 21 Feb 2020 13:12:39 -0300 Subject: [PATCH] timecodestamper: Add seeking support The approach is quite simple and doesn't take all use cases into account, it only implements support when we are using the internal timecode we create ourself. Also the way we compute the sought frame count is naive, but it works for simple cases. --- gst/timecode/gsttimecodestamper.c | 81 ++++++++++++++++++++++++++++++++++++--- gst/timecode/gsttimecodestamper.h | 5 +++ 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/gst/timecode/gsttimecodestamper.c b/gst/timecode/gsttimecodestamper.c index bd4b78f..9ad1551 100644 --- a/gst/timecode/gsttimecodestamper.c +++ b/gst/timecode/gsttimecodestamper.c @@ -119,6 +119,8 @@ static void gst_timecodestamper_get_property (GObject * object, guint prop_id, static void gst_timecodestamper_dispose (GObject * object); static gboolean gst_timecodestamper_sink_event (GstBaseTransform * trans, GstEvent * event); +static gboolean gst_timecodestamper_src_event (GstBaseTransform * trans, + GstEvent * event); static GstFlowReturn gst_timecodestamper_transform_ip (GstBaseTransform * vfilter, GstBuffer * buffer); static gboolean gst_timecodestamper_stop (GstBaseTransform * trans); @@ -320,6 +322,7 @@ gst_timecodestamper_class_init (GstTimeCodeStamperClass * klass) GST_DEBUG_FUNCPTR (gst_timecodestamper_release_pad); trans_class->sink_event = GST_DEBUG_FUNCPTR (gst_timecodestamper_sink_event); + trans_class->src_event = GST_DEBUG_FUNCPTR (gst_timecodestamper_src_event); #if HAVE_LTC trans_class->query = GST_DEBUG_FUNCPTR (gst_timecodestamper_query); #endif @@ -355,6 +358,8 @@ gst_timecodestamper_init (GstTimeCodeStamper * timecodestamper) timecodestamper->last_tc_running_time = GST_CLOCK_TIME_NONE; timecodestamper->rtc_tc = NULL; + timecodestamper->seeked_frames = -1; + #if HAVE_LTC g_mutex_init (&timecodestamper->mutex); g_cond_init (&timecodestamper->ltc_cond_video); @@ -842,6 +847,15 @@ gst_timecodestamper_sink_event (GstBaseTransform * trans, GstEvent * event) gst_event_unref (event); return FALSE; } + + GST_OBJECT_LOCK (timecodestamper); + if (timecodestamper->tc_source == GST_TIME_CODE_STAMPER_SOURCE_INTERNAL + && GST_EVENT_SEQNUM (event) == timecodestamper->prev_seek_seqnum) { + timecodestamper->reset_internal_tc_from_seek = TRUE; + timecodestamper->prev_seek_seqnum = GST_SEQNUM_INVALID; + } + GST_OBJECT_UNLOCK (timecodestamper); + break; } case GST_EVENT_CAPS: @@ -907,6 +921,53 @@ gst_timecodestamper_sink_event (GstBaseTransform * trans, GstEvent * event) return ret; } +static gboolean +gst_timecodestamper_src_event (GstBaseTransform * trans, GstEvent * event) +{ + GstTimeCodeStamper *timecodestamper = GST_TIME_CODE_STAMPER (trans); + + GST_DEBUG_OBJECT (trans, "received event %" GST_PTR_FORMAT, event); + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_SEEK: + { + gdouble rate; + GstSeekType start_type; + gint64 start; + GstFormat format; + + gst_event_parse_seek (event, &rate, &format, NULL, &start_type, &start, + NULL, NULL); + + if (rate < 0) { + GST_ERROR_OBJECT (timecodestamper, "Reverse playback is not supported"); + return FALSE; + } + + if (format != GST_FORMAT_TIME) { + GST_ERROR_OBJECT (timecodestamper, + "Seeking is only supported in TIME format"); + return FALSE; + } + + GST_OBJECT_LOCK (timecodestamper); + if (timecodestamper->vinfo.fps_d && timecodestamper->vinfo.fps_n) { + timecodestamper->prev_seek_seqnum = GST_EVENT_SEQNUM (event); + timecodestamper->seeked_frames = gst_util_uint64_scale (start, + timecodestamper->vinfo.fps_n, + timecodestamper->vinfo.fps_d * GST_SECOND); + } + GST_OBJECT_UNLOCK (timecodestamper); + break; + } + default: + break; + } + + return + GST_BASE_TRANSFORM_CLASS (gst_timecodestamper_parent_class)->src_event + (trans, event); +} + #if HAVE_LTC static gboolean gst_timecodestamper_query (GstBaseTransform * trans, @@ -1082,24 +1143,34 @@ gst_timecodestamper_transform_ip (GstBaseTransform * vfilter, /* If we don't have an internal timecode yet then either a new one was just * set via the property or we just started. Initialize it here, otherwise * increment it by one */ - if (!timecodestamper->internal_tc) { + if (!timecodestamper->internal_tc + || timecodestamper->reset_internal_tc_from_seek) { gchar *tc_str; - if (timecodestamper->set_internal_tc) + timecodestamper->reset_internal_tc_from_seek = FALSE; + if (timecodestamper->set_internal_tc) { timecodestamper->internal_tc = gst_video_time_code_new (timecodestamper->vinfo.fps_n, timecodestamper->vinfo.fps_d, - timecodestamper->set_internal_tc->config.latest_daily_jam, - tc_flags, + timecodestamper->set_internal_tc->config.latest_daily_jam, tc_flags, timecodestamper->set_internal_tc->hours, timecodestamper->set_internal_tc->minutes, timecodestamper->set_internal_tc->seconds, timecodestamper->set_internal_tc->frames, timecodestamper->set_internal_tc->field_count); - else + } else { timecodestamper->internal_tc = gst_video_time_code_new (timecodestamper->vinfo.fps_n, timecodestamper->vinfo.fps_d, dt_frame, tc_flags, 0, 0, 0, 0, 0); + if (timecodestamper->seeked_frames > 0) { + GST_DEBUG_OBJECT (timecodestamper, + "Adding %" G_GINT64_FORMAT " frames that were seeked", + timecodestamper->seeked_frames); + gst_video_time_code_add_frames (timecodestamper->internal_tc, + timecodestamper->seeked_frames); + timecodestamper->seeked_frames = -1; + } + } tc_str = gst_video_time_code_to_string (timecodestamper->internal_tc); GST_DEBUG_OBJECT (timecodestamper, "Initialized internal timecode to %s", diff --git a/gst/timecode/gsttimecodestamper.h b/gst/timecode/gsttimecodestamper.h index 700657d..f4387ec 100644 --- a/gst/timecode/gsttimecodestamper.h +++ b/gst/timecode/gsttimecodestamper.h @@ -99,6 +99,11 @@ struct _GstTimeCodeStamper /* Internal state */ GstVideoInfo vinfo; /* protected by object lock, changed only from video streaming thread */ + /* Seek handling, protected by the object lock */ + guint32 prev_seek_seqnum; + gboolean reset_internal_tc_from_seek; + gint64 seeked_frames; + /* LTC specific fields */ #if HAVE_LTC GMutex mutex; -- 2.7.4