videodecoder: Keep still meaningfull pending events on FLUSH_STOP
authorThibault Saunier <thibault.saunier@collabora.com>
Mon, 14 Oct 2013 21:56:55 +0000 (18:56 -0300)
committerThibault Saunier <tsaunier@gnome.org>
Tue, 3 Jun 2014 11:03:49 +0000 (13:03 +0200)
Only EOS and segment should be deleted in that case.

+ Add a testcase

https://bugzilla.gnome.org/show_bug.cgi?id=709868

gst-libs/gst/video/gstvideodecoder.c
tests/check/libs/videodecoder.c

index a106763..9760619 100644 (file)
@@ -978,6 +978,25 @@ gst_video_decoder_drain_out (GstVideoDecoder * dec, gboolean at_eos)
   return ret;
 }
 
+static GList *
+_flush_events (GstPad * pad, GList * events)
+{
+  GList *tmp;
+
+  for (tmp = events; tmp; tmp = tmp->next) {
+    if (GST_EVENT_TYPE (tmp->data) == GST_EVENT_EOS ||
+        GST_EVENT_TYPE (tmp->data) == GST_EVENT_SEGMENT ||
+        !GST_EVENT_IS_STICKY (tmp->data)) {
+      gst_event_unref (tmp->data);
+    } else {
+      gst_pad_store_sticky_event (pad, GST_EVENT_CAST (tmp->data));
+    }
+  }
+  g_list_free (events);
+
+  return NULL;
+}
+
 static gboolean
 gst_video_decoder_sink_event_default (GstVideoDecoder * decoder,
     GstEvent * event)
@@ -1128,7 +1147,17 @@ gst_video_decoder_sink_event_default (GstVideoDecoder * decoder,
     }
     case GST_EVENT_FLUSH_STOP:
     {
+      GList *l;
+
       GST_VIDEO_DECODER_STREAM_LOCK (decoder);
+      for (l = priv->frames; l; l = l->next) {
+        GstVideoCodecFrame *frame = l->data;
+
+        frame->events = _flush_events (decoder->srcpad, frame->events);
+      }
+      priv->current_frame_events = _flush_events (decoder->srcpad,
+          decoder->priv->current_frame_events);
+
       /* well, this is kind of worse than a DISCONT */
       gst_video_decoder_flush (decoder, TRUE);
       GST_VIDEO_DECODER_STREAM_UNLOCK (decoder);
index b8a2c49..14f721f 100644 (file)
@@ -422,6 +422,109 @@ GST_START_TEST (videodecoder_playback_with_events)
 
 GST_END_TEST;
 
+GST_START_TEST (videodecoder_flush_events)
+{
+  GstSegment segment;
+  GstBuffer *buffer;
+  guint64 i;
+  GList *events_iter;
+
+  setup_videodecodertester ();
+
+  gst_pad_set_active (mysrcpad, TRUE);
+  gst_element_set_state (dec, GST_STATE_PLAYING);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  send_startup_events ();
+
+  /* push a new segment */
+  gst_segment_init (&segment, GST_FORMAT_TIME);
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_segment (&segment)));
+
+  /* push buffers, the data is actually a number so we can track them */
+  for (i = 0; i < NUM_BUFFERS; i++) {
+    if (i % 10 == 0) {
+      GstTagList *tags;
+
+      tags = gst_tag_list_new (GST_TAG_TRACK_NUMBER, i, NULL);
+      fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_tag (tags)));
+    } else {
+      buffer = create_test_buffer (i);
+
+      fail_unless (gst_pad_push (mysrcpad, buffer) == GST_FLOW_OK);
+    }
+  }
+
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_eos ()));
+
+  events_iter = events;
+  /* make sure the usual events have been received */
+  {
+    GstEvent *sstart = events_iter->data;
+    fail_unless (GST_EVENT_TYPE (sstart) == GST_EVENT_STREAM_START);
+    events_iter = g_list_next (events_iter);
+  }
+  {
+    GstEvent *caps_event = events_iter->data;
+    fail_unless (GST_EVENT_TYPE (caps_event) == GST_EVENT_CAPS);
+    events_iter = g_list_next (events_iter);
+  }
+  {
+    GstEvent *segment_event = events_iter->data;
+    fail_unless (GST_EVENT_TYPE (segment_event) == GST_EVENT_SEGMENT);
+    events_iter = g_list_next (events_iter);
+  }
+
+  /* check that EOS was received */
+  fail_unless (GST_PAD_IS_EOS (mysrcpad));
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_flush_start ()));
+  fail_unless (GST_PAD_IS_EOS (mysrcpad));
+
+  /* Check that we have tags */
+  {
+    GstEvent *tags = gst_pad_get_sticky_event (mysrcpad, GST_EVENT_TAG, 0);
+
+    fail_unless (tags != NULL);
+    gst_event_unref (tags);
+  }
+
+  /* Check that we still have a segment set */
+  {
+    GstEvent *segment =
+        gst_pad_get_sticky_event (mysrcpad, GST_EVENT_SEGMENT, 0);
+
+    fail_unless (segment != NULL);
+    gst_event_unref (segment);
+  }
+
+  fail_unless (gst_pad_push_event (mysrcpad, gst_event_new_flush_stop (TRUE)));
+  fail_if (GST_PAD_IS_EOS (mysrcpad));
+
+  /* Check that the segment was flushed on FLUSH_STOP */
+  {
+    GstEvent *segment =
+        gst_pad_get_sticky_event (mysrcpad, GST_EVENT_SEGMENT, 0);
+
+    fail_unless (segment == NULL);
+  }
+
+  /* Check the tags were not lost on FLUSH_STOP */
+  {
+    GstEvent *tags = gst_pad_get_sticky_event (mysrcpad, GST_EVENT_TAG, 0);
+
+    fail_unless (tags != NULL);
+    gst_event_unref (tags);
+
+  }
+
+  g_list_free_full (buffers, (GDestroyNotify) gst_buffer_unref);
+  buffers = NULL;
+
+  cleanup_videodecodertest ();
+}
+
+GST_END_TEST;
+
 
 /* Check https://bugzilla.gnome.org/show_bug.cgi?id=721835 */
 GST_START_TEST (videodecoder_playback_first_frames_not_decoded)
@@ -727,6 +830,7 @@ gst_videodecoder_suite (void)
 
   tcase_add_test (tc, videodecoder_backwards_playback);
   tcase_add_test (tc, videodecoder_backwards_buffer_after_segment);
+  tcase_add_test (tc, videodecoder_flush_events);
 
   return s;
 }