From b69c605c2c4ebd57bf64885aa0860dd06afddcee Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 23 Feb 2011 16:50:43 +0100 Subject: [PATCH 1/9] wavparse: tune output max buffer size to material ... to avoid ending up with tons of short time buffers for e.g. high sample rate audio. --- gst/wavparse/gstwavparse.c | 19 ++++++++++++++++--- gst/wavparse/gstwavparse.h | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/gst/wavparse/gstwavparse.c b/gst/wavparse/gstwavparse.c index 6e56f8ef22..5f8a789c4e 100644 --- a/gst/wavparse/gstwavparse.c +++ b/gst/wavparse/gstwavparse.c @@ -1156,6 +1156,8 @@ gst_waveparse_ignore_chunk (GstWavParse * wav, GstBuffer * buf, guint32 tag, return TRUE; } +#define MAX_BUFFER_SIZE 4096 + static GstFlowReturn gst_wavparse_stream_headers (GstWavParse * wav) { @@ -1578,6 +1580,19 @@ gst_wavparse_stream_headers (GstWavParse * wav) wav->state = GST_WAVPARSE_DATA; + /* determine reasonable max buffer size, + * that is, buffers not too small either size or time wise + * so we do not end up with too many of them */ + /* var abuse */ + upstream_size = 0; + gst_wavparse_time_to_bytepos (wav, 40 * GST_MSECOND, &upstream_size); + wav->max_buf_size = upstream_size; + wav->max_buf_size = MAX (wav->max_buf_size, MAX_BUFFER_SIZE); + if (wav->blockalign > 0) + wav->max_buf_size -= (wav->max_buf_size % wav->blockalign); + + GST_DEBUG_OBJECT (wav, "max buffer size %d", wav->max_buf_size); + return GST_FLOW_OK; /* ERROR */ @@ -1802,8 +1817,6 @@ gst_wavparse_add_src_pad (GstWavParse * wav, GstBuffer * buf) } } -#define MAX_BUFFER_SIZE 4096 - static GstFlowReturn gst_wavparse_stream_data (GstWavParse * wav) { @@ -1826,7 +1839,7 @@ iterate_adapter: * amounts of data regardless of the playback rate */ desired = MIN (gst_guint64_to_gdouble (wav->dataleft), - MAX_BUFFER_SIZE * wav->segment.abs_rate); + wav->max_buf_size * wav->segment.abs_rate); if (desired >= wav->blockalign && wav->blockalign > 0) desired -= (desired % wav->blockalign); diff --git a/gst/wavparse/gstwavparse.h b/gst/wavparse/gstwavparse.h index 29ce814b95..ecac96881e 100644 --- a/gst/wavparse/gstwavparse.h +++ b/gst/wavparse/gstwavparse.h @@ -90,6 +90,7 @@ struct _GstWavParse { gboolean vbr; guint bytes_per_sample; + guint max_buf_size; /* position in data part */ guint64 offset; From 910a6f0c96bc7c0fc4410be0ae8c9fa72bef9f9c Mon Sep 17 00:00:00 2001 From: David Schleef Date: Fri, 4 Mar 2011 18:37:38 -0800 Subject: [PATCH 2/9] v4l2: Use #ifdefs for V4L2_PIX_FMT_PJPG It's only recently added to kernel headers. --- sys/v4l2/gstv4l2object.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c index 6cf9036e2e..52961974d5 100644 --- a/sys/v4l2/gstv4l2object.c +++ b/sys/v4l2/gstv4l2object.c @@ -774,7 +774,9 @@ static const GstV4L2FormatDesc gst_v4l2_formats[] = { /* compressed formats */ {V4L2_PIX_FMT_MJPEG, TRUE}, {V4L2_PIX_FMT_JPEG, TRUE}, +#ifdef V4L2_PIX_FMT_PJPG {V4L2_PIX_FMT_PJPG, TRUE}, +#endif {V4L2_PIX_FMT_DV, TRUE}, {V4L2_PIX_FMT_MPEG, FALSE}, @@ -815,10 +817,16 @@ gst_v4l2_object_get_format_from_fourcc (GstV4l2Object * v4l2object, return fmt; /* special case for jpeg */ if (fmt->pixelformat == V4L2_PIX_FMT_MJPEG || - fmt->pixelformat == V4L2_PIX_FMT_JPEG || - fmt->pixelformat == V4L2_PIX_FMT_PJPG) { - if (fourcc == V4L2_PIX_FMT_JPEG - || fourcc == V4L2_PIX_FMT_MJPEG || fourcc == V4L2_PIX_FMT_PJPG) { + fmt->pixelformat == V4L2_PIX_FMT_JPEG +#ifdef V4L2_PIX_FMT_PJPG + || fmt->pixelformat == V4L2_PIX_FMT_PJPG +#endif + ) { + if (fourcc == V4L2_PIX_FMT_JPEG || fourcc == V4L2_PIX_FMT_MJPEG +#ifdef V4L2_PIX_FMT_PJPG + || fourcc == V4L2_PIX_FMT_PJPG +#endif + ) { return fmt; } } @@ -858,9 +866,11 @@ gst_v4l2_object_format_get_rank (const struct v4l2_fmtdesc *fmt) switch (fourcc) { case V4L2_PIX_FMT_MJPEG: +#ifdef V4L2_PIX_FMT_PJPG case V4L2_PIX_FMT_PJPG: rank = JPEG_BASE_RANK; break; +#endif case V4L2_PIX_FMT_JPEG: rank = JPEG_BASE_RANK + 1; break; @@ -1077,7 +1087,9 @@ gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc) switch (fourcc) { case V4L2_PIX_FMT_MJPEG: /* Motion-JPEG */ +#ifdef V4L2_PIX_FMT_PJPG case V4L2_PIX_FMT_PJPG: /* Progressive-JPEG */ +#endif case V4L2_PIX_FMT_JPEG: /* JFIF JPEG */ structure = gst_structure_new ("image/jpeg", NULL); break; From 92808b101050aac4327040835bb9bc4b4fca075a Mon Sep 17 00:00:00 2001 From: Jon Nordby Date: Sat, 5 Mar 2011 23:22:58 +0000 Subject: [PATCH 3/9] cairooverlay: Remove unnecessary gtk/gtk-x11 use in example. This removes code, and allows the example to be used on any platform. Fixes bug #643981. --- tests/examples/Makefile.am | 4 -- tests/examples/cairo/Makefile.am | 9 +--- tests/examples/cairo/cairo_overlay.c | 75 ++-------------------------- 3 files changed, 7 insertions(+), 81 deletions(-) diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am index 4437a80185..26ddac75cf 100644 --- a/tests/examples/Makefile.am +++ b/tests/examples/Makefile.am @@ -5,14 +5,10 @@ JACK_DIR= endif if USE_CAIRO_GOBJECT -if HAVE_GTK_X11 CAIRO_DIR=cairo else CAIRO_DIR= endif -else -CAIRO_DIR= -endif SUBDIRS = audiofx equalizer $(JACK_DIR) level pulse \ rtp shapewipe spectrum v4l2 $(CAIRO_DIR) diff --git a/tests/examples/cairo/Makefile.am b/tests/examples/cairo/Makefile.am index 5fa772d952..7fcecb9ed0 100644 --- a/tests/examples/cairo/Makefile.am +++ b/tests/examples/cairo/Makefile.am @@ -1,12 +1,7 @@ if USE_CAIRO_GOBJECT -if HAVE_GTK_X11 noinst_PROGRAMS = cairo_overlay endif -endif cairo_overlay_SOURCES = cairo_overlay.c -cairo_overlay_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) \ - $(GTK_CFLAGS) $(CAIRO_CFLAGS) -cairo_overlay_LDFLAGS = \ - $(GST_LIBS) -lgstinterfaces-0.10 -lgstvideo-$(GST_MAJORMINOR) \ - $(GTK_LIBS) $(CAIRO_LIBS) +cairo_overlay_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(CAIRO_CFLAGS) +cairo_overlay_LDFLAGS = -lgstvideo-$(GST_MAJORMINOR) $(CAIRO_LIBS) diff --git a/tests/examples/cairo/cairo_overlay.c b/tests/examples/cairo/cairo_overlay.c index 52c947b1c2..ea921e606c 100644 --- a/tests/examples/cairo/cairo_overlay.c +++ b/tests/examples/cairo/cairo_overlay.c @@ -19,73 +19,15 @@ /* * Example showing usage of the cairooverlay element - * - * Note: The example program not run on non-X11 platforms because - * it is using the xvimageoverlay element. That part of the code was - * roughly based on gst_x_overlay documentation. */ #include #include -#include #include #include -#include - -#include - -static gulong video_window_xid = 0; - -static GstBusSyncReply -bus_sync_handler (GstBus * bus, GstMessage * message, gpointer user_data) -{ - if (GST_MESSAGE_TYPE (message) != GST_MESSAGE_ELEMENT) - return GST_BUS_PASS; - if (!gst_structure_has_name (message->structure, "prepare-xwindow-id")) - return GST_BUS_PASS; - - if (video_window_xid != 0) { - GstXOverlay *xoverlay; - - xoverlay = GST_X_OVERLAY (GST_MESSAGE_SRC (message)); - gst_x_overlay_set_window_handle (xoverlay, video_window_xid); - } else { - g_warning ("Should have obtained video_window_xid by now!"); - } - - gst_message_unref (message); - return GST_BUS_DROP; -} - -static void -video_widget_realize_cb (GtkWidget * widget, gpointer data) -{ - video_window_xid = GDK_WINDOW_XID (widget->window); -} - -static GtkWidget * -setup_gtk_window (void) -{ - GtkWidget *video_window; - GtkWidget *app_window; - - app_window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - video_window = gtk_drawing_area_new (); - g_signal_connect (video_window, "realize", - G_CALLBACK (video_widget_realize_cb), NULL); - gtk_widget_set_double_buffered (video_window, FALSE); - - gtk_container_add (GTK_CONTAINER (app_window), video_window); - gtk_widget_show_all (app_window); - - gtk_widget_realize (app_window); - g_assert (video_window_xid != 0); - - return app_window; -} +#include /* Datastructure to share the state we are interested in between * prepare and render function. */ @@ -137,7 +79,6 @@ setup_gst_pipeline (CairoOverlayState * overlay_state) GstElement *pipeline; GstElement *cairo_overlay; GstElement *source, *adaptor1, *adaptor2, *sink; - GstBus *bus; pipeline = gst_pipeline_new ("cairo-overlay-example"); @@ -146,7 +87,7 @@ setup_gst_pipeline (CairoOverlayState * overlay_state) adaptor1 = gst_element_factory_make ("ffmpegcolorspace", "adaptor1"); cairo_overlay = gst_element_factory_make ("cairooverlay", "overlay"); adaptor2 = gst_element_factory_make ("ffmpegcolorspace", "adaptor2"); - sink = gst_element_factory_make ("xvimagesink", "sink"); + sink = gst_element_factory_make ("autovideosink", "sink"); /* If failing, the element could not be created */ g_assert (cairo_overlay); @@ -165,31 +106,25 @@ setup_gst_pipeline (CairoOverlayState * overlay_state) g_warning ("Failed to link elements!"); } - bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); - gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bus_sync_handler, NULL); - gst_object_unref (bus); - return pipeline; } int main (int argc, char **argv) { - GtkWidget *window; + GMainLoop *loop; GstElement *pipeline; CairoOverlayState *overlay_state; - gtk_init (&argc, &argv); gst_init (&argc, &argv); + loop = g_main_loop_new (NULL, FALSE); - window = setup_gtk_window (); overlay_state = g_new0 (CairoOverlayState, 1); pipeline = setup_gst_pipeline (overlay_state); gst_element_set_state (pipeline, GST_STATE_PLAYING); - gtk_main (); + g_main_loop_run (loop); gst_object_unref (pipeline); - gtk_widget_destroy (GTK_WIDGET (window)); g_free (overlay_state); } From 8b9183c63388d2a510b07d20bd4ca3d124523c19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 7 Mar 2011 10:46:12 +0100 Subject: [PATCH 4/9] cairooverlay: Use LDADD instead of LDFLAGS for libs and add $(GST_LIBS) --- tests/examples/cairo/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/examples/cairo/Makefile.am b/tests/examples/cairo/Makefile.am index 7fcecb9ed0..45f546892b 100644 --- a/tests/examples/cairo/Makefile.am +++ b/tests/examples/cairo/Makefile.am @@ -4,4 +4,4 @@ endif cairo_overlay_SOURCES = cairo_overlay.c cairo_overlay_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(CAIRO_CFLAGS) -cairo_overlay_LDFLAGS = -lgstvideo-$(GST_MAJORMINOR) $(CAIRO_LIBS) +cairo_overlay_LDADD = -lgstvideo-$(GST_MAJORMINOR) $(GST_LIBS) $(CAIRO_LIBS) From 7f85827bf7144f0efb36726a05d1101b551bbe9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 7 Mar 2011 10:47:23 +0100 Subject: [PATCH 5/9] examples: Always dist the cairo example --- tests/examples/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/examples/Makefile.am b/tests/examples/Makefile.am index 26ddac75cf..50a972516f 100644 --- a/tests/examples/Makefile.am +++ b/tests/examples/Makefile.am @@ -14,6 +14,6 @@ SUBDIRS = audiofx equalizer $(JACK_DIR) level pulse \ rtp shapewipe spectrum v4l2 $(CAIRO_DIR) DIST_SUBDIRS = audiofx equalizer jack level pulse \ - rtp shapewipe spectrum v4l2 $(CAIRO_DIR) + rtp shapewipe spectrum v4l2 cairo include $(top_srcdir)/common/parallel-subdirs.mak From 1a8aa16612ed36b489c7112a908fd207bd0b3e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 7 Mar 2011 10:54:22 +0100 Subject: [PATCH 6/9] cairooverlay: Add a bus handler to the example to handle EOS/ERROR/WARNING Also clean up the pipeline properly. --- tests/examples/cairo/cairo_overlay.c | 48 +++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/tests/examples/cairo/cairo_overlay.c b/tests/examples/cairo/cairo_overlay.c index ea921e606c..c941b53b2d 100644 --- a/tests/examples/cairo/cairo_overlay.c +++ b/tests/examples/cairo/cairo_overlay.c @@ -29,6 +29,41 @@ #include + +static gboolean +on_message (GstBus * bus, GstMessage * message, gpointer user_data) +{ + GMainLoop *loop = (GMainLoop *) user_data; + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_ERROR:{ + GError *err = NULL; + gchar *debug; + + gst_message_parse_error (message, &err, &debug); + g_critical ("Got ERROR: %s (%s)", err->message, GST_STR_NULL (debug)); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_WARNING:{ + GError *err = NULL; + gchar *debug; + + gst_message_parse_warning (message, &err, &debug); + g_warning ("Got WARNING: %s (%s)", err->message, GST_STR_NULL (debug)); + g_main_loop_quit (loop); + break; + } + case GST_MESSAGE_EOS: + g_main_loop_quit (loop); + break; + default: + break; + } + + return TRUE; +} + /* Datastructure to share the state we are interested in between * prepare and render function. */ typedef struct @@ -114,17 +149,22 @@ main (int argc, char **argv) { GMainLoop *loop; GstElement *pipeline; - CairoOverlayState *overlay_state; + GstBus *bus; + CairoOverlayState overlay_state = { FALSE, 0, 0 }; gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); - overlay_state = g_new0 (CairoOverlayState, 1); - pipeline = setup_gst_pipeline (overlay_state); + pipeline = setup_gst_pipeline (&overlay_state); + + bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); + gst_bus_add_signal_watch (bus); + g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop); + gst_object_unref (GST_OBJECT (bus)); gst_element_set_state (pipeline, GST_STATE_PLAYING); g_main_loop_run (loop); + gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (pipeline); - g_free (overlay_state); } From f84b8a69cba9c538f5546869cb4ef454ad5efb9d Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 7 Mar 2011 11:01:06 +0100 Subject: [PATCH 7/9] jitterbuffer: reset element base_time upon flush ... to arrange for properly scheduled timeout (following seek). --- gst/rtpmanager/gstrtpjitterbuffer.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index fcaef015a1..ca836429cf 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -881,6 +881,8 @@ static void gst_rtp_jitter_buffer_flush_stop (GstRtpJitterBuffer * jitterbuffer) { GstRtpJitterBufferPrivate *priv; + GstClock *clock; + GstClockTime ts; priv = jitterbuffer->priv; @@ -902,6 +904,18 @@ gst_rtp_jitter_buffer_flush_stop (GstRtpJitterBuffer * jitterbuffer) GST_DEBUG_OBJECT (jitterbuffer, "flush and reset jitterbuffer"); rtp_jitter_buffer_flush (priv->jbuf); rtp_jitter_buffer_reset_skew (priv->jbuf); + /* sync_time for scheduling timeouts needs proper element base_time + * However, following a seek new base_time only trickles down upon PLAYING + * upon which time quite some processing has already passed + * (which also needs correct base time) */ + clock = gst_element_get_clock (GST_ELEMENT_CAST (jitterbuffer)); + if (clock) { + ts = gst_clock_get_time (clock); + GST_DEBUG_OBJECT (jitterbuffer, "new base time %" GST_TIME_FORMAT, + GST_TIME_ARGS (ts)); + gst_object_unref (clock); + gst_element_set_base_time (GST_ELEMENT_CAST (jitterbuffer), ts); + } JBUF_UNLOCK (priv); } From 3c9a4239bfb7e3a06a9dfefd4a9b696607b9e094 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 7 Mar 2011 16:56:18 +0100 Subject: [PATCH 8/9] jitterbuffer: avoid trying to buffer more than is available. That is, in case of short (or near eos of) stream, deadlock (until timeout) would occur trying to buffer more than is yet forthcoming. --- gst/rtpmanager/gstrtpjitterbuffer.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index ca836429cf..c8965ac9e9 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -1232,6 +1232,22 @@ parse_failed: } } +/* call with jbuf lock held */ +static void +check_buffering_percent (GstRtpJitterBuffer * jitterbuffer, gint * percent) +{ + GstRtpJitterBufferPrivate *priv = jitterbuffer->priv; + + /* too short a stream, or too close to EOS will never really fill buffer */ + if (*percent != -1 && priv->npt_stop != -1 && + priv->npt_stop - priv->npt_start <= + rtp_jitter_buffer_get_delay (priv->jbuf)) { + GST_DEBUG_OBJECT (jitterbuffer, "short stream; faking full buffer"); + rtp_jitter_buffer_set_buffering (priv->jbuf, FALSE); + *percent = 100; + } +} + static void post_buffering_percent (GstRtpJitterBuffer * jitterbuffer, gint percent) { @@ -1406,6 +1422,8 @@ gst_rtp_jitter_buffer_chain (GstPad * pad, GstBuffer * buffer) GST_DEBUG_OBJECT (jitterbuffer, "Pushed packet #%d, now %d packets, tail: %d", seqnum, rtp_jitter_buffer_num_packets (priv->jbuf), tail); + check_buffering_percent (jitterbuffer, &percent); + finished: JBUF_UNLOCK (priv); @@ -1836,6 +1854,8 @@ push_buffer: /* when we get here we are ready to pop and push the buffer */ outbuf = rtp_jitter_buffer_pop (priv->jbuf, &percent); + check_buffering_percent (jitterbuffer, &percent); + if (G_UNLIKELY (discont || priv->discont)) { /* set DISCONT flag when we missed a packet. We pushed the buffer writable * into the jitterbuffer so we can modify now. */ From 1f7f434df6dedf896d2925560e36a1fe0875763e Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Mon, 7 Mar 2011 16:56:43 +0100 Subject: [PATCH 9/9] jitterbuffer: also estimate eos if very near eos --- gst/rtpmanager/gstrtpjitterbuffer.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/gst/rtpmanager/gstrtpjitterbuffer.c b/gst/rtpmanager/gstrtpjitterbuffer.c index c8965ac9e9..9f08203221 100644 --- a/gst/rtpmanager/gstrtpjitterbuffer.c +++ b/gst/rtpmanager/gstrtpjitterbuffer.c @@ -1873,17 +1873,25 @@ push_buffer: elapsed = compute_elapsed (jitterbuffer, outbuf); - if (elapsed > priv->last_elapsed) { + if (elapsed > priv->last_elapsed || !priv->last_elapsed) { guint64 left; priv->last_elapsed = elapsed; left = priv->npt_stop - priv->npt_start; + GST_LOG_OBJECT (jitterbuffer, "left %" GST_TIME_FORMAT, + GST_TIME_ARGS (left)); if (elapsed > 0) estimated = gst_util_uint64_scale (out_time, left, elapsed); - else - estimated = -1; + else { + /* if there is almost nothing left, + * we may never advance enough to end up in the above case */ + if (left < GST_SECOND) + estimated = GST_SECOND; + else + estimated = -1; + } GST_LOG_OBJECT (jitterbuffer, "elapsed %" GST_TIME_FORMAT ", estimated %" GST_TIME_FORMAT, GST_TIME_ARGS (elapsed), GST_TIME_ARGS (estimated));