mpegdemux: Add ignore-scr property to ignore broken SCR
authorSeungha Yang <seungha@centricular.com>
Wed, 11 Mar 2020 08:18:56 +0000 (17:18 +0900)
committerSeungha Yang <seungha@centricular.com>
Wed, 11 Mar 2020 12:06:20 +0000 (21:06 +0900)
Some MPEG-PS streams might not be compliant but the SCR can be ignored
if PTS/DTS in PES header is consistently increased.

gst/mpegdemux/gstmpegdemux.c
gst/mpegdemux/gstmpegdemux.h

index 9e58d0a..e900377 100644 (file)
@@ -91,9 +91,12 @@ enum
 enum
 {
   PROP_0,
+  PROP_IGNORE_SCR,
   /* FILL ME */
 };
 
+#define DEFAULT_IGNORE_SCR FALSE
+
 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
@@ -140,6 +143,10 @@ static void gst_ps_demux_base_init (GstPsDemuxClass * klass);
 static void gst_ps_demux_class_init (GstPsDemuxClass * klass);
 static void gst_ps_demux_init (GstPsDemux * demux);
 static void gst_ps_demux_finalize (GstPsDemux * demux);
+static void gst_ps_demux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec);
+static void gst_ps_demux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
 static void gst_ps_demux_reset (GstPsDemux * demux);
 
 static gboolean gst_ps_demux_sink_event (GstPad * pad, GstObject * parent,
@@ -247,8 +254,24 @@ gst_ps_demux_class_init (GstPsDemuxClass * klass)
   gstelement_class = (GstElementClass *) klass;
 
   gobject_class->finalize = (GObjectFinalizeFunc) gst_ps_demux_finalize;
+  gobject_class->set_property = gst_ps_demux_set_property;
+  gobject_class->get_property = gst_ps_demux_get_property;
 
   gstelement_class->change_state = gst_ps_demux_change_state;
+
+  /**
+   * GstPsDemux:ignore-scr:
+   *
+   * Ignore SCR (System Clock Reference) data from MPEG-PS Pack Header.
+   * This can help with playback of some broken files.
+   *
+   * Since: 1.18
+   */
+  g_object_class_install_property (gobject_class, PROP_IGNORE_SCR,
+      g_param_spec_boolean ("ignore-scr", "Ignore SCR data for timing",
+          "Ignore SCR data for timing", DEFAULT_IGNORE_SCR,
+          G_PARAM_READWRITE | GST_PARAM_MUTABLE_READY |
+          G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -279,6 +302,8 @@ gst_ps_demux_init (GstPsDemux * demux)
   demux->flowcombiner = gst_flow_combiner_new ();
 
   gst_ps_demux_reset (demux);
+
+  demux->ignore_scr = DEFAULT_IGNORE_SCR;
 }
 
 static void
@@ -296,6 +321,36 @@ gst_ps_demux_finalize (GstPsDemux * demux)
 }
 
 static void
+gst_ps_demux_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstPsDemux *demux = GST_PS_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_IGNORE_SCR:
+      demux->ignore_scr = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_ps_demux_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstPsDemux *demux = GST_PS_DEMUX (object);
+
+  switch (prop_id) {
+    case PROP_IGNORE_SCR:
+      g_value_set_boolean (value, demux->ignore_scr);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
 gst_ps_demux_reset (GstPsDemux * demux)
 {
   /* Clean up the streams and pads we allocated */
@@ -1736,6 +1791,20 @@ gst_ps_demux_parse_pack_start (GstPsDemux * demux)
 
     data += 8;
   }
+
+  if (demux->ignore_scr) {
+    /* update only first/current_scr with raw scr value to start streaming
+     * after parsing 2 seconds long data with no-more-pad */
+    if (demux->first_scr == G_MAXUINT64) {
+      demux->first_scr = scr;
+      demux->first_scr_offset = demux->cur_scr_offset;
+    }
+
+    demux->current_scr = scr;
+
+    goto out;
+  }
+
   new_rate *= MPEG_MUX_RATE_MULT;
 
   /* scr adjusted is the new scr found + the colected adjustment */
@@ -1851,15 +1920,16 @@ gst_ps_demux_parse_pack_start (GstPsDemux * demux)
    * adapter */
   demux->bytes_since_scr = avail;
 
-  gst_adapter_unmap (demux->adapter);
-  gst_adapter_flush (demux->adapter, length);
-  ADAPTER_OFFSET_FLUSH (length);
-
   /* Now check for all streams if they're behind the new SCR and if
    * they are then move them forward to the SCR position */
   gst_ps_demux_send_gap_updates (demux,
       MPEGTIME_TO_GSTTIME (demux->current_scr - demux->first_scr));
 
+out:
+  gst_adapter_unmap (demux->adapter);
+  gst_adapter_flush (demux->adapter, length);
+  ADAPTER_OFFSET_FLUSH (length);
+
   return GST_FLOW_OK;
 
 lost_sync:
index 9e4501d..e2af68b 100644 (file)
@@ -156,6 +156,9 @@ struct _GstPsDemux
 
   /* Indicates an MPEG-2 stream */
   gboolean is_mpeg2_pack;
+
+  /* properties */
+  gboolean ignore_scr;
 };
 
 struct _GstPsDemuxClass