06f43ef55031ea4bbb3171b9aacf971873160e81
[platform/upstream/gst-plugins-good.git] / ext / pango / gsttextoverlay.c
1
2
3
4 #ifdef HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7 #include <gst/gst.h>
8 #include "gsttextoverlay.h"
9 /*#include "gsttexttestsrc.h"*/
10 /*#include "gstsubparse.h"*/
11 /*#include "SDL_blit.h"*/
12
13 static GstElementDetails textoverlay_details = {
14     "Text Overlay",
15     "Filter/Editor/Video",
16     "Adds text strings on top of a video buffer",
17     "Gustavo J. A. M. Carneiro <gjc@inescporto.pt>"
18 };
19
20 enum {
21     ARG_0,
22     ARG_TEXT, 
23     ARG_VALIGN, 
24     ARG_HALIGN, 
25     ARG_X0, 
26     ARG_Y0, 
27     ARG_FONT_DESC, 
28 };
29
30
31 GST_PAD_TEMPLATE_FACTORY(textoverlay_src_template_factory,
32                          "src",
33                          GST_PAD_SRC,
34                          GST_PAD_ALWAYS,
35                          GST_CAPS_NEW(
36                              "textoverlay_src",
37                              "video/x-raw-yuv",
38                              "format",          GST_PROPS_LIST(
39                                  GST_PROPS_FOURCC(GST_STR_FOURCC("I420"))
40                                  ),
41                              "width",           GST_PROPS_INT_RANGE(0, G_MAXINT), 
42                              "height",          GST_PROPS_INT_RANGE(0, G_MAXINT)
43                              )
44     )
45
46 GST_PAD_TEMPLATE_FACTORY(video_sink_template_factory,
47                          "video_sink",
48                          GST_PAD_SINK,
49                          GST_PAD_ALWAYS,
50                          GST_CAPS_NEW(
51                              "video_sink",
52                              "video/x-raw-yuv",
53                              "format",          GST_PROPS_LIST(
54                                  GST_PROPS_FOURCC(GST_STR_FOURCC("I420"))
55                                  ),
56                              "width",           GST_PROPS_INT_RANGE(0, G_MAXINT),
57                              "height",          GST_PROPS_INT_RANGE(0, G_MAXINT)
58                              )
59     )
60
61 GST_PAD_TEMPLATE_FACTORY(text_sink_template_factory,
62                          "text_sink",
63                          GST_PAD_SINK,
64                          GST_PAD_ALWAYS,
65                          GST_CAPS_NEW(
66                              "text_sink",
67                              "text/x-pango-markup", 
68                              NULL
69                              )
70     )
71
72 static void                  gst_textoverlay_base_init (gpointer g_class);
73 static void                  gst_textoverlay_class_init(GstTextOverlayClass *klass);
74 static void                  gst_textoverlay_init(GstTextOverlay      *overlay);
75 static void                  gst_textoverlay_set_property(GObject             *object, 
76                                                            guint                prop_id, 
77                                                            const GValue        *value, 
78                                                            GParamSpec          *pspec);
79 static void                  gst_textoverlay_get_property(GObject             *object, 
80                                                            guint                prop_id, 
81                                                            GValue              *value, 
82                                                            GParamSpec          *pspec);
83 static GstElementStateReturn gst_textoverlay_change_state(GstElement          *element);
84 static void                  gst_textoverlay_finalize(GObject             *object);
85
86
87 static GstElementClass *parent_class = NULL;
88 /*static guint gst_textoverlay_signals[LAST_SIGNAL] = { 0 }; */
89
90
91 GType
92 gst_textoverlay_get_type(void)
93 {
94     static GType textoverlay_type = 0;
95
96     if (!textoverlay_type) {
97         static const GTypeInfo textoverlay_info = {
98             sizeof(GstTextOverlayClass), 
99             gst_textoverlay_base_init,
100             NULL,
101             (GClassInitFunc)gst_textoverlay_class_init,
102             NULL,
103             NULL,
104             sizeof(GstTextOverlay),
105             0,
106             (GInstanceInitFunc)gst_textoverlay_init,
107         };
108         textoverlay_type = g_type_register_static(GST_TYPE_ELEMENT, "GstTextOverlay", 
109                                                   &textoverlay_info, 0);
110     }
111     return textoverlay_type;
112 }
113
114 static void
115 gst_textoverlay_base_init (gpointer g_class)
116 {
117     GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
118
119     gst_element_class_add_pad_template (element_class, GST_PAD_TEMPLATE_GET (textoverlay_src_template_factory));
120     gst_element_class_add_pad_template (element_class, GST_PAD_TEMPLATE_GET (video_sink_template_factory));
121     gst_element_class_add_pad_template (element_class, GST_PAD_TEMPLATE_GET (text_sink_template_factory));
122
123     gst_element_class_set_details (element_class, &textoverlay_details);
124 }
125
126 static void
127 gst_textoverlay_class_init(GstTextOverlayClass *klass)
128 {
129     GObjectClass *gobject_class;
130     GstElementClass *gstelement_class;
131
132     gobject_class = (GObjectClass*)klass;
133     gstelement_class = (GstElementClass*)klass;
134
135     parent_class = g_type_class_peek_parent(klass);
136
137     gobject_class->finalize = gst_textoverlay_finalize;
138     gobject_class->set_property = gst_textoverlay_set_property;
139     gobject_class->get_property = gst_textoverlay_get_property;
140
141     gstelement_class->change_state = gst_textoverlay_change_state;
142     klass->pango_context = pango_ft2_get_context(72, 72);
143     g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TEXT, 
144                                     g_param_spec_string("text", "text", 
145                                                         "Text to be display,"
146                                                         " in pango markup format.", 
147                                                         "", G_PARAM_WRITABLE));
148     g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VALIGN, 
149                                     g_param_spec_string("valign", "vertical alignment", 
150                                                         "Vertical alignment of the text. "
151                                                         "Can be either 'baseline', 'bottom', or 'top'", 
152                                                         "baseline", G_PARAM_WRITABLE));
153     g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HALIGN, 
154                                     g_param_spec_string("halign", "horizontal alignment", 
155                                                         "Horizontal alignment of the text. "
156                                                         "Can be either 'left', 'right', or 'center'", 
157                                                         "center", G_PARAM_WRITABLE));
158     g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_X0, 
159                                     g_param_spec_int("x0", "X position", 
160                                                      "Initial X position."
161                                                      " Horizontal aligment takes this point"
162                                                      " as reference.", 
163                                                      G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE));
164     g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_Y0, 
165                                     g_param_spec_int("y0", "Y position", 
166                                                      "Initial Y position."
167                                                      " Vertical aligment takes this point"
168                                                      " as reference.", 
169                                                      G_MININT, G_MAXINT, 0, G_PARAM_WRITABLE));
170     g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FONT_DESC, 
171                                     g_param_spec_string("font-desc", "font description", 
172                                                         "Pango font description of font "
173                                                         "to be used for rendering. "
174                                                         "See documentation of "
175                                                         "pango_font_description_from_string"
176                                                         " for syntax.", 
177                                                         "", G_PARAM_WRITABLE));
178 }
179
180
181 static void
182 resize_bitmap(GstTextOverlay *overlay, int width, int height)
183 {
184     FT_Bitmap *bitmap = &overlay->bitmap;
185     int        pitch = (width|3) + 1;
186     int        size = pitch*height;
187
188     /* no need to keep reallocating; just keep the maximum size so far */
189     if (size <= overlay->bitmap_buffer_size) {
190         bitmap->rows = height;
191         bitmap->width = width;
192         bitmap->pitch = pitch;
193         memset(bitmap->buffer, 0, overlay->bitmap_buffer_size);
194         return;
195     }
196     if (!bitmap->buffer) {
197         /* initialize */
198         bitmap->pixel_mode = ft_pixel_mode_grays;
199         bitmap->num_grays = 256;
200     }
201     if (bitmap->buffer)
202         bitmap->buffer = g_realloc(bitmap->buffer, size);
203     else
204         bitmap->buffer = g_malloc(size);
205     bitmap->rows = height;
206     bitmap->width = width;
207     bitmap->pitch = pitch;
208     memset(bitmap->buffer, 0, size);
209     overlay->bitmap_buffer_size = size;
210 }
211
212 static void
213 render_text(GstTextOverlay *overlay)
214 {
215     PangoRectangle ink_rect, logical_rect;
216
217     pango_layout_get_pixel_extents(overlay->layout, &ink_rect, &logical_rect);
218     resize_bitmap(overlay, ink_rect.width, ink_rect.height + ink_rect.y);
219     pango_ft2_render_layout(&overlay->bitmap, overlay->layout, 0, 0);
220     overlay->baseline_y = ink_rect.y;
221 }
222
223 /* static GstPadLinkReturn */
224 /* gst_textoverlay_text_sinkconnect (GstPad *pad, GstCaps *caps) */
225 /* { */
226 /*     return GST_PAD_LINK_DONE; */
227 /* } */
228
229
230 static GstPadLinkReturn
231 gst_textoverlay_video_sinkconnect(GstPad *pad, GstCaps *caps)
232 {
233     GstTextOverlay *overlay;
234
235     overlay = GST_TEXTOVERLAY(gst_pad_get_parent(pad));
236
237     if (!GST_CAPS_IS_FIXED(caps))
238         return GST_PAD_LINK_DELAYED;
239
240     overlay->width = overlay->height = 0;
241     gst_caps_get_int(caps, "width", &overlay->width);
242     gst_caps_get_int(caps, "height", &overlay->height);
243
244     return gst_pad_try_set_caps(overlay->srcpad, caps);
245 }
246
247
248 static void
249 gst_text_overlay_blit_yuv420(GstTextOverlay *overlay, FT_Bitmap *bitmap,
250                              guchar *pixbuf, int x0, int y0)
251 {
252     int y;                      /* text bitmap coordinates */
253     int x1, y1;                 /* video buffer coordinates */
254     int rowinc, bit_rowinc, uv_rowinc;
255     guchar *p, *bitp, *u_p;
256     int video_width = overlay->width, video_height = overlay->height;
257     int bitmap_x0 = x0 < 1? -(x0 - 1) : 1; /* 1 pixel border */
258     int bitmap_y0 = y0 < 1? -(y0 - 1) : 1; /* 1 pixel border */
259     int bitmap_width = bitmap->width - bitmap_x0;
260     int bitmap_height = bitmap->rows - bitmap_y0;
261     int u_plane_size;
262     int skip_y, skip_x;
263     guchar v;
264
265     if (x0 + bitmap_x0 + bitmap_width > video_width - 1) /* 1 pixel border */
266         bitmap_width -= x0 + bitmap_x0 + bitmap_width - video_width + 1;
267     if (y0 + bitmap_y0 + bitmap_height > video_height - 1) /* 1 pixel border */
268         bitmap_height -= y0 + bitmap_y0 + bitmap_height - video_height + 1;
269
270     rowinc = video_width - bitmap_width;
271     uv_rowinc = video_width / 2 - bitmap_width / 2;
272     bit_rowinc = bitmap->pitch - bitmap_width;
273     u_plane_size = (video_width / 2)*(video_height / 2);
274
275     y1 = y0 + bitmap_y0;
276     x1 = x0 + bitmap_x0;
277     p = pixbuf + video_width*y1 + x1;
278     bitp = bitmap->buffer + bitmap->pitch*bitmap_y0 + bitmap_x0;
279     for (y = bitmap_y0; y < bitmap_height; y++){
280       int n;
281       for(n=bitmap_width; n>0; --n){
282         v = *bitp;
283         if (v) {
284           p[-1] = CLAMP(p[-1] - v, 0, 255);
285           p[ 1] = CLAMP(p[ 1] - v, 0, 255);
286           p[-video_width] = CLAMP(p[-video_width] - v, 0, 255);
287           p[ video_width] = CLAMP(p[ video_width] - v, 0, 255);
288         }
289         p++;
290         bitp++;
291       }
292       p += rowinc;
293       bitp += bit_rowinc;
294     }
295
296     y = bitmap_y0;
297     y1 = y0 + bitmap_y0;
298     x1 = x0 + bitmap_x0;
299     bitp = bitmap->buffer + bitmap->pitch*bitmap_y0 + bitmap_x0;
300     p = pixbuf + video_width*y1 + x1;
301     u_p = pixbuf + video_width*video_height + (video_width >> 1)*(y1 >> 1) + (x1 >> 1);
302     skip_y = 0;
303     skip_x = 0;
304
305     for ( ; y < bitmap_height; y++){
306       int n;
307       x1 = x0 + bitmap_x0;
308       skip_x = 0;
309       for(n = bitmap_width; n>0; --n){
310         v = *bitp;
311         if (v) {
312           *p = v;
313           if (!skip_y) {
314             u_p[0] = u_p[u_plane_size] = 0x80;
315           }
316         }
317         if (!skip_y) {
318           skip_x = !skip_x;
319           if (!skip_x) u_p++;
320         }
321         p++;
322         bitp++;
323       }
324       /*if (!skip_x && !skip_y) u_p--; */
325       p += rowinc;
326       bitp += bit_rowinc;
327       skip_y = !skip_y;
328       u_p += skip_y? uv_rowinc : 0;
329     }
330 }
331
332
333 static void
334 gst_textoverlay_video_chain(GstPad *pad, GstData *_data)
335 {
336     GstBuffer *buf = GST_BUFFER (_data);
337     GstTextOverlay *overlay;
338     guchar         *pixbuf;
339     gint            x0, y0;
340
341     g_return_if_fail(pad != NULL);
342     g_return_if_fail(GST_IS_PAD(pad));
343     g_return_if_fail(buf != NULL);
344     overlay = GST_TEXTOVERLAY(gst_pad_get_parent(pad));
345     g_return_if_fail(overlay != NULL);
346     g_return_if_fail(GST_IS_TEXTOVERLAY(overlay));
347
348     pixbuf = GST_BUFFER_DATA(buf);
349
350     x0 = overlay->x0;
351     y0 = overlay->y0;
352     switch (overlay->valign)
353     {
354     case GST_TEXT_OVERLAY_VALIGN_BOTTOM:
355         y0 += overlay->bitmap.rows;
356         break;
357     case GST_TEXT_OVERLAY_VALIGN_BASELINE:
358         y0 -= (overlay->bitmap.rows - overlay->baseline_y);
359         break;
360     case GST_TEXT_OVERLAY_VALIGN_TOP:
361         break;
362     }
363
364     switch (overlay->halign)
365     {
366     case GST_TEXT_OVERLAY_HALIGN_LEFT:
367         break;
368     case GST_TEXT_OVERLAY_HALIGN_RIGHT:
369         x0 -= overlay->bitmap.width;
370         break;
371     case GST_TEXT_OVERLAY_HALIGN_CENTER:
372         x0 -= overlay->bitmap.width / 2;
373         break;
374     }
375
376     if (overlay->bitmap.buffer)
377         gst_text_overlay_blit_yuv420(overlay, &overlay->bitmap, pixbuf, x0, y0);
378
379     gst_pad_push(overlay->srcpad, GST_DATA (buf));
380 }
381
382 #define PAST_END(buffer, time) \
383   (GST_BUFFER_TIMESTAMP (buffer) != GST_CLOCK_TIME_NONE && \
384    GST_BUFFER_DURATION (buffer) != GST_CLOCK_TIME_NONE && \
385    GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer) \
386      < (time))
387
388 static void
389 gst_textoverlay_loop(GstElement *element)
390 {
391     GstTextOverlay *overlay;
392     GstBuffer      *video_frame;
393     guint64         now;
394
395     g_return_if_fail(element != NULL);
396     g_return_if_fail(GST_IS_TEXTOVERLAY(element));
397     overlay = GST_TEXTOVERLAY(element);
398
399     video_frame = GST_BUFFER (gst_pad_pull(overlay->video_sinkpad));
400     now = GST_BUFFER_TIMESTAMP(video_frame);
401
402     /*
403      * This state machine has a bug that can't be resolved easily.
404      * (Needs a more complicated state machine.)  Basically, if the
405      * text that came from a buffer from the sink pad is being
406      * displayed, and the default text is changed by set_parameter,
407      * we'll incorrectly display the default text.
408      *
409      * Otherwise, this is a pretty decent state machine that handles
410      * buffer timestamps and durations correctly.  (I think)
411      */
412
413     while (overlay->next_buffer == NULL){
414       GST_DEBUG("attempting to pull a buffer");
415
416       /* read all text buffers until we get one "in the future" */
417       if(!GST_PAD_IS_USABLE(overlay->text_sinkpad)){
418         break;
419       }
420       overlay->next_buffer = GST_BUFFER (gst_pad_pull(overlay->text_sinkpad));
421       if (!overlay->next_buffer)
422         break;
423
424       if (PAST_END(overlay->next_buffer, now)){
425         gst_buffer_unref(overlay->next_buffer);
426         overlay->next_buffer = NULL;
427       }
428     }
429
430     if (overlay->next_buffer && 
431         (GST_BUFFER_TIMESTAMP(overlay->next_buffer) <= now ||
432         GST_BUFFER_TIMESTAMP(overlay->next_buffer) == GST_CLOCK_TIME_NONE)){
433       GST_DEBUG("using new buffer");
434
435       if (overlay->current_buffer){
436         gst_buffer_unref (overlay->current_buffer);
437       }
438       overlay->current_buffer = overlay->next_buffer;
439       overlay->next_buffer = NULL;
440
441       GST_DEBUG ( "rendering '%*s'", 
442           GST_BUFFER_SIZE(overlay->current_buffer),
443           GST_BUFFER_DATA(overlay->current_buffer));
444       pango_layout_set_markup(overlay->layout,
445           GST_BUFFER_DATA(overlay->current_buffer),
446           GST_BUFFER_SIZE(overlay->current_buffer));
447       render_text(overlay);
448       overlay->need_render = FALSE;
449     }
450
451     if (overlay->current_buffer && PAST_END(overlay->current_buffer, now)){
452       GST_DEBUG("dropping old buffer");
453
454       gst_buffer_unref(overlay->current_buffer);
455       overlay->current_buffer = NULL;
456
457       overlay->need_render = TRUE;
458     }
459
460     if(overlay->need_render){
461       GST_DEBUG ( "rendering '%s'", overlay->default_text);
462       pango_layout_set_markup(overlay->layout,
463           overlay->default_text, strlen(overlay->default_text));
464       render_text(overlay);
465
466       overlay->need_render = FALSE;
467     }
468
469     gst_textoverlay_video_chain(overlay->srcpad, GST_DATA (video_frame));
470 }
471
472
473 static GstElementStateReturn
474 gst_textoverlay_change_state(GstElement *element)
475 {
476     GstTextOverlay *overlay;
477
478     overlay = GST_TEXTOVERLAY(element);
479
480     switch (GST_STATE_TRANSITION(element))
481     {
482     case GST_STATE_PAUSED_TO_PLAYING:
483         break;
484     case GST_STATE_PLAYING_TO_PAUSED:
485         break;
486     case GST_STATE_PAUSED_TO_READY:
487         break;
488     }
489
490     parent_class->change_state(element);
491
492     return GST_STATE_SUCCESS;
493 }
494
495 static void
496 gst_textoverlay_finalize(GObject *object)
497 {
498     GstTextOverlay *overlay = GST_TEXTOVERLAY(object);
499
500     if (overlay->layout) {
501         g_object_unref(overlay->layout);
502         overlay->layout = NULL;
503     }
504     if (overlay->bitmap.buffer) {
505         g_free(overlay->bitmap.buffer);
506         overlay->bitmap.buffer = NULL;
507     }
508
509     G_OBJECT_CLASS(parent_class)->finalize(object);
510 }
511
512 static void
513 gst_textoverlay_init(GstTextOverlay *overlay)
514 {
515     /* video sink */
516     overlay->video_sinkpad = gst_pad_new_from_template(
517         GST_PAD_TEMPLATE_GET(video_sink_template_factory), "video_sink");
518 /*     gst_pad_set_chain_function(overlay->video_sinkpad, gst_textoverlay_video_chain); */
519     gst_pad_set_link_function(overlay->video_sinkpad, gst_textoverlay_video_sinkconnect);
520     gst_element_add_pad(GST_ELEMENT(overlay), overlay->video_sinkpad);
521
522     /* text sink */
523     overlay->text_sinkpad = gst_pad_new_from_template(
524         GST_PAD_TEMPLATE_GET(text_sink_template_factory), "text_sink");
525 /*     gst_pad_set_link_function(overlay->text_sinkpad, gst_textoverlay_text_sinkconnect); */
526     gst_element_add_pad(GST_ELEMENT(overlay), overlay->text_sinkpad);
527
528     /* (video) source */
529     overlay->srcpad = gst_pad_new_from_template(
530         GST_PAD_TEMPLATE_GET(textoverlay_src_template_factory), "src");
531     gst_element_add_pad(GST_ELEMENT(overlay), overlay->srcpad);
532
533     overlay->layout = pango_layout_new(GST_TEXTOVERLAY_GET_CLASS(overlay)->pango_context);
534     memset(&overlay->bitmap, 0, sizeof(overlay->bitmap));
535
536     overlay->halign = GST_TEXT_OVERLAY_HALIGN_CENTER;
537     overlay->valign = GST_TEXT_OVERLAY_VALIGN_BASELINE;
538     overlay->x0 = overlay->y0 = 0;
539
540     overlay->default_text = g_strdup("");
541     overlay->need_render = TRUE;
542
543     gst_element_set_loop_function(GST_ELEMENT(overlay), gst_textoverlay_loop);
544 }
545
546
547 static void
548 gst_textoverlay_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
549 {
550     GstTextOverlay *overlay;
551
552     /* it's not null if we got it, but it might not be ours */
553     g_return_if_fail(GST_IS_TEXTOVERLAY(object));
554     overlay = GST_TEXTOVERLAY(object);
555
556     switch (prop_id)
557     {
558
559     case ARG_TEXT:
560         if(overlay->default_text){
561           g_free(overlay->default_text);
562         }
563         overlay->default_text = g_strdup(g_value_get_string(value));
564         overlay->need_render = TRUE;
565         break;
566
567     case ARG_VALIGN:
568         if (strcasecmp(g_value_get_string(value), "baseline") == 0)
569             overlay->valign = GST_TEXT_OVERLAY_VALIGN_BASELINE;
570         else if (strcasecmp(g_value_get_string(value), "bottom") == 0)
571             overlay->valign = GST_TEXT_OVERLAY_VALIGN_BOTTOM;
572         else if (strcasecmp(g_value_get_string(value), "top") == 0)
573             overlay->valign = GST_TEXT_OVERLAY_VALIGN_TOP;
574         else
575             g_warning("Invalid 'valign' property value: %s", 
576                       g_value_get_string(value));
577         break;
578
579     case ARG_HALIGN:
580         if (strcasecmp(g_value_get_string(value), "left") == 0)
581             overlay->halign = GST_TEXT_OVERLAY_HALIGN_LEFT;
582         else if (strcasecmp(g_value_get_string(value), "right") == 0)
583             overlay->halign = GST_TEXT_OVERLAY_HALIGN_RIGHT;
584         else if (strcasecmp(g_value_get_string(value), "center") == 0)
585             overlay->halign = GST_TEXT_OVERLAY_HALIGN_CENTER;
586         else
587             g_warning("Invalid 'halign' property value: %s", 
588                       g_value_get_string(value));
589         break;
590
591     case ARG_X0:
592         overlay->x0 = g_value_get_int(value);
593         break;
594
595     case ARG_Y0:
596         overlay->y0 = g_value_get_int(value);
597         break;
598
599     case ARG_FONT_DESC:
600     {
601         PangoFontDescription *desc;
602         desc = pango_font_description_from_string(g_value_get_string(value));
603         if (desc) {
604             g_message("font description set: %s", g_value_get_string(value));
605             pango_layout_set_font_description(overlay->layout, desc);
606             pango_font_description_free(desc);
607             render_text(overlay);
608         } else
609             g_warning("font description parse failed: %s", g_value_get_string(value));
610         break;
611     }
612
613     default:
614         break;
615     }
616 }
617
618 static void
619 gst_textoverlay_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
620 {
621     GstTextOverlay *overlay;
622
623     /* it's not null if we got it, but it might not be ours */
624     g_return_if_fail(GST_IS_TEXTOVERLAY(object));
625     overlay = GST_TEXTOVERLAY(object);
626
627     switch (prop_id) {
628     default:
629         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
630         break;
631     }
632 }
633
634 static gboolean
635 plugin_init(GstPlugin *plugin)
636 {
637     if (!gst_element_register (plugin, "textoverlay", GST_RANK_PRIMARY, GST_TYPE_TEXTOVERLAY))
638         return FALSE;
639
640     /*texttestsrc_plugin_init(module, plugin);*/
641     /*subparse_plugin_init(module, plugin);*/
642     return TRUE;
643 }
644
645 GST_PLUGIN_DEFINE (
646     GST_VERSION_MAJOR,
647     GST_VERSION_MINOR,
648     "textoverlay",
649     "Text overlay",
650     plugin_init,
651     VERSION,
652     "GPL",
653     GST_COPYRIGHT,
654     GST_PACKAGE,
655     GST_ORIGIN)
656