gstplaysink: Properly reset chain when receiving a custom flush event.
authorAndre Moreira Magalhaes (andrunko) <andre.magalhaes@collabora.co.uk>
Wed, 16 May 2012 13:41:41 +0000 (10:41 -0300)
committerThiago Santos <thiago.sousa.santos@collabora.com>
Wed, 6 Jun 2012 19:31:08 +0000 (16:31 -0300)
https://bugzilla.gnome.org/show_bug.cgi?id=638168

Conflicts:

gst/playback/gstplaysink.c

gst/playback/gstplaysink.c

index 24872a6..19bce39 100644 (file)
@@ -256,6 +256,9 @@ struct _GstPlaySink
   GstColorBalance *colorbalance_element;
   GList *colorbalance_channels; /* CONTRAST, BRIGHTNESS, HUE, SATURATION */
   gint colorbalance_values[4];
+
+  GstSegment text_segment;
+  gboolean text_flush;
 };
 
 struct _GstPlaySinkClass
@@ -346,6 +349,8 @@ static void notify_mute_cb (GObject * object, GParamSpec * pspec,
 
 static void update_av_offset (GstPlaySink * playsink);
 
+static GQuark _playsink_reset_segment_event_marker_id = 0;
+
 /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */
 
 static void gst_play_sink_overlay_init (gpointer g_iface,
@@ -572,6 +577,9 @@ gst_play_sink_class_init (GstPlaySinkClass * klass)
 
   klass->reconfigure = GST_DEBUG_FUNCPTR (gst_play_sink_reconfigure);
   klass->convert_sample = GST_DEBUG_FUNCPTR (gst_play_sink_convert_sample);
+
+  _playsink_reset_segment_event_marker_id =
+      g_quark_from_static_string ("gst-playsink-reset-segment-event-marker");
 }
 
 static void
@@ -1834,6 +1842,152 @@ setup_video_chain (GstPlaySink * playsink, gboolean raw, gboolean async)
   return TRUE;
 }
 
+static void
+_generate_update_newsegment_event (GstPad * pad, GstSegment * segment,
+    GstEvent ** event1)
+{
+  GstEvent *event;
+  GstStructure *structure;
+  event = gst_event_new_segment (segment);
+  structure = gst_event_writable_structure (event);
+  gst_structure_id_set (structure,
+      _playsink_reset_segment_event_marker_id, G_TYPE_BOOLEAN, TRUE, NULL);
+  *event1 = event;
+}
+
+static gboolean
+gst_play_sink_text_sink_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_object_get_parent (parent));
+  gboolean ret;
+  const GstStructure *structure = gst_event_get_structure (event);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_DOWNSTREAM_OOB &&
+      structure
+      && strcmp (gst_structure_get_name (structure),
+          "subtitleoverlay-flush-subtitle") == 0) {
+    GST_DEBUG_OBJECT (pad,
+        "Custom subtitle flush event received, marking to flush text");
+    GST_PLAY_SINK_LOCK (playsink);
+    playsink->text_flush = TRUE;
+    GST_PLAY_SINK_UNLOCK (playsink);
+  } else if (GST_EVENT_TYPE (event) == GST_EVENT_FLUSH_STOP) {
+    GST_DEBUG_OBJECT (pad,
+        "Resetting text segment because of flush-stop event");
+    gst_segment_init (&playsink->text_segment, GST_FORMAT_UNDEFINED);
+  }
+
+  ret = gst_proxy_pad_event_default (pad, parent, gst_event_ref (event));
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_SEGMENT) {
+    const GstSegment *segment;
+
+    gst_event_parse_segment (event, &segment);
+    GST_DEBUG_OBJECT (pad, "Segment event: %" GST_SEGMENT_FORMAT, segment);
+
+    if (playsink->text_segment.format != segment->format) {
+      GST_DEBUG_OBJECT (pad, "Text segment format changed: %s -> %s",
+          gst_format_get_name (playsink->text_segment.format),
+          gst_format_get_name (segment->format));
+    }
+
+    GST_DEBUG_OBJECT (pad, "Old text segment: %" GST_SEGMENT_FORMAT,
+        &playsink->text_segment);
+    gst_segment_copy_into (segment, &playsink->text_segment);
+    GST_DEBUG_OBJECT (pad, "New text segment: %" GST_SEGMENT_FORMAT,
+        &playsink->text_segment);
+  }
+
+  gst_event_unref (event);
+  gst_object_unref (playsink);
+  return ret;
+}
+
+static GstFlowReturn
+gst_play_sink_text_sink_chain (GstPad * pad, GstObject * parent,
+    GstBuffer * buffer)
+{
+  GstBin *tbin = GST_BIN_CAST (gst_pad_get_parent (pad));
+  GstPlaySink *playsink = GST_PLAY_SINK_CAST (gst_pad_get_parent (tbin));
+
+  GstFlowReturn ret = gst_proxy_pad_chain_default (pad, parent, buffer);
+
+  if (ret == GST_FLOW_FLUSHING && playsink->text_flush) {
+    GstEvent *event;
+    GstSegment *text_segment;
+    GstStructure *structure;
+
+    GST_DEBUG_OBJECT (pad,
+        "Ignoring wrong state due to flush text being marked");
+    GST_PLAY_SINK_LOCK (playsink);
+    playsink->text_flush = FALSE;
+    text_segment = gst_segment_copy (&playsink->text_segment);
+    GST_PLAY_SINK_UNLOCK (playsink);
+
+    /* make queue drop all cached data.
+     * This event will be dropped on the src pad. */
+    event = gst_event_new_flush_stop (TRUE);
+    structure = gst_event_writable_structure (event);
+    gst_structure_id_set (structure,
+        _playsink_reset_segment_event_marker_id, G_TYPE_BOOLEAN, TRUE, NULL);
+    GST_DEBUG_OBJECT (playsink,
+        "Pushing flush-stop event with reset segment marker set: %"
+        GST_PTR_FORMAT, structure);
+    gst_pad_send_event (pad, event);
+
+    /* Re-sync queue segment info after flush-stop.
+     * This event will be dropped on the src pad. */
+    if (text_segment->format != GST_FORMAT_UNDEFINED) {
+      GstEvent *event1;
+
+      _generate_update_newsegment_event (pad, text_segment, &event1);
+      GST_DEBUG_OBJECT (playsink,
+          "Pushing segment event with reset "
+          "segment marker set: %" GST_PTR_FORMAT, event1);
+      gst_pad_send_event (pad, event1);
+    }
+
+    gst_segment_free (text_segment);
+
+    ret = GST_FLOW_OK;
+  }
+
+  gst_object_unref (playsink);
+  gst_object_unref (tbin);
+  return ret;
+}
+
+static gboolean
+gst_play_sink_text_src_event (GstPad * pad, GstObject * parent,
+    GstEvent * event)
+{
+  gboolean ret;
+  const GstStructure *structure;
+
+  GST_DEBUG_OBJECT (pad, "Got event %" GST_PTR_FORMAT, event);
+
+  structure = gst_event_get_structure (event);
+
+  if (structure &&
+      gst_structure_id_has_field (structure,
+          _playsink_reset_segment_event_marker_id)) {
+    /* the events marked with a reset segment marker
+     * are sent internally to reset the queue and
+     * must be dropped here */
+    GST_DEBUG_OBJECT (pad, "Dropping event with reset "
+        "segment marker set: %" GST_PTR_FORMAT, event);
+    ret = TRUE;
+    goto out;
+  }
+
+  ret = gst_proxy_pad_event_default (pad, parent, gst_event_ref (event));
+
+out:
+  gst_event_unref (event);
+  return ret;
+}
+
 /* make an element for playback of video with subtitles embedded.
  * Only used for *raw* video streams.
  *
@@ -2027,11 +2181,21 @@ gen_text_chain (GstPlaySink * playsink)
   if (textsinkpad) {
     chain->textsinkpad = gst_ghost_pad_new ("text_sink", textsinkpad);
     gst_object_unref (textsinkpad);
+
+    gst_pad_set_event_function (chain->textsinkpad,
+        GST_DEBUG_FUNCPTR (gst_play_sink_text_sink_event));
+    gst_pad_set_chain_function (chain->textsinkpad,
+        GST_DEBUG_FUNCPTR (gst_play_sink_text_sink_chain));
+
     gst_element_add_pad (chain->chain.bin, chain->textsinkpad);
   }
   if (srcpad) {
     chain->srcpad = gst_ghost_pad_new ("src", srcpad);
     gst_object_unref (srcpad);
+
+    gst_pad_set_event_function (chain->srcpad,
+        GST_DEBUG_FUNCPTR (gst_play_sink_text_src_event));
+
     gst_element_add_pad (chain->chain.bin, chain->srcpad);
   }
 
@@ -3954,6 +4118,8 @@ gst_play_sink_change_state (GstElement * element, GstStateChange transition)
   playsink = GST_PLAY_SINK (element);
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
+      gst_segment_init (&playsink->text_segment, GST_FORMAT_UNDEFINED);
+
       playsink->need_async_start = TRUE;
       /* we want to go async to PAUSED until we managed to configure and add the
        * sinks */