From 2d6efbbae20a2f53bed19eb76643b45ee4a8756a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim-Philipp=20M=C3=BCller?= Date: Wed, 15 Aug 2018 12:14:24 +0100 Subject: [PATCH] matroskademux: make max backtrack distance for keyframe search configurable Add property instead of hardcoding it in the code. In some scenarios such as CCTV variable fps and extra long GOPs are used to minimise storage space, for example. In those cases there might not be any keyframes for many minutes, so provide a property to override the max allowed distance. https://bugzilla.gnome.org/show_bug.cgi?id=790696 --- gst/matroska/matroska-demux.c | 61 +++++++++++++++++++++++++++++-------------- gst/matroska/matroska-demux.h | 2 ++ 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/gst/matroska/matroska-demux.c b/gst/matroska/matroska-demux.c index 8dbe543..5f94c60 100644 --- a/gst/matroska/matroska-demux.c +++ b/gst/matroska/matroska-demux.c @@ -85,11 +85,13 @@ enum PROP_0, PROP_METADATA, PROP_STREAMINFO, - PROP_MAX_GAP_TIME + PROP_MAX_GAP_TIME, + PROP_MAX_BACKTRACK_DISTANCE }; -#define DEFAULT_MAX_GAP_TIME (2 * GST_SECOND) -#define INVALID_DATA_THRESHOLD (2 * 1024 * 1024) +#define DEFAULT_MAX_GAP_TIME (2 * GST_SECOND) +#define DEFAULT_MAX_BACKTRACK_DISTANCE 30 +#define INVALID_DATA_THRESHOLD (2 * 1024 * 1024) static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, @@ -217,6 +219,15 @@ gst_matroska_demux_class_init (GstMatroskaDemuxClass * klass) "gaps longer than this (0 = disabled).", 0, G_MAXUINT64, DEFAULT_MAX_GAP_TIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_MAX_BACKTRACK_DISTANCE, + g_param_spec_uint ("max-backtrack-distance", + "Maximum backtrack distance", + "Maximum backtrack distance in seconds when seeking without " + "and index in pull mode and search for a keyframe " + "(0 = disable backtracking).", + 0, G_MAXUINT, DEFAULT_MAX_BACKTRACK_DISTANCE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_matroska_demux_change_state); gstelement_class->send_event = @@ -264,6 +275,7 @@ gst_matroska_demux_init (GstMatroskaDemux * demux) /* property defaults */ demux->max_gap_time = DEFAULT_MAX_GAP_TIME; + demux->max_backtrack_distance = DEFAULT_MAX_BACKTRACK_DISTANCE; GST_OBJECT_FLAG_SET (demux, GST_ELEMENT_FLAG_INDEXABLE); @@ -2082,12 +2094,6 @@ bit_reader_skip_ebml_num (GstBitReader * br) * (random value, mostly for sanity checking) */ #define MAX_CLUSTER_INFO_PROBE_LENGTH 256 -/* Don't scan back more than this much in time from the cluster we originally - * landed on. This is mostly a sanity check in case a file always has keyframes - * in the middle of clusters and never at the beginning. Without this we would - * always scan back to the beginning of the file in that case. */ -#define MAX_CLUSTER_BACKTRACK_SECS 30 - static gboolean gst_matroska_demux_peek_cluster_info (GstMatroskaDemux * demux, ClusterInfo * cluster, guint64 offset) @@ -2249,13 +2255,18 @@ gst_matroska_demux_scan_back_for_keyframe_cluster (GstMatroskaDemux * demux, break; } + /* Don't scan back more than this much in time from the cluster we + * originally landed on. This is mostly a sanity check in case a file + * always has keyframes in the middle of clusters and never at the + * beginning. Without this we would always scan back to the beginning + * of the file in that case. */ if (cluster.time != GST_CLOCK_TIME_NONE) { GstClockTimeDiff distance = GST_CLOCK_DIFF (cluster.time, *cluster_time); - if (distance < 0 || distance > MAX_CLUSTER_BACKTRACK_SECS * GST_SECOND) { + if (distance < 0 || distance > demux->max_backtrack_distance * GST_SECOND) { GST_DEBUG_OBJECT (demux, "Haven't found cluster with keyframe within " "%u secs of original seek target cluster, stopping", - MAX_CLUSTER_BACKTRACK_SECS); + demux->max_backtrack_distance); break; } } @@ -2495,15 +2506,17 @@ retry: /* If we have video and can easily backtrack, check if we landed on a cluster * that starts with a keyframe - and if not backtrack until we find one that * does. */ - if (demux->have_nonintraonly_v_streams && demux->seen_cluster_prevsize) { - if (gst_matroska_demux_scan_back_for_keyframe_cluster (demux, - &cluster_offset, &cluster_time)) { - GST_INFO_OBJECT (demux, "Adjusted cluster to %" GST_TIME_FORMAT " @ " - "%" G_GUINT64_FORMAT, GST_TIME_ARGS (cluster_time), cluster_offset); + if (demux->have_nonintraonly_v_streams && demux->max_backtrack_distance > 0) { + if (demux->seen_cluster_prevsize) { + if (gst_matroska_demux_scan_back_for_keyframe_cluster (demux, + &cluster_offset, &cluster_time)) { + GST_INFO_OBJECT (demux, "Adjusted cluster to %" GST_TIME_FORMAT " @ " + "%" G_GUINT64_FORMAT, GST_TIME_ARGS (cluster_time), cluster_offset); + } + } else { + GST_FIXME_OBJECT (demux, "implement scanning back to prev cluster " + "without cluster prev size field"); } - } else if (demux->have_nonintraonly_v_streams) { - GST_FIXME_OBJECT (demux, "implement scanning back to prev cluster without " - "cluster prev size field"); } entry = g_new0 (GstMatroskaIndex, 1); @@ -6716,6 +6729,11 @@ gst_matroska_demux_set_property (GObject * object, demux->max_gap_time = g_value_get_uint64 (value); GST_OBJECT_UNLOCK (demux); break; + case PROP_MAX_BACKTRACK_DISTANCE: + GST_OBJECT_LOCK (demux); + demux->max_backtrack_distance = g_value_get_uint (value); + GST_OBJECT_UNLOCK (demux); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -6737,6 +6755,11 @@ gst_matroska_demux_get_property (GObject * object, g_value_set_uint64 (value, demux->max_gap_time); GST_OBJECT_UNLOCK (demux); break; + case PROP_MAX_BACKTRACK_DISTANCE: + GST_OBJECT_LOCK (demux); + g_value_set_uint (value, demux->max_backtrack_distance); + GST_OBJECT_UNLOCK (demux); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; diff --git a/gst/matroska/matroska-demux.h b/gst/matroska/matroska-demux.h index 3a27374..67a2610 100644 --- a/gst/matroska/matroska-demux.h +++ b/gst/matroska/matroska-demux.h @@ -116,6 +116,8 @@ typedef struct _GstMatroskaDemux { * cluster has it, all but * the first will have it. */ + guint max_backtrack_distance; /* in seconds (0 = don't backtrack) */ + /* gap handling */ guint64 max_gap_time; -- 2.7.4