61
83
GST_STATIC_CAPS ("application/x-ass; application/x-ssa")
64
static void gst_assrender_set_property (GObject * object, guint prop_id,
86
static void gst_ass_render_set_property (GObject * object, guint prop_id,
65
87
const GValue * value, GParamSpec * pspec);
66
static void gst_assrender_get_property (GObject * object, guint prop_id,
88
static void gst_ass_render_get_property (GObject * object, guint prop_id,
67
89
GValue * value, GParamSpec * pspec);
69
static void gst_assrender_finalize (GObject * object);
91
static void gst_ass_render_finalize (GObject * object);
71
static GstStateChangeReturn gst_assrender_change_state (GstElement * element,
93
static GstStateChangeReturn gst_ass_render_change_state (GstElement * element,
72
94
GstStateChange transition);
74
GST_BOILERPLATE (Gstassrender, gst_assrender, GstElement, GST_TYPE_ELEMENT);
76
static GstCaps *gst_assrender_getcaps (GstPad * pad);
78
static gboolean gst_assrender_setcaps_video (GstPad * pad, GstCaps * caps);
79
static gboolean gst_assrender_setcaps_text (GstPad * pad, GstCaps * caps);
81
static GstFlowReturn gst_assrender_chain_video (GstPad * pad, GstBuffer * buf);
82
static GstFlowReturn gst_assrender_chain_text (GstPad * pad, GstBuffer * buf);
84
static gboolean gst_assrender_event_video (GstPad * pad, GstEvent * event);
85
static gboolean gst_assrender_event_text (GstPad * pad, GstEvent * event);
96
GST_BOILERPLATE (GstAssRender, gst_ass_render, GstElement, GST_TYPE_ELEMENT);
98
static GstCaps *gst_ass_render_getcaps (GstPad * pad);
100
static gboolean gst_ass_render_setcaps_video (GstPad * pad, GstCaps * caps);
101
static gboolean gst_ass_render_setcaps_text (GstPad * pad, GstCaps * caps);
103
static GstFlowReturn gst_ass_render_chain_video (GstPad * pad, GstBuffer * buf);
104
static GstFlowReturn gst_ass_render_chain_text (GstPad * pad, GstBuffer * buf);
106
static gboolean gst_ass_render_event_video (GstPad * pad, GstEvent * event);
107
static gboolean gst_ass_render_event_text (GstPad * pad, GstEvent * event);
108
static gboolean gst_ass_render_event_src (GstPad * pad, GstEvent * event);
110
static GstFlowReturn gst_ass_render_bufferalloc_video (GstPad * pad,
111
guint64 offset, guint size, GstCaps * caps, GstBuffer ** buffer);
113
static gboolean gst_ass_render_query_src (GstPad * pad, GstQuery * query);
88
gst_assrender_base_init (gpointer gclass)
116
gst_ass_render_base_init (gpointer gclass)
90
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
118
GstElementClass *element_class = (GstElementClass *) gclass;
92
120
gst_element_class_add_pad_template (element_class,
93
121
gst_static_pad_template_get (&src_factory));
99
127
gst_element_class_set_details_simple (element_class, "ASS/SSA Render",
100
128
"Mixer/Video/Overlay/Subtitle",
101
129
"Renders ASS/SSA subtitles with libass",
102
"Benjamin Schmitz <vortex@wolpzone.de>");
130
"Benjamin Schmitz <vortex@wolpzone.de>, "
131
"Sebastian Dröge <sebastian.droege@collabora.co.uk>");
105
134
/* initialize the plugin's class */
107
gst_assrender_class_init (GstassrenderClass * klass)
136
gst_ass_render_class_init (GstAssRenderClass * klass)
109
GObjectClass *gobject_class;
110
GstElementClass *gstelement_class;
112
gobject_class = (GObjectClass *) klass;
113
gstelement_class = (GstElementClass *) klass;
115
gobject_class->set_property = gst_assrender_set_property;
116
gobject_class->get_property = gst_assrender_get_property;
118
gobject_class->finalize = gst_assrender_finalize;
120
g_object_class_install_property (gobject_class, ARG_ENABLE,
121
g_param_spec_boolean ("enable", "Toggle rendering",
138
GObjectClass *gobject_class = (GObjectClass *) klass;
139
GstElementClass *gstelement_class = (GstElementClass *) klass;
141
gobject_class->set_property = gst_ass_render_set_property;
142
gobject_class->get_property = gst_ass_render_get_property;
143
gobject_class->finalize = gst_ass_render_finalize;
145
g_object_class_install_property (gobject_class, PROP_ENABLE,
146
g_param_spec_boolean ("enable", "Enable",
122
147
"Enable rendering of subtitles", TRUE,
123
148
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
124
g_object_class_install_property (gobject_class, ARG_EMBEDDEDFONTS,
125
g_param_spec_boolean ("embeddedfonts", "Use embedded fonts",
149
g_object_class_install_property (gobject_class, PROP_EMBEDDEDFONTS,
150
g_param_spec_boolean ("embeddedfonts", "Embedded Fonts",
126
151
"Extract and use fonts embedded in the stream", TRUE,
127
152
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
129
154
gstelement_class->change_state =
130
GST_DEBUG_FUNCPTR (gst_assrender_change_state);
134
gst_assrender_init (Gstassrender * render, GstassrenderClass * gclass)
155
GST_DEBUG_FUNCPTR (gst_ass_render_change_state);
158
#if defined(LIBASS_VERSION) && LIBASS_VERSION >= 0x00907000
160
_libass_message_cb (gint level, const gchar * fmt, va_list args, gpointer data)
162
GstAssRender *render = GST_ASS_RENDER (data);
163
gchar *message = g_strdup_vprintf (fmt, args);
166
GST_CAT_ERROR_OBJECT (gst_ass_render_lib_debug, render, message);
168
GST_CAT_WARNING_OBJECT (gst_ass_render_lib_debug, render, message);
170
GST_CAT_INFO_OBJECT (gst_ass_render_lib_debug, render, message);
172
GST_CAT_DEBUG_OBJECT (gst_ass_render_lib_debug, render, message);
174
GST_CAT_LOG_OBJECT (gst_ass_render_lib_debug, render, message);
181
gst_ass_render_init (GstAssRender * render, GstAssRenderClass * gclass)
136
183
GST_DEBUG_OBJECT (render, "init");
470
#define CREATE_RGB_BLIT_FUNCTION(name,bpp,R,G,B) \
472
blit_##name (GstAssRender * render, ASS_Image * ass_image, GstBuffer * buffer) \
475
gint alpha, r, g, b, k; \
479
gint width = render->width; \
480
gint height = render->height; \
481
gint dst_stride = GST_ROUND_UP_4 (width * bpp); \
483
gint src_stride, src_skip; \
485
while (ass_image) { \
486
if (ass_image->dst_y > height || ass_image->dst_x > width) \
489
/* blend subtitles onto the video frame */ \
490
alpha = 255 - ((ass_image->color) & 0xff); \
491
r = ((ass_image->color) >> 24) & 0xff; \
492
g = ((ass_image->color) >> 16) & 0xff; \
493
b = ((ass_image->color) >> 8) & 0xff; \
494
src = ass_image->bitmap; \
495
dst = buffer->data + ass_image->dst_y * dst_stride + ass_image->dst_x * bpp; \
497
w = MIN (ass_image->w, width - ass_image->dst_x); \
498
h = MIN (ass_image->h, height - ass_image->dst_y); \
499
src_stride = ass_image->stride; \
500
src_skip = ass_image->stride - w; \
501
dst_skip = dst_stride - w * bpp; \
503
for (y = 0; y < h; y++) { \
504
for (x = 0; x < w; x++) { \
505
k = src[0] * alpha / 255; \
506
dst[R] = (k * r + (255 - k) * dst[R]) / 255; \
507
dst[G] = (k * g + (255 - k) * dst[G]) / 255; \
508
dst[B] = (k * b + (255 - k) * dst[B]) / 255; \
517
ass_image = ass_image->next; \
519
GST_LOG_OBJECT (render, "amount of rendered ass_image: %u", counter); \
522
CREATE_RGB_BLIT_FUNCTION (rgb, 3, 0, 1, 2);
523
CREATE_RGB_BLIT_FUNCTION (bgr, 3, 2, 1, 0);
524
CREATE_RGB_BLIT_FUNCTION (xrgb, 4, 1, 2, 3);
525
CREATE_RGB_BLIT_FUNCTION (xbgr, 4, 3, 2, 1);
526
CREATE_RGB_BLIT_FUNCTION (rgbx, 4, 0, 1, 2);
527
CREATE_RGB_BLIT_FUNCTION (bgrx, 4, 2, 1, 0);
529
#undef CREATE_RGB_BLIT_FUNCTION
532
rgb_to_y (gint r, gint g, gint b)
536
ret = (gint) (((19595 * r) >> 16) + ((38470 * g) >> 16) + ((7471 * b) >> 16));
537
ret = CLAMP (ret, 0, 255);
542
rgb_to_u (gint r, gint g, gint b)
547
(gint) (-((11059 * r) >> 16) - ((21709 * g) >> 16) + ((32768 * b) >> 16) +
549
ret = CLAMP (ret, 0, 255);
554
rgb_to_v (gint r, gint g, gint b)
559
(gint) (((32768 * r) >> 16) - ((27439 * g) >> 16) - ((5329 * b) >> 16) +
561
ret = CLAMP (ret, 0, 255);
566
blit_i420 (GstAssRender * render, ASS_Image * ass_image, GstBuffer * buffer)
569
gint alpha, r, g, b, k, k2;
572
guint8 *dst_y, *dst_u, *dst_v;
575
gint width = render->width;
576
gint height = render->height;
578
gint y_offset, y_height, y_width, y_stride;
579
gint u_offset, u_height, u_width, u_stride;
580
gint v_offset, v_height, v_width, v_stride;
583
gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 0, width,
586
gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 1, width,
589
gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, 2, width,
593
gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 0, height);
595
gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 1, height);
597
gst_video_format_get_component_height (GST_VIDEO_FORMAT_I420, 2, height);
600
gst_video_format_get_component_width (GST_VIDEO_FORMAT_I420, 0, width);
602
gst_video_format_get_component_width (GST_VIDEO_FORMAT_I420, 1, width);
604
gst_video_format_get_component_width (GST_VIDEO_FORMAT_I420, 2, width);
606
y_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width);
607
u_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width);
608
v_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 2, width);
611
if (ass_image->dst_y > height || ass_image->dst_x > width)
614
/* blend subtitles onto the video frame */
615
alpha = 255 - ((ass_image->color) & 0xff);
616
r = ((ass_image->color) >> 24) & 0xff;
617
g = ((ass_image->color) >> 16) & 0xff;
618
b = ((ass_image->color) >> 8) & 0xff;
620
Y = rgb_to_y (r, g, b);
621
U = rgb_to_u (r, g, b);
622
V = rgb_to_v (r, g, b);
624
w = MIN (ass_image->w, width - ass_image->dst_x);
625
h = MIN (ass_image->h, height - ass_image->dst_y);
630
src_stride = ass_image->stride;
632
src = ass_image->bitmap;
634
buffer->data + y_offset + ass_image->dst_y * y_stride +
637
buffer->data + u_offset + ((ass_image->dst_y + 1) / 2) * u_stride +
638
(ass_image->dst_x + 1) / 2;
640
buffer->data + v_offset + ((ass_image->dst_y + 1) / 2) * v_stride +
641
(ass_image->dst_x + 1) / 2;
643
for (y = 0; y < h - 1; y += 2) {
644
for (x = 0; x < w - 1; x += 2) {
645
k = src[0] * alpha / 255;
647
dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
649
k = src[1] * alpha / 255;
651
dst_y[1] = (k * Y + (255 - k) * dst_y[1]) / 255;
656
k = src[0] * alpha / 255;
658
dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
660
k = src[1] * alpha / 255;
662
dst_y[1] = (k * Y + (255 - k) * dst_y[1]) / 255;
665
dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
666
dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
670
src += -src_stride + 2;
671
dst_y += -y_stride + 2;
675
k = src[0] * alpha / 255;
677
dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
682
k = src[0] * alpha / 255;
684
dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
687
dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
688
dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
692
src += -src_stride + 1;
693
dst_y += -y_stride + 1;
696
src += src_stride + (src_stride - w);
697
dst_y += y_stride + (y_stride - w);
698
dst_u += u_stride - w2;
699
dst_v += v_stride - w2;
703
for (x = 0; x < w - 1; x += 2) {
704
k = src[0] * alpha / 255;
706
dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
708
k = src[1] * alpha / 255;
710
dst_y[1] = (k * Y + (255 - k) * dst_y[1]) / 255;
713
dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
714
dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
723
k = src[0] * alpha / 255;
725
dst_y[0] = (k * Y + (255 - k) * dst_y[0]) / 255;
727
dst_u[0] = (k2 * U + (255 - k2) * dst_u[0]) / 255;
728
dst_v[0] = (k2 * V + (255 - k2) * dst_v[0]) / 255;
734
ass_image = ass_image->next;
737
GST_LOG_OBJECT (render, "amount of rendered ass_image: %u", counter);
344
gst_assrender_setcaps_video (GstPad * pad, GstCaps * caps)
741
gst_ass_render_setcaps_video (GstPad * pad, GstCaps * caps)
346
Gstassrender *render;
347
GstStructure *structure;
743
GstAssRender *render = GST_ASS_RENDER (gst_pad_get_parent (pad));
348
744
gboolean ret = FALSE;
349
745
gint par_n = 1, par_d = 1;
351
render = GST_ASSRENDER (gst_pad_get_parent (pad));
353
748
render->width = 0;
354
749
render->height = 0;
356
structure = gst_caps_get_structure (caps, 0);
358
gst_structure_get_fraction (structure, "pixel-aspect-ratio", &par_n, &par_d);
360
if (gst_structure_get_int (structure, "width", &render->width) &&
361
gst_structure_get_int (structure, "height", &render->height)) {
364
ret = gst_pad_set_caps (render->srcpad, caps);
365
ass_set_frame_size (render->ass_renderer, render->width, render->height);
367
dar = (((gdouble) par_n) * ((gdouble) render->width));
368
dar /= (((gdouble) par_d) * ((gdouble) render->height));
369
#if !defined(LIBASS_VERSION) || LIBASS_VERSION < 0x00907000
370
ass_set_aspect_ratio (render->ass_renderer, dar);
372
ass_set_aspect_ratio (render->ass_renderer,
373
dar, ((gdouble) render->width) / ((gdouble) render->height));
375
ass_set_font_scale (render->ass_renderer, 1.0);
376
ass_set_hinting (render->ass_renderer, ASS_HINTING_NATIVE);
378
#if !defined(LIBASS_VERSION) || LIBASS_VERSION < 0x00907000
379
ass_set_fonts (render->ass_renderer, "Arial", "sans-serif");
380
ass_set_fonts (render->ass_renderer, NULL, "Sans");
382
ass_set_fonts (render->ass_renderer, "Arial", "sans-serif", 1, NULL, 1);
383
ass_set_fonts (render->ass_renderer, NULL, "Sans", 1, NULL, 1);
385
ass_set_margins (render->ass_renderer, 0, 0, 0, 0);
386
ass_set_use_margins (render->ass_renderer, 0);
388
render->renderer_init_ok = TRUE;
390
GST_DEBUG_OBJECT (render, "ass renderer setup complete");
392
GST_ERROR_OBJECT (render, "Invalid caps %" GST_PTR_FORMAT, caps);
751
if (!gst_video_format_parse_caps (caps, &render->format, &render->width,
753
!gst_video_parse_caps_framerate (caps, &render->fps_n, &render->fps_d)) {
754
GST_ERROR_OBJECT (render, "Can't parse caps: %" GST_PTR_FORMAT, caps);
759
gst_video_parse_caps_pixel_aspect_ratio (caps, &par_n, &par_d);
761
ret = gst_pad_set_caps (render->srcpad, caps);
765
switch (render->format) {
766
case GST_VIDEO_FORMAT_RGB:
767
render->blit = blit_rgb;
769
case GST_VIDEO_FORMAT_BGR:
770
render->blit = blit_bgr;
772
case GST_VIDEO_FORMAT_xRGB:
773
render->blit = blit_xrgb;
775
case GST_VIDEO_FORMAT_xBGR:
776
render->blit = blit_xbgr;
778
case GST_VIDEO_FORMAT_RGBx:
779
render->blit = blit_rgbx;
781
case GST_VIDEO_FORMAT_BGRx:
782
render->blit = blit_bgrx;
784
case GST_VIDEO_FORMAT_I420:
785
render->blit = blit_i420;
792
g_mutex_lock (render->ass_mutex);
793
ass_set_frame_size (render->ass_renderer, render->width, render->height);
795
dar = (((gdouble) par_n) * ((gdouble) render->width))
796
/ (((gdouble) par_d) * ((gdouble) render->height));
797
#if !defined(LIBASS_VERSION) || LIBASS_VERSION < 0x00907000
798
ass_set_aspect_ratio (render->ass_renderer, dar);
800
ass_set_aspect_ratio (render->ass_renderer,
801
dar, ((gdouble) render->width) / ((gdouble) render->height));
803
ass_set_font_scale (render->ass_renderer, 1.0);
804
ass_set_hinting (render->ass_renderer, ASS_HINTING_LIGHT);
806
#if !defined(LIBASS_VERSION) || LIBASS_VERSION < 0x00907000
807
ass_set_fonts (render->ass_renderer, "Arial", "sans-serif");
808
ass_set_fonts (render->ass_renderer, NULL, "Sans");
810
ass_set_fonts (render->ass_renderer, "Arial", "sans-serif", 1, NULL, 1);
811
ass_set_fonts (render->ass_renderer, NULL, "Sans", 1, NULL, 1);
813
ass_set_margins (render->ass_renderer, 0, 0, 0, 0);
814
ass_set_use_margins (render->ass_renderer, 0);
815
g_mutex_unlock (render->ass_mutex);
817
render->renderer_init_ok = TRUE;
819
GST_DEBUG_OBJECT (render, "ass renderer setup complete");
396
822
gst_object_unref (render);
402
gst_assrender_setcaps_text (GstPad * pad, GstCaps * caps)
828
gst_ass_render_setcaps_text (GstPad * pad, GstCaps * caps)
404
Gstassrender *render;
830
GstAssRender *render = GST_ASS_RENDER (gst_pad_get_parent (pad));
405
831
GstStructure *structure;
406
832
const GValue *value;