add hls pathes to support hw codec 12/55412/1 accepted/tizen/mobile/20151228.233306 accepted/tizen/tv/20151228.232157 accepted/tizen/wearable/20151228.231452 submit/tizen/20151228.110604
authorEunhae Choi <eunhae1.choi@samsung.com>
Wed, 23 Dec 2015 11:44:59 +0000 (20:44 +0900)
committerEunhae Choi <eunhae1.choi@samsung.com>
Wed, 23 Dec 2015 11:45:10 +0000 (20:45 +0900)
Change-Id: I53f77546d9292c8cc63e4ba07a8c33a00777e18c
Signed-off-by: Eunhae Choi <eunhae1.choi@samsung.com>
ext/hls/gsthlsdemux.c
ext/hls/gsthlsdemux.h
gst-libs/gst/adaptivedemux/gstadaptivedemux.c
gst-libs/gst/adaptivedemux/gstadaptivedemux.h
gst/mpegtsdemux/mpegtsbase.c
gst/mpegtsdemux/mpegtsbase.h
gst/mpegtsdemux/tsdemux.c
gst/mpegtsdemux/tsdemux.h
gst/videoparsers/gsth264parse.c
packaging/gst-plugins-bad.spec

index 1c05fa8..0adc329 100644 (file)
@@ -273,6 +273,15 @@ gst_hls_demux_create_pad (GstHLSDemux * hlsdemux)
   return pad;
 }
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+static GstPad *
+gst_hls_demux_stream_create_pad (GstAdaptiveDemuxStream * stream)
+{
+  GstHLSDemux *hlsdemux = GST_HLS_DEMUX_CAST (stream->demux);
+  return gst_hls_demux_create_pad (hlsdemux);
+}
+#endif
+
 static guint64
 gst_hls_demux_get_bitrate (GstHLSDemux * hlsdemux)
 {
@@ -574,8 +583,15 @@ gst_hls_demux_handle_buffer (GstAdaptiveDemux * demux,
 
     GST_DEBUG_OBJECT (hlsdemux, "Typefind result: %" GST_PTR_FORMAT " prob:%d",
         caps, prob);
-
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+    gst_adaptive_demux_stream_check_switch_pad (stream, caps,
+        gst_hls_demux_stream_create_pad);
+    GST_DEBUG_OBJECT (stream->pad, "Overwriting PTS to %" GST_TIME_FORMAT,
+        GST_TIME_ARGS (hlsdemux->current_pts));
+    stream->fragment.timestamp = hlsdemux->current_pts;
+#else
     gst_adaptive_demux_stream_set_caps (stream, caps);
+#endif
     hlsdemux->do_typefind = FALSE;
   }
 
@@ -716,6 +732,9 @@ gst_hls_demux_update_fragment_info (GstAdaptiveDemuxStream * stream)
   }
 
   /* set up our source for download */
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  hlsdemux->current_pts = timestamp;
+#endif
   if (hlsdemux->reset_pts || discont) {
     stream->fragment.timestamp = timestamp;
   } else {
@@ -759,8 +778,10 @@ gst_hls_demux_select_bitrate (GstAdaptiveDemuxStream * stream, guint64 bitrate)
     return FALSE;
 
   gst_hls_demux_change_playlist (hlsdemux, bitrate, &changed);
+#ifndef GST_EXT_AVOID_PAD_SWITCHING
   if (changed)
     gst_hls_demux_setup_streams (GST_ADAPTIVE_DEMUX_CAST (hlsdemux));
+#endif
   return changed;
 }
 
index daa3670..68248e5 100644 (file)
@@ -70,6 +70,10 @@ struct _GstHLSDemux
   GstM3U8Client *client;        /* M3U8 client */
   gboolean do_typefind;         /* Whether we need to typefind the next buffer */
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  GstClockTime current_pts;
+#endif
+
   /* Cache for the last key */
   gchar *key_url;
   GstFragment *key_fragment;
index 9f74c65..bee190e 100644 (file)
@@ -658,11 +658,55 @@ gst_adaptive_demux_set_stream_struct_size (GstAdaptiveDemux * demux,
   demux->stream_struct_size = struct_size;
 }
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+static void
+gst_adaptive_demux_stream_push_stream_start (GstAdaptiveDemux * demux,
+    GstAdaptiveDemuxStream * stream)
+{
+  GstPad *pad = stream->pad;
+  gchar *stream_id;
+  GstEvent *event;
+  gchar *name = gst_pad_get_name (pad);
+
+  stream_id =
+      gst_pad_create_stream_id_printf (pad, GST_ELEMENT_CAST (demux), "%s-%04d",
+      name, stream->stream_id_counter++);
+
+  event =
+      gst_pad_get_sticky_event (GST_ADAPTIVE_DEMUX_SINK_PAD (demux),
+      GST_EVENT_STREAM_START, 0);
+  if (event) {
+    if (gst_event_parse_group_id (event, &demux->group_id))
+      demux->have_group_id = TRUE;
+    else
+      demux->have_group_id = FALSE;
+    gst_event_unref (event);
+  } else if (!demux->have_group_id) {
+    demux->have_group_id = TRUE;
+    demux->group_id = gst_util_group_id_next ();
+  }
+  event = gst_event_new_stream_start (stream_id);
+  if (demux->have_group_id)
+    gst_event_set_group_id (event, demux->group_id);
+
+  gst_pad_push_event (pad, event);
+  g_free (stream_id);
+  g_free (name);
+}
+#endif
+
 static gboolean
 gst_adaptive_demux_expose_stream (GstAdaptiveDemux * demux,
     GstAdaptiveDemuxStream * stream)
 {
   GstPad *pad = stream->pad;
+
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  gst_pad_set_active (pad, TRUE);
+  stream->need_header = TRUE;
+
+  gst_adaptive_demux_stream_push_stream_start (demux, stream);
+#else
   gchar *name = gst_pad_get_name (pad);
   GstEvent *event;
   gchar *stream_id;
@@ -692,6 +736,7 @@ gst_adaptive_demux_expose_stream (GstAdaptiveDemux * demux,
   gst_pad_push_event (pad, event);
   g_free (stream_id);
   g_free (name);
+#endif
 
   GST_DEBUG_OBJECT (demux, "Adding srcpad %s:%s with caps %" GST_PTR_FORMAT,
       GST_DEBUG_PAD_NAME (pad), stream->pending_caps);
@@ -1373,6 +1418,73 @@ gst_adaptive_demux_stream_set_caps (GstAdaptiveDemuxStream * stream,
   gst_caps_replace (&stream->pending_caps, caps);
   gst_caps_unref (caps);
 }
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+
+/**
+ * gst_adaptive_demux_stream_check_switch_pad:
+ * @stream:
+ * @caps: the #GstCaps of the new stream
+ * @create_pad_func: callback to create a pad if needed
+ *
+ * Compares @caps with the current caps on pad and with the allowed
+ * downstream caps. If the caps is compatible it just sets a new caps
+ * on the pad, otherwise it will request a new pad to be created and
+ * switch pads.
+ *
+ * This only works currently for streams that only have a single output
+ * due to the way pad switching works in groups. (HLS demux can use it)
+ *
+ * Return: %TRUE if a new pad was created
+ */
+gboolean
+gst_adaptive_demux_stream_check_switch_pad (GstAdaptiveDemuxStream * stream,
+    GstCaps * caps, GstAdaptiveDemuxStreamCreatePadFunc create_pad_func)
+{
+  GstCaps *current_caps;
+  gboolean ret;
+
+  current_caps = gst_pad_get_current_caps (stream->pad);
+  if (current_caps == NULL || gst_caps_is_equal (current_caps, caps) ||
+      gst_pad_query_accept_caps (stream->pad, caps)) {
+
+    /* no need to switch pads */
+    ret = FALSE;
+    GST_DEBUG_OBJECT (stream->pad, "New caps compatible with old one."
+        " Scheduling new stream-start, caps and segment events");
+    gst_adaptive_demux_stream_push_stream_start (stream->demux, stream);
+    gst_adaptive_demux_stream_set_caps (stream, caps);
+    if (stream->pending_segment)
+      gst_event_unref (stream->pending_segment);
+    stream->pending_segment = gst_event_new_segment (&stream->segment);
+  } else {
+    GstPad *old_pad;
+
+    /* need to switch pad for a new one */
+    ret = TRUE;
+
+    GST_DEBUG_OBJECT (stream->pad, "New caps is incompatible with old "
+        "one. Need to switch pads");
+    old_pad = stream->pad;
+    stream->pad = create_pad_func (stream);
+    gst_adaptive_demux_stream_set_caps (stream, caps);
+    gst_adaptive_demux_expose_stream (stream->demux, stream);
+
+    /* FIXME currently there is no way of properly replacing a single
+     * pad in the stream. This will only work for streams that have
+     * a single source pad */
+    gst_element_no_more_pads (GST_ELEMENT_CAST (stream->demux));
+
+    gst_pad_push_event (old_pad, gst_event_new_eos ());
+    gst_pad_set_active (old_pad, FALSE);
+    gst_element_remove_pad (GST_ELEMENT_CAST (stream->demux), old_pad);
+    gst_object_unref (old_pad);
+  }
+
+  if (current_caps)
+    gst_caps_unref (current_caps);
+  return ret;
+}
+#endif
 
 void
 gst_adaptive_demux_stream_set_tags (GstAdaptiveDemuxStream * stream,
index b65b6d6..71ce5ff 100644 (file)
@@ -91,6 +91,10 @@ typedef struct _GstAdaptiveDemux GstAdaptiveDemux;
 typedef struct _GstAdaptiveDemuxClass GstAdaptiveDemuxClass;
 typedef struct _GstAdaptiveDemuxPrivate GstAdaptiveDemuxPrivate;
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+typedef GstPad * (*GstAdaptiveDemuxStreamCreatePadFunc) (GstAdaptiveDemuxStream * stream);
+#endif
+
 struct _GstAdaptiveDemuxStreamFragment
 {
   GstClockTime timestamp;
@@ -117,6 +121,9 @@ struct _GstAdaptiveDemuxStream
 
   GstAdaptiveDemux *demux;
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  gint stream_id_counter;
+#endif
   GstSegment segment;
 
   GstAdapter *adapter;
@@ -455,6 +462,11 @@ GstFlowReturn
 gst_adaptive_demux_stream_advance_fragment_unlocked (GstAdaptiveDemux * demux,
     GstAdaptiveDemuxStream * stream, GstClockTime duration);
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+gboolean gst_adaptive_demux_stream_check_switch_pad (GstAdaptiveDemuxStream * stream,
+    GstCaps * caps, GstAdaptiveDemuxStreamCreatePadFunc create_pad_func);
+#endif
+
 G_END_DECLS
 
 #endif
index d46a47e..9f4631f 100644 (file)
@@ -160,12 +160,54 @@ mpegts_base_get_property (GObject * object, guint prop_id,
   }
 }
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+static void
+mpegts_base_clear (MpegTSBase * base)
+{
+  mpegts_packetizer_clear (base->packetizer);
+  memset (base->is_pes, 0, 1024);
+  memset (base->known_psi, 0, 1024);
+
+  /* FIXME : Actually these are not *always* know SI streams
+   * depending on the variant of mpeg-ts being used. */
+
+  /* Known PIDs : PAT, TSDT, IPMP CIT */
+  MPEGTS_BIT_SET (base->known_psi, 0);
+  MPEGTS_BIT_SET (base->known_psi, 2);
+  MPEGTS_BIT_SET (base->known_psi, 3);
+  /* TDT, TOT, ST */
+  MPEGTS_BIT_SET (base->known_psi, 0x14);
+  /* network synchronization */
+  MPEGTS_BIT_SET (base->known_psi, 0x15);
+
+  /* ATSC */
+  MPEGTS_BIT_SET (base->known_psi, 0x1ffb);
+
+  if (base->pat) {
+    g_ptr_array_unref (base->pat);
+    base->pat = NULL;
+  }
+
+  gst_segment_init (&base->segment, GST_FORMAT_UNDEFINED);
+  base->last_seek_seqnum = (guint32) - 1;
+
+  base->seen_pat = FALSE;
+  base->seek_offset = -1;
+
+  g_hash_table_foreach_remove (base->programs, (GHRFunc) remove_each_program,
+      base);
+}
+#endif
 
 static void
 mpegts_base_reset (MpegTSBase * base)
 {
   MpegTSBaseClass *klass = GST_MPEGTS_BASE_GET_CLASS (base);
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  mpegts_base_clear (base);
+  base->mode = BASE_MODE_STREAMING;
+#else
   mpegts_packetizer_clear (base->packetizer);
   memset (base->is_pes, 0, 1024);
   memset (base->known_psi, 0, 1024);
@@ -199,7 +241,7 @@ mpegts_base_reset (MpegTSBase * base)
 
   g_hash_table_foreach_remove (base->programs, (GHRFunc) remove_each_program,
       base);
-
+#endif
   if (klass->reset)
     klass->reset (base);
 }
@@ -263,6 +305,33 @@ mpegts_base_finalize (GObject * object)
     G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+MpegTSBaseStream *
+mpegts_base_stream_ref (MpegTSBaseStream * stream)
+{
+  g_return_val_if_fail (stream != NULL, NULL);
+
+  GST_TRACE ("%p ref %d->%d", stream, stream->refcount, stream->refcount + 1);
+
+  g_atomic_int_inc (&stream->refcount);
+
+  return stream;
+}
+
+void
+mpegts_base_stream_unref (MpegTSBaseStream * stream)
+{
+  g_return_if_fail (stream != NULL);
+
+  GST_TRACE ("%p unref %d->%d", stream, stream->refcount, stream->refcount - 1);
+
+  g_return_if_fail (stream->refcount > 0);
+
+  if (g_atomic_int_dec_and_test (&stream->refcount)) {
+    g_free (stream);
+  }
+}
+#endif
 
 /* returns NULL if no matching descriptor found *
  * otherwise returns a descriptor that needs to *
@@ -452,6 +521,9 @@ mpegts_base_program_add_stream (MpegTSBase * base,
   }
 
   bstream = g_malloc0 (base->stream_size);
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  bstream->refcount = 1;
+#endif
   bstream->pid = pid;
   bstream->stream_type = stream_type;
   bstream->stream = stream;
@@ -494,7 +566,11 @@ mpegts_base_program_remove_stream (MpegTSBase * base,
     klass->stream_removed (base, stream);
 
   program->stream_list = g_list_remove_all (program->stream_list, stream);
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  mpegts_base_stream_unref (stream);
+#else
   g_free (stream);
+#endif
   program->streams[pid] = NULL;
 }
 
@@ -1060,6 +1136,15 @@ mpegts_base_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
       res = GST_MPEGTS_BASE_GET_CLASS (base)->push_event (base, event);
       break;
     case GST_EVENT_STREAM_START:
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+      GST_DEBUG_OBJECT (base,
+          "Handling stream-start, flushing all pending data");
+      mpegts_base_drain (base);
+      mpegts_base_flush (base, TRUE);
+      mpegts_packetizer_flush (base->packetizer, TRUE);
+      mpegts_base_clear (base);
+      mpegts_packetizer_clear (base->packetizer);
+#endif
       gst_event_unref (event);
       break;
     case GST_EVENT_CAPS:
index c427bd7..36754cb 100644 (file)
@@ -57,6 +57,9 @@ typedef struct _MpegTSBaseProgram MpegTSBaseProgram;
 
 struct _MpegTSBaseStream
 {
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  gint                refcount;
+#endif
   guint16             pid;
   guint8              stream_type;
 
@@ -211,6 +214,10 @@ struct _MpegTSBaseClass {
 
 G_GNUC_INTERNAL GType mpegts_base_get_type(void);
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+G_GNUC_INTERNAL MpegTSBaseStream *mpegts_base_stream_ref (MpegTSBaseStream * stream);
+G_GNUC_INTERNAL void mpegts_base_stream_unref (MpegTSBaseStream * stream);
+#endif
 G_GNUC_INTERNAL MpegTSBaseProgram *mpegts_base_get_program (MpegTSBase * base, gint program_number);
 G_GNUC_INTERNAL MpegTSBaseProgram *mpegts_base_add_program (MpegTSBase * base, gint program_number, guint16 pmt_pid);
 
index 8971bc8..547fc60 100644 (file)
@@ -195,6 +195,10 @@ struct _TSDemuxStream
 
   GstTsDemuxKeyFrameScanFunction scan_function;
   TSDemuxH264ParsingInfos h264infos;
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  /* For pad matching to avoid switching pads */
+  TSDemuxStream *matched_stream;
+#endif
 };
 
 #define VIDEO_CAPS \
@@ -297,7 +301,12 @@ static GstFlowReturn
 gst_ts_demux_push_pending_data (GstTSDemux * demux, TSDemuxStream * stream);
 static void gst_ts_demux_stream_flush (TSDemuxStream * stream,
     GstTSDemux * demux, gboolean hard);
-
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+static void gst_ts_demux_remove_stream (GstTSDemux * tsdemux,
+    TSDemuxStream * stream, gboolean push_eos);
+static void gst_ts_demux_remove_old_streams (GstTSDemux * demux,
+    gboolean push_eos);
+#endif
 static gboolean push_event (MpegTSBase * base, GstEvent * event);
 static void gst_ts_demux_check_and_sync_streams (GstTSDemux * demux,
     GstClockTime time);
@@ -401,6 +410,9 @@ gst_ts_demux_reset (MpegTSBase * base)
   demux->group_id = G_MAXUINT;
 
   demux->last_seek_offset = -1;
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  gst_ts_demux_remove_old_streams (demux, FALSE);
+#endif
 }
 
 static void
@@ -1031,11 +1043,49 @@ gst_ts_demux_create_tags (TSDemuxStream * stream)
   }
 }
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+static void
+gst_ts_demux_stream_send_stream_start (MpegTSBase * base,
+    MpegTSBaseStream * bstream, GstPad * pad)
+{
+  GstTSDemux *demux = GST_TS_DEMUX_CAST (base);
+  TSDemuxStream *stream = (TSDemuxStream *) bstream;
+  GstEvent *event;
+  gchar *stream_id;
+
+  stream_id =
+      gst_pad_create_stream_id_printf (pad, GST_ELEMENT_CAST (base), "%08x",
+      bstream->pid);
+
+  event = gst_pad_get_sticky_event (base->sinkpad, GST_EVENT_STREAM_START, 0);
+  if (event) {
+    if (gst_event_parse_group_id (event, &demux->group_id))
+      demux->have_group_id = TRUE;
+    else
+      demux->have_group_id = FALSE;
+    gst_event_unref (event);
+  } else if (!demux->have_group_id) {
+    demux->have_group_id = TRUE;
+    demux->group_id = gst_util_group_id_next ();
+  }
+  event = gst_event_new_stream_start (stream_id);
+  if (demux->have_group_id)
+    gst_event_set_group_id (event, demux->group_id);
+  if (stream->sparse)
+    gst_event_set_stream_flags (event, GST_STREAM_FLAG_SPARSE);
+
+  gst_pad_push_event (pad, event);
+  g_free (stream_id);
+}
+#endif
+
 static GstPad *
 create_pad_for_stream (MpegTSBase * base, MpegTSBaseStream * bstream,
     MpegTSBaseProgram * program)
 {
+#ifndef GST_EXT_AVOID_PAD_SWITCHING
   GstTSDemux *demux = GST_TS_DEMUX (base);
+#endif
   TSDemuxStream *stream = (TSDemuxStream *) bstream;
   gchar *name = NULL;
   GstCaps *caps = NULL;
@@ -1359,6 +1409,16 @@ done:
   }
 
   if (template && name && caps) {
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+    GST_LOG ("stream:%p creating pad with name %s and caps %" GST_PTR_FORMAT,
+        stream, name, caps);
+    pad = gst_pad_new_from_template (template, name);
+    gst_pad_set_active (pad, TRUE);
+    gst_pad_use_fixed_caps (pad);
+
+    stream->sparse = sparse;
+    gst_ts_demux_stream_send_stream_start (base, bstream, pad);
+#else
     GstEvent *event;
     gchar *stream_id;
 
@@ -1391,6 +1451,7 @@ done:
 
     gst_pad_push_event (pad, event);
     g_free (stream_id);
+#endif
     gst_pad_set_caps (pad, caps);
     if (!stream->taglist)
       stream->taglist = gst_tag_list_new_empty ();
@@ -1410,6 +1471,25 @@ done:
   return pad;
 }
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+static void
+gst_ts_demux_remove_old_streams (GstTSDemux * demux, gboolean push_eos)
+{
+  if (demux->old_streams) {
+    GList *iter;
+    for (iter = demux->old_streams; iter; iter = g_list_next (iter)) {
+      TSDemuxStream *stream = iter->data;
+
+      gst_ts_demux_remove_stream (demux, stream, push_eos);
+      mpegts_base_stream_unref ((MpegTSBaseStream *) stream);
+    }
+    g_list_free (demux->old_streams);
+    demux->old_streams = NULL;
+  }
+
+}
+#endif
+
 static void
 gst_ts_demux_stream_added (MpegTSBase * base, MpegTSBaseStream * bstream,
     MpegTSBaseProgram * program)
@@ -1465,10 +1545,49 @@ tsdemux_h264_parsing_info_clear (TSDemuxH264ParsingInfos * h264infos)
   }
 }
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+static void
+gst_ts_demux_stream_rename_stopping_pad (GstTSDemux * demux,
+    TSDemuxStream * stream)
+{
+  if (stream->pad) {
+    gchar *name;
+
+    GST_DEBUG_OBJECT (stream->pad, "Renaming stopping pad: %s",
+        GST_PAD_NAME (stream->pad));
+    name = g_strdup_printf ("%s_stopping", GST_PAD_NAME (stream->pad));
+    gst_object_set_name (GST_OBJECT_CAST (stream->pad), name);
+
+    g_free (name);
+  }
+}
+
+static void
+gst_ts_demux_remove_stream (GstTSDemux * tsdemux, TSDemuxStream * stream,
+    gboolean push_eos)
+{
+  if (stream->pad) {
+    if (push_eos && stream->active) {
+      GST_DEBUG_OBJECT (stream->pad, "Pushing out EOS");
+      gst_pad_push_event (stream->pad, gst_event_new_eos ());
+      gst_pad_set_active (stream->pad, FALSE);
+    }
+
+    GST_DEBUG_OBJECT (stream->pad, "Removing pad");
+    gst_element_remove_pad (GST_ELEMENT_CAST (tsdemux), stream->pad);
+    stream->active = FALSE;
+    stream->pad = NULL;
+  }
+}
+#endif
+
 static void
 gst_ts_demux_stream_removed (MpegTSBase * base, MpegTSBaseStream * bstream)
 {
   TSDemuxStream *stream = (TSDemuxStream *) bstream;
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  GstTSDemux *tsdemux = (GstTSDemux *) base;
+#endif
 
   if (stream->pad) {
     gst_flow_combiner_remove_pad (GST_TS_DEMUX_CAST (base)->flowcombiner,
@@ -1479,17 +1598,21 @@ gst_ts_demux_stream_removed (MpegTSBase * base, MpegTSBaseStream * bstream)
         /* Flush out all data */
         GST_DEBUG_OBJECT (stream->pad, "Flushing out pending data");
         gst_ts_demux_push_pending_data ((GstTSDemux *) base, stream);
-
+#ifndef GST_EXT_AVOID_PAD_SWITCHING
         GST_DEBUG_OBJECT (stream->pad, "Pushing out EOS");
         gst_pad_push_event (stream->pad, gst_event_new_eos ());
         gst_pad_set_active (stream->pad, FALSE);
+#endif
       }
-
+#ifndef GST_EXT_AVOID_PAD_SWITCHING
       GST_DEBUG_OBJECT (stream->pad, "Removing pad");
       gst_element_remove_pad (GST_ELEMENT_CAST (base), stream->pad);
       stream->active = FALSE;
+#endif
     }
+#ifndef GST_EXT_AVOID_PAD_SWITCHING
     stream->pad = NULL;
+#endif
   }
 
   gst_ts_demux_stream_flush (stream, GST_TS_DEMUX_CAST (base), TRUE);
@@ -1500,6 +1623,12 @@ gst_ts_demux_stream_removed (MpegTSBase * base, MpegTSBaseStream * bstream)
   }
 
   tsdemux_h264_parsing_info_clear (&stream->h264infos);
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  /* Keep our reference as we can only finish the stream once we added
+   * pads for the new program or the pipeline might go EOS */
+  mpegts_base_stream_ref (bstream);
+  tsdemux->old_streams = g_list_append (tsdemux->old_streams, bstream);
+#endif
 }
 
 static void
@@ -1567,6 +1696,117 @@ gst_ts_demux_flush_streams (GstTSDemux * demux, gboolean hard)
     gst_ts_demux_stream_flush (walk->data, demux, hard);
 }
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+static gboolean
+gst_ts_demux_find_matching_stream (GstTSDemux * demux, TSDemuxStream * stream,
+    GList * streams_list)
+{
+  GstCaps *this_caps;
+
+  if (stream->pad == NULL)
+    return TRUE;
+
+  this_caps = gst_pad_get_current_caps (stream->pad);
+  for (; streams_list; streams_list = g_list_next (streams_list)) {
+    TSDemuxStream *other_stream = streams_list->data;
+
+    if (other_stream->pad == NULL)
+      continue;
+
+    if (other_stream->matched_stream)
+      continue;
+
+    if (gst_pad_peer_query_accept_caps (other_stream->pad, this_caps)) {
+      /* TODO we are not checking the PIDs so the pad names will be
+       * inconsistent with the new streams' PIDs */
+      other_stream->matched_stream = stream;
+      stream->matched_stream = other_stream;
+      gst_caps_unref (this_caps);
+      return TRUE;
+    }
+  }
+
+  gst_caps_unref (this_caps);
+  GST_DEBUG_OBJECT (demux, "No match found for stream: %p %" GST_PTR_FORMAT,
+      stream, stream->pad);
+  return FALSE;
+}
+
+static gboolean
+push_sticky_event (GstPad * pad, GstEvent ** event, gpointer udata)
+{
+  GstPad *other_pad = udata;
+
+  gst_pad_push_event (other_pad, gst_event_ref (*event));
+
+  return TRUE;
+}
+
+static gboolean
+gst_ts_demux_check_streams_match (GstTSDemux * demux)
+{
+  GList *iter;
+  gint old_length = 0;
+  gint new_length = 0;
+
+  if (!demux->old_streams) {
+    GST_DEBUG_OBJECT (demux, "No old streams present, streams don't match");
+    return FALSE;
+  }
+
+  /* Initialize matching variables */
+  for (iter = demux->program->stream_list; iter; iter = g_list_next (iter)) {
+    TSDemuxStream *stream = iter->data;
+    if (stream->pad) {
+      new_length++;
+      stream->matched_stream = NULL;
+    }
+  }
+  for (iter = demux->old_streams; iter; iter = g_list_next (iter)) {
+    TSDemuxStream *stream = iter->data;
+    if (stream->pad) {
+      old_length++;
+      stream->matched_stream = NULL;
+    }
+  }
+
+  if (new_length != old_length) {
+    GST_DEBUG_OBJECT (demux,
+        "Number of streams is different, no match possible");
+    return FALSE;
+  }
+
+  for (iter = demux->program->stream_list; iter; iter = g_list_next (iter)) {
+    if (!gst_ts_demux_find_matching_stream (demux, iter->data,
+            demux->old_streams))
+      return FALSE;
+  }
+
+  GST_DEBUG_OBJECT (demux, "Streams matched, no need for pad switching");
+
+  /* do the pad replacement, unref pads from new streams and use the pads
+   * from the old ones */
+  for (iter = demux->program->stream_list; iter; iter = g_list_next (iter)) {
+    TSDemuxStream *stream = iter->data;
+
+    if (stream->pad) {
+      GstPad *pad = stream->pad;
+
+      stream->pad = stream->matched_stream->pad;
+      stream->matched_stream->pad = NULL;
+
+      gst_ts_demux_stream_send_stream_start ((MpegTSBase *) demux,
+          (MpegTSBaseStream *) stream, stream->pad);
+
+      gst_pad_sticky_events_foreach (pad, push_sticky_event, stream->pad);
+
+      gst_object_unref (pad);
+    }
+  }
+
+  return TRUE;
+}
+#endif
 static void
 gst_ts_demux_program_started (MpegTSBase * base, MpegTSBaseProgram * program)
 {
@@ -1590,13 +1830,34 @@ gst_ts_demux_program_started (MpegTSBase * base, MpegTSBaseProgram * program)
       gst_event_unref (demux->segment_event);
       demux->segment_event = NULL;
     }
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+    /* Check if the new streams match the old ones to
+     * prevent switching pads if not needed */
+    if (gst_ts_demux_check_streams_match (demux))
+      return;
+
+    /* 1) Rename old pad names to avoid clashes (matching PIDs)
+     * 2) add new streams
+     * 3) Fire no-more-pads */
+    for (tmp = demux->old_streams; tmp; tmp = tmp->next) {
+      TSDemuxStream *stream = (TSDemuxStream *) tmp->data;
+      gst_ts_demux_stream_rename_stopping_pad (demux, stream);
+    }
+    for (tmp = program->stream_list; tmp; tmp = tmp->next) {
+      TSDemuxStream *stream = (TSDemuxStream *) tmp->data;
+      activate_pad_for_stream (demux, stream);
+    }
+    gst_element_no_more_pads ((GstElement *) demux);
 
+    gst_ts_demux_remove_old_streams (demux, TRUE);
+#else
     /* Add all streams, then fire no-more-pads */
     for (tmp = program->stream_list; tmp; tmp = tmp->next) {
       TSDemuxStream *stream = (TSDemuxStream *) tmp->data;
       activate_pad_for_stream (demux, stream);
     }
     gst_element_no_more_pads ((GstElement *) demux);
+#endif
   }
 }
 
index b689412..4d95948 100644 (file)
@@ -66,6 +66,10 @@ struct _GstTSDemux
   /*< private >*/
   MpegTSBaseProgram *program;  /* Current program */
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  GList *old_streams;
+#endif
+
   /* segments to be sent */
   GstSegment segment;
   GstEvent *segment_event;
index 915c2d7..a7812c4 100644 (file)
@@ -201,6 +201,9 @@ gst_h264_parse_reset_stream_info (GstH264Parse * h264parse)
 {
   gint i;
 
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+  h264parse->state = 0;
+#endif
   h264parse->width = 0;
   h264parse->height = 0;
   h264parse->fps_num = 0;
@@ -2721,6 +2724,12 @@ gst_h264_parse_event (GstBaseParse * parse, GstEvent * event)
       res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
       break;
     }
+#ifdef GST_EXT_AVOID_PAD_SWITCHING
+    case GST_EVENT_STREAM_START:
+      res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
+      gst_h264_parse_reset ((GstH264Parse *) parse);
+      break;
+#endif
     default:
       res = GST_BASE_PARSE_CLASS (parent_class)->sink_event (parse, event);
       break;
index 1c4d4c4..f8d404e 100644 (file)
@@ -4,7 +4,7 @@
 
 Name:           gst-plugins-bad
 Version:        1.6.1
-Release:        1
+Release:        2
 Summary:        GStreamer Streaming-Media Framework Plug-Ins
 License:        GPL-2.0+ and LGPL-2.1+
 Group:          Multimedia/Framework
@@ -80,7 +80,7 @@ processing capabilities can be added simply by installing new plug-ins.
 %build
 export V=1
 NOCONFIGURE=1 ./autogen.sh
-export CFLAGS="-DGST_WLSINK_ENHANCEMENT -DGST_TBM_SUPPORT -DMESA_EGL_NO_X11_HEADERS"
+export CFLAGS="-DGST_WLSINK_ENHANCEMENT -DGST_TBM_SUPPORT -DMESA_EGL_NO_X11_HEADERS -DGST_EXT_AVOID_PAD_SWITCHING"
 %configure\
     --disable-static\
     --disable-examples\