basesrc: Add public gst_base_src_negotiate () function
authorCarlos Rafael Giani <crg7475@mailbox.org>
Mon, 24 Jun 2019 12:35:16 +0000 (14:35 +0200)
committerCarlos Rafael Giani <crg7475@mailbox.org>
Mon, 1 Jul 2019 09:16:09 +0000 (11:16 +0200)
This is useful for when format changes occur mid-stream.

libs/gst/base/gstbasesrc.c
libs/gst/base/gstbasesrc.h
tests/check/libs/basesrc.c

index b68b386..f128cc9 100644 (file)
@@ -360,7 +360,7 @@ static GstFlowReturn gst_base_src_getrange (GstPad * pad, GstObject * parent,
 static GstFlowReturn gst_base_src_get_range (GstBaseSrc * src, guint64 offset,
     guint length, GstBuffer ** buf);
 static gboolean gst_base_src_seekable (GstBaseSrc * src);
-static gboolean gst_base_src_negotiate (GstBaseSrc * basesrc);
+static gboolean gst_base_src_negotiate_unlocked (GstBaseSrc * basesrc);
 static gboolean gst_base_src_update_length (GstBaseSrc * src, guint64 offset,
     guint * length, gboolean force);
 
@@ -2804,7 +2804,7 @@ gst_base_src_loop (GstPad * pad)
 
   /* check if we need to renegotiate */
   if (gst_pad_check_reconfigure (pad)) {
-    if (!gst_base_src_negotiate (src)) {
+    if (!gst_base_src_negotiate_unlocked (src)) {
       gst_pad_mark_reconfigure (pad);
       if (GST_PAD_IS_FLUSHING (pad)) {
         GST_LIVE_LOCK (src);
@@ -3374,7 +3374,7 @@ no_caps:
 }
 
 static gboolean
-gst_base_src_negotiate (GstBaseSrc * basesrc)
+gst_base_src_negotiate_unlocked (GstBaseSrc * basesrc)
 {
   GstBaseSrcClass *bclass;
   gboolean result;
@@ -3401,6 +3401,39 @@ gst_base_src_negotiate (GstBaseSrc * basesrc)
   return result;
 }
 
+/**
+ * gst_base_src_negotiate:
+ * @basesrc: base source instance
+ *
+ * Negotiates src pad caps with downstream elements.
+ * Unmarks GST_PAD_FLAG_NEED_RECONFIGURE in any case. But marks it again
+ * if #GstBaseSrcClass.negotiate() fails.
+ *
+ * Do not call this in the #GstBaseSrcClass.fill() vmethod. Call this in
+ * #GstBaseSrcClass.create() or in #GstBaseSrcClass.alloc(), _before_ any
+ * buffer is allocated.
+ *
+ * Returns: %TRUE if the negotiation succeeded, else %FALSE.
+ *
+ * Since: 1.18
+ */
+gboolean
+gst_base_src_negotiate (GstBaseSrc * src)
+{
+  gboolean ret = TRUE;
+
+  g_return_val_if_fail (GST_IS_BASE_SRC (src), FALSE);
+
+  GST_PAD_STREAM_LOCK (src->srcpad);
+  gst_pad_check_reconfigure (src->srcpad);
+  ret = gst_base_src_negotiate_unlocked (src);
+  if (!ret)
+    gst_pad_mark_reconfigure (src->srcpad);
+  GST_PAD_STREAM_UNLOCK (src->srcpad);
+
+  return ret;
+}
+
 static gboolean
 gst_base_src_start (GstBaseSrc * basesrc)
 {
index d4f3730..527e8e1 100644 (file)
@@ -276,6 +276,9 @@ GST_BASE_API
 gboolean        gst_base_src_is_async         (GstBaseSrc *src);
 
 GST_BASE_API
+gboolean        gst_base_src_negotiate        (GstBaseSrc *src);
+
+GST_BASE_API
 void            gst_base_src_start_complete   (GstBaseSrc * basesrc, GstFlowReturn ret);
 
 GST_BASE_API
index f964cba..253d69a 100644 (file)
@@ -909,6 +909,8 @@ typedef struct
   GstBaseSrc parent;
   GstSegment *segment;
   gboolean n_output_buffers;
+  gsize num_times_negotiate_called;
+  gboolean do_renegotiate;
 } TimeSrc;
 
 typedef GstBaseSrcClass TimeSrcClass;
@@ -923,6 +925,8 @@ time_src_init (TimeSrc * src)
   gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
   gst_base_src_set_automatic_eos (GST_BASE_SRC (src), FALSE);
   src->n_output_buffers = 0;
+  src->num_times_negotiate_called = 0;
+  src->do_renegotiate = FALSE;
 }
 
 /* This test src outputs a compressed format, with a single GOP
@@ -941,6 +945,11 @@ time_src_create (GstBaseSrc * bsrc, guint64 offset, guint size,
   if (src->segment->position >= src->segment->stop)
     return GST_FLOW_EOS;
 
+  if (src->do_renegotiate) {
+    gst_base_src_negotiate (bsrc);
+    src->do_renegotiate = FALSE;
+  }
+
   *p_buf = gst_buffer_new ();
   GST_BUFFER_PTS (*p_buf) = src->segment->position;
   GST_BUFFER_DURATION (*p_buf) = GST_SECOND;
@@ -973,6 +982,14 @@ time_src_is_seekable (GstBaseSrc * bsrc)
   return TRUE;
 }
 
+static gboolean
+time_src_negotiate (GstBaseSrc * bsrc)
+{
+  TimeSrc *src = (TimeSrc *) bsrc;
+  src->num_times_negotiate_called++;
+  return GST_BASE_SRC_CLASS (time_src_parent_class)->negotiate (bsrc);
+}
+
 static void
 time_src_class_init (TimeSrcClass * klass)
 {
@@ -984,6 +1001,7 @@ time_src_class_init (TimeSrcClass * klass)
   gstbasesrc_class->create = time_src_create;
   gstbasesrc_class->do_seek = time_src_do_seek;
   gstbasesrc_class->is_seekable = time_src_is_seekable;
+  gstbasesrc_class->negotiate = time_src_negotiate;
 }
 
 GST_START_TEST (basesrc_time_automatic_eos)
@@ -1033,6 +1051,63 @@ GST_START_TEST (basesrc_time_automatic_eos)
 
 GST_END_TEST;
 
+GST_START_TEST (basesrc_negotiate)
+{
+  GstElement *src, *sink;
+  GstElement *pipe;
+  GstSegment seg;
+
+  src = g_object_new (time_src_get_type (), NULL);
+  sink = gst_element_factory_make ("fakesink", NULL);
+
+  pipe = gst_pipeline_new (NULL);
+
+  gst_bin_add (GST_BIN (pipe), src);
+  gst_bin_add (GST_BIN (pipe), sink);
+
+  gst_element_link (src, sink);
+
+  /* Use some default segment to get the stream going. */
+  gst_segment_init (&seg, GST_FORMAT_TIME);
+  ((TimeSrc *) src)->segment = gst_segment_copy (&seg);
+
+  /* Check that gst_base_src_negotiate () actually ends up calling
+   * the negotiate () vmethod by first running the test pipeline
+   * normally, and then running it with a gst_base_src_negotiate ()
+   * call, and checking how many times negotiate () was called in
+   * both cases. */
+
+  /* Run pipeline, keep do_renegotiate at FALSE, so
+   * gst_base_src_negotiate () won't be called. negotiate () still
+   * will be called once, as part of the regular caps negotiation
+   * sequence. */
+  fail_unless (((TimeSrc *) src)->num_times_negotiate_called == 0);
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+  gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
+  fail_unless (((TimeSrc *) src)->num_times_negotiate_called == 1);
+  gst_element_set_state (pipe, GST_STATE_NULL);
+
+  ((TimeSrc *) src)->num_times_negotiate_called = 0;
+
+  /* Run pipeline, set do_renegotiate to TRUE. This will cause
+   * negotiate () to be called twice: Once during caps negotiation,
+   * and once by the gst_base_src_negotiate () call in the
+   * time_src_create () function. */
+  ((TimeSrc *) src)->do_renegotiate = TRUE;
+  fail_unless (((TimeSrc *) src)->num_times_negotiate_called == 0);
+  gst_element_set_state (pipe, GST_STATE_PLAYING);
+  gst_element_get_state (pipe, NULL, NULL, GST_CLOCK_TIME_NONE);
+  fail_unless (((TimeSrc *) src)->num_times_negotiate_called == 2);
+  gst_element_set_state (pipe, GST_STATE_NULL);
+
+  if (((TimeSrc *) src)->segment)
+    gst_segment_free (((TimeSrc *) src)->segment);
+
+  gst_object_unref (pipe);
+}
+
+GST_END_TEST;
+
 static Suite *
 gst_basesrc_suite (void)
 {
@@ -1050,6 +1125,7 @@ gst_basesrc_suite (void)
   tcase_add_test (tc, basesrc_seek_on_last_buffer);
   tcase_add_test (tc, basesrc_create_bufferlist);
   tcase_add_test (tc, basesrc_time_automatic_eos);
+  tcase_add_test (tc, basesrc_negotiate);
 
   return s;
 }