From: Joan Pau Beltran Date: Fri, 15 Jul 2016 11:20:29 +0000 (+0200) Subject: appsink: add _pull_sample/preroll() variants with timeout X-Git-Tag: 1.19.3~511^2~2745 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c6722c06a040a333188793d7f4403dd983c04815;p=platform%2Fupstream%2Fgstreamer.git appsink: add _pull_sample/preroll() variants with timeout The _pull_sample() and _pull_preroll() functions block until a sample is available, EOS happens or the pipeline is shut down (returning NULL in the last two cases). This adds _try_pull_sample() and _try_pull_preroll() functions with a timeout argument to specify the maximum amount of time to wait for a new sample. To avoid code duplication, wait forever if the timeout is GST_CLOCK_TIME_NONE and use that to implement _pull_sample/_pull_preroll with the original behavior. Add also corresponding action signals "try-pull-sample" and "try-pull-preroll". https://bugzilla.gnome.org/show_bug.cgi?id=768852 --- diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt index 71623e1..358d345 100644 --- a/docs/libs/gst-plugins-base-libs-sections.txt +++ b/docs/libs/gst-plugins-base-libs-sections.txt @@ -104,6 +104,8 @@ gst_app_sink_set_drop gst_app_sink_get_drop gst_app_sink_pull_preroll gst_app_sink_pull_sample +gst_app_sink_try_pull_preroll +gst_app_sink_try_pull_sample GstAppSinkCallbacks gst_app_sink_set_callbacks diff --git a/gst-libs/gst/app/gstappsink.c b/gst-libs/gst/app/gstappsink.c index eca5008..7b8d481 100644 --- a/gst-libs/gst/app/gstappsink.c +++ b/gst-libs/gst/app/gstappsink.c @@ -33,7 +33,9 @@ * The normal way of retrieving samples from appsink is by using the * gst_app_sink_pull_sample() and gst_app_sink_pull_preroll() methods. * These methods block until a sample becomes available in the sink or when the - * sink is shut down or reaches EOS. + * sink is shut down or reaches EOS. There are also timed variants of these + * methods, gst_app_sink_try_pull_sample() and gst_app_sink_try_pull_preroll(), + * which accept a timeout parameter to limit the amount of time to wait. * * Appsink will internally use a queue to collect buffers from the streaming * thread. If the application is not pulling samples fast enough, this queue @@ -111,6 +113,8 @@ enum /* actions */ SIGNAL_PULL_PREROLL, SIGNAL_PULL_SAMPLE, + SIGNAL_TRY_PULL_PREROLL, + SIGNAL_TRY_PULL_SAMPLE, LAST_SIGNAL }; @@ -332,6 +336,68 @@ gst_app_sink_class_init (GstAppSinkClass * klass) g_signal_new ("pull-sample", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass, pull_sample), NULL, NULL, NULL, GST_TYPE_SAMPLE, 0, G_TYPE_NONE); + /** + * GstAppSink::try-pull-preroll: + * @appsink: the appsink element to emit this signal on + * @timeout: the maximum amount of time to wait for the preroll sample + * + * Get the last preroll sample in @appsink. This was the sample that caused the + * appsink to preroll in the PAUSED state. This sample can be pulled many times + * and remains available to the application even after EOS. + * + * This function is typically used when dealing with a pipeline in the PAUSED + * state. Calling this function after doing a seek will give the sample right + * after the seek position. + * + * Note that the preroll sample will also be returned as the first sample + * when calling gst_app_sink_pull_sample() or the "pull-sample" action signal. + * + * If an EOS event was received before any buffers or the timeout expires, + * this function returns %NULL. Use gst_app_sink_is_eos () to check for the EOS + * condition. + * + * This function blocks until a preroll sample or EOS is received, the appsink + * element is set to the READY/NULL state, or the timeout expires. + * + * Returns: a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires. + * + * Since: 1.10 + */ + gst_app_sink_signals[SIGNAL_TRY_PULL_PREROLL] = + g_signal_new ("try-pull-preroll", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstAppSinkClass, try_pull_preroll), NULL, NULL, NULL, + GST_TYPE_SAMPLE, 1, GST_TYPE_CLOCK_TIME); + /** + * GstAppSink::try-pull-sample: + * @appsink: the appsink element to emit this signal on + * @timeout: the maximum amount of time to wait for a sample + * + * This function blocks until a sample or EOS becomes available or the appsink + * element is set to the READY/NULL state or the timeout expires. + * + * This function will only return samples when the appsink is in the PLAYING + * state. All rendered samples will be put in a queue so that the application + * can pull samples at its own rate. + * + * Note that when the application does not pull samples fast enough, the + * queued samples could consume a lot of memory, especially when dealing with + * raw video frames. It's possible to control the behaviour of the queue with + * the "drop" and "max-buffers" properties. + * + * If an EOS event was received before any buffers or the timeout expires, + * this function returns %NULL. Use gst_app_sink_is_eos () to check + * for the EOS condition. + * + * Returns: a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires. + * + * Since: 1.10 + */ + gst_app_sink_signals[SIGNAL_TRY_PULL_SAMPLE] = + g_signal_new ("try-pull-sample", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (GstAppSinkClass, try_pull_sample), NULL, NULL, NULL, + GST_TYPE_SAMPLE, 1, GST_TYPE_CLOCK_TIME); gst_element_class_set_static_metadata (element_class, "AppSink", "Generic/Sink", "Allow the application to get access to raw buffer", @@ -353,6 +419,8 @@ gst_app_sink_class_init (GstAppSinkClass * klass) klass->pull_preroll = gst_app_sink_pull_preroll; klass->pull_sample = gst_app_sink_pull_sample; + klass->try_pull_preroll = gst_app_sink_try_pull_preroll; + klass->try_pull_sample = gst_app_sink_try_pull_sample; g_type_class_add_private (klass, sizeof (GstAppSinkPrivate)); } @@ -1197,13 +1265,80 @@ gst_app_sink_get_wait_on_eos (GstAppSink * appsink) GstSample * gst_app_sink_pull_preroll (GstAppSink * appsink) { - GstSample *sample = NULL; + return gst_app_sink_try_pull_preroll (appsink, GST_CLOCK_TIME_NONE); +} + +/** + * gst_app_sink_pull_sample: + * @appsink: a #GstAppSink + * + * This function blocks until a sample or EOS becomes available or the appsink + * element is set to the READY/NULL state. + * + * This function will only return samples when the appsink is in the PLAYING + * state. All rendered buffers will be put in a queue so that the application + * can pull samples at its own rate. Note that when the application does not + * pull samples fast enough, the queued buffers could consume a lot of memory, + * especially when dealing with raw video frames. + * + * If an EOS event was received before any buffers, this function returns + * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. + * + * Returns: (transfer full): a #GstSample or NULL when the appsink is stopped or EOS. + * Call gst_sample_unref() after usage. + */ +GstSample * +gst_app_sink_pull_sample (GstAppSink * appsink) +{ + return gst_app_sink_try_pull_sample (appsink, GST_CLOCK_TIME_NONE); +} + +/** + * gst_app_sink_try_pull_preroll: + * @appsink: a #GstAppSink + * @timeout: the maximum amount of time to wait for the preroll sample + * + * Get the last preroll sample in @appsink. This was the sample that caused the + * appsink to preroll in the PAUSED state. This sample can be pulled many times + * and remains available to the application even after EOS. + * + * This function is typically used when dealing with a pipeline in the PAUSED + * state. Calling this function after doing a seek will give the sample right + * after the seek position. + * + * Note that the preroll sample will also be returned as the first sample + * when calling gst_app_sink_pull_sample(). + * + * If an EOS event was received before any buffers or the timeout expires, + * this function returns %NULL. Use gst_app_sink_is_eos () to check for the EOS + * condition. + * + * This function blocks until a preroll sample or EOS is received, the appsink + * element is set to the READY/NULL state, or the timeout expires. + * + * Returns: (transfer full): a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires. + * Call gst_sample_unref() after usage. + * + * Since: 1.10 + */ +GstSample * +gst_app_sink_try_pull_preroll (GstAppSink * appsink, GstClockTime timeout) +{ GstAppSinkPrivate *priv; + GstSample *sample = NULL; + gboolean timeout_valid; + gint64 end_time; g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL); priv = appsink->priv; + timeout_valid = GST_CLOCK_TIME_IS_VALID (timeout); + + if (timeout_valid) + end_time = + g_get_monotonic_time () + timeout / (GST_SECOND / G_TIME_SPAN_SECOND); + g_mutex_lock (&priv->mutex); while (TRUE) { @@ -1219,7 +1354,12 @@ gst_app_sink_pull_preroll (GstAppSink * appsink) /* nothing to return, wait */ GST_DEBUG_OBJECT (appsink, "waiting for the preroll buffer"); - g_cond_wait (&priv->cond, &priv->mutex); + if (timeout_valid) { + if (!g_cond_wait_until (&priv->cond, &priv->mutex, end_time)) + goto expired; + } else { + g_cond_wait (&priv->cond, &priv->mutex); + } } sample = gst_sample_new (priv->preroll, priv->preroll_caps, &priv->preroll_segment, @@ -1230,6 +1370,12 @@ gst_app_sink_pull_preroll (GstAppSink * appsink) return sample; /* special conditions */ +expired: + { + GST_DEBUG_OBJECT (appsink, "timeout expired, return NULL"); + g_mutex_unlock (&priv->mutex); + return NULL; + } eos: { GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL"); @@ -1245,11 +1391,12 @@ not_started: } /** - * gst_app_sink_pull_sample: + * gst_app_sink_try_pull_sample: * @appsink: a #GstAppSink + * @timeout: the maximum amount of time to wait for a sample * * This function blocks until a sample or EOS becomes available or the appsink - * element is set to the READY/NULL state. + * element is set to the READY/NULL state or the timeout expires. * * This function will only return samples when the appsink is in the PLAYING * state. All rendered buffers will be put in a queue so that the application @@ -1257,22 +1404,32 @@ not_started: * pull samples fast enough, the queued buffers could consume a lot of memory, * especially when dealing with raw video frames. * - * If an EOS event was received before any buffers, this function returns - * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. + * If an EOS event was received before any buffers or the timeout expires, + * this function returns %NULL. Use gst_app_sink_is_eos () to check for the EOS + * condition. * - * Returns: (transfer full): a #GstSample or NULL when the appsink is stopped or EOS. - * Call gst_sample_unref() after usage. + * Returns: (transfer full): a #GstSample or NULL when the appsink is stopped or EOS or the timeout expires. + * Call gst_sample_unref() after usage. + * + * Since: 1.10 */ - GstSample * -gst_app_sink_pull_sample (GstAppSink * appsink) +gst_app_sink_try_pull_sample (GstAppSink * appsink, GstClockTime timeout) { + GstAppSinkPrivate *priv; GstSample *sample = NULL; GstBuffer *buffer; - GstAppSinkPrivate *priv; + gboolean timeout_valid; + gint64 end_time; g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL); + timeout_valid = GST_CLOCK_TIME_IS_VALID (timeout); + + if (timeout_valid) + end_time = + g_get_monotonic_time () + timeout / (GST_SECOND / G_TIME_SPAN_SECOND); + priv = appsink->priv; g_mutex_lock (&priv->mutex); @@ -1290,7 +1447,12 @@ gst_app_sink_pull_sample (GstAppSink * appsink) /* nothing to return, wait */ GST_DEBUG_OBJECT (appsink, "waiting for a buffer"); - g_cond_wait (&priv->cond, &priv->mutex); + if (timeout_valid) { + if (!g_cond_wait_until (&priv->cond, &priv->mutex, end_time)) + goto expired; + } else { + g_cond_wait (&priv->cond, &priv->mutex); + } } buffer = dequeue_buffer (appsink); GST_DEBUG_OBJECT (appsink, "we have a buffer %p", buffer); @@ -1303,6 +1465,12 @@ gst_app_sink_pull_sample (GstAppSink * appsink) return sample; /* special conditions */ +expired: + { + GST_DEBUG_OBJECT (appsink, "timeout expired, return NULL"); + g_mutex_unlock (&priv->mutex); + return NULL; + } eos: { GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL"); diff --git a/gst-libs/gst/app/gstappsink.h b/gst-libs/gst/app/gstappsink.h index e268b62..8217d26 100644 --- a/gst-libs/gst/app/gstappsink.h +++ b/gst-libs/gst/app/gstappsink.h @@ -94,9 +94,11 @@ struct _GstAppSinkClass /* actions */ GstSample * (*pull_preroll) (GstAppSink *appsink); GstSample * (*pull_sample) (GstAppSink *appsink); + GstSample * (*try_pull_preroll) (GstAppSink *appsink, GstClockTime timeout); + GstSample * (*try_pull_sample) (GstAppSink *appsink, GstClockTime timeout); /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; + gpointer _gst_reserved[GST_PADDING - 2]; }; GType gst_app_sink_get_type(void); @@ -120,6 +122,8 @@ gboolean gst_app_sink_get_wait_on_eos (GstAppSink *appsink); GstSample * gst_app_sink_pull_preroll (GstAppSink *appsink); GstSample * gst_app_sink_pull_sample (GstAppSink *appsink); +GstSample * gst_app_sink_try_pull_preroll (GstAppSink *appsink, GstClockTime timeout); +GstSample * gst_app_sink_try_pull_sample (GstAppSink *appsink, GstClockTime timeout); void gst_app_sink_set_callbacks (GstAppSink * appsink, GstAppSinkCallbacks *callbacks, diff --git a/win32/common/libgstapp.def b/win32/common/libgstapp.def index de99f19..1a7184e 100644 --- a/win32/common/libgstapp.def +++ b/win32/common/libgstapp.def @@ -14,6 +14,8 @@ EXPORTS gst_app_sink_set_emit_signals gst_app_sink_set_max_buffers gst_app_sink_set_wait_on_eos + gst_app_sink_try_pull_preroll + gst_app_sink_try_pull_sample gst_app_src_end_of_stream gst_app_src_get_caps gst_app_src_get_current_level_bytes