From 6b9594ac99d5b4ecdd235afcbfb02e042d4e778c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 8 Mar 2006 09:53:31 +0000 Subject: [PATCH] ext/libvisual/visual.c: Cleanups, post nice errors. Original commit message from CVS: * ext/libvisual/visual.c: (gst_visual_init), (gst_visual_clear_actors), (gst_visual_dispose), (gst_visual_reset), (gst_visual_src_setcaps), (gst_visual_sink_setcaps), (gst_vis_src_negotiate), (gst_visual_sink_event), (gst_visual_src_event), (get_buffer), (gst_visual_chain), (gst_visual_change_state): Cleanups, post nice errors. Handle sink and src events. Implement simple QoS. * gst-libs/gst/video/gstvideosink.c: (gst_video_sink_init): Use new basesink methods to configure max-lateness. Small doc update. * gst/ffmpegcolorspace/gstffmpegcolorspace.c: (gst_ffmpegcsp_transform_caps), (gst_ffmpegcsp_set_caps): Debug statement cleanups. * gst/volume/gstvolume.c: (gst_volume_class_init): Simple cleanup. --- ChangeLog | 23 ++ ext/libvisual/visual.c | 232 ++++++++++++++++----- gst-libs/gst/video/gstvideosink.c | 11 +- gst/ffmpegcolorspace/gstffmpegcolorspace.c | 11 +- gst/volume/gstvolume.c | 9 +- 5 files changed, 221 insertions(+), 65 deletions(-) diff --git a/ChangeLog b/ChangeLog index b25da3dccb..ccc4f91f53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2006-03-08 Wim Taymans + + * ext/libvisual/visual.c: (gst_visual_init), + (gst_visual_clear_actors), (gst_visual_dispose), + (gst_visual_reset), (gst_visual_src_setcaps), + (gst_visual_sink_setcaps), (gst_vis_src_negotiate), + (gst_visual_sink_event), (gst_visual_src_event), (get_buffer), + (gst_visual_chain), (gst_visual_change_state): + Cleanups, post nice errors. + Handle sink and src events. + Implement simple QoS. + + * gst-libs/gst/video/gstvideosink.c: (gst_video_sink_init): + Use new basesink methods to configure max-lateness. + Small doc update. + + * gst/ffmpegcolorspace/gstffmpegcolorspace.c: + (gst_ffmpegcsp_transform_caps), (gst_ffmpegcsp_set_caps): + Debug statement cleanups. + + * gst/volume/gstvolume.c: (gst_volume_class_init): + Simple cleanup. + 2006-03-08 Tim-Philipp Müller * ext/pango/gsttextoverlay.c: (gst_text_overlay_class_init), diff --git a/ext/libvisual/visual.c b/ext/libvisual/visual.c index 701ba923a0..0e9f619cd4 100644 --- a/ext/libvisual/visual.c +++ b/ext/libvisual/visual.c @@ -62,10 +62,19 @@ struct _GstVisual gint fps_d; gint width; gint height; + GstClockTime duration; + guint outsize; + + /* samples per frame based on caps */ + guint spf; /* state stuff */ GstAdapter *adapter; guint count; + + /* QoS stuff *//* with LOCK */ + gdouble proportion; + GstClockTime earliest_time; }; struct _GstVisualClass @@ -109,6 +118,8 @@ static void gst_visual_dispose (GObject * object); static GstStateChangeReturn gst_visual_change_state (GstElement * element, GstStateChange transition); static GstFlowReturn gst_visual_chain (GstPad * pad, GstBuffer * buffer); +static gboolean gst_visual_sink_event (GstPad * pad, GstEvent * event); +static gboolean gst_visual_src_event (GstPad * pad, GstEvent * event); static gboolean gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps); static gboolean gst_visual_src_setcaps (GstPad * pad, GstCaps * caps); @@ -191,17 +202,31 @@ gst_visual_init (GstVisual * visual) visual->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink"); gst_pad_set_setcaps_function (visual->sinkpad, gst_visual_sink_setcaps); gst_pad_set_chain_function (visual->sinkpad, gst_visual_chain); + gst_pad_set_event_function (visual->sinkpad, gst_visual_sink_event); gst_element_add_pad (GST_ELEMENT (visual), visual->sinkpad); visual->srcpad = gst_pad_new_from_static_template (&src_template, "src"); gst_pad_set_setcaps_function (visual->srcpad, gst_visual_src_setcaps); gst_pad_set_getcaps_function (visual->srcpad, gst_visual_getcaps); + gst_pad_set_event_function (visual->srcpad, gst_visual_src_event); gst_element_add_pad (GST_ELEMENT (visual), visual->srcpad); - visual->next_ts = 0; visual->adapter = gst_adapter_new (); } +static void +gst_visual_clear_actors (GstVisual * visual) +{ + if (visual->actor) { + visual_object_unref (VISUAL_OBJECT (visual->actor)); + visual->actor = NULL; + } + if (visual->video) { + visual_object_unref (VISUAL_OBJECT (visual->video)); + visual->video = NULL; + } +} + static void gst_visual_dispose (GObject * object) { @@ -211,19 +236,23 @@ gst_visual_dispose (GObject * object) g_object_unref (visual->adapter); visual->adapter = NULL; } + gst_visual_clear_actors (visual); - if (visual->actor) { - visual_object_unref (VISUAL_OBJECT (visual->actor)); - visual->actor = NULL; - } - - if (visual->video) { - visual_object_unref (VISUAL_OBJECT (visual->video)); - visual->video = NULL; - } GST_CALL_PARENT (G_OBJECT_CLASS, dispose, (object)); } +static void +gst_visual_reset (GstVisual * visual) +{ + visual->next_ts = -1; + gst_adapter_clear (visual->adapter); + + GST_OBJECT_LOCK (visual); + visual->proportion = 1.0; + visual->earliest_time = -1; + GST_OBJECT_UNLOCK (visual); +} + static GstCaps * gst_visual_getcaps (GstPad * pad) { @@ -296,6 +325,15 @@ gst_visual_src_setcaps (GstPad * pad, GstCaps * caps) visual_video_set_dimension (visual->video, visual->width, visual->height); visual_actor_video_negotiate (visual->actor, 0, FALSE, FALSE); + /* precalc some values */ + visual->outsize = + visual->video->height * GST_ROUND_UP_4 (visual->video->width) * + visual->video->bpp; + visual->spf = + gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n); + visual->duration = + gst_util_uint64_scale_int (GST_SECOND, visual->fps_d, visual->fps_n); + gst_object_unref (visual); return TRUE; @@ -316,6 +354,11 @@ gst_visual_sink_setcaps (GstPad * pad, GstCaps * caps) gst_structure_get_int (structure, "rate", &visual->rate); + if (visual->fps_n != 0) { + visual->spf = + gst_util_uint64_scale_int (visual->rate, visual->fps_d, visual->fps_n); + } + gst_object_unref (visual); return TRUE; } @@ -356,12 +399,74 @@ gst_vis_src_negotiate (GstVisual * visual) no_format: { + GST_ELEMENT_ERROR (visual, STREAM, FORMAT, (NULL), + ("could not negotiate output format")); gst_caps_unref (intersect); gst_caps_unref (othercaps); return FALSE; } } +static gboolean +gst_visual_sink_event (GstPad * pad, GstEvent * event) +{ + GstVisual *visual; + gboolean res; + + visual = GST_VISUAL (gst_pad_get_parent (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_FLUSH_START: + res = gst_pad_push_event (visual->srcpad, event); + break; + case GST_EVENT_FLUSH_STOP: + /* reset QoS and adapter. */ + gst_visual_reset (visual); + res = gst_pad_push_event (visual->srcpad, event); + break; + default: + res = gst_pad_push_event (visual->srcpad, event); + break; + } + + gst_object_unref (visual); + return res; +} + +static gboolean +gst_visual_src_event (GstPad * pad, GstEvent * event) +{ + GstVisual *visual; + gboolean res; + + visual = GST_VISUAL (gst_pad_get_parent (pad)); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_QOS: + { + gdouble proportion; + GstClockTimeDiff diff; + GstClockTime timestamp; + + gst_event_parse_qos (event, &proportion, &diff, ×tamp); + + GST_OBJECT_LOCK (visual); + visual->proportion = proportion; + visual->earliest_time = timestamp + diff; + GST_OBJECT_UNLOCK (visual); + + res = gst_pad_push_event (visual->sinkpad, event); + break; + } + default: + res = gst_pad_push_event (visual->sinkpad, event); + break; + } + + gst_object_unref (visual); + return res; +} + static GstFlowReturn get_buffer (GstVisual * visual, GstBuffer ** outbuf) { @@ -377,9 +482,8 @@ get_buffer (GstVisual * visual, GstBuffer ** outbuf) ret = gst_pad_alloc_buffer_and_set_caps (visual->srcpad, - GST_BUFFER_OFFSET_NONE, - visual->video->height * GST_ROUND_UP_4 (visual->video->width) * - visual->video->bpp, GST_PAD_CAPS (visual->srcpad), outbuf); + GST_BUFFER_OFFSET_NONE, visual->outsize, + GST_PAD_CAPS (visual->srcpad), outbuf); if (ret != GST_FLOW_OK) return ret; @@ -397,7 +501,6 @@ gst_visual_chain (GstPad * pad, GstBuffer * buffer) guint i; GstVisual *visual = GST_VISUAL (gst_pad_get_parent (pad)); GstFlowReturn ret = GST_FLOW_OK; - guint spf; GST_DEBUG_OBJECT (visual, "chain function called"); @@ -415,15 +518,33 @@ gst_visual_chain (GstPad * pad, GstBuffer * buffer) if (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE) visual->next_ts = GST_BUFFER_TIMESTAMP (buffer); - /* spf = samples per frame */ - spf = ((guint64) (visual->rate) * visual->fps_d) / visual->fps_n; gst_adapter_push (visual->adapter, buffer); - while (gst_adapter_available (visual->adapter) > MAX (512, spf) * 4 && + while (gst_adapter_available (visual->adapter) > MAX (512, visual->spf) * 4 && (ret == GST_FLOW_OK)) { + gboolean need_skip; + /* Read 512 samples per channel */ - const guint16 *data = - (const guint16 *) gst_adapter_peek (visual->adapter, 512 * 4); + const guint16 *data; + + data = (const guint16 *) gst_adapter_peek (visual->adapter, 512 * 4); + + GST_DEBUG_OBJECT (visual, "QoS: in: %" G_GUINT64_FORMAT + ", earliest: %" G_GUINT64_FORMAT, visual->next_ts, + visual->earliest_time); + + if (visual->next_ts != -1) { + GST_OBJECT_LOCK (visual); + /* check for QoS, don't compute buffers that are known to be latea */ + need_skip = visual->earliest_time != -1 && + visual->next_ts <= visual->earliest_time; + GST_OBJECT_UNLOCK (visual); + + if (need_skip) { + GST_WARNING_OBJECT (visual, "skipping frame because of QoS"); + goto skip; + } + } for (i = 0; i < 512; i++) { visual->audio.plugpcm[0][i] = *data++; @@ -436,33 +557,29 @@ gst_visual_chain (GstPad * pad, GstBuffer * buffer) goto beach; } } + visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf)); + visual_audio_analyze (&visual->audio); + visual_actor_run (visual->actor, &visual->audio); + visual_video_set_buffer (visual->video, NULL); - if (visual->video != NULL) { - visual_video_set_buffer (visual->video, GST_BUFFER_DATA (outbuf)); - visual_audio_analyze (&visual->audio); - visual_actor_run (visual->actor, &visual->audio); + GST_BUFFER_TIMESTAMP (outbuf) = visual->next_ts; + GST_BUFFER_DURATION (outbuf) = visual->duration; - GST_BUFFER_TIMESTAMP (outbuf) = visual->next_ts; - GST_BUFFER_DURATION (outbuf) = gst_util_uint64_scale_int (GST_SECOND, - visual->fps_d, visual->fps_n); - visual->next_ts += GST_BUFFER_DURATION (outbuf); - ret = gst_pad_push (visual->srcpad, outbuf); - outbuf = NULL; - } + ret = gst_pad_push (visual->srcpad, outbuf); + outbuf = NULL; + + GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input", + visual->spf); + skip: + /* interpollate next timestamp */ + if (visual->next_ts != -1) + visual->next_ts += visual->duration; /* Flush out the number of samples per frame * channels * sizeof (gint16) */ - /* Recompute spf in case caps changed */ - spf = ((guint64) (visual->rate) * visual->fps_d) / visual->fps_n; - GST_DEBUG_OBJECT (visual, "finished frame, flushing %u samples from input", - spf); gst_adapter_flush (visual->adapter, - MIN (gst_adapter_available (visual->adapter), spf * 4)); + MIN (gst_adapter_available (visual->adapter), visual->spf * 4)); } - /* so we're on the safe side */ - if (visual->video) - visual_video_set_buffer (visual->video, NULL); - if (outbuf != NULL) gst_buffer_unref (outbuf); @@ -485,18 +602,17 @@ gst_visual_change_state (GstElement * element, GstStateChange transition) plugname); visual->video = visual_video_new (); + /* can't have a play without actors */ if (!visual->actor || !visual->video) - return GST_STATE_CHANGE_FAILURE; + goto no_actors; + + if (visual_actor_realize (visual->actor) != 0) + goto no_realize; - if (visual_actor_realize (visual->actor) != 0) { - visual_object_unref (VISUAL_OBJECT (visual->actor)); - visual->actor = NULL; - return GST_STATE_CHANGE_FAILURE; - } visual_actor_set_video (visual->actor, visual->video); break; case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_adapter_clear (visual->adapter); + gst_visual_reset (visual); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; @@ -510,21 +626,31 @@ gst_visual_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: - visual->next_ts = 0; break; case GST_STATE_CHANGE_READY_TO_NULL: - if (visual->actor) - visual_object_unref (VISUAL_OBJECT (visual->actor)); - if (visual->video) - visual_object_unref (VISUAL_OBJECT (visual->video)); - visual->actor = NULL; - visual->video = NULL; + gst_visual_clear_actors (visual); break; default: break; } return ret; + + /* ERRORS */ +no_actors: + { + GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL), + ("could not create actors")); + gst_visual_clear_actors (visual); + return GST_STATE_CHANGE_FAILURE; + } +no_realize: + { + GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL), + ("could not realize actor")); + gst_visual_clear_actors (visual); + return GST_STATE_CHANGE_FAILURE; + } } static void diff --git a/gst-libs/gst/video/gstvideosink.c b/gst-libs/gst/video/gstvideosink.c index 4ac08b1d7d..c427497830 100644 --- a/gst-libs/gst/video/gstvideosink.c +++ b/gst-libs/gst/video/gstvideosink.c @@ -25,8 +25,12 @@ * * * - * Provides useful functions and a base class for video sinks. Right now it's - * mostly used as a place holder for adding common code later on. + * Provides useful functions and a base class for video sinks. + * + * + * GstVideoSink will configure the default base sink to drop frames that + * arrive later than 20ms as this is considered the default threshold for + * observing out-of-sync frames. * * */ @@ -99,7 +103,8 @@ gst_video_sink_init (GstVideoSink * videosink) { videosink->width = 0; videosink->height = 0; - GST_BASE_SINK (videosink)->abidata.ABI.max_lateness = 20 * GST_MSECOND; + + gst_base_sink_set_max_lateness (GST_BASE_SINK (videosink), 20 * GST_MSECOND); } static void diff --git a/gst/ffmpegcolorspace/gstffmpegcolorspace.c b/gst/ffmpegcolorspace/gstffmpegcolorspace.c index 8d4b5ba9ca..f8d5059e96 100644 --- a/gst/ffmpegcolorspace/gstffmpegcolorspace.c +++ b/gst/ffmpegcolorspace/gstffmpegcolorspace.c @@ -154,6 +154,7 @@ gst_ffmpegcsp_transform_caps (GstBaseTransform * btrans, GST_DEBUG_OBJECT (btrans, "transformed %" GST_PTR_FORMAT " into %" GST_PTR_FORMAT, caps, result); + return result; } @@ -251,28 +252,28 @@ gst_ffmpegcsp_set_caps (GstBaseTransform * btrans, GstCaps * incaps, /* ERRORS */ no_width_height: { - GST_DEBUG ("did not specify width or height"); + GST_DEBUG_OBJECT (space, "did not specify width or height"); space->from_pixfmt = PIX_FMT_NB; space->to_pixfmt = PIX_FMT_NB; return FALSE; } no_framerate: { - GST_DEBUG ("did not specify framerate"); + GST_DEBUG_OBJECT (space, "did not specify framerate"); space->from_pixfmt = PIX_FMT_NB; space->to_pixfmt = PIX_FMT_NB; return FALSE; } format_mismatch: { - GST_DEBUG ("input and output formats do not match"); + GST_DEBUG_OBJECT (space, "input and output formats do not match"); space->from_pixfmt = PIX_FMT_NB; space->to_pixfmt = PIX_FMT_NB; return FALSE; } invalid_in_caps: { - GST_DEBUG ("could not configure context for input format"); + GST_DEBUG_OBJECT (space, "could not configure context for input format"); av_free (ctx); space->from_pixfmt = PIX_FMT_NB; space->to_pixfmt = PIX_FMT_NB; @@ -280,7 +281,7 @@ invalid_in_caps: } invalid_out_caps: { - GST_DEBUG ("could not configure context for output format"); + GST_DEBUG_OBJECT (space, "could not configure context for output format"); av_free (ctx); space->from_pixfmt = PIX_FMT_NB; space->to_pixfmt = PIX_FMT_NB; diff --git a/gst/volume/gstvolume.c b/gst/volume/gstvolume.c index 4da0180573..fdaaa38ddb 100644 --- a/gst/volume/gstvolume.c +++ b/gst/volume/gstvolume.c @@ -278,8 +278,11 @@ static void gst_volume_class_init (GstVolumeClass * klass) { GObjectClass *gobject_class; + GstBaseTransformClass *trans_class; gobject_class = (GObjectClass *) klass; + trans_class = (GstBaseTransformClass *) klass; + gobject_class->set_property = volume_set_property; gobject_class->get_property = volume_get_property; gobject_class->dispose = gst_volume_dispose; @@ -293,10 +296,8 @@ gst_volume_class_init (GstVolumeClass * klass) 0.0, VOLUME_MAX_DOUBLE, 1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - GST_BASE_TRANSFORM_CLASS (klass)->transform_ip = - GST_DEBUG_FUNCPTR (volume_transform_ip); - GST_BASE_TRANSFORM_CLASS (klass)->set_caps = - GST_DEBUG_FUNCPTR (volume_set_caps); + trans_class->transform_ip = GST_DEBUG_FUNCPTR (volume_transform_ip); + trans_class->set_caps = GST_DEBUG_FUNCPTR (volume_set_caps); } static void