From e2150b11ff8a98a3b7081d8106bca496a91c6b2b Mon Sep 17 00:00:00 2001 From: Lane Brooks Date: Tue, 11 Jan 2011 10:34:33 -0700 Subject: [PATCH 01/18] textoverlay: converted AYUV to use 'A OVER B' alpha compositing 'A OVER B' compositing is explained at http://en.wikipedia.org/wiki/Alpha_compositing. Previously, overlaying text on a transparent background image left the text overlay also transparent. This pipeline shows such an example: gst-launch videotestsrc pattern=white ! video/x-raw-yuv,format=\(fourcc\)AYUV ! alpha alpha=0.0 ! textoverlay text=Testing auto-resize=False font-desc=60px ! videomixer ! ffmpegcolorspace ! autovideosink With this patch, text is composited "OVER" the background image and thus is visible regardless of the alpha of the background image. The overlay in the above pipeline works after applying this patch. --- ext/pango/gsttextoverlay.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/ext/pango/gsttextoverlay.c b/ext/pango/gsttextoverlay.c index ca38dc1ff2..6cd9db7afe 100644 --- a/ext/pango/gsttextoverlay.c +++ b/ext/pango/gsttextoverlay.c @@ -143,6 +143,12 @@ GST_DEBUG_CATEGORY (pango_debug); ret = (v0 * alpha + v1 * (255 - alpha)) / 255; \ } +#define OVER(ret, alphaA, Ca, alphaB, Cb, alphaNew) \ +{ \ + ret = (Ca * alphaA + Cb * alphaB * (255 - alphaA) / 255) / alphaNew; \ + ret = CLAMP (ret, 0, 255); \ +} + #if G_BYTE_ORDER == G_LITTLE_ENDIAN # define CAIRO_ARGB_A 3 # define CAIRO_ARGB_R 2 @@ -1617,7 +1623,7 @@ static inline void gst_text_overlay_blit_AYUV (GstTextOverlay * overlay, guint8 * rgb_pixels, gint xpos, gint ypos) { - int a, r, g, b; + int a, r, g, b, a1; int y, u, v; int i, j; int h, w; @@ -1649,14 +1655,17 @@ gst_text_overlay_blit_AYUV (GstTextOverlay * overlay, CAIRO_UNPREMULTIPLY (a, r, g, b); + // convert background to yuv COMP_Y (y, r, g, b); COMP_U (u, r, g, b); COMP_V (v, r, g, b); - a = (a * dest[0] + 128) >> 8; - BLEND (dest[1], a, y, dest[1]); - BLEND (dest[2], a, u, dest[2]); - BLEND (dest[3], a, v, dest[3]); + // preform text "OVER" background alpha compositing + a1 = a + (dest[0] * (255 - a)) / 255 + 1; // add 1 to prevent divide by 0 + OVER (dest[1], a, y, dest[0], dest[1], a1); + OVER (dest[2], a, u, dest[0], dest[2], a1); + OVER (dest[3], a, v, dest[0], dest[3], a1); + dest[0] = a1 - 1; // remove the temporary 1 we added pimage += 4; dest += 4; From 200ee96338e73932074ad977d2187a7b7c163d96 Mon Sep 17 00:00:00 2001 From: Lane Brooks Date: Mon, 17 Jan 2011 21:12:18 -0700 Subject: [PATCH 02/18] textoverlay: Added support for ARGB and other RGB alpha variants --- ext/pango/gsttextoverlay.c | 123 +++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/ext/pango/gsttextoverlay.c b/ext/pango/gsttextoverlay.c index 6cd9db7afe..1d0f25b849 100644 --- a/ext/pango/gsttextoverlay.c +++ b/ext/pango/gsttextoverlay.c @@ -193,6 +193,10 @@ static GstStaticPadTemplate src_template_factory = GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_xRGB ";" + GST_VIDEO_CAPS_RGBA ";" + GST_VIDEO_CAPS_BGRA ";" + GST_VIDEO_CAPS_ARGB ";" + GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_YUV ("{AYUV, I420, UYVY, NV12, NV21}")) ); @@ -202,6 +206,10 @@ static GstStaticPadTemplate video_sink_template_factory = GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_xRGB ";" + GST_VIDEO_CAPS_RGBA ";" + GST_VIDEO_CAPS_BGRA ";" + GST_VIDEO_CAPS_ARGB ";" + GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_YUV ("{AYUV, I420, UYVY, NV12, NV21}")) ); @@ -1470,6 +1478,36 @@ gst_text_overlay_shade_xRGB (GstTextOverlay * overlay, guchar * dest, } } +#define ARGB_SHADE_FUNCTION(name, OFFSET) \ +static inline void \ +gst_text_overlay_shade_##name (GstTextOverlay * overlay, guchar * dest, \ +gint x0, gint x1, gint y0, gint y1) \ +{ \ + gint i, j;\ + \ + x0 = CLAMP (x0 - BOX_XPAD, 0, overlay->width);\ + x1 = CLAMP (x1 + BOX_XPAD, 0, overlay->width);\ + \ + y0 = CLAMP (y0 - BOX_YPAD, 0, overlay->height);\ + y1 = CLAMP (y1 + BOX_YPAD, 0, overlay->height);\ + \ + for (i = y0; i < y1; i++) {\ + for (j = x0; j < x1; j++) {\ + gint y, y_pos, k;\ + y_pos = (i * 4 * overlay->width) + j * 4;\ + for (k = OFFSET; k < 3+OFFSET; k++) {\ + y = dest[y_pos + k] + overlay->shading_value;\ + dest[y_pos + k] = CLAMP (y, 0, 255);\ + }\ + }\ + }\ +} +ARGB_SHADE_FUNCTION (ARGB, 1); +ARGB_SHADE_FUNCTION (ABGR, 1); +ARGB_SHADE_FUNCTION (RGBA, 0); +ARGB_SHADE_FUNCTION (BGRA, 0); + + /* FIXME: * - use proper strides and offset for I420 * - don't draw over the edge of the picture (try a longer @@ -1722,6 +1760,55 @@ gst_text_overlay_blit_##name (GstTextOverlay * overlay, \ xRGB_BLIT_FUNCTION (xRGB, 1, 2, 3); xRGB_BLIT_FUNCTION (BGRx, 2, 1, 0); +#define ARGB_BLIT_FUNCTION(name, A, R, G, B) \ +static inline void \ +gst_text_overlay_blit_##name (GstTextOverlay * overlay, \ + guint8 * rgb_pixels, gint xpos, gint ypos) \ +{ \ + int a, r, g, b, a1; \ + int i, j; \ + int h, w; \ + guchar *pimage, *dest; \ + \ + w = overlay->image_width; \ + h = overlay->image_height; \ + \ + if (xpos < 0) { \ + xpos = 0; \ + } \ + \ + if (xpos + w > overlay->width) { \ + w = overlay->width - xpos; \ + } \ + \ + if (ypos + h > overlay->height) { \ + h = overlay->height - ypos; \ + } \ + \ + for (i = 0; i < h; i++) { \ + pimage = overlay->text_image + i * overlay->image_width * 4; \ + dest = rgb_pixels + (i + ypos) * 4 * overlay->width + xpos * 4; \ + for (j = 0; j < w; j++) { \ + a = pimage[CAIRO_ARGB_A]; \ + b = pimage[CAIRO_ARGB_B]; \ + g = pimage[CAIRO_ARGB_G]; \ + r = pimage[CAIRO_ARGB_R]; \ + CAIRO_UNPREMULTIPLY (a, r, g, b); \ + a1 = a + (dest[A] * (255 - a)) / 255 + 1; \ + OVER (dest[R], a, r, dest[0], dest[R], a1); \ + OVER (dest[G], a, g, dest[0], dest[G], a1); \ + OVER (dest[B], a, b, dest[0], dest[B], a1); \ + dest[A] = a1 - 1; \ + pimage += 4; \ + dest += 4; \ + } \ + } \ +} +ARGB_BLIT_FUNCTION (RGBA, 3, 0, 1, 2); +ARGB_BLIT_FUNCTION (BGRA, 3, 2, 1, 0); +ARGB_BLIT_FUNCTION (ARGB, 0, 1, 2, 3); +ARGB_BLIT_FUNCTION (ABGR, 0, 3, 2, 1); + static void gst_text_overlay_render_text (GstTextOverlay * overlay, const gchar * text, gint textlen) @@ -1849,6 +1936,26 @@ gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame) GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, ypos, ypos + overlay->image_height); break; + case GST_VIDEO_FORMAT_ARGB: + gst_text_overlay_shade_ARGB (overlay, + GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, + ypos, ypos + overlay->image_height); + break; + case GST_VIDEO_FORMAT_ABGR: + gst_text_overlay_shade_ABGR (overlay, + GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, + ypos, ypos + overlay->image_height); + break; + case GST_VIDEO_FORMAT_RGBA: + gst_text_overlay_shade_RGBA (overlay, + GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, + ypos, ypos + overlay->image_height); + break; + case GST_VIDEO_FORMAT_BGRA: + gst_text_overlay_shade_BGRA (overlay, + GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, + ypos, ypos + overlay->image_height); + break; default: g_assert_not_reached (); } @@ -1884,6 +1991,22 @@ gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame) gst_text_overlay_blit_xRGB (overlay, GST_BUFFER_DATA (video_frame), xpos, ypos); break; + case GST_VIDEO_FORMAT_ARGB: + gst_text_overlay_blit_ARGB (overlay, + GST_BUFFER_DATA (video_frame), xpos, ypos); + break; + case GST_VIDEO_FORMAT_ABGR: + gst_text_overlay_blit_ABGR (overlay, + GST_BUFFER_DATA (video_frame), xpos, ypos); + break; + case GST_VIDEO_FORMAT_RGBA: + gst_text_overlay_blit_RGBA (overlay, + GST_BUFFER_DATA (video_frame), xpos, ypos); + break; + case GST_VIDEO_FORMAT_BGRA: + gst_text_overlay_blit_BGRA (overlay, + GST_BUFFER_DATA (video_frame), xpos, ypos); + break; default: g_assert_not_reached (); } From 026776ca23c40e241d17aaff5520c2a82ae46f4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 1 Apr 2011 10:39:31 +0200 Subject: [PATCH 03/18] textoverlay: Add support for xBGR and RGBx Now all RGB variants are supported. --- ext/pango/gsttextoverlay.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ext/pango/gsttextoverlay.c b/ext/pango/gsttextoverlay.c index 1d0f25b849..21ac0138aa 100644 --- a/ext/pango/gsttextoverlay.c +++ b/ext/pango/gsttextoverlay.c @@ -192,7 +192,9 @@ static GstStaticPadTemplate src_template_factory = GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";" + GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_xRGB ";" + GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";" GST_VIDEO_CAPS_ARGB ";" @@ -205,7 +207,9 @@ static GstStaticPadTemplate video_sink_template_factory = GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx ";" + GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_xRGB ";" + GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_BGRA ";" GST_VIDEO_CAPS_ARGB ";" @@ -1453,6 +1457,8 @@ gst_text_overlay_shade_packed_Y (GstTextOverlay * overlay, guchar * dest, } #define gst_text_overlay_shade_BGRx gst_text_overlay_shade_xRGB +#define gst_text_overlay_shade_RGBx gst_text_overlay_shade_xRGB +#define gst_text_overlay_shade_xBGR gst_text_overlay_shade_xRGB static inline void gst_text_overlay_shade_xRGB (GstTextOverlay * overlay, guchar * dest, gint x0, gint x1, gint y0, gint y1) @@ -1759,6 +1765,8 @@ gst_text_overlay_blit_##name (GstTextOverlay * overlay, \ } xRGB_BLIT_FUNCTION (xRGB, 1, 2, 3); xRGB_BLIT_FUNCTION (BGRx, 2, 1, 0); +xRGB_BLIT_FUNCTION (xBGR, 3, 2, 1); +xRGB_BLIT_FUNCTION (RGBx, 0, 1, 2); #define ARGB_BLIT_FUNCTION(name, A, R, G, B) \ static inline void \ @@ -1931,11 +1939,21 @@ gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame) GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, ypos, ypos + overlay->image_height); break; + case GST_VIDEO_FORMAT_xBGR: + gst_text_overlay_shade_xBGR (overlay, + GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, + ypos, ypos + overlay->image_height); + break; case GST_VIDEO_FORMAT_BGRx: gst_text_overlay_shade_BGRx (overlay, GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, ypos, ypos + overlay->image_height); break; + case GST_VIDEO_FORMAT_RGBx: + gst_text_overlay_shade_RGBx (overlay, + GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, + ypos, ypos + overlay->image_height); + break; case GST_VIDEO_FORMAT_ARGB: gst_text_overlay_shade_ARGB (overlay, GST_BUFFER_DATA (video_frame), xpos, xpos + overlay->image_width, @@ -1991,6 +2009,14 @@ gst_text_overlay_push_frame (GstTextOverlay * overlay, GstBuffer * video_frame) gst_text_overlay_blit_xRGB (overlay, GST_BUFFER_DATA (video_frame), xpos, ypos); break; + case GST_VIDEO_FORMAT_RGBx: + gst_text_overlay_blit_RGBx (overlay, + GST_BUFFER_DATA (video_frame), xpos, ypos); + break; + case GST_VIDEO_FORMAT_xBGR: + gst_text_overlay_blit_xBGR (overlay, + GST_BUFFER_DATA (video_frame), xpos, ypos); + break; case GST_VIDEO_FORMAT_ARGB: gst_text_overlay_blit_ARGB (overlay, GST_BUFFER_DATA (video_frame), xpos, ypos); From c3aae3dc1755b0f9881617e137f6f7c8eda0a5f5 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Wed, 16 Feb 2011 16:07:49 -0300 Subject: [PATCH 04/18] oggmux: Keep track of pad's segments https://bugzilla.gnome.org/show_bug.cgi?id=643775 --- ext/ogg/gstoggmux.c | 36 ++++++++++++++++++++++++++++++++---- ext/ogg/gstoggmux.h | 2 ++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/ext/ogg/gstoggmux.c b/ext/ogg/gstoggmux.c index f2194f5119..ae6fdde253 100644 --- a/ext/ogg/gstoggmux.c +++ b/ext/ogg/gstoggmux.c @@ -292,6 +292,11 @@ gst_ogg_mux_ogg_pad_destroy_notify (GstCollectData * data) g_queue_free (oggpad->pagebuffers); oggpad->pagebuffers = NULL; } + + if (oggpad->segment) { + gst_segment_free (oggpad->segment); + oggpad->segment = NULL; + } } static GstPadLinkReturn @@ -319,11 +324,28 @@ gst_ogg_mux_sink_event (GstPad * pad, GstEvent * event) GST_DEBUG_PAD_NAME (pad)); switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_NEWSEGMENT: - /* We don't support NEWSEGMENT events */ - gst_event_unref (event); - ret = FALSE; + case GST_EVENT_NEWSEGMENT:{ + gboolean update; + gdouble rate; + gdouble applied_rate; + GstFormat format; + gint64 start, stop, position; + + g_return_val_if_fail (ogg_pad->segment != NULL, FALSE); + + gst_event_parse_new_segment_full (event, &update, &rate, + &applied_rate, &format, &start, &stop, &position); + + /* We don't support non time NEWSEGMENT events */ + if (format != GST_FORMAT_TIME) { + gst_event_unref (event); + return FALSE; + } + gst_segment_set_newsegment_full (ogg_pad->segment, update, rate, + applied_rate, format, start, stop, position); + break; + } default: ret = TRUE; break; @@ -427,6 +449,9 @@ gst_ogg_mux_request_new_pad (GstElement * element, oggpad->pagebuffers = g_queue_new (); oggpad->map.headers = NULL; oggpad->map.queued = NULL; + oggpad->segment = gst_segment_new (); + gst_segment_set_newsegment (oggpad->segment, FALSE, 1, GST_FORMAT_TIME, + 0, -1, 0); oggpad->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad); gst_pad_set_event_function (newpad, @@ -1674,6 +1699,9 @@ gst_ogg_mux_init_collectpads (GstCollectPads * collect) oggpad->prev_delta = FALSE; oggpad->data_pushed = FALSE; oggpad->pagebuffers = g_queue_new (); + oggpad->segment = gst_segment_new (); + gst_segment_set_newsegment (oggpad->segment, FALSE, 1, GST_FORMAT_TIME, + 0, -1, 0); walk = g_slist_next (walk); } diff --git a/ext/ogg/gstoggmux.h b/ext/ogg/gstoggmux.h index 6812f82ca2..62ac3ce5b7 100644 --- a/ext/ogg/gstoggmux.h +++ b/ext/ogg/gstoggmux.h @@ -53,6 +53,8 @@ typedef struct GstOggStream map; gboolean have_type; + GstSegment *segment; + /* These two buffers make a very simple queue - they enter as 'next_buffer' * and (usually) leave as 'buffer', except at EOS, when buffer will be NULL */ GstBuffer *buffer; /* the first waiting buffer for the pad */ From d1c74779f940ea4d261031afaa7b890fc779b6b1 Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Thu, 3 Mar 2011 08:45:15 -0300 Subject: [PATCH 05/18] oggmux: Use running time instead of timestamps Theora and vorbis use running time (which is correct) for calculating the granulepos for their ogg packets. Oggmux, however, used timestamps to order the received buffers. This patch makes it use the running time to compare buffer times and also to timestamp pushed buffers. Some bits of the code still use timestamps, but they are only used to calculate durations, so it should be fine. https://bugzilla.gnome.org/show_bug.cgi?id=643775 --- ext/ogg/gstoggmux.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/ext/ogg/gstoggmux.c b/ext/ogg/gstoggmux.c index ae6fdde253..256e13f39f 100644 --- a/ext/ogg/gstoggmux.c +++ b/ext/ogg/gstoggmux.c @@ -62,6 +62,11 @@ GST_DEBUG_CATEGORY_STATIC (gst_ogg_mux_debug); ? GST_BUFFER_TIMESTAMP (buf) + GST_BUFFER_DURATION (buf) \ : GST_BUFFER_TIMESTAMP (buf)) +#define GST_BUFFER_RUNNING_TIME(buf, oggpad) \ + (GST_BUFFER_DURATION_IS_VALID (buf) \ + ? gst_segment_to_running_time ((oggpad)->segment, GST_FORMAT_TIME, \ + GST_BUFFER_TIMESTAMP (buf)) : 0) + #define GST_GP_FORMAT "[gp %8" G_GINT64_FORMAT "]" #define GST_GP_CAST(_gp) ((gint64) _gp) @@ -538,7 +543,8 @@ gst_ogg_mux_buffer_from_page (GstOggMux * mux, ogg_page * page, gboolean delta) } static GstFlowReturn -gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer) +gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer, + GstOggPadData * oggpad) { GstCaps *caps; @@ -549,11 +555,11 @@ gst_ogg_mux_push_buffer (GstOggMux * mux, GstBuffer * buffer) /* Ensure we have monotonically increasing timestamps in the output. */ if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer)) { - if (mux->last_ts != GST_CLOCK_TIME_NONE && - GST_BUFFER_TIMESTAMP (buffer) < mux->last_ts) + gint64 run_time = GST_BUFFER_RUNNING_TIME (buffer, oggpad); + if (mux->last_ts != GST_CLOCK_TIME_NONE && run_time < mux->last_ts) GST_BUFFER_TIMESTAMP (buffer) = mux->last_ts; else - mux->last_ts = GST_BUFFER_TIMESTAMP (buffer); + mux->last_ts = run_time; } caps = gst_pad_get_negotiated_caps (mux->srcpad); @@ -628,7 +634,7 @@ gst_ogg_mux_dequeue_page (GstOggMux * mux, GstFlowReturn * flowret) while (buf && GST_BUFFER_OFFSET_END (buf) == -1) { GST_LOG_OBJECT (pad->collect.pad, "[gp -1] pushing page"); g_queue_pop_head (pad->pagebuffers); - *flowret = gst_ogg_mux_push_buffer (mux, buf); + *flowret = gst_ogg_mux_push_buffer (mux, buf, pad); buf = g_queue_peek_head (pad->pagebuffers); ret = TRUE; } @@ -662,7 +668,7 @@ gst_ogg_mux_dequeue_page (GstOggMux * mux, GstFlowReturn * flowret) GST_GP_FORMAT " pushing oldest page buffer %p (granulepos time %" GST_TIME_FORMAT ")", GST_BUFFER_OFFSET_END (buf), buf, GST_TIME_ARGS (GST_BUFFER_OFFSET (buf))); - *flowret = gst_ogg_mux_push_buffer (mux, buf); + *flowret = gst_ogg_mux_push_buffer (mux, buf, opad); ret = TRUE; } @@ -753,6 +759,11 @@ gst_ogg_mux_compare_pads (GstOggMux * ogg_mux, GstOggPadData * first, if (secondtime == GST_CLOCK_TIME_NONE) return 1; + firsttime = gst_segment_to_running_time (first->segment, GST_FORMAT_TIME, + firsttime); + secondtime = gst_segment_to_running_time (second->segment, GST_FORMAT_TIME, + secondtime); + /* first buffer has higher timestamp, second one should go first */ if (secondtime < firsttime) return 1; @@ -1226,7 +1237,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux) hbufs = g_list_delete_link (hbufs, hbufs); - if ((ret = gst_ogg_mux_push_buffer (mux, buf)) != GST_FLOW_OK) + if ((ret = gst_ogg_mux_push_buffer (mux, buf, NULL)) != GST_FLOW_OK) break; } /* free any remaining nodes/buffers in case we couldn't push them */ From fc56c7677328e7ae7fdfa8484dd5c71f655933d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 1 Apr 2011 10:57:08 +0200 Subject: [PATCH 06/18] oggmux: Reset the segment on flush-stop events and when going back to READY --- ext/ogg/gstoggmux.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ext/ogg/gstoggmux.c b/ext/ogg/gstoggmux.c index 256e13f39f..26b160eb4b 100644 --- a/ext/ogg/gstoggmux.c +++ b/ext/ogg/gstoggmux.c @@ -351,6 +351,10 @@ gst_ogg_mux_sink_event (GstPad * pad, GstEvent * event) break; } + case GST_EVENT_FLUSH_STOP:{ + gst_segment_init (ogg_pad->segment, GST_FORMAT_UNDEFINED); + break; + } default: ret = TRUE; break; @@ -1744,6 +1748,8 @@ gst_ogg_mux_clear_collectpads (GstCollectPads * collect) gst_buffer_unref (oggpad->next_buffer); oggpad->next_buffer = NULL; } + + gst_segment_init (oggpad->segment, GST_FORMAT_UNDEFINED); } } From 1c475f10e1bf76a060c54e227ae3dfd54802c17c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 1 Apr 2011 11:00:38 +0200 Subject: [PATCH 07/18] oggmux: Store the segment directly inside the pad Also initialize it always in TIME format. We require TIME segments in oggmux anyway and drop newsegment events in other formats and assume an open-ended segment starting at 0. --- ext/ogg/gstoggmux.c | 29 ++++++++++------------------- ext/ogg/gstoggmux.h | 2 +- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/ext/ogg/gstoggmux.c b/ext/ogg/gstoggmux.c index 26b160eb4b..7c99c78a17 100644 --- a/ext/ogg/gstoggmux.c +++ b/ext/ogg/gstoggmux.c @@ -64,7 +64,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_ogg_mux_debug); #define GST_BUFFER_RUNNING_TIME(buf, oggpad) \ (GST_BUFFER_DURATION_IS_VALID (buf) \ - ? gst_segment_to_running_time ((oggpad)->segment, GST_FORMAT_TIME, \ + ? gst_segment_to_running_time (&(oggpad)->segment, GST_FORMAT_TIME, \ GST_BUFFER_TIMESTAMP (buf)) : 0) #define GST_GP_FORMAT "[gp %8" G_GINT64_FORMAT "]" @@ -297,11 +297,6 @@ gst_ogg_mux_ogg_pad_destroy_notify (GstCollectData * data) g_queue_free (oggpad->pagebuffers); oggpad->pagebuffers = NULL; } - - if (oggpad->segment) { - gst_segment_free (oggpad->segment); - oggpad->segment = NULL; - } } static GstPadLinkReturn @@ -336,8 +331,6 @@ gst_ogg_mux_sink_event (GstPad * pad, GstEvent * event) GstFormat format; gint64 start, stop, position; - g_return_val_if_fail (ogg_pad->segment != NULL, FALSE); - gst_event_parse_new_segment_full (event, &update, &rate, &applied_rate, &format, &start, &stop, &position); @@ -346,13 +339,13 @@ gst_ogg_mux_sink_event (GstPad * pad, GstEvent * event) gst_event_unref (event); return FALSE; } - gst_segment_set_newsegment_full (ogg_pad->segment, update, rate, + gst_segment_set_newsegment_full (&ogg_pad->segment, update, rate, applied_rate, format, start, stop, position); break; } case GST_EVENT_FLUSH_STOP:{ - gst_segment_init (ogg_pad->segment, GST_FORMAT_UNDEFINED); + gst_segment_init (&ogg_pad->segment, GST_FORMAT_TIME); break; } default: @@ -458,9 +451,8 @@ gst_ogg_mux_request_new_pad (GstElement * element, oggpad->pagebuffers = g_queue_new (); oggpad->map.headers = NULL; oggpad->map.queued = NULL; - oggpad->segment = gst_segment_new (); - gst_segment_set_newsegment (oggpad->segment, FALSE, 1, GST_FORMAT_TIME, - 0, -1, 0); + + gst_segment_init (&oggpad->segment, GST_FORMAT_TIME); oggpad->collect_event = (GstPadEventFunction) GST_PAD_EVENTFUNC (newpad); gst_pad_set_event_function (newpad, @@ -763,9 +755,9 @@ gst_ogg_mux_compare_pads (GstOggMux * ogg_mux, GstOggPadData * first, if (secondtime == GST_CLOCK_TIME_NONE) return 1; - firsttime = gst_segment_to_running_time (first->segment, GST_FORMAT_TIME, + firsttime = gst_segment_to_running_time (&first->segment, GST_FORMAT_TIME, firsttime); - secondtime = gst_segment_to_running_time (second->segment, GST_FORMAT_TIME, + secondtime = gst_segment_to_running_time (&second->segment, GST_FORMAT_TIME, secondtime); /* first buffer has higher timestamp, second one should go first */ @@ -1714,9 +1706,8 @@ gst_ogg_mux_init_collectpads (GstCollectPads * collect) oggpad->prev_delta = FALSE; oggpad->data_pushed = FALSE; oggpad->pagebuffers = g_queue_new (); - oggpad->segment = gst_segment_new (); - gst_segment_set_newsegment (oggpad->segment, FALSE, 1, GST_FORMAT_TIME, - 0, -1, 0); + + gst_segment_init (&oggpad->segment, GST_FORMAT_TIME); walk = g_slist_next (walk); } @@ -1749,7 +1740,7 @@ gst_ogg_mux_clear_collectpads (GstCollectPads * collect) oggpad->next_buffer = NULL; } - gst_segment_init (oggpad->segment, GST_FORMAT_UNDEFINED); + gst_segment_init (&oggpad->segment, GST_FORMAT_TIME); } } diff --git a/ext/ogg/gstoggmux.h b/ext/ogg/gstoggmux.h index 62ac3ce5b7..933226d07a 100644 --- a/ext/ogg/gstoggmux.h +++ b/ext/ogg/gstoggmux.h @@ -53,7 +53,7 @@ typedef struct GstOggStream map; gboolean have_type; - GstSegment *segment; + GstSegment segment; /* These two buffers make a very simple queue - they enter as 'next_buffer' * and (usually) leave as 'buffer', except at EOS, when buffer will be NULL */ From a2532fc3f7ebc3598f3e3a9fb8106f563afe9c99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 1 Apr 2011 12:09:44 +0200 Subject: [PATCH 08/18] vorbistag: Use g_base64_decode_inplace() Instead of using the GLib base64 decoding functions manually to do inplace base64 decoding. This makes the code easier to understand. --- gst-libs/gst/tag/gstvorbistag.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/gst-libs/gst/tag/gstvorbistag.c b/gst-libs/gst/tag/gstvorbistag.c index 0b3ad57056..add3c9771b 100644 --- a/gst-libs/gst/tag/gstvorbistag.c +++ b/gst-libs/gst/tag/gstvorbistag.c @@ -313,28 +313,20 @@ gst_vorbis_tag_add_coverart (GstTagList * tags, gchar * img_data_base64, { GstBuffer *img; gsize img_len; - guchar *out; - guint save = 0; - gint state = 0; if (base64_len < 2) goto not_enough_data; /* img_data_base64 points to a temporary copy of the base64 encoded data, so * it's safe to do inpace decoding here - * TODO: glib 2.20 and later provides g_base64_decode_inplace, so change this - * to use glib's API instead once it's in wider use: - * http://bugzilla.gnome.org/show_bug.cgi?id=564728 - * http://svn.gnome.org/viewvc/glib?view=revision&revision=7807 */ - out = (guchar *) img_data_base64; - img_len = g_base64_decode_step (img_data_base64, base64_len, - out, &state, &save); - + */ + g_base64_decode_inplace (img_data_base64, &img_len); if (img_len == 0) goto decode_failed; - img = gst_tag_image_data_to_image_buffer (out, img_len, - GST_TAG_IMAGE_TYPE_NONE); + img = + gst_tag_image_data_to_image_buffer ((const guint8 *) img_data_base64, + img_len, GST_TAG_IMAGE_TYPE_NONE); if (img == NULL) goto convert_failed; From 57ff12bb0d3dd6936bd160b35e4fa45796959440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 1 Apr 2011 12:28:28 +0200 Subject: [PATCH 09/18] vorbistag: Add support for METADATA_BLOCK_PICTURE tags This is the official, standardized way of embedding pictures inside vorbiscomments now. Parsing code taken from flacparse and slightly changed. Fixes bug #635669. --- gst-libs/gst/tag/gstvorbistag.c | 62 +++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/gst-libs/gst/tag/gstvorbistag.c b/gst-libs/gst/tag/gstvorbistag.c index add3c9771b..140e06943d 100644 --- a/gst-libs/gst/tag/gstvorbistag.c +++ b/gst-libs/gst/tag/gstvorbistag.c @@ -37,6 +37,7 @@ #include "config.h" #endif #include +#include #include "gsttageditingprivate.h" #include #include @@ -355,6 +356,65 @@ convert_failed: } } +/* Standardized way of adding pictures to vorbiscomments: + * http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE + */ +static void +gst_vorbis_tag_add_metadata_block_picture (GstTagList * tags, + gchar * value, gint value_len) +{ + GstByteReader reader; + guint32 img_len = 0, img_type = 0; + guint32 img_mimetype_len = 0, img_description_len = 0; + gsize decoded_len; + const guint8 *data; + + /* img_data_base64 points to a temporary copy of the base64 encoded data, so + * it's safe to do inpace decoding here + */ + g_base64_decode_inplace (value, &decoded_len); + if (decoded_len == 0) + goto decode_failed; + + gst_byte_reader_init (&reader, (guint8 *) value, decoded_len); + + if (!gst_byte_reader_get_uint32_be (&reader, &img_type)) + goto error; + + if (!gst_byte_reader_get_uint32_be (&reader, &img_mimetype_len)) + goto error; + if (!gst_byte_reader_skip (&reader, img_mimetype_len)) + goto error; + + if (!gst_byte_reader_get_uint32_be (&reader, &img_description_len)) + goto error; + if (!gst_byte_reader_skip (&reader, img_description_len)) + goto error; + + /* Skip width, height, color depth and number of colors for + * indexed formats */ + if (!gst_byte_reader_skip (&reader, 4 * 4)) + goto error; + + if (!gst_byte_reader_get_uint32_be (&reader, &img_len)) + goto error; + + if (!gst_byte_reader_get_data (&reader, img_len, &data)) + goto error; + + gst_tag_list_add_id3_image (tags, data, img_len, img_type); + + return; + +error: + GST_WARNING + ("Couldn't extract image or image type from METADATA_BLOCK_PICTURE tag"); + return; +decode_failed: + GST_WARNING ("Failed to decode Base64 data from METADATA_BLOCK_PICTURE tag"); + return; +} + /** * gst_tag_list_from_vorbiscomment_buffer: * @buffer: buffer to convert @@ -433,6 +493,8 @@ gst_tag_list_from_vorbiscomment_buffer (const GstBuffer * buffer, continue; } else if (g_ascii_strcasecmp (cur, "COVERART") == 0) { gst_vorbis_tag_add_coverart (list, value, value_len); + } else if (g_ascii_strcasecmp (cur, "METADATA_BLOCK_PICTURE") == 0) { + gst_vorbis_tag_add_metadata_block_picture (list, value, value_len); } else { gst_vorbis_tag_add (list, cur, value); } From 35064fdc8283f3ba51a4c0082c4d97f9c20eb668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 1 Apr 2011 12:52:05 +0200 Subject: [PATCH 10/18] vorbistag: Write GST_TAG_IMAGE and GST_TAG_PREVIEW_IMAGE as METADATA_BLOCK_PICTURE This is the official, standardized way of embedding images into vorbiscomments now. --- gst-libs/gst/tag/gstvorbistag.c | 66 +++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/gst-libs/gst/tag/gstvorbistag.c b/gst-libs/gst/tag/gstvorbistag.c index 140e06943d..4f16636e5e 100644 --- a/gst-libs/gst/tag/gstvorbistag.c +++ b/gst-libs/gst/tag/gstvorbistag.c @@ -38,6 +38,7 @@ #endif #include #include +#include #include "gsttageditingprivate.h" #include #include @@ -518,34 +519,74 @@ typedef struct MyForEach; static GList * -gst_tag_to_coverart (const GValue * image_value) +gst_tag_to_metadata_block_picture (const gchar * tag, + const GValue * image_value) { - gchar *coverart_data, *data_result, *mime_result; + gchar *comment_data, *data_result; const gchar *mime_type; + guint mime_type_len; GstStructure *mime_struct; GstBuffer *buffer; GList *l = NULL; + GstByteWriter writer; + GstTagImageType image_type = GST_TAG_IMAGE_TYPE_NONE; + gint width = 0, height = 0; + guint8 *metadata_block; + guint metadata_block_len; g_return_val_if_fail (image_value != NULL, NULL); buffer = gst_value_get_buffer (image_value); g_return_val_if_fail (gst_caps_is_fixed (buffer->caps), NULL); mime_struct = gst_caps_get_structure (buffer->caps, 0); - mime_type = gst_structure_get_name (mime_struct); - if (strcmp (mime_type, "text/uri-list") == 0) { - /* URI reference */ - coverart_data = g_strndup ((gchar *) buffer->data, buffer->size); + mime_type = gst_structure_get_name (mime_struct); + if (strcmp (mime_type, "text/uri-list") == 0) + mime_type = "-->"; + mime_type_len = strlen (mime_type); + + gst_structure_get (mime_struct, "image-type", GST_TYPE_TAG_IMAGE_TYPE, + &image_type, "width", G_TYPE_INT, &width, "height", G_TYPE_INT, &height, + NULL); + + metadata_block_len = 32 + mime_type_len + GST_BUFFER_SIZE (buffer); + gst_byte_writer_init_with_size (&writer, metadata_block_len, TRUE); + + if (image_type == GST_TAG_IMAGE_TYPE_NONE + && strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0) { + gst_byte_writer_put_uint32_be_unchecked (&writer, 0x01); } else { - coverart_data = g_base64_encode (buffer->data, buffer->size); + /* Convert to ID3v2 APIC image type */ + if (image_type == GST_TAG_IMAGE_TYPE_NONE) + image_type = GST_TAG_IMAGE_TYPE_UNDEFINED; + else + image_type = image_type + 2; + gst_byte_writer_put_uint32_be_unchecked (&writer, image_type); } - data_result = g_strdup_printf ("COVERART=%s", coverart_data); - mime_result = g_strdup_printf ("COVERARTMIME=%s", mime_type); - g_free (coverart_data); + gst_byte_writer_put_uint32_be_unchecked (&writer, mime_type_len); + gst_byte_writer_put_data_unchecked (&writer, (guint8 *) mime_type, + mime_type_len); + /* description length */ + gst_byte_writer_put_uint32_be_unchecked (&writer, 0); + gst_byte_writer_put_uint32_be_unchecked (&writer, width); + gst_byte_writer_put_uint32_be_unchecked (&writer, height); + /* color depth */ + gst_byte_writer_put_uint32_be_unchecked (&writer, 0); + /* for indexed formats the number of colors */ + gst_byte_writer_put_uint32_be_unchecked (&writer, 0); + gst_byte_writer_put_uint32_be_unchecked (&writer, GST_BUFFER_SIZE (buffer)); + gst_byte_writer_put_data_unchecked (&writer, GST_BUFFER_DATA (buffer), + GST_BUFFER_SIZE (buffer)); + g_assert (gst_byte_writer_get_pos (&writer) == metadata_block_len); + + metadata_block = gst_byte_writer_reset_and_get_data (&writer); + comment_data = g_base64_encode (metadata_block, metadata_block_len); + g_free (metadata_block); + data_result = g_strdup_printf ("METADATA_BLOCK_PICTURE=%s", comment_data); + g_free (comment_data); l = g_list_append (l, data_result); - l = g_list_append (l, mime_result); return l; } @@ -580,7 +621,8 @@ gst_tag_to_vorbis_comments (const GstTagList * list, const gchar * tag) if ((strcmp (tag, GST_TAG_PREVIEW_IMAGE) == 0 && gst_tag_list_get_tag_size (list, GST_TAG_IMAGE) == 0) || strcmp (tag, GST_TAG_IMAGE) == 0) { - return gst_tag_to_coverart (gst_tag_list_get_value_index (list, tag, 0)); + return gst_tag_to_metadata_block_picture (tag, + gst_tag_list_get_value_index (list, tag, 0)); } if (strcmp (tag, GST_TAG_EXTENDED_COMMENT) != 0) { From fbc60fc6f45a676430c1ebd5b81a5e2ff12b9934 Mon Sep 17 00:00:00 2001 From: Josep Torra Date: Fri, 1 Apr 2011 15:33:42 +0200 Subject: [PATCH 11/18] textoverlay: fix comparison is always false due to limited range of data type Perform calculation in a temp var with enough room as there's guarantee that ret will be able to hold the result for example in _blit_AYUV. --- ext/pango/gsttextoverlay.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/pango/gsttextoverlay.c b/ext/pango/gsttextoverlay.c index 21ac0138aa..914c216952 100644 --- a/ext/pango/gsttextoverlay.c +++ b/ext/pango/gsttextoverlay.c @@ -145,8 +145,9 @@ GST_DEBUG_CATEGORY (pango_debug); #define OVER(ret, alphaA, Ca, alphaB, Cb, alphaNew) \ { \ - ret = (Ca * alphaA + Cb * alphaB * (255 - alphaA) / 255) / alphaNew; \ - ret = CLAMP (ret, 0, 255); \ + gint _tmp; \ + _tmp = (Ca * alphaA + Cb * alphaB * (255 - alphaA) / 255) / alphaNew; \ + ret = CLAMP (_tmp, 0, 255); \ } #if G_BYTE_ORDER == G_LITTLE_ENDIAN From cd425d37870892f56248c7f2464a42da3e9f438d Mon Sep 17 00:00:00 2001 From: Josep Torra Date: Fri, 1 Apr 2011 15:34:30 +0200 Subject: [PATCH 12/18] oggmux: fix warning building in mac os x --- ext/ogg/gstoggmux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ogg/gstoggmux.c b/ext/ogg/gstoggmux.c index 7c99c78a17..437ebbff77 100644 --- a/ext/ogg/gstoggmux.c +++ b/ext/ogg/gstoggmux.c @@ -1197,7 +1197,7 @@ gst_ogg_mux_send_headers (GstOggMux * mux) if (hwalk == NULL) { GST_LOG_OBJECT (mux, "flushing page as packet %" G_GUINT64_FORMAT " is first or " - "last packet", packet.packetno); + "last packet", (guint64) packet.packetno); while (ogg_stream_flush (&pad->map.stream, &page)) { GstBuffer *hbuf = gst_ogg_mux_buffer_from_page (mux, &page, FALSE); From 629cac4cadf7ed600c1abb67eb78e4c9f477c487 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Wed, 23 Mar 2011 23:10:51 -0700 Subject: [PATCH 13/18] video: Fix height calculation for YUV9/YVU9 --- gst-libs/gst/video/video.c | 4 ++-- tests/check/libs/video.c | 8 -------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/gst-libs/gst/video/video.c b/gst-libs/gst/video/video.c index fd265a13e6..efb2e9f051 100644 --- a/gst-libs/gst/video/video.c +++ b/gst-libs/gst/video/video.c @@ -1926,9 +1926,9 @@ gst_video_format_get_component_offset (GstVideoFormat format, if (component == 0) return 0; if (component == 1) - return GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height); + return GST_ROUND_UP_4 (width) * height; if (component == 2) { - return GST_ROUND_UP_4 (width) * GST_ROUND_UP_2 (height) + + return GST_ROUND_UP_4 (width) * height + GST_ROUND_UP_4 (GST_ROUND_UP_4 (width) / 4) * (GST_ROUND_UP_4 (height) / 4); } diff --git a/tests/check/libs/video.c b/tests/check/libs/video.c index 34d28e049a..dc5ef88546 100644 --- a/tests/check/libs/video.c +++ b/tests/check/libs/video.c @@ -424,14 +424,6 @@ GST_START_TEST (test_video_formats) off1 = gst_video_format_get_component_offset (fmt, 1, w, h); off2 = gst_video_format_get_component_offset (fmt, 2, w, h); - /* FIXME: for YUV9/YVU9 old videotestsrc code disagrees with new code - * - figure out which is right */ - if (fmt == GST_VIDEO_FORMAT_YUV9 || fmt == GST_VIDEO_FORMAT_YVU9) { - if (w == 1 && h == 1) - GST_ERROR ("FIXME: fix GST_VIDEO_FORMAT_YUV9/YVU9 size checks"); - goto skip_check; - } - fail_unless_equals_int (size, (unsigned long) paintinfo.endptr); fail_unless_equals_int (off0, (unsigned long) paintinfo.yp); fail_unless_equals_int (off1, (unsigned long) paintinfo.up); From 12513a95375677be08f34967ff6060a1b49c7656 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Fri, 1 Apr 2011 13:55:26 -0700 Subject: [PATCH 14/18] Remove setting of plugindir from Makefiles --- gst/encoding/Makefile.am | 2 -- gst/playback/Makefile.am | 2 -- 2 files changed, 4 deletions(-) diff --git a/gst/encoding/Makefile.am b/gst/encoding/Makefile.am index 0e287fad13..2bd7cddfa8 100644 --- a/gst/encoding/Makefile.am +++ b/gst/encoding/Makefile.am @@ -6,8 +6,6 @@ glib_gen_basename = gstencode built_sources = gstencode-marshal.c built_headers = gstencode-marshal.h -plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@ - plugin_LTLIBRARIES = libgstencodebin.la libgstencodebin_la_SOURCES = \ diff --git a/gst/playback/Makefile.am b/gst/playback/Makefile.am index 6e7130e4ce..b78e2e2823 100644 --- a/gst/playback/Makefile.am +++ b/gst/playback/Makefile.am @@ -6,8 +6,6 @@ glib_gen_basename = gstplay built_sources = gstplay-marshal.c built_headers = gstplay-marshal.h -plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@ - plugin_LTLIBRARIES = libgstplaybin.la libgstdecodebin.la libgstdecodebin2.la libgstplaybin_la_SOURCES = \ From 588ac0ae6fdfb55c612cc84f5426cbf1ee4aec4e Mon Sep 17 00:00:00 2001 From: Havard Graff Date: Tue, 8 Feb 2011 18:27:43 +0100 Subject: [PATCH 15/18] baseaudiosink: don't allow aligning behind the read-segment Given a large enough drift-tolerance, one could end up in a situation where one would keep aligning the written buffers behind the current read-segment position. The result for the reader would be complete silence, possible preceded by very choppy audio. By checking the available headroom, one can determine if there is room to do alignment, or if one should resort to a resync instead to get the pointers back on track. Also refactor the alignment-logic out of the render function for cleaner code. --- gst-libs/gst/audio/gstbaseaudiosink.c | 75 ++++++++++++++++++--------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/gst-libs/gst/audio/gstbaseaudiosink.c b/gst-libs/gst/audio/gstbaseaudiosink.c index c0f6008f35..60930926bc 100644 --- a/gst-libs/gst/audio/gstbaseaudiosink.c +++ b/gst-libs/gst/audio/gstbaseaudiosink.c @@ -1319,6 +1319,56 @@ flushing: } } +static gint64 +gst_base_audio_sink_get_alignment (GstBaseAudioSink * sink, GstClockTime sample_offset) +{ + GstRingBuffer *ringbuf = sink->ringbuffer; + gint64 align; + gint64 diff; + gint64 maxdrift; + gint segdone = g_atomic_int_get (&ringbuf->segdone) - ringbuf->segbase; + gint64 samples_done = segdone * ringbuf->samples_per_seg; + gint64 headroom = sample_offset - samples_done; + gboolean allow_align = TRUE; + + /* now try to align the sample to the previous one, first see how big the + * difference is. */ + if (sample_offset >= sink->next_sample) + diff = sample_offset - sink->next_sample; + else + diff = sink->next_sample - sample_offset; + + /* calculate the max allowed drift in units of samples. By default this is + * 20ms and should be anough to compensate for timestamp rounding errors. */ + maxdrift = (ringbuf->spec.rate * sink->priv->drift_tolerance) / GST_MSECOND; + + /* calc align with previous sample */ + align = sink->next_sample - sample_offset; + + /* don't align if it means writing behind the read-segment */ + if (diff > headroom && align < 0) + allow_align = FALSE; + + if (G_LIKELY (diff < maxdrift && allow_align)) { + GST_DEBUG_OBJECT (sink, + "align with prev sample, ABS (%" G_GINT64_FORMAT ") < %" + G_GINT64_FORMAT, align, maxdrift); + } else { + /* calculate sample diff in seconds for error message */ + gint64 diff_s = gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate); + /* timestamps drifted apart from previous samples too much, we need to + * resync. We log this as an element warning. */ + GST_WARNING_OBJECT (sink, + "Unexpected discontinuity in audio timestamps of " + "%s%" GST_TIME_FORMAT ", resyncing", + sample_offset > sink->next_sample ? "+" : "-", + GST_TIME_ARGS (diff_s)); + align = 0; + } + + return align; +} + static GstFlowReturn gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf) { @@ -1340,7 +1390,6 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf) GstFlowReturn ret; GstSegment clip_seg; gint64 time_offset; - gint64 maxdrift; sink = GST_BASE_AUDIO_SINK (bsink); @@ -1574,29 +1623,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf) goto no_align; } - /* now try to align the sample to the previous one, first see how big the - * difference is. */ - if (sample_offset >= sink->next_sample) - diff = sample_offset - sink->next_sample; - else - diff = sink->next_sample - sample_offset; - - /* calculate the max allowed drift in units of samples. By default this is - * 20ms and should be anough to compensate for timestamp rounding errors. */ - maxdrift = (ringbuf->spec.rate * sink->priv->drift_tolerance) / GST_MSECOND; - - if (G_LIKELY (diff < maxdrift)) { - /* calc align with previous sample */ - align = sink->next_sample - sample_offset; - GST_DEBUG_OBJECT (sink, - "align with prev sample, ABS (%" G_GINT64_FORMAT ") < %" - G_GINT64_FORMAT, align, maxdrift); - } else { - GST_DEBUG_OBJECT (sink, - "discont timestamp (%" G_GINT64_FORMAT ") >= %" G_GINT64_FORMAT, diff, - maxdrift); - align = 0; - } + align = gst_base_audio_sink_get_alignment (sink, sample_offset); sink->priv->last_align = align; /* apply alignment */ From 63cfa2a50da29ef897ce598abe60a3cbda950989 Mon Sep 17 00:00:00 2001 From: Havard Graff Date: Sat, 22 Jan 2011 23:09:32 +0100 Subject: [PATCH 16/18] baseaudiosrc: protect against ringbuffer disappearing while in a query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Observed a case where the src went to null-state during the query, hence the spec pointer was no longer valid, and gst_util_unit64_scale_int crashed (assertion `denom > 0´failed) Add locking to make sure the ringbuffer can't disappear. --- gst-libs/gst/audio/gstbaseaudiosrc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gst-libs/gst/audio/gstbaseaudiosrc.c b/gst-libs/gst/audio/gstbaseaudiosrc.c index 06aa3abffa..adf9254ae6 100644 --- a/gst-libs/gst/audio/gstbaseaudiosrc.c +++ b/gst-libs/gst/audio/gstbaseaudiosrc.c @@ -628,9 +628,12 @@ gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query) GstClockTime min_latency, max_latency; GstRingBufferSpec *spec; + GST_OBJECT_LOCK (src); if (G_UNLIKELY (src->ringbuffer == NULL - || src->ringbuffer->spec.rate == 0)) + || src->ringbuffer->spec.rate == 0)) { + GST_OBJECT_UNLOCK (src); goto done; + } spec = &src->ringbuffer->spec; @@ -642,6 +645,7 @@ gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query) max_latency = gst_util_uint64_scale_int (spec->segtotal * spec->segsize, GST_SECOND, spec->rate * spec->bytes_per_sample); + GST_OBJECT_UNLOCK (src); GST_DEBUG_OBJECT (src, "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT, From 0f8edca902c09622493d23776859bab2348837f6 Mon Sep 17 00:00:00 2001 From: Stian Johansen Date: Wed, 23 Feb 2011 10:55:12 +0100 Subject: [PATCH 17/18] baseaudiosrc: Add src object lock around call to ringbuffer parse caps. A race was observed between query() and setcaps() where the latter would change the ringbuffer spec while the former was performing operations based this data. --- gst-libs/gst/audio/gstbaseaudiosrc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gst-libs/gst/audio/gstbaseaudiosrc.c b/gst-libs/gst/audio/gstbaseaudiosrc.c index adf9254ae6..7c7ec935b0 100644 --- a/gst-libs/gst/audio/gstbaseaudiosrc.c +++ b/gst-libs/gst/audio/gstbaseaudiosrc.c @@ -560,14 +560,20 @@ gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps) spec->buffer_time = src->buffer_time; spec->latency_time = src->latency_time; + GST_OBJECT_LOCK (src); if (!gst_ring_buffer_parse_caps (spec, caps)) + { + GST_OBJECT_UNLOCK (src); goto parse_error; + } /* calculate suggested segsize and segtotal */ spec->segsize = spec->rate * spec->bytes_per_sample * spec->latency_time / GST_MSECOND; spec->segtotal = spec->buffer_time / spec->latency_time; + GST_OBJECT_UNLOCK (src); + GST_DEBUG ("release old ringbuffer"); gst_ring_buffer_release (src->ringbuffer); From cec628a414b8c7ce0a904a579ecd79defbdcb2df Mon Sep 17 00:00:00 2001 From: Trond Andersen Date: Fri, 11 Mar 2011 10:41:11 +0100 Subject: [PATCH 18/18] rtcpbuffer: fix invalid read in validation of padding in rtcp packet --- gst-libs/gst/rtp/gstrtcpbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.c b/gst-libs/gst/rtp/gstrtcpbuffer.c index 096f79ec36..bdaf89bfcc 100644 --- a/gst-libs/gst/rtp/gstrtcpbuffer.c +++ b/gst-libs/gst/rtp/gstrtcpbuffer.c @@ -163,7 +163,7 @@ gst_rtcp_buffer_validate_data (guint8 * data, guint len) goto wrong_length; /* get padding */ - pad_bytes = data[len - 1]; + pad_bytes = data[data_len - 1]; if (data_len != pad_bytes) goto wrong_padding; }