summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian.droege@collabora.co.uk>2009-12-07 15:31:41 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2009-12-07 17:10:34 +0100
commitd8fc5de450233f4ff85851adb5fb141aeef52a72 (patch)
tree2f044cf7924cb21023eb7213099b658740fd61ad
parent3e55a5ba7f5b15b72027d55945e5368b85c9a0bf (diff)
assrender: Optimize blit function and add support for all other non-alpha RGB formats
Also make sure to not write behind array bounds.
-rw-r--r--ext/assrender/gstassrender.c182
-rw-r--r--ext/assrender/gstassrender.h4
2 files changed, 126 insertions, 60 deletions
diff --git a/ext/assrender/gstassrender.c b/ext/assrender/gstassrender.c
index 61b9447ff..1acfd2f4b 100644
--- a/ext/assrender/gstassrender.c
+++ b/ext/assrender/gstassrender.c
@@ -46,14 +46,18 @@ enum
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
+ GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
+ GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx)
);
static GstStaticPadTemplate video_sink_factory =
-GST_STATIC_PAD_TEMPLATE ("video_sink",
+ GST_STATIC_PAD_TEMPLATE ("video_sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
+ GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_xBGR ";"
+ GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx)
);
static GstStaticPadTemplate text_sink_factory =
@@ -359,57 +363,143 @@ gst_ass_render_getcaps (GstPad * pad)
return caps;
}
+#define CREATE_RGB_BLIT_FUNCTION(name,bpp,R,G,B) \
+static void \
+blit_##name (GstAssRender * render, ASS_Image * ass_image, GstBuffer * buffer) \
+{ \
+ guint counter = 0; \
+ guint8 alpha, r, g, b, k; \
+ const guint8 *src; \
+ guint8 *dst; \
+ gint x, y, w, h; \
+ gint width = render->width; \
+ gint height = render->height; \
+ gint dst_stride = GST_ROUND_UP_4 (width * bpp); \
+ gint dst_skip; \
+ gint src_stride, src_skip; \
+ \
+ while (ass_image) { \
+ if (ass_image->dst_y > height || ass_image->dst_x > width) \
+ goto next; \
+ \
+ /* blend subtitles onto the video frame */ \
+ alpha = 255 - ((ass_image->color) & 0xff); \
+ r = ((ass_image->color) >> 24) & 0xff; \
+ g = ((ass_image->color) >> 16) & 0xff; \
+ b = ((ass_image->color) >> 8) & 0xff; \
+ src = ass_image->bitmap; \
+ dst = buffer->data + ass_image->dst_y * dst_stride + ass_image->dst_x * bpp; \
+ \
+ w = MIN (ass_image->w, width - ass_image->dst_x); \
+ h = MIN (ass_image->h, height - ass_image->dst_y); \
+ src_stride = ass_image->stride; \
+ src_skip = ass_image->stride - w; \
+ dst_skip = dst_stride - w * bpp; \
+ \
+ for (y = 0; y < h; y++) { \
+ for (x = 0; x < w; x++) { \
+ k = ((guint8) src[0]) * alpha / 255; \
+ dst[R] = (k * r + (255 - k) * dst[R]) / 255; \
+ dst[G] = (k * g + (255 - k) * dst[G]) / 255; \
+ dst[B] = (k * b + (255 - k) * dst[B]) / 255; \
+ src++; \
+ dst += bpp; \
+ } \
+ src += src_skip; \
+ dst += dst_skip; \
+ } \
+next: \
+ counter++; \
+ ass_image = ass_image->next; \
+ } \
+ GST_LOG_OBJECT (render, "amount of rendered ass_image: %u", counter); \
+}
+
+CREATE_RGB_BLIT_FUNCTION (rgb, 3, 0, 1, 2);
+CREATE_RGB_BLIT_FUNCTION (bgr, 3, 2, 1, 0);
+CREATE_RGB_BLIT_FUNCTION (xrgb, 4, 1, 2, 3);
+CREATE_RGB_BLIT_FUNCTION (xbgr, 4, 3, 2, 1);
+CREATE_RGB_BLIT_FUNCTION (rgbx, 4, 0, 1, 2);
+CREATE_RGB_BLIT_FUNCTION (bgrx, 4, 2, 1, 0);
+
+#undef CREATE_RGB_BLIT_FUNCTION
+
static gboolean
gst_ass_render_setcaps_video (GstPad * pad, GstCaps * caps)
{
GstAssRender *render = GST_ASS_RENDER (gst_pad_get_parent (pad));
- GstStructure *structure;
gboolean ret = FALSE;
gint par_n = 1, par_d = 1;
+ gdouble dar;
render->width = 0;
render->height = 0;
- structure = gst_caps_get_structure (caps, 0);
+ if (!gst_video_format_parse_caps (caps, &render->format, &render->width,
+ &render->height)) {
+ GST_ERROR_OBJECT (render, "Can't parse caps: %" GST_PTR_FORMAT, caps);
+ ret = FALSE;
+ goto out;
+ }
- gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_n, &par_d);
+ gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d);
- if (gst_structure_get_int (structure, "width", &render->width) &&
- gst_structure_get_int (structure, "height", &render->height)) {
- gdouble dar;
+ ret = gst_pad_set_caps (render->srcpad, caps);
+ if (!ret)
+ goto out;
- ret = gst_pad_set_caps (render->srcpad, caps);
- ass_set_frame_size (render->ass_renderer, render->width, render->height);
+ switch (render->format) {
+ case GST_VIDEO_FORMAT_RGB:
+ render->blit = blit_rgb;
+ break;
+ case GST_VIDEO_FORMAT_BGR:
+ render->blit = blit_bgr;
+ break;
+ case GST_VIDEO_FORMAT_xRGB:
+ render->blit = blit_xrgb;
+ break;
+ case GST_VIDEO_FORMAT_xBGR:
+ render->blit = blit_xbgr;
+ break;
+ case GST_VIDEO_FORMAT_RGBx:
+ render->blit = blit_rgbx;
+ break;
+ case GST_VIDEO_FORMAT_BGRx:
+ render->blit = blit_bgrx;
+ break;
+ default:
+ ret = FALSE;
+ goto out;
+ }
+
+ ass_set_frame_size (render->ass_renderer, render->width, render->height);
- dar = (((gdouble) par_n) * ((gdouble) render->width));
- dar /= (((gdouble) par_d) * ((gdouble) render->height));
+ dar = (((gdouble) par_n) * ((gdouble) render->width))
+ / (((gdouble) par_d) * ((gdouble) render->height));
#if !defined(LIBASS_VERSION) || LIBASS_VERSION < 0x00907000
- ass_set_aspect_ratio (render->ass_renderer, dar);
+ ass_set_aspect_ratio (render->ass_renderer, dar);
#else
- ass_set_aspect_ratio (render->ass_renderer,
- dar, ((gdouble) render->width) / ((gdouble) render->height));
+ ass_set_aspect_ratio (render->ass_renderer,
+ dar, ((gdouble) render->width) / ((gdouble) render->height));
#endif
- ass_set_font_scale (render->ass_renderer, 1.0);
- ass_set_hinting (render->ass_renderer, ASS_HINTING_NATIVE);
+ ass_set_font_scale (render->ass_renderer, 1.0);
+ ass_set_hinting (render->ass_renderer, ASS_HINTING_NATIVE);
#if !defined(LIBASS_VERSION) || LIBASS_VERSION < 0x00907000
- ass_set_fonts (render->ass_renderer, "Arial", "sans-serif");
- ass_set_fonts (render->ass_renderer, NULL, "Sans");
+ ass_set_fonts (render->ass_renderer, "Arial", "sans-serif");
+ ass_set_fonts (render->ass_renderer, NULL, "Sans");
#else
- ass_set_fonts (render->ass_renderer, "Arial", "sans-serif", 1, NULL, 1);
- ass_set_fonts (render->ass_renderer, NULL, "Sans", 1, NULL, 1);
+ ass_set_fonts (render->ass_renderer, "Arial", "sans-serif", 1, NULL, 1);
+ ass_set_fonts (render->ass_renderer, NULL, "Sans", 1, NULL, 1);
#endif
- ass_set_margins (render->ass_renderer, 0, 0, 0, 0);
- ass_set_use_margins (render->ass_renderer, 0);
+ ass_set_margins (render->ass_renderer, 0, 0, 0, 0);
+ ass_set_use_margins (render->ass_renderer, 0);
- render->renderer_init_ok = TRUE;
+ render->renderer_init_ok = TRUE;
- GST_DEBUG_OBJECT (render, "ass renderer setup complete");
- } else {
- GST_ERROR_OBJECT (render, "Invalid caps %" GST_PTR_FORMAT, caps);
- ret = FALSE;
- }
+ GST_DEBUG_OBJECT (render, "ass renderer setup complete");
+out:
gst_object_unref (render);
return ret;
@@ -569,7 +659,6 @@ gst_ass_render_chain_video (GstPad * pad, GstBuffer * buffer)
/* now start rendering subtitles, if all conditions are met */
if (render->renderer_init_ok && render->track_init_ok && render->enable) {
- gint counter;
GstClockTime running_time;
gdouble timestamp;
#ifndef GST_DISABLE_GST_DEBUG
@@ -595,7 +684,7 @@ gst_ass_render_chain_video (GstPad * pad, GstBuffer * buffer)
/* not sure what the last parameter to this call is for (detect_change) */
ass_image = ass_render_frame (render->ass_renderer, render->ass_track,
- timestamp, 0);
+ timestamp, NULL);
if (ass_image == NULL) {
GST_LOG_OBJECT (render, "nothing to render right now");
@@ -603,34 +692,7 @@ gst_ass_render_chain_video (GstPad * pad, GstBuffer * buffer)
return ret;
}
- counter = 0;
- while (ass_image) {
- /* blend subtitles onto the video frame */
- guint8 alpha = 255 - ((ass_image->color) & 0xff);
- guint8 r = ((ass_image->color) >> 24) & 0xff;
- guint8 g = ((ass_image->color) >> 16) & 0xff;
- guint8 b = ((ass_image->color) >> 8) & 0xff;
- guint8 *src = ass_image->bitmap;
- guint8 *dst =
- buffer->data + ass_image->dst_y *
- GST_ROUND_UP_4 (render->width * 3) + ass_image->dst_x * 3;
- guint x = 0;
- guint y = 0;
-
- for (y = 0; y < ass_image->h; y++) {
- for (x = 0; x < ass_image->w; x++) {
- guint8 k = ((guint8) src[x]) * alpha / 255;
- dst[x * 3] = (k * r + (255 - k) * dst[x * 3]) / 255;
- dst[x * 3 + 1] = (k * g + (255 - k) * dst[x * 3 + 1]) / 255;
- dst[x * 3 + 2] = (k * b + (255 - k) * dst[x * 3 + 2]) / 255;
- }
- src += ass_image->stride;
- dst += GST_ROUND_UP_4 (render->width * 3);
- }
- counter++;
- ass_image = ass_image->next;
- }
- GST_LOG_OBJECT (render, "amount of rendered ass_image: %d", counter);
+ render->blit (render, ass_image, buffer);
}
ret = gst_pad_push (render->srcpad, buffer);
diff --git a/ext/assrender/gstassrender.h b/ext/assrender/gstassrender.h
index 43ce5f8d8..c680dc5ae 100644
--- a/ext/assrender/gstassrender.h
+++ b/ext/assrender/gstassrender.h
@@ -21,6 +21,7 @@
#define __GST_ASS_RENDER_H__
#include <gst/gst.h>
+#include <gst/video/video.h>
#include <ass/ass.h>
#include <ass/ass_types.h>
@@ -42,6 +43,7 @@ G_BEGIN_DECLS
typedef struct _GstAssRender GstAssRender;
typedef struct _GstAssRenderClass GstAssRenderClass;
+typedef void (*GstAssRenderBlitFunction) (GstAssRender *render, ASS_Image *ass_image, GstBuffer *buffer);
struct _GstAssRender
{
@@ -51,7 +53,9 @@ struct _GstAssRender
GstSegment video_segment;
+ GstVideoFormat format;
gint width, height;
+ GstAssRenderBlitFunction blit;
GMutex *subtitle_mutex;
GCond *subtitle_cond;