diff options
-rw-r--r-- | docs/libs/gst-plugins-base-libs-sections.txt | 9 | ||||
-rw-r--r-- | gst-libs/gst/app/gstappsink.c | 536 | ||||
-rw-r--r-- | gst-libs/gst/app/gstappsink.h | 31 | ||||
-rw-r--r-- | gst-libs/gst/audio/gstaudiobasesink.c | 2 | ||||
-rw-r--r-- | gst-libs/gst/video/convertframe.c | 140 | ||||
-rw-r--r-- | gst-libs/gst/video/video.h | 12 | ||||
-rw-r--r-- | gst/playback/gstplaybin2.c | 51 | ||||
-rw-r--r-- | gst/playback/gstplaysink.c | 120 | ||||
-rw-r--r-- | gst/playback/gstplaysink.h | 6 | ||||
-rw-r--r-- | tests/check/libs/video.c | 47 | ||||
-rw-r--r-- | tests/examples/app/appsink-src.c | 26 | ||||
-rw-r--r-- | tests/examples/app/appsrc_ex.c | 10 | ||||
-rw-r--r-- | tests/examples/seek/seek.c | 31 |
13 files changed, 463 insertions, 558 deletions
diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt index 7d8247648..cd5c15c78 100644 --- a/docs/libs/gst-plugins-base-libs-sections.txt +++ b/docs/libs/gst-plugins-base-libs-sections.txt @@ -60,8 +60,7 @@ gst_app_sink_get_max_buffers gst_app_sink_set_drop gst_app_sink_get_drop gst_app_sink_pull_preroll -gst_app_sink_pull_buffer -gst_app_sink_pull_buffer_list +gst_app_sink_pull_sample GstAppSinkCallbacks gst_app_sink_set_callbacks <SUBSECTION Standard> @@ -2103,9 +2102,9 @@ gst_video_calculate_display_ratio gst_video_format_to_fourcc gst_video_format_from_fourcc gst_video_parse_caps_palette -GstVideoConvertFrameCallback -gst_video_convert_frame -gst_video_convert_frame_async +GstVideoConvertSampleCallback +gst_video_convert_sample +gst_video_convert_sample_async gst_video_event_new_still_frame gst_video_event_parse_still_frame <SUBSECTION Standard> diff --git a/gst-libs/gst/app/gstappsink.c b/gst-libs/gst/app/gstappsink.c index 3bfcd596a..5cb3d3903 100644 --- a/gst-libs/gst/app/gstappsink.c +++ b/gst-libs/gst/app/gstappsink.c @@ -19,9 +19,9 @@ */ /** * SECTION:gstappsink - * @short_description: Easy way for applications to extract buffers from a + * @short_description: Easy way for applications to extract samples from a * pipeline - * @see_also: #GstBaseSink, appsrc + * @see_also: #GstSample, #GstBaseSink, appsrc * * Appsink is a sink plugin that supports many different methods for making * the application get a handle on the GStreamer data in a pipeline. Unlike @@ -30,13 +30,13 @@ * appsink can be used by linking to the gstappsink.h header file to access the * methods or by using the appsink action signals and properties. * - * The normal way of retrieving buffers from appsink is by using the - * gst_app_sink_pull_buffer() and gst_app_sink_pull_preroll() methods. - * These methods block until a buffer becomes available in the sink or when the + * 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. * * Appsink will internally use a queue to collect buffers from the streaming - * thread. If the application is not pulling buffers fast enough, this queue + * thread. If the application is not pulling samples fast enough, this queue * will consume a lot of memory over time. The "max-buffers" property can be * used to limit the queue size. The "drop" property controls whether the * streaming thread blocks or if older buffers are dropped when the maximum @@ -44,14 +44,14 @@ * affect real-time performance and should be avoided. * * If a blocking behaviour is not desirable, setting the "emit-signals" property - * to %TRUE will make appsink emit the "new-buffer" and "new-preroll" signals - * when a buffer can be pulled without blocking. + * to %TRUE will make appsink emit the "new-sample" and "new-preroll" signals + * when a sample can be pulled without blocking. * * The "caps" property on appsink can be used to control the formats that * appsink can receive. This property can contain non-fixed caps, the format of - * the pulled buffers can be obtained by getting the buffer caps. + * the pulled samples can be obtained by getting the sample caps. * - * If one of the pull-preroll or pull-buffer methods return %NULL, the appsink + * If one of the pull-preroll or pull-sample methods return %NULL, the appsink * is stopped or in the EOS state. You can check for the EOS state with the * "eos" property or with the gst_app_sink_is_eos() method. * @@ -70,16 +70,17 @@ #include <gst/gst.h> #include <gst/base/gstbasesink.h> #include <gst/gstbuffer.h> -#include <gst/gstbufferlist.h> #include <string.h> +#include "gstapp-marshal.h" #include "gstappsink.h" struct _GstAppSinkPrivate { GstCaps *caps; gboolean emit_signals; + guint num_buffers; guint max_buffers; gboolean drop; @@ -87,6 +88,9 @@ struct _GstAppSinkPrivate GMutex *mutex; GQueue *queue; GstBuffer *preroll; + GstCaps *preroll_caps; + GstCaps *last_caps; + GstSegment last_segment; gboolean flushing; gboolean unlock; gboolean started; @@ -95,8 +99,6 @@ struct _GstAppSinkPrivate GstAppSinkCallbacks callbacks; gpointer user_data; GDestroyNotify notify; - - gboolean buffer_lists_supported; }; GST_DEBUG_CATEGORY_STATIC (app_sink_debug); @@ -107,13 +109,11 @@ enum /* signals */ SIGNAL_EOS, SIGNAL_NEW_PREROLL, - SIGNAL_NEW_BUFFER, - SIGNAL_NEW_BUFFER_LIST, + SIGNAL_NEW_SAMPLE, /* actions */ SIGNAL_PULL_PREROLL, - SIGNAL_PULL_BUFFER, - SIGNAL_PULL_BUFFER_LIST, + SIGNAL_PULL_SAMPLE, LAST_SIGNAL }; @@ -158,14 +158,10 @@ static gboolean gst_app_sink_stop (GstBaseSink * psink); static gboolean gst_app_sink_event (GstBaseSink * sink, GstEvent * event); static GstFlowReturn gst_app_sink_preroll (GstBaseSink * psink, GstBuffer * buffer); -static GstFlowReturn gst_app_sink_render_common (GstBaseSink * psink, - GstMiniObject * data, gboolean is_list); static GstFlowReturn gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer); -static GstFlowReturn gst_app_sink_render_list (GstBaseSink * psink, - GstBufferList * list); +static gboolean gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps); static GstCaps *gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter); -static GstMiniObject *gst_app_sink_pull_object (GstAppSink * appsink); static guint gst_app_sink_signals[LAST_SIGNAL] = { 0 }; @@ -174,40 +170,6 @@ G_DEFINE_TYPE_WITH_CODE (GstAppSink, gst_app_sink, GST_TYPE_BASE_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_app_sink_uri_handler_init)); -/* Can't use glib-genmarshal for this, as it doesn't know how to handle - * GstMiniObject-based types, which are a new fundamental type */ -static void -gst_app_marshal_BUFFER__VOID (GClosure * closure, - GValue * return_value, - guint n_param_values, - const GValue * param_values, - gpointer invocation_hint, gpointer marshal_data) -{ - typedef GstBuffer *(*GMarshalFunc_BUFFER__VOID) (gpointer data1, - gpointer data2); - register GMarshalFunc_BUFFER__VOID callback; - register GCClosure *cc = (GCClosure *) closure; - register gpointer data1, data2; - GstBuffer *v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 1); - - if (G_CCLOSURE_SWAP_DATA (closure)) { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } else { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = - (GMarshalFunc_BUFFER__VOID) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, data2); - - gst_value_take_buffer (return_value, v_return); -} - static void gst_app_sink_class_init (GstAppSinkClass * klass) { @@ -265,12 +227,12 @@ gst_app_sink_class_init (GstAppSinkClass * klass) * GstAppSink::new-preroll: * @appsink: the appsink element that emited the signal * - * Signal that a new preroll buffer is available. + * Signal that a new preroll sample is available. * * This signal is emited from the steaming thread and only when the * "emit-signals" property is %TRUE. * - * The new preroll buffer can be retrieved with the "pull-preroll" action + * The new preroll sample can be retrieved with the "pull-preroll" action * signal or gst_app_sink_pull_preroll() either from this signal callback * or from any other thread. * @@ -282,126 +244,80 @@ gst_app_sink_class_init (GstAppSinkClass * klass) G_STRUCT_OFFSET (GstAppSinkClass, new_preroll), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); /** - * GstAppSink::new-buffer: - * @appsink: the appsink element that emited the signal - * - * Signal that a new buffer is available. - * - * This signal is emited from the steaming thread and only when the - * "emit-signals" property is %TRUE. - * - * The new buffer can be retrieved with the "pull-buffer" action - * signal or gst_app_sink_pull_buffer() either from this signal callback - * or from any other thread. - * - * Note that this signal is only emited when the "emit-signals" property is - * set to %TRUE, which it is not by default for performance reasons. - */ - gst_app_sink_signals[SIGNAL_NEW_BUFFER] = - g_signal_new ("new-buffer", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstAppSinkClass, new_buffer), - NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); - /** - * GstAppSink::new-buffer-list: + * GstAppSink::new-sample: * @appsink: the appsink element that emited the signal * - * Signal that a new bufferlist is available. + * Signal that a new sample is available. * * This signal is emited from the steaming thread and only when the * "emit-signals" property is %TRUE. * - * The new buffer can be retrieved with the "pull-buffer-list" action - * signal or gst_app_sink_pull_buffer_list() either from this signal callback + * The new sample can be retrieved with the "pull-sample" action + * signal or gst_app_sink_pull_sample() either from this signal callback * or from any other thread. * * Note that this signal is only emited when the "emit-signals" property is * set to %TRUE, which it is not by default for performance reasons. */ - gst_app_sink_signals[SIGNAL_NEW_BUFFER_LIST] = - g_signal_new ("new-buffer-list", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstAppSinkClass, new_buffer_list), + gst_app_sink_signals[SIGNAL_NEW_SAMPLE] = + g_signal_new ("new-sample", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstAppSinkClass, new_sample), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE); /** * GstAppSink::pull-preroll: * @appsink: the appsink element to emit this signal on * - * Get the last preroll buffer in @appsink. This was the buffer that caused the - * appsink to preroll in the PAUSED state. This buffer can be pulled many times + * 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 buffer right + * state. Calling this function after doing a seek will give the sample right * after the seek position. * - * Note that the preroll buffer will also be returned as the first buffer - * when calling gst_app_sink_pull_buffer() or the "pull-buffer" action signal. + * 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, this function returns * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. * - * This function blocks until a preroll buffer or EOS is received or the appsink + * This function blocks until a preroll sample or EOS is received or the appsink * element is set to the READY/NULL state. * - * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS. + * Returns: a #GstSample or NULL when the appsink is stopped or EOS. */ gst_app_sink_signals[SIGNAL_PULL_PREROLL] = g_signal_new ("pull-preroll", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass, - pull_preroll), NULL, NULL, gst_app_marshal_BUFFER__VOID, - GST_TYPE_BUFFER, 0, G_TYPE_NONE); - /** - * GstAppSink::pull-buffer: - * @appsink: the appsink element to emit this signal on - * - * This function blocks until a buffer or EOS becomes available or the appsink - * element is set to the READY/NULL state. - * - * This function will only return buffers when the appsink is in the PLAYING - * state. All rendered buffers will be put in a queue so that the application - * can pull buffers at its own rate. - * - * Note that when the application does not pull buffers fast enough, the - * queued buffers 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, this function returns - * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. - * - * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS. - */ - gst_app_sink_signals[SIGNAL_PULL_BUFFER] = - g_signal_new ("pull-buffer", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass, - pull_buffer), NULL, NULL, gst_app_marshal_BUFFER__VOID, - GST_TYPE_BUFFER, 0, G_TYPE_NONE); + pull_preroll), NULL, NULL, __gst_app_marshal_BOXED__VOID, + GST_TYPE_SAMPLE, 0, G_TYPE_NONE); /** - * GstAppSink::pull-buffer-list: + * GstAppSink::pull-sample: * @appsink: the appsink element to emit this signal on * - * This function blocks until a buffer list or EOS becomes available or the appsink + * 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 bufferlists when the appsink is in the PLAYING - * state. All rendered bufferlists will be put in a queue so that the application - * can pull bufferlists at its own rate. + * 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 bufferlists fast enough, the - * queued bufferlists could consume a lot of memory, especially when dealing with + * 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, this function returns * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. * - * Returns: a #GstBufferList or NULL when the appsink is stopped or EOS. + * Returns: a #GstSample or NULL when the appsink is stopped or EOS. */ - gst_app_sink_signals[SIGNAL_PULL_BUFFER_LIST] = - g_signal_new ("pull-buffer-list", G_TYPE_FROM_CLASS (klass), + gst_app_sink_signals[SIGNAL_PULL_SAMPLE] = + g_signal_new ("pull-sample", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstAppSinkClass, - pull_buffer_list), NULL, NULL, gst_app_marshal_BUFFER__VOID, - GST_TYPE_BUFFER_LIST, 0, G_TYPE_NONE); + pull_sample), NULL, NULL, __gst_app_marshal_BOXED__VOID, + GST_TYPE_SAMPLE, 0, G_TYPE_NONE); gst_element_class_set_details_simple (element_class, "AppSink", "Generic/Sink", "Allow the application to get access to raw buffer", @@ -417,12 +333,11 @@ gst_app_sink_class_init (GstAppSinkClass * klass) basesink_class->event = gst_app_sink_event; basesink_class->preroll = gst_app_sink_preroll; basesink_class->render = gst_app_sink_render; - basesink_class->render_list = gst_app_sink_render_list; basesink_class->get_caps = gst_app_sink_getcaps; + basesink_class->set_caps = gst_app_sink_setcaps; klass->pull_preroll = gst_app_sink_pull_preroll; - klass->pull_buffer = gst_app_sink_pull_buffer; - klass->pull_buffer_list = gst_app_sink_pull_buffer_list; + klass->pull_sample = gst_app_sink_pull_sample; g_type_class_add_private (klass, sizeof (GstAppSinkPrivate)); } @@ -466,12 +381,11 @@ gst_app_sink_dispose (GObject * obj) GST_OBJECT_UNLOCK (appsink); g_mutex_lock (priv->mutex); - if (priv->preroll) { - gst_buffer_unref (priv->preroll); - priv->preroll = NULL; - } while ((queue_obj = g_queue_pop_head (priv->queue))) gst_mini_object_unref (queue_obj); + gst_buffer_replace (&priv->preroll, NULL); + gst_caps_replace (&priv->preroll_caps, NULL); + gst_caps_replace (&priv->last_caps, NULL); g_mutex_unlock (priv->mutex); G_OBJECT_CLASS (parent_class)->dispose (obj); @@ -591,24 +505,10 @@ gst_app_sink_flush_unlocked (GstAppSink * appsink) gst_buffer_replace (&priv->preroll, NULL); while ((obj = g_queue_pop_head (priv->queue))) gst_mini_object_unref (obj); + priv->num_buffers = 0; g_cond_signal (priv->cond); } -#define NEW_BUFFER_LIST_SIGID \ - gst_app_sink_signals[SIGNAL_NEW_BUFFER_LIST] - -static gboolean -gst_app_sink_check_buffer_lists_support (GstAppSink * appsink) -{ - gboolean ret; - - ret = (appsink->priv->callbacks.new_buffer_list != NULL) || - g_signal_has_handler_pending (appsink, NEW_BUFFER_LIST_SIGID, 0, FALSE); - - GST_INFO_OBJECT (appsink, "application supports buffer lists: %d", ret); - return ret; -} - static gboolean gst_app_sink_start (GstBaseSink * psink) { @@ -619,8 +519,7 @@ gst_app_sink_start (GstBaseSink * psink) GST_DEBUG_OBJECT (appsink, "starting"); priv->flushing = FALSE; priv->started = TRUE; - priv->buffer_lists_supported = - gst_app_sink_check_buffer_lists_support (appsink); + gst_segment_init (&priv->last_segment, GST_FORMAT_TIME); g_mutex_unlock (priv->mutex); return TRUE; @@ -637,6 +536,23 @@ gst_app_sink_stop (GstBaseSink * psink) priv->flushing = TRUE; priv->started = FALSE; gst_app_sink_flush_unlocked (appsink); + gst_caps_replace (&priv->preroll_caps, NULL); + gst_caps_replace (&priv->last_caps, NULL); + g_mutex_unlock (priv->mutex); + + return TRUE; +} + +static gboolean +gst_app_sink_setcaps (GstBaseSink * sink, GstCaps * caps) +{ + GstAppSink *appsink = GST_APP_SINK_CAST (sink); + GstAppSinkPrivate *priv = appsink->priv; + + g_mutex_lock (priv->mutex); + GST_DEBUG_OBJECT (appsink, "receiving CAPS"); + g_queue_push_tail (priv->queue, gst_event_new_caps (caps)); + gst_caps_replace (&priv->preroll_caps, caps); g_mutex_unlock (priv->mutex); return TRUE; @@ -649,8 +565,13 @@ gst_app_sink_event (GstBaseSink * sink, GstEvent * event) GstAppSinkPrivate *priv = appsink->priv; switch (event->type) { + case GST_EVENT_SEGMENT: + g_mutex_lock (priv->mutex); + GST_DEBUG_OBJECT (appsink, "receiving SEGMENT"); + g_queue_push_tail (priv->queue, gst_event_ref (event)); + g_mutex_unlock (priv->mutex); + break; case GST_EVENT_EOS: - g_mutex_lock (priv->mutex); GST_DEBUG_OBJECT (appsink, "receiving EOS"); priv->is_eos = TRUE; @@ -715,9 +636,52 @@ flushing: } } +static GstBuffer * +dequeue_buffer (GstAppSink * appsink) +{ + GstAppSinkPrivate *priv = appsink->priv; + GstBuffer *buffer; + + do { + GstMiniObject *obj; + + obj = g_queue_pop_head (priv->queue); + + if (GST_IS_BUFFER (obj)) { + buffer = GST_BUFFER_CAST (obj); + GST_DEBUG_OBJECT (appsink, "dequeued buffer %p", buffer); + priv->num_buffers--; + break; + } else if (GST_IS_EVENT (obj)) { + GstEvent *event = GST_EVENT_CAST (obj); + + switch (GST_EVENT_TYPE (obj)) { + case GST_EVENT_CAPS: + { + GstCaps *caps; + + gst_event_parse_caps (event, &caps); + GST_DEBUG_OBJECT (appsink, "activating caps %" GST_PTR_FORMAT, caps); + gst_caps_replace (priv->last_caps, caps); + break; + } + case GST_EVENT_SEGMENT: + gst_event_copy_segment (event, &priv->last_segment); + GST_DEBUG_OBJECT (appsink, "activated segment %" GST_SEGMENT_FORMAT, + &priv->last_segment); + break; + default: + break; + } + gst_mini_object_unref (obj); + } + } while (TRUE); + + return buffer; +} + static GstFlowReturn -gst_app_sink_render_common (GstBaseSink * psink, GstMiniObject * data, - gboolean is_list) +gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer) { GstFlowReturn ret; GstAppSink *appsink = GST_APP_SINK_CAST (psink); @@ -729,20 +693,21 @@ restart: if (priv->flushing) goto flushing; - GST_DEBUG_OBJECT (appsink, "pushing render buffer%s %p on queue (%d)", - is_list ? " list" : "", data, priv->queue->length); + GST_DEBUG_OBJECT (appsink, "pushing render buffer %p on queue (%d)", + buffer, priv->num_buffers); - while (priv->max_buffers > 0 && priv->queue->length >= priv->max_buffers) { + while (priv->max_buffers > 0 && priv->num_buffers >= priv->max_buffers) { if (priv->drop) { - GstMiniObject *obj; + GstBuffer *old; - /* we need to drop the oldest buffer/list and try again */ - obj = g_queue_pop_head (priv->queue); - GST_DEBUG_OBJECT (appsink, "dropping old buffer/list %p", obj); - gst_mini_object_unref (obj); + /* we need to drop the oldest buffer and try again */ + if ((old = dequeue_buffer (appsink))) { + GST_DEBUG_OBJECT (appsink, "dropping old buffer %p", old); + gst_buffer_unref (old); + } } else { GST_DEBUG_OBJECT (appsink, "waiting for free space, length %d >= %d", - priv->queue->length, priv->max_buffers); + priv->num_buffers, priv->max_buffers); if (priv->unlock) { /* we are asked to unlock, call the wait_preroll method */ @@ -761,22 +726,17 @@ restart: } } /* we need to ref the buffer when pushing it in the queue */ - g_queue_push_tail (priv->queue, gst_mini_object_ref (data)); + g_queue_push_tail (priv->queue, gst_buffer_ref (buffer)); + priv->num_buffers++; g_cond_signal (priv->cond); emit = priv->emit_signals; g_mutex_unlock (priv->mutex); - if (is_list) { - if (priv->callbacks.new_buffer_list) - priv->callbacks.new_buffer_list (appsink, priv->user_data); - else if (emit) - g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER_LIST], 0); - } else { - if (priv->callbacks.new_buffer) - priv->callbacks.new_buffer (appsink, priv->user_data); - else if (emit) - g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_BUFFER], 0); - } + if (priv->callbacks.new_sample) + priv->callbacks.new_sample (appsink, priv->user_data); + else if (emit) + g_signal_emit (appsink, gst_app_sink_signals[SIGNAL_NEW_SAMPLE], 0); + return GST_FLOW_OK; flushing: @@ -792,43 +752,6 @@ stopping: } } -static GstFlowReturn -gst_app_sink_render (GstBaseSink * psink, GstBuffer * buffer) -{ - return gst_app_sink_render_common (psink, GST_MINI_OBJECT_CAST (buffer), - FALSE); -} - -static GstFlowReturn -gst_app_sink_render_list (GstBaseSink * sink, GstBufferList * list) -{ - GstFlowReturn flow; - GstAppSink *appsink; - GstBuffer *buffer; - guint i, len; - - appsink = GST_APP_SINK_CAST (sink); - - if (appsink->priv->buffer_lists_supported) - return gst_app_sink_render_common (sink, GST_MINI_OBJECT_CAST (list), TRUE); - - /* The application doesn't support buffer lists, extract individual buffers - * then and push them one-by-one */ - GST_INFO_OBJECT (sink, "chaining each group in list as a merged buffer"); - - len = gst_buffer_list_length (list); - - flow = GST_FLOW_OK; - for (i = 0; i < len; i++) { - buffer = gst_buffer_list_get (list, i); - flow = gst_app_sink_render (sink, buffer); - if (flow != GST_FLOW_OK) - break; - } - - return flow; -} - static GstCaps * gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter) { @@ -849,55 +772,6 @@ gst_app_sink_getcaps (GstBaseSink * psink, GstCaps * filter) return caps; } -static GstMiniObject * -gst_app_sink_pull_object (GstAppSink * appsink) -{ - GstMiniObject *obj = NULL; - GstAppSinkPrivate *priv; - - g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL); - - priv = appsink->priv; - - g_mutex_lock (priv->mutex); - - while (TRUE) { - GST_DEBUG_OBJECT (appsink, "trying to grab a buffer/list"); - if (!priv->started) - goto not_started; - - if (!g_queue_is_empty (priv->queue)) - break; - - if (priv->is_eos) - goto eos; - - /* nothing to return, wait */ - GST_DEBUG_OBJECT (appsink, "waiting for a buffer/list"); - g_cond_wait (priv->cond, priv->mutex); - } - obj = g_queue_pop_head (priv->queue); - GST_DEBUG_OBJECT (appsink, "we have a buffer/list %p", obj); - g_cond_signal (priv->cond); - g_mutex_unlock (priv->mutex); - - return obj; - - /* special conditions */ -eos: - { - GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL"); - g_mutex_unlock (priv->mutex); - return NULL; - } -not_started: - { - GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL"); - g_mutex_unlock (priv->mutex); - return NULL; - } -} - /* external API */ /** @@ -968,13 +842,13 @@ gst_app_sink_get_caps (GstAppSink * appsink) * gst_app_sink_is_eos: * @appsink: a #GstAppSink * - * Check if @appsink is EOS, which is when no more buffers can be pulled because + * Check if @appsink is EOS, which is when no more samples can be pulled because * an EOS event was received. * * This function also returns %TRUE when the appsink is not in the PAUSED or * PLAYING state. * - * Returns: %TRUE if no more buffers can be pulled and the appsink is EOS. + * Returns: %TRUE if no more samples can be pulled and the appsink is EOS. * * Since: 0.10.22 */ @@ -992,7 +866,7 @@ gst_app_sink_is_eos (GstAppSink * appsink) if (!priv->started) goto not_started; - if (priv->is_eos && g_queue_is_empty (priv->queue)) { + if (priv->is_eos && priv->num_buffers == 0) { GST_DEBUG_OBJECT (appsink, "we are EOS and the queue is empty"); ret = TRUE; } else { @@ -1016,7 +890,7 @@ not_started: * @appsink: a #GstAppSink * @emit: the new state * - * Make appsink emit the "new-preroll" and "new-buffer" signals. This option is + * Make appsink emit the "new-preroll" and "new-sample" signals. This option is * by default disabled because signal emission is expensive and unneeded when * the application prefers to operate in pull mode. * @@ -1040,9 +914,9 @@ gst_app_sink_set_emit_signals (GstAppSink * appsink, gboolean emit) * gst_app_sink_get_emit_signals: * @appsink: a #GstAppSink * - * Check if appsink will emit the "new-preroll" and "new-buffer" signals. + * Check if appsink will emit the "new-preroll" and "new-sample" signals. * - * Returns: %TRUE if @appsink is emiting the "new-preroll" and "new-buffer" + * Returns: %TRUE if @appsink is emiting the "new-preroll" and "new-sample" * signals. * * Since: 0.10.22 @@ -1071,7 +945,7 @@ gst_app_sink_get_emit_signals (GstAppSink * appsink) * * Set the maximum amount of buffers that can be queued in @appsink. After this * amount of buffers are queued in appsink, any more buffers will block upstream - * elements until a buffer is pulled from @appsink. + * elements until a sample is pulled from @appsink. * * Since: 0.10.22 */ @@ -1181,31 +1055,31 @@ gst_app_sink_get_drop (GstAppSink * appsink) * gst_app_sink_pull_preroll: * @appsink: a #GstAppSink * - * Get the last preroll buffer in @appsink. This was the buffer that caused the - * appsink to preroll in the PAUSED state. This buffer can be pulled many times + * 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 buffer right + * state. Calling this function after doing a seek will give the sample right * after the seek position. * - * Note that the preroll buffer will also be returned as the first buffer - * when calling gst_app_sink_pull_buffer(). + * 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, this function returns * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. * - * This function blocks until a preroll buffer or EOS is received or the appsink + * This function blocks until a preroll sample or EOS is received or the appsink * element is set to the READY/NULL state. * * Returns: a #GstBuffer or NULL when the appsink is stopped or EOS. * * Since: 0.10.22 */ -GstBuffer * +GstSample * gst_app_sink_pull_preroll (GstAppSink * appsink) { - GstBuffer *buf = NULL; + GstSample *sample = NULL; GstAppSinkPrivate *priv; g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL); @@ -1229,11 +1103,13 @@ gst_app_sink_pull_preroll (GstAppSink * appsink) GST_DEBUG_OBJECT (appsink, "waiting for the preroll buffer"); g_cond_wait (priv->cond, priv->mutex); } - buf = gst_buffer_ref (priv->preroll); - GST_DEBUG_OBJECT (appsink, "we have the preroll buffer %p", buf); + sample = + gst_sample_new (priv->preroll, priv->preroll_caps, &priv->last_segment, + NULL); + GST_DEBUG_OBJECT (appsink, "we have the preroll sample %p", sample); g_mutex_unlock (priv->mutex); - return buf; + return sample; /* special conditions */ eos: @@ -1251,16 +1127,16 @@ not_started: } /** - * gst_app_sink_pull_buffer: + * gst_app_sink_pull_sample: * @appsink: a #GstAppSink * - * This function blocks until a buffer or EOS becomes available or the appsink + * 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 buffers when the appsink is in the PLAYING + * 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 buffers at its own rate. Note that when the application does not - * pull buffers fast enough, the queued buffers could consume a lot of memory, + * 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 @@ -1271,37 +1147,57 @@ not_started: * Since: 0.10.22 */ -GstBuffer * -gst_app_sink_pull_buffer (GstAppSink * appsink) +GstSample * +gst_app_sink_pull_sample (GstAppSink * appsink) { - GST_DEBUG_OBJECT (appsink, "pull a buffer"); - return GST_BUFFER_CAST (gst_app_sink_pull_object (appsink)); -} + GstSample *sample = NULL; + GstBuffer *buffer; + GstAppSinkPrivate *priv; -/** - * gst_app_sink_pull_buffer_list: - * @appsink: a #GstAppSink - * - * This function blocks until a buffer list or EOS becomes available or the - * appsink element is set to the READY/NULL state. - * - * This function will only return buffer lists when the appsink is in the - * PLAYING state. All rendered buffer lists will be put in a queue so that - * the application can pull buffer lists at its own rate. Note that when - * the application does not pull buffer lists fast enough, the queued buffer - * lists could consume a lot of memory, especially when dealing with raw - * video frames. - * - * If an EOS event was received before any buffer lists, this function returns - * %NULL. Use gst_app_sink_is_eos () to check for the EOS condition. - * - * Returns: a #GstBufferList or NULL when the appsink is stopped or EOS. - */ -GstBufferList * -gst_app_sink_pull_buffer_list (GstAppSink * appsink) -{ - GST_DEBUG_OBJECT (appsink, "pull a buffer list"); - return GST_BUFFER_LIST_CAST (gst_app_sink_pull_object (appsink)); + g_return_val_if_fail (GST_IS_APP_SINK (appsink), NULL); + + priv = appsink->priv; + + g_mutex_lock (priv->mutex); + + while (TRUE) { + GST_DEBUG_OBJECT (appsink, "trying to grab a buffer"); + if (!priv->started) + goto not_started; + + if (priv->num_buffers == 0) + break; + + if (priv->is_eos) + goto eos; + + /* nothing to return, wait */ + GST_DEBUG_OBJECT (appsink, "waiting for a buffer"); + g_cond_wait (priv->cond, priv->mutex); + } + buffer = dequeue_buffer (appsink); + GST_DEBUG_OBJECT (appsink, "we have a buffer %p", buffer); + sample = gst_sample_new (buffer, priv->last_caps, &priv->last_segment, NULL); + gst_buffer_unref (buffer); + + g_cond_signal (priv->cond); + g_mutex_unlock (priv->mutex); + + return sample; + + /* special conditions */ +eos: + { + GST_DEBUG_OBJECT (appsink, "we are EOS, return NULL"); + g_mutex_unlock (priv->mutex); + return NULL; + } +not_started: + { + GST_DEBUG_OBJECT (appsink, "we are stopped, return NULL"); + g_mutex_unlock (priv->mutex); + return NULL; + } } /** @@ -1311,7 +1207,7 @@ gst_app_sink_pull_buffer_list (GstAppSink * appsink) * @user_data: a user_data argument for the callbacks * @notify: a destroy notify function * - * Set callbacks which will be executed for each new preroll, new buffer and eos. + * Set callbacks which will be executed for each new preroll, new sample and eos. * This is an alternative to using the signals, it has lower overhead and is thus * less expensive, but also less flexible. * @@ -1351,8 +1247,6 @@ gst_app_sink_set_callbacks (GstAppSink * appsink, priv->callbacks = *callbacks; priv->user_data = user_data; priv->notify = notify; - priv->buffer_lists_supported = - gst_app_sink_check_buffer_lists_support (appsink); GST_OBJECT_UNLOCK (appsink); } diff --git a/gst-libs/gst/app/gstappsink.h b/gst-libs/gst/app/gstappsink.h index 4bca82b67..5259dec6c 100644 --- a/gst-libs/gst/app/gstappsink.h +++ b/gst-libs/gst/app/gstappsink.h @@ -47,20 +47,15 @@ typedef struct _GstAppSinkPrivate GstAppSinkPrivate; * GstAppSinkCallbacks: * @eos: Called when the end-of-stream has been reached. This callback * is called from the steaming thread. - * @new_preroll: Called when a new preroll buffer is available. + * @new_preroll: Called when a new preroll sample is available. * This callback is called from the steaming thread. - * The new preroll buffer can be retrieved with + * The new preroll sample can be retrieved with * gst_app_sink_pull_preroll() either from this callback * or from any other thread. - * @new_buffer: Called when a new buffer is available. + * @new_sample: Called when a new sample is available. * This callback is called from the steaming thread. - * The new buffer can be retrieved with - * gst_app_sink_pull_buffer() either from this callback - * or from any other thread. - * @new_buffer_list: Called when a new bufferlist is available. - * This callback is called from the steaming thread. - * The new bufferlist can be retrieved with - * gst_app_sink_pull_buffer_list() either from this callback + * The new sample can be retrieved with + * gst_app_sink_pull_sample() either from this callback * or from any other thread. * * A set of callbacks that can be installed on the appsink with @@ -71,8 +66,7 @@ typedef struct _GstAppSinkPrivate GstAppSinkPrivate; typedef struct { void (*eos) (GstAppSink *sink, gpointer user_data); GstFlowReturn (*new_preroll) (GstAppSink *sink, gpointer user_data); - GstFlowReturn (*new_buffer) (GstAppSink *sink, gpointer user_data); - GstFlowReturn (*new_buffer_list) (GstAppSink *sink, gpointer user_data); + GstFlowReturn (*new_sample) (GstAppSink *sink, gpointer user_data); /*< private >*/ gpointer _gst_reserved[GST_PADDING]; @@ -96,13 +90,11 @@ struct _GstAppSinkClass /* signals */ void (*eos) (GstAppSink *sink); void (*new_preroll) (GstAppSink *sink); - void (*new_buffer) (GstAppSink *sink); - void (*new_buffer_list) (GstAppSink *sink); + void (*new_sample) (GstAppSink *sink); /* actions */ - GstBuffer * (*pull_preroll) (GstAppSink *sink); - GstBuffer * (*pull_buffer) (GstAppSink *sink); - GstBufferList * (*pull_buffer_list) (GstAppSink *sink); + GstSample * (*pull_preroll) (GstAppSink *sink); + GstSample * (*pull_sample) (GstAppSink *sink); /*< private >*/ gpointer _gst_reserved[GST_PADDING]; @@ -124,9 +116,8 @@ guint gst_app_sink_get_max_buffers (GstAppSink *appsink); void gst_app_sink_set_drop (GstAppSink *appsink, gboolean drop); gboolean gst_app_sink_get_drop (GstAppSink *appsink); -GstBuffer * gst_app_sink_pull_preroll (GstAppSink *appsink); -GstBuffer * gst_app_sink_pull_buffer (GstAppSink *appsink); -GstBufferList * gst_app_sink_pull_buffer_list (GstAppSink *appsink); +GstSample * gst_app_sink_pull_preroll (GstAppSink *appsink); +GstSample * gst_app_sink_pull_sample (GstAppSink *appsink); void gst_app_sink_set_callbacks (GstAppSink * appsink, GstAppSinkCallbacks *callbacks, diff --git a/gst-libs/gst/audio/gstaudiobasesink.c b/gst-libs/gst/audio/gstaudiobasesink.c index d7c1090a4..19a1c6536 100644 --- a/gst-libs/gst/audio/gstaudiobasesink.c +++ b/gst-libs/gst/audio/gstaudiobasesink.c @@ -318,7 +318,7 @@ gst_audio_base_sink_init (GstAudioBaseSink * audiobasesink) basesink->can_activate_push = TRUE; basesink->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL; - gst_base_sink_set_last_buffer_enabled (basesink, FALSE); + gst_base_sink_set_last_sample_enabled (basesink, FALSE); if (DEFAULT_PROVIDE_CLOCK) GST_OBJECT_FLAG_SET (basesink, GST_ELEMENT_FLAG_PROVIDE_CLOCK); else diff --git a/gst-libs/gst/video/convertframe.c b/gst-libs/gst/video/convertframe.c index 663924822..73dcfb1fc 100644 --- a/gst-libs/gst/video/convertframe.c +++ b/gst-libs/gst/video/convertframe.c @@ -144,13 +144,15 @@ build_convert_frame_pipeline (GstElement ** src_element, goto link_failed; GST_DEBUG ("linking csp->vscale"); - if (!gst_element_link_pads (csp, "src", vscale, "sink")) + if (!gst_element_link_pads_full (csp, "src", vscale, "sink", + GST_PAD_LINK_CHECK_NOTHING)) goto link_failed; if (caps_are_raw (to_caps)) { GST_DEBUG ("linking vscale->sink"); - if (!gst_element_link_pads (vscale, "src", sink, "sink")) + if (!gst_element_link_pads_full (vscale, "src", sink, "sink", + GST_PAD_LINK_CHECK_NOTHING)) goto link_failed; } else { encoder = get_encoder (to_caps, &error); @@ -230,9 +232,8 @@ link_failed: } /** - * gst_video_convert_frame: - * @buf: a #GstBuffer - * @from_caps: the #GstCaps to convert from + * gst_video_convert_sample: + * @sample: a #GstSample * @to_caps: the #GstCaps to convert to * @timeout: the maximum amount of time allowed for the processing. * @error: pointer to a #GError. Can be %NULL. @@ -243,29 +244,36 @@ link_failed: * * The width, height and pixel-aspect-ratio can also be specified in the output caps. * - * Returns: The converted #GstBuffer, or %NULL if an error happened (in which case @err + * Returns: The converted #GstSample, or %NULL if an error happened (in which case @err * will point to the #GError). * * Since: 0.10.31 * */ -GstBuffer * -gst_video_convert_frame (GstBuffer * buf, GstCaps * from_caps, - const GstCaps * to_caps, GstClockTime timeout, GError ** error) +GstSample * +gst_video_convert_sample (GstSample * sample, const GstCaps * to_caps, + GstClockTime timeout, GError ** error) { GstMessage *msg; - GstBuffer *result = NULL; + GstBuffer *buf; + GstSample *result = NULL; GError *err = NULL; GstBus *bus; - GstCaps *to_caps_copy = NULL; + GstCaps *from_caps, *to_caps_copy = NULL; GstFlowReturn ret; GstElement *pipeline, *src, *sink; guint i, n; - g_return_val_if_fail (buf != NULL, NULL); + g_return_val_if_fail (sample != NULL, NULL); g_return_val_if_fail (to_caps != NULL, NULL); + + buf = gst_sample_get_buffer (sample); + g_return_val_if_fail (buf != NULL, NULL); + + from_caps = gst_sample_get_caps (sample); g_return_val_if_fail (from_caps != NULL, NULL); + to_caps_copy = gst_caps_new_empty (); n = gst_caps_get_size (to_caps); for (i = 0; i < n; i++) { @@ -364,28 +372,30 @@ typedef struct { GMutex *mutex; GstElement *pipeline; - GstVideoConvertFrameCallback callback; + GstVideoConvertSampleCallback callback; gpointer user_data; GDestroyNotify destroy_notify; GMainContext *context; - GstBuffer *buffer; + GstSample *sample; + //GstBuffer *buffer; gulong timeout_id; gboolean finished; -} GstVideoConvertFrameContext; +} GstVideoConvertSampleContext; typedef struct { - GstVideoConvertFrameCallback callback; - GstBuffer *buffer; + GstVideoConvertSampleCallback callback; + GstSample *sample; + //GstBuffer *buffer; GError *error; gpointer user_data; GDestroyNotify destroy_notify; - GstVideoConvertFrameContext *context; -} GstVideoConvertFrameCallbackContext; + GstVideoConvertSampleContext *context; +} GstVideoConvertSampleCallbackContext; static void -gst_video_convert_frame_context_free (GstVideoConvertFrameContext * ctx) +gst_video_convert_frame_context_free (GstVideoConvertSampleContext * ctx) { /* Wait until all users of the mutex are done */ g_mutex_lock (ctx->mutex); @@ -393,29 +403,31 @@ gst_video_convert_frame_context_free (GstVideoConvertFrameContext * ctx) g_mutex_free (ctx->mutex); if (ctx->timeout_id) g_source_remove (ctx->timeout_id); - if (ctx->buffer) - gst_buffer_unref (ctx->buffer); + //if (ctx->buffer) + // gst_buffer_unref (ctx->buffer); + if (ctx->sample) + gst_sample_unref (ctx->sample); g_main_context_unref (ctx->context); gst_element_set_state (ctx->pipeline, GST_STATE_NULL); gst_object_unref (ctx->pipeline); - g_slice_free (GstVideoConvertFrameContext, ctx); + g_slice_free (GstVideoConvertSampleContext, ctx); } static void gst_video_convert_frame_callback_context_free - (GstVideoConvertFrameCallbackContext * ctx) + (GstVideoConvertSampleCallbackContext * ctx) { if (ctx->context) gst_video_convert_frame_context_free (ctx->context); - g_slice_free (GstVideoConvertFrameCallbackContext, ctx); + g_slice_free (GstVideoConvertSampleCallbackContext, ctx); } static gboolean -convert_frame_dispatch_callback (GstVideoConvertFrameCallbackContext * ctx) +convert_frame_dispatch_callback (GstVideoConvertSampleCallbackContext * ctx) { - ctx->callback (ctx->buffer, ctx->error, ctx->user_data); + ctx->callback (ctx->sample, ctx->error, ctx->user_data); if (ctx->destroy_notify) ctx->destroy_notify (ctx->user_data); @@ -424,21 +436,22 @@ convert_frame_dispatch_callback (GstVideoConvertFrameCallbackContext * ctx) } static void -convert_frame_finish (GstVideoConvertFrameContext * context, GstBuffer * buffer, - GError * error) +convert_frame_finish (GstVideoConvertSampleContext * context, + GstSample * sample, GError * error) { GSource *source; - GstVideoConvertFrameCallbackContext *ctx; + GstVideoConvertSampleCallbackContext *ctx; if (context->timeout_id) g_source_remove (context->timeout_id); context->timeout_id = 0; - ctx = g_slice_new (GstVideoConvertFrameCallbackContext); + ctx = g_slice_new (GstVideoConvertSampleCallbackContext); ctx->callback = context->callback; ctx->user_data = context->user_data; ctx->destroy_notify = context->destroy_notify; - ctx->buffer = buffer; + ctx->sample = sample; + //ctx->buffer = buffer; ctx->error = error; ctx->context = context; @@ -453,7 +466,7 @@ convert_frame_finish (GstVideoConvertFrameContext * context, GstBuffer * buffer, } static gboolean -convert_frame_timeout_callback (GstVideoConvertFrameContext * context) +convert_frame_timeout_callback (GstVideoConvertSampleContext * context) { GError *error; @@ -476,7 +489,7 @@ done: static gboolean convert_frame_bus_callback (GstBus * bus, GstMessage * message, - GstVideoConvertFrameContext * context) + GstVideoConvertSampleContext * context) { g_mutex_lock (context->mutex); @@ -510,19 +523,21 @@ done: static void convert_frame_need_data_callback (GstElement * src, guint size, - GstVideoConvertFrameContext * context) + GstVideoConvertSampleContext * context) { GstFlowReturn ret = GST_FLOW_ERROR; GError *error; + GstBuffer *buffer; g_mutex_lock (context->mutex); if (context->finished) goto done; - g_signal_emit_by_name (src, "push-buffer", context->buffer, &ret); - gst_buffer_unref (context->buffer); - context->buffer = NULL; + buffer = gst_sample_get_buffer (context->sample); + g_signal_emit_by_name (src, "push-buffer", buffer, &ret); + gst_sample_unref (context->sample); + context->sample = NULL; if (ret != GST_FLOW_OK) { GST_ERROR ("Could not push video frame: %s", gst_flow_get_name (ret)); @@ -541,10 +556,10 @@ done: } static void -convert_frame_new_buffer_callback (GstElement * sink, - GstVideoConvertFrameContext * context) +convert_frame_new_preroll_callback (GstElement * sink, + GstVideoConvertSampleContext * context) { - GstBuffer *buf = NULL; + GstSample *sample = NULL; GError *error = NULL; g_mutex_lock (context->mutex); @@ -552,14 +567,13 @@ convert_frame_new_buffer_callback (GstElement * sink, if (context->finished) goto done; - g_signal_emit_by_name (sink, "pull-preroll", &buf); + g_signal_emit_by_name (sink, "pull-preroll", &sample); - if (!buf) { + if (!sample) { error = g_error_new (GST_CORE_ERROR, GST_CORE_ERROR_FAILED, - "Could not get converted video frame"); + "Could not get converted video sample"); } - - convert_frame_finish (context, buf, error); + convert_frame_finish (context, sample, error); g_signal_handlers_disconnect_by_func (sink, convert_frame_need_data_callback, context); @@ -569,12 +583,11 @@ done: } /** - * gst_video_convert_frame_async: - * @buf: a #GstBuffer - * @from_caps: the #GstCaps to convert from + * gst_video_convert_sample_async: + * @sample: a #GstSample * @to_caps: the #GstCaps to convert to * @timeout: the maximum amount of time allowed for the processing. - * @callback: %GstVideoConvertFrameCallback that will be called after conversion. + * @callback: %GstVideoConvertSampleCallback that will be called after conversion. * @user_data: extra data that will be passed to the @callback * @destroy_notify: %GDestroyNotify to be called after @user_data is not needed anymore * @@ -596,22 +609,28 @@ done: * */ void -gst_video_convert_frame_async (GstBuffer * buf, GstCaps * from_caps, +gst_video_convert_sample_async (GstSample * sample, const GstCaps * to_caps, GstClockTime timeout, - GstVideoConvertFrameCallback callback, gpointer user_data, + GstVideoConvertSampleCallback callback, gpointer user_data, GDestroyNotify destroy_notify) { GMainContext *context = NULL; GError *error = NULL; GstBus *bus; - GstCaps *to_caps_copy = NULL; + GstBuffer *buf; + GstCaps *from_caps, *to_caps_copy = NULL; GstElement *pipeline, *src, *sink; guint i, n; GSource *source; - GstVideoConvertFrameContext *ctx; + GstVideoConvertSampleContext *ctx; + g_return_if_fail (sample != NULL); + buf = gst_sample_get_buffer (sample); g_return_if_fail (buf != NULL); + g_return_if_fail (to_caps != NULL); + + from_caps = gst_sample_get_caps (sample); g_return_if_fail (from_caps != NULL); g_return_if_fail (callback != NULL); @@ -638,9 +657,10 @@ gst_video_convert_frame_async (GstBuffer * buf, GstCaps * from_caps, bus = gst_element_get_bus (pipeline); - ctx = g_slice_new0 (GstVideoConvertFrameContext); + ctx = g_slice_new0 (GstVideoConvertSampleContext); ctx->mutex = g_mutex_new (); - ctx->buffer = gst_buffer_ref (buf); + //ctx->buffer = gst_buffer_ref (buf); + ctx->sample = gst_sample_ref (sample); ctx->callback = callback; ctx->user_data = user_data; ctx->destroy_notify = destroy_notify; @@ -659,7 +679,7 @@ gst_video_convert_frame_async (GstBuffer * buf, GstCaps * from_caps, g_signal_connect (src, "need-data", G_CALLBACK (convert_frame_need_data_callback), ctx); g_signal_connect (sink, "new-preroll", - G_CALLBACK (convert_frame_new_buffer_callback), ctx); + G_CALLBACK (convert_frame_new_preroll_callback), ctx); source = gst_bus_create_watch (bus); g_source_set_callback (source, (GSourceFunc) convert_frame_bus_callback, @@ -676,16 +696,16 @@ gst_video_convert_frame_async (GstBuffer * buf, GstCaps * from_caps, /* ERRORS */ no_pipeline: { - GstVideoConvertFrameCallbackContext *ctx; + GstVideoConvertSampleCallbackContext *ctx; GSource *source; gst_caps_unref (to_caps_copy); - ctx = g_slice_new0 (GstVideoConvertFrameCallbackContext); + ctx = g_slice_new0 (GstVideoConvertSampleCallbackContext); ctx->callback = callback; ctx->user_data = user_data; ctx->destroy_notify = destroy_notify; - ctx->buffer = NULL; + ctx->sample = NULL; ctx->error = error; source = g_timeout_source_new (0); diff --git a/gst-libs/gst/video/video.h b/gst-libs/gst/video/video.h index 42a2024e4..57dff7ac6 100644 --- a/gst-libs/gst/video/video.h +++ b/gst-libs/gst/video/video.h @@ -705,20 +705,18 @@ GstEvent * gst_video_event_new_still_frame (gboolean in_still); gboolean gst_video_event_parse_still_frame (GstEvent * event, gboolean * in_still); -/* convert/encode video frame from one format to another */ +/* convert/encode video sample from one format to another */ -typedef void (*GstVideoConvertFrameCallback) (GstBuffer * buf, GError *error, gpointer user_data); +typedef void (*GstVideoConvertSampleCallback) (GstSample * sample, GError *error, gpointer user_data); -void gst_video_convert_frame_async (GstBuffer * buf, - GstCaps * from_caps, +void gst_video_convert_sample_async (GstSample * sample, const GstCaps * to_caps, GstClockTime timeout, - GstVideoConvertFrameCallback callback, + GstVideoConvertSampleCallback callback, gpointer user_data, GDestroyNotify destroy_notify); -GstBuffer * gst_video_convert_frame (GstBuffer * buf, - GstCaps * from_caps, +GstSample * gst_video_convert_sample (GstSample * sample, const GstCaps * to_caps, GstClockTime timeout, GError ** error); diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index b99c28c46..f29ce8eeb 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -44,7 +44,7 @@ * meta info (tag) extraction * </listitem> * <listitem> - * easy access to the last video frame + * easy access to the last video sample * </listitem> * <listitem> * buffering when playing streams over a network @@ -436,8 +436,8 @@ struct _GstPlayBinClass GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream); GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream); - /* get the last video frame and convert it to the given caps */ - GstBuffer *(*convert_frame) (GstPlayBin * playbin, GstCaps * caps); + /* get the last video sample and convert it to the given caps */ + GstSample *(*convert_sample) (GstPlayBin * playbin, GstCaps * caps); /* get audio/video/text pad for a stream */ GstPad *(*get_video_pad) (GstPlayBin * playbin, gint stream); @@ -491,7 +491,7 @@ enum PROP_TEXT_SINK, PROP_VOLUME, PROP_MUTE, - PROP_FRAME, + PROP_SAMPLE, PROP_FONT_DESC, PROP_CONNECTION_SPEED, PROP_BUFFER_SIZE, @@ -505,7 +505,7 @@ enum enum { SIGNAL_ABOUT_TO_FINISH, - SIGNAL_CONVERT_FRAME, + SIGNAL_CONVERT_SAMPLE, SIGNAL_VIDEO_CHANGED, SIGNAL_AUDIO_CHANGED, SIGNAL_TEXT_CHANGED, @@ -544,7 +544,7 @@ static GstTagList *gst_play_bin_get_audio_tags (GstPlayBin * playbin, static GstTagList *gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream); -static GstBuffer *gst_play_bin_convert_frame (GstPlayBin * playbin, +static GstSample *gst_play_bin_convert_sample (GstPlayBin * playbin, GstCaps * caps); static GstPad *gst_play_bin_get_video_pad (GstPlayBin * playbin, gint stream); @@ -756,16 +756,17 @@ gst_play_bin_class_init (GstPlayBinClass * klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstPlayBin:frame: + * GstPlayBin:sample: * @playbin: a #GstPlayBin * - * Get the currently rendered or prerolled frame in the video sink. - * The #GstCaps on the buffer will describe the format of the buffer. + * Get the currently rendered or prerolled sample in the video sink. + * The #GstCaps in the sample will describe the format of the buffer. */ - g_object_class_install_property (gobject_klass, PROP_FRAME, - g_param_spec_boxed ("frame", "Frame", - "The last frame (NULL = no video available)", - GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_klass, PROP_SAMPLE, + g_param_spec_boxed ("sample", "Sample", + "The last sample (NULL = no video available)", + GST_TYPE_SAMPLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_klass, PROP_FONT_DESC, g_param_spec_string ("subtitle-font-desc", "Subtitle font description", @@ -1019,7 +1020,7 @@ gst_play_bin_class_init (GstPlayBinClass * klass) G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL, gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT); /** - * GstPlayBin::convert-frame + * GstPlayBin::convert-sample * @playbin: a #GstPlayBin * @caps: the target format of the frame * @@ -1033,11 +1034,11 @@ gst_play_bin_class_init (GstPlayBinClass * klass) * %NULL is returned when no current buffer can be retrieved or when the * conversion failed. */ - gst_play_bin_signals[SIGNAL_CONVERT_FRAME] = - g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass), + gst_play_bin_signals[SIGNAL_CONVERT_SAMPLE] = + g_signal_new ("convert-sample", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstPlayBinClass, convert_frame), NULL, NULL, - gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS); + G_STRUCT_OFFSET (GstPlayBinClass, convert_sample), NULL, NULL, + gst_play_marshal_SAMPLE__BOXED, GST_TYPE_SAMPLE, 1, GST_TYPE_CAPS); /** * GstPlayBin::get-video-pad @@ -1095,7 +1096,7 @@ gst_play_bin_class_init (GstPlayBinClass * klass) klass->get_audio_tags = gst_play_bin_get_audio_tags; klass->get_text_tags = gst_play_bin_get_text_tags; - klass->convert_frame = gst_play_bin_convert_frame; + klass->convert_sample = gst_play_bin_convert_sample; klass->get_video_pad = gst_play_bin_get_video_pad; klass->get_audio_pad = gst_play_bin_get_audio_pad; @@ -1524,10 +1525,10 @@ gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream) return result; } -static GstBuffer * -gst_play_bin_convert_frame (GstPlayBin * playbin, GstCaps * caps) +static GstSample * +gst_play_bin_convert_sample (GstPlayBin * playbin, GstCaps * caps) { - return gst_play_sink_convert_frame (playbin->playsink, caps); + return gst_play_sink_convert_sample (playbin->playsink, caps); } /* Returns current stream number, or -1 if none has been selected yet */ @@ -2104,9 +2105,9 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value, case PROP_MUTE: g_value_set_boolean (value, gst_play_sink_get_mute (playbin->playsink)); break; - case PROP_FRAME: - gst_value_take_buffer (value, - gst_play_sink_get_last_frame (playbin->playsink)); + case PROP_SAMPLE: + gst_value_take_sample (value, + gst_play_sink_get_last_sample (playbin->playsink)); break; case PROP_FONT_DESC: g_value_take_string (value, diff --git a/gst/playback/gstplaysink.c b/gst/playback/gstplaysink.c index 0259204e0..9f5335353 100644 --- a/gst/playback/gstplaysink.c +++ b/gst/playback/gstplaysink.c @@ -210,7 +210,7 @@ struct _GstPlaySinkClass gboolean (*reconfigure) (GstPlaySink * playsink); - GstBuffer *(*convert_frame) (GstPlaySink * playsink, GstCaps * caps); + GstSample *(*convert_sample) (GstPlaySink * playsink, GstCaps * caps); }; @@ -252,7 +252,7 @@ enum PROP_FONT_DESC, PROP_SUBTITLE_ENCODING, PROP_VIS_PLUGIN, - PROP_FRAME, + PROP_SAMPLE, PROP_AV_OFFSET, PROP_VIDEO_SINK, PROP_AUDIO_SINK, @@ -292,18 +292,18 @@ static void notify_mute_cb (GObject * object, GParamSpec * pspec, static void update_av_offset (GstPlaySink * playsink); void -gst_play_marshal_BUFFER__BOXED (GClosure * closure, +gst_play_marshal_SAMPLE__BOXED (GClosure * closure, GValue * return_value G_GNUC_UNUSED, guint n_param_values, const GValue * param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { - typedef GstBuffer *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1, + typedef GstSample *(*GMarshalFunc_OBJECT__BOXED) (gpointer data1, gpointer arg_1, gpointer data2); register GMarshalFunc_OBJECT__BOXED callback; register GCClosure *cc = (GCClosure *) closure; register gpointer data1, data2; - GstBuffer *v_return; + GstSample *v_return; g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values == 2); @@ -319,7 +319,7 @@ gst_play_marshal_BUFFER__BOXED (GClosure * closure, v_return = callback (data1, g_value_get_boxed (param_values + 1), data2); - gst_value_take_buffer (return_value, v_return); + gst_value_take_sample (return_value, v_return); } /* static guint gst_play_sink_signals[LAST_SIGNAL] = { 0 }; */ @@ -386,17 +386,15 @@ gst_play_sink_class_init (GstPlaySinkClass * klass) "the visualization element to use (NULL = default)", GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** - * GstPlaySink:frame: + * GstPlaySink:sample: * - * Get the currently rendered or prerolled frame in the video sink. - * The #GstCaps on the buffer will describe the format of the buffer. - * - * Since: 0.10.30 + * Get the currently rendered or prerolled sample in the video sink. + * The #GstCaps in the sample will describe the format of the buffer. */ - g_object_class_install_property (gobject_klass, PROP_FRAME, - g_param_spec_boxed ("frame", "Frame", - "The last frame (NULL = no video available)", - GST_TYPE_BUFFER, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_klass, PROP_SAMPLE, + g_param_spec_boxed ("sample", "Sample", + "The last sample (NULL = no video available)", + GST_TYPE_SAMPLE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GstPlaySink:av-offset: * @@ -455,26 +453,24 @@ gst_play_sink_class_init (GstPlaySinkClass * klass) reconfigure), NULL, NULL, gst_marshal_BOOLEAN__VOID, G_TYPE_BOOLEAN, 0, G_TYPE_NONE); /** - * GstPlaySink::convert-frame + * GstPlaySink::convert-sample * @playsink: a #GstPlaySink - * @caps: the target format of the frame + * @caps: the target format of the sample * - * Action signal to retrieve the currently playing video frame in the format + * Action signal to retrieve the currently playing video sample in the format * specified by @caps. * If @caps is %NULL, no conversion will be performed and this function is - * equivalent to the #GstPlaySink::frame property. + * equivalent to the #GstPlaySink::sample property. * - * Returns: a #GstBuffer of the current video frame converted to #caps. - * The caps on the buffer will describe the final layout of the buffer data. - * %NULL is returned when no current buffer can be retrieved or when the + * Returns: a #GstSample of the current video sample converted to #caps. + * The caps in the sample will describe the final layout of the buffer data. + * %NULL is returned when no current sample can be retrieved or when the * conversion failed. - * - * Since: 0.10.30 */ - g_signal_new ("convert-frame", G_TYPE_FROM_CLASS (klass), + g_signal_new ("convert-sample", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstPlaySinkClass, convert_frame), NULL, NULL, - gst_play_marshal_BUFFER__BOXED, GST_TYPE_BUFFER, 1, GST_TYPE_CAPS); + G_STRUCT_OFFSET (GstPlaySinkClass, convert_sample), NULL, NULL, + gst_play_marshal_SAMPLE__BOXED, GST_TYPE_SAMPLE, 1, GST_TYPE_CAPS); gst_element_class_add_pad_template (gstelement_klass, gst_static_pad_template_get (&audiorawtemplate)); @@ -503,7 +499,7 @@ gst_play_sink_class_init (GstPlaySinkClass * klass) GST_DEBUG_FUNCPTR (gst_play_sink_handle_message); klass->reconfigure = GST_DEBUG_FUNCPTR (gst_play_sink_reconfigure); - klass->convert_frame = GST_DEBUG_FUNCPTR (gst_play_sink_convert_frame); + klass->convert_sample = GST_DEBUG_FUNCPTR (gst_play_sink_convert_sample); } static void @@ -2797,24 +2793,24 @@ gst_play_sink_get_av_offset (GstPlaySink * playsink) } /** - * gst_play_sink_get_last_frame: + * gst_play_sink_get_last_sample: * @playsink: a #GstPlaySink * - * Get the last displayed frame from @playsink. This frame is in the native - * format of the sink element, the caps on the result buffer contain the format + * Get the last displayed sample from @playsink. This sample is in the native + * format of the sink element, the caps in the result sample contain the format * of the frame data. * - * Returns: a #GstBuffer with the frame data or %NULL when no video frame is + * Returns: a #GstSample with the frame data or %NULL when no video frame is * available. */ -GstBuffer * -gst_play_sink_get_last_frame (GstPlaySink * playsink) +GstSample * +gst_play_sink_get_last_sample (GstPlaySink * playsink) { - GstBuffer *result = NULL; + GstSample *result = NULL; GstPlayVideoChain *chain; GST_PLAY_SINK_LOCK (playsink); - GST_DEBUG_OBJECT (playsink, "taking last frame"); + GST_DEBUG_OBJECT (playsink, "taking last sample"); /* get the video chain if we can */ if ((chain = (GstPlayVideoChain *) playsink->videochain)) { GST_DEBUG_OBJECT (playsink, "found video chain"); @@ -2827,9 +2823,9 @@ gst_play_sink_get_last_frame (GstPlaySink * playsink) /* find and get the last-buffer property now */ if ((elem = gst_play_sink_find_property (playsink, chain->sink, - "last-buffer", GST_TYPE_BUFFER))) { - GST_DEBUG_OBJECT (playsink, "getting last-buffer property"); - g_object_get (elem, "last-buffer", &result, NULL); + "last-sample", GST_TYPE_SAMPLE))) { + GST_DEBUG_OBJECT (playsink, "getting last-sample property"); + g_object_get (elem, "last-sample", &result, NULL); gst_object_unref (elem); } } @@ -2840,7 +2836,7 @@ gst_play_sink_get_last_frame (GstPlaySink * playsink) } /** - * gst_play_sink_convert_frame: + * gst_play_sink_convert_sample: * @playsink: a #GstPlaySink * @caps: a #GstCaps * @@ -2852,28 +2848,36 @@ gst_play_sink_get_last_frame (GstPlaySink * playsink) * Returns: a #GstBuffer with the frame data or %NULL when no video frame is * available or when the conversion failed. */ -GstBuffer * -gst_play_sink_convert_frame (GstPlaySink * playsink, GstCaps * caps) +GstSample * +gst_play_sink_convert_sample (GstPlaySink * playsink, GstCaps * caps) { - GstBuffer *result; + GstSample *result; + GError *err = NULL; - result = gst_play_sink_get_last_frame (playsink); + result = gst_play_sink_get_last_sample (playsink); if (result != NULL && caps != NULL) { - GstBuffer *temp; - GError *err = NULL; - - /* FIXME, need to get the input buffer caps */ - temp = gst_video_convert_frame (result, NULL, caps, 25 * GST_SECOND, &err); - gst_buffer_unref (result); - if (temp == NULL && err) { - /* I'm really uncertain whether we should make playsink post an error - * on the bus or not. It's not like it's a critical issue regarding - * playsink behaviour. */ - GST_ERROR ("Error converting frame: %s", err->message); - } + GstSample *temp; + + temp = gst_video_convert_sample (result, caps, 25 * GST_SECOND, &err); + if (temp == NULL && err) + goto error; + + gst_sample_unref (result); result = temp; } return result; + + /* ERRORS */ +error: + { + /* I'm really uncertain whether we should make playsink post an error + * on the bus or not. It's not like it's a critical issue regarding + * playsink behaviour. */ + GST_ERROR ("Error converting frame: %s", err->message); + gst_sample_unref (result); + g_error_free (err); + return NULL; + } } static gboolean @@ -3700,8 +3704,8 @@ gst_play_sink_get_property (GObject * object, guint prop_id, case PROP_VIS_PLUGIN: g_value_take_object (value, gst_play_sink_get_vis_plugin (playsink)); break; - case PROP_FRAME: - gst_value_take_buffer (value, gst_play_sink_get_last_frame (playsink)); + case PROP_SAMPLE: + gst_value_take_sample (value, gst_play_sink_get_last_sample (playsink)); break; case PROP_AV_OFFSET: g_value_set_int64 (value, gst_play_sink_get_av_offset (playsink)); diff --git a/gst/playback/gstplaysink.h b/gst/playback/gstplaysink.h index 6759ea438..51fe14b74 100644 --- a/gst/playback/gstplaysink.h +++ b/gst/playback/gstplaysink.h @@ -94,15 +94,15 @@ gchar * gst_play_sink_get_subtitle_encoding (GstPlaySink *playsink); void gst_play_sink_set_av_offset (GstPlaySink *playsink, gint64 av_offset); gint64 gst_play_sink_get_av_offset (GstPlaySink *playsink); -GstBuffer * gst_play_sink_get_last_frame (GstPlaySink * playsink); -GstBuffer * gst_play_sink_convert_frame (GstPlaySink * playsink, GstCaps * caps); +GstSample * gst_play_sink_get_last_sample (GstPlaySink * playsink); +GstSample * gst_play_sink_convert_sample (GstPlaySink * playsink, GstCaps * caps); gboolean gst_play_sink_reconfigure (GstPlaySink * playsink); gboolean gst_play_sink_plugin_init (GstPlugin * plugin); void -gst_play_marshal_BUFFER__BOXED (GClosure * closure, +gst_play_marshal_SAMPLE__BOXED (GClosure * closure, GValue * return_value G_GNUC_UNUSED, guint n_param_values, const GValue * param_values, diff --git a/tests/check/libs/video.c b/tests/check/libs/video.c index 67198239c..1d826f064 100644 --- a/tests/check/libs/video.c +++ b/tests/check/libs/video.c @@ -667,7 +667,8 @@ GST_START_TEST (test_convert_frame) { GstVideoInfo vinfo; GstCaps *from_caps, *to_caps; - GstBuffer *from_buffer, *to_buffer; + GstBuffer *from_buffer; + GstSample *from_sample, *to_sample; GError *error = NULL; gint i; guint8 *data; @@ -693,14 +694,16 @@ GST_START_TEST (test_convert_frame) vinfo.par_d = 1; from_caps = gst_video_info_to_caps (&vinfo); + from_sample = gst_sample_new (from_buffer, from_caps, NULL, NULL); + to_caps = gst_caps_from_string ("something/that, does=(string)not, exist=(boolean)FALSE"); - to_buffer = - gst_video_convert_frame (from_buffer, from_caps, to_caps, + to_sample = + gst_video_convert_sample (from_sample, to_caps, GST_CLOCK_TIME_NONE, &error); - fail_if (to_buffer != NULL); + fail_if (to_sample != NULL); fail_unless (error != NULL); g_error_free (error); error = NULL; @@ -713,15 +716,16 @@ GST_START_TEST (test_convert_frame) vinfo.par_d = 2; to_caps = gst_video_info_to_caps (&vinfo); - to_buffer = - gst_video_convert_frame (from_buffer, from_caps, to_caps, + to_sample = + gst_video_convert_sample (from_sample, to_caps, GST_CLOCK_TIME_NONE, &error); - fail_unless (to_buffer != NULL); + fail_unless (to_sample != NULL); fail_unless (error == NULL); gst_buffer_unref (from_buffer); gst_caps_unref (from_caps); - gst_buffer_unref (to_buffer); + gst_sample_unref (from_sample); + gst_sample_unref (to_sample); gst_caps_unref (to_caps); } @@ -730,15 +734,15 @@ GST_END_TEST; typedef struct { GMainLoop *loop; - GstBuffer *buffer; + GstSample *sample; GError *error; } ConvertFrameContext; static void -convert_frame_async_callback (GstBuffer * buf, GError * err, +convert_sample_async_callback (GstSample * sample, GError * err, ConvertFrameContext * cf_data) { - cf_data->buffer = buf; + cf_data->sample = sample; cf_data->error = err; g_main_loop_quit (cf_data->loop); @@ -749,6 +753,7 @@ GST_START_TEST (test_convert_frame_async) GstVideoInfo vinfo; GstCaps *from_caps, *to_caps; GstBuffer *from_buffer; + GstSample *from_sample; gint i; guint8 *data; GMainLoop *loop; @@ -781,14 +786,18 @@ GST_START_TEST (test_convert_frame_async) loop = cf_data.loop = g_main_loop_new (NULL, FALSE); - gst_video_convert_frame_async (from_buffer, from_caps, to_caps, + from_sample = gst_sample_new (from_buffer, from_caps, NULL, NULL); + gst_buffer_unref (from_buffer); + gst_caps_unref (from_caps); + + gst_video_convert_sample_async (from_sample, to_caps, GST_CLOCK_TIME_NONE, - (GstVideoConvertFrameCallback) convert_frame_async_callback, &cf_data, + (GstVideoConvertSampleCallback) convert_sample_async_callback, &cf_data, NULL); g_main_loop_run (loop); - fail_if (cf_data.buffer != NULL); + fail_if (cf_data.sample != NULL); fail_unless (cf_data.error != NULL); g_error_free (cf_data.error); cf_data.error = NULL; @@ -801,17 +810,15 @@ GST_START_TEST (test_convert_frame_async) vinfo.fps_n = 25; vinfo.fps_d = 1; to_caps = gst_video_info_to_caps (&vinfo); - gst_video_convert_frame_async (from_buffer, from_caps, to_caps, + gst_video_convert_sample_async (from_sample, to_caps, GST_CLOCK_TIME_NONE, - (GstVideoConvertFrameCallback) convert_frame_async_callback, &cf_data, + (GstVideoConvertSampleCallback) convert_sample_async_callback, &cf_data, NULL); g_main_loop_run (loop); - fail_unless (cf_data.buffer != NULL); + fail_unless (cf_data.sample != NULL); fail_unless (cf_data.error == NULL); - gst_buffer_unref (from_buffer); - gst_caps_unref (from_caps); - gst_buffer_unref (cf_data.buffer); + gst_sample_unref (cf_data.sample); gst_caps_unref (to_caps); g_main_loop_unref (loop); diff --git a/tests/examples/app/appsink-src.c b/tests/examples/app/appsink-src.c index 9772e8adb..8f8ae0a6d 100644 --- a/tests/examples/app/appsink-src.c +++ b/tests/examples/app/appsink-src.c @@ -19,25 +19,21 @@ typedef struct /* called when the appsink notifies us that there is a new buffer ready for * processing */ static void -on_new_buffer_from_source (GstElement * elt, ProgramData * data) +on_new_sample_from_sink (GstElement * elt, ProgramData * data) { - guint size; + GstSample *sample; GstBuffer *app_buffer, *buffer; GstElement *source; - /* get the buffer from appsink */ - buffer = gst_app_sink_pull_buffer (GST_APP_SINK (elt)); + /* get the sample from appsink */ + sample = gst_app_sink_pull_sample (GST_APP_SINK (elt)); + buffer = gst_sample_get_buffer (sample); - /* turn it into an app buffer, it's not really needed, we could simply push - * the retrieved buffer from appsink into appsrc just fine. */ - size = gst_buffer_get_size (buffer); - g_print ("Pushing a buffer of size %d\n", size); - app_buffer = gst_buffer_new_and_alloc (size); + /* make a copy */ + app_buffer = gst_buffer_copy (buffer); - gst_buffer_copy_into (app_buffer, buffer, GST_BUFFER_COPY_MEMORY, 0, size); - - /* we don't need the appsink buffer anymore */ - gst_buffer_unref (buffer); + /* we don't need the appsink sample anymore */ + gst_sample_unref (sample); /* get source an push new buffer */ source = gst_bin_get_by_name (GST_BIN (data->sink), "testsource"); @@ -134,8 +130,8 @@ main (int argc, char *argv[]) * push as fast as it can, hence the sync=false */ testsink = gst_bin_get_by_name (GST_BIN (data->source), "testsink"); g_object_set (G_OBJECT (testsink), "emit-signals", TRUE, "sync", FALSE, NULL); - g_signal_connect (testsink, "new-buffer", - G_CALLBACK (on_new_buffer_from_source), data); + g_signal_connect (testsink, "new-sample", + G_CALLBACK (on_new_sample_from_sink), data); gst_object_unref (testsink); /* setting up sink pipeline, we push audio data into this pipeline that will diff --git a/tests/examples/app/appsrc_ex.c b/tests/examples/app/appsrc_ex.c index 5468a667c..7dacbbb55 100644 --- a/tests/examples/app/appsrc_ex.c +++ b/tests/examples/app/appsrc_ex.c @@ -71,14 +71,14 @@ main (int argc, char *argv[]) /* _is_eos() does not block and returns TRUE if there is not currently an EOS * to be retrieved */ while (!gst_app_sink_is_eos (GST_APP_SINK (app->sink))) { - GstBuffer *buf; + GstSample *sample; /* pull the next item, this can return NULL when there is no more data and * EOS has been received */ - buf = gst_app_sink_pull_buffer (GST_APP_SINK (app->sink)); - printf ("retrieved buffer %p\n", buf); - if (buf) - gst_buffer_unref (buf); + sample = gst_app_sink_pull_sample (GST_APP_SINK (app->sink)); + printf ("retrieved sample %p\n", sample); + if (sample) + gst_sample_unref (sample); } gst_element_set_state (app->pipe, GST_STATE_NULL); diff --git a/tests/examples/seek/seek.c b/tests/examples/seek/seek.c index d06e4dea9..86d766359 100644 --- a/tests/examples/seek/seek.c +++ b/tests/examples/seek/seek.c @@ -1143,26 +1143,24 @@ volume_notify_cb (GstElement * pipeline, GParamSpec * arg, gpointer user_dat) static void shot_cb (GtkButton * button, gpointer data) { - GstBuffer *buffer; + GstSample *sample = NULL; GstCaps *caps; + GST_DEBUG ("taking snapshot"); + /* convert to our desired format (RGB24) */ - caps = gst_caps_new_simple ("video/x-raw-rgb", - "bpp", G_TYPE_INT, 24, "depth", G_TYPE_INT, 24, + caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "RGB", /* Note: we don't ask for a specific width/height here, so that * videoscale can adjust dimensions from a non-1/1 pixel aspect * ratio to a 1/1 pixel-aspect-ratio */ - "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, - "endianness", G_TYPE_INT, G_BIG_ENDIAN, - "red_mask", G_TYPE_INT, 0xff0000, - "green_mask", G_TYPE_INT, 0x00ff00, - "blue_mask", G_TYPE_INT, 0x0000ff, NULL); - - /* convert the latest frame to the requested format */ - g_signal_emit_by_name (pipeline, "convert-frame", caps, &buffer); + "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL); + + /* convert the latest sample to the requested format */ + g_signal_emit_by_name (pipeline, "convert-sample", caps, &sample); gst_caps_unref (caps); - if (buffer) { + if (sample) { + GstBuffer *buffer; GstCaps *caps; GstStructure *s; gboolean res; @@ -1176,11 +1174,7 @@ shot_cb (GtkButton * button, gpointer data) * that it can only be an rgb buffer. The only thing we have not specified * on the caps is the height, which is dependant on the pixel-aspect-ratio * of the source material */ -#if 0 - caps = GST_BUFFER_CAPS (buffer); -#endif - /* FIXME, need to get the caps of the buffer somehow */ - caps = NULL; + caps = gst_sample_get_caps (sample); if (!caps) { g_warning ("could not get snapshot format\n"); goto done; @@ -1197,6 +1191,7 @@ shot_cb (GtkButton * button, gpointer data) /* create pixmap from buffer and save, gstreamer video buffers have a stride * that is rounded up to the nearest multiple of 4 */ + buffer = gst_sample_get_buffer (sample); data = gst_buffer_map (buffer, &size, NULL, GST_MAP_READ); pixbuf = gdk_pixbuf_new_from_data (data, GDK_COLORSPACE_RGB, FALSE, 8, width, height, @@ -1207,7 +1202,7 @@ shot_cb (GtkButton * button, gpointer data) gst_buffer_unmap (buffer, data, size); done: - gst_buffer_unref (buffer); + gst_sample_unref (sample); } } |