wavparse: fix seeking in READY state
authorGuillaume Desmottes <guillaume.desmottes@collabora.com>
Thu, 18 Feb 2021 09:34:25 +0000 (10:34 +0100)
committerGuillaume Desmottes <guillaume.desmottes@collabora.com>
Thu, 18 Feb 2021 15:32:24 +0000 (16:32 +0100)
wavparse claims to be able to support seeking in the READY state by
saving the pending seek event and actually seeking later after having parsed the
header.
Problem was that this seek event was reset on the READY to PAUSED
transition, making all this code useless. Fixing it by stop resetting
on READY to PAUSED transition as we already reset on PAUSED to READY
and when initiating the element.

Note that DTS marker detection isn't support in such scenario as
gst_type_find_helper_for_buffer() needs a buffer containing the
beginning of the stream.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/879>

gst/wavparse/gstwavparse.c
tests/check/elements/wavparse.c

index a097206..01acf03 100644 (file)
@@ -1918,7 +1918,8 @@ gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf)
   g_assert (wav->caps != NULL);
 
   s = gst_caps_get_structure (wav->caps, 0);
-  if (s && gst_structure_has_name (s, "audio/x-raw") && buf != NULL) {
+  if (s && gst_structure_has_name (s, "audio/x-raw") && buf != NULL
+      && (GST_BUFFER_OFFSET (buf) == 0 || !GST_BUFFER_OFFSET_IS_VALID (buf))) {
     GstTypeFindProbability prob;
     GstCaps *tf_caps;
 
@@ -2926,7 +2927,6 @@ gst_wavparse_change_state (GstElement * element, GstStateChange transition)
     case GST_STATE_CHANGE_NULL_TO_READY:
       break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      gst_wavparse_reset (wav);
       break;
     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       break;
index 3691dde..8a5702d 100644 (file)
@@ -143,6 +143,72 @@ GST_START_TEST (test_empty_file_push)
 
 GST_END_TEST;
 
+static GstPadProbeReturn
+fakesink_buffer_cb (GstPad * sink, GstPadProbeInfo * info, gpointer user_data)
+{
+  GstClockTime *ts = user_data;
+  GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
+
+  fail_unless (buf);
+  if (!GST_CLOCK_TIME_IS_VALID (*ts))
+    *ts = GST_BUFFER_PTS (buf);
+
+  return GST_PAD_PROBE_OK;
+}
+
+GST_START_TEST (test_seek)
+{
+  GstStateChangeReturn ret;
+  GstElement *pipeline;
+  GstMessage *msg;
+  GstElement *wavparse, *fakesink;
+  GstPad *pad;
+  GstClockTime seek_position = (20 * GST_MSECOND);
+  GstClockTime first_ts = GST_CLOCK_TIME_NONE;
+
+  pipeline = create_pipeline (GST_PAD_MODE_PULL);
+  wavparse = gst_bin_get_by_name (GST_BIN (pipeline), "wavparse");
+  fail_unless (wavparse);
+  fakesink = gst_bin_get_by_name (GST_BIN (pipeline), "fakesink");
+  fail_unless (fakesink);
+
+  pad = gst_element_get_static_pad (fakesink, "sink");
+  fail_unless (pad);
+  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, fakesink_buffer_cb,
+      &first_ts, NULL);
+  gst_object_unref (pad);
+
+  /* wavparse is able to seek in the READY state */
+  ret = gst_element_set_state (pipeline, GST_STATE_READY);
+  fail_unless_equals_int (ret, GST_STATE_CHANGE_SUCCESS);
+
+  fail_unless (gst_element_seek_simple (wavparse, GST_FORMAT_TIME,
+          GST_SEEK_FLAG_FLUSH, seek_position));
+
+  ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);
+  fail_unless_equals_int (ret, GST_STATE_CHANGE_ASYNC);
+
+  ret = gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
+  fail_unless_equals_int (ret, GST_STATE_CHANGE_SUCCESS);
+
+  msg = gst_bus_timed_pop_filtered (GST_ELEMENT_BUS (pipeline),
+      GST_CLOCK_TIME_NONE, GST_MESSAGE_EOS | GST_MESSAGE_ERROR);
+
+  /* check that the first buffer produced by wavparse matches the seek
+     position we requested */
+  fail_unless_equals_clocktime (first_ts, seek_position);
+
+  fail_unless_equals_string (GST_MESSAGE_TYPE_NAME (msg), "eos");
+
+  gst_message_unref (msg);
+  gst_element_set_state (pipeline, GST_STATE_NULL);
+  gst_object_unref (wavparse);
+  gst_object_unref (fakesink);
+  gst_object_unref (pipeline);
+}
+
+GST_END_TEST;
+
 static Suite *
 wavparse_suite (void)
 {
@@ -154,6 +220,7 @@ wavparse_suite (void)
   tcase_add_test (tc_chain, test_empty_file_push);
   tcase_add_test (tc_chain, test_simple_file_pull);
   tcase_add_test (tc_chain, test_simple_file_push);
+  tcase_add_test (tc_chain, test_seek);
   return s;
 }