Merge branch 'master' into 0.11
[platform/upstream/gst-plugins-base.git] / ext / pango / gstclockoverlay.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2005> Tim-Philipp Müller <tim@centricular.net>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * SECTION:element-clockoverlay
23  * @see_also: #GstBaseTextOverlay, #GstTimeOverlay
24  *
25  * This element overlays the current clock time on top of a video
26  * stream. You can position the text and configure the font details
27  * using the properties of the #GstBaseTextOverlay class. By default, the
28  * time is displayed in the top left corner of the picture, with some
29  * padding to the left and to the top.
30  *
31  * <refsect2>
32  * <title>Example launch lines</title>
33  * |[
34  * gst-launch -v videotestsrc ! clockoverlay ! xvimagesink
35  * ]| Display the current time in the top left corner of the video picture
36  * |[
37  * gst-launch -v videotestsrc ! clockoverlay halign=right valign=bottom text="Edge City" shaded-background=true ! videoconvert ! ximagesink
38  * ]| Another pipeline that displays the current time with some leading
39  * text in the bottom right corner of the video picture, with the background
40  * of the text being shaded in order to make it more legible on top of a
41  * bright video background.
42  * </refsect2>
43  */
44
45 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #include <gstclockoverlay.h>
50 #include <gst/video/video.h>
51 #include <time.h>
52
53
54 #define DEFAULT_PROP_TIMEFORMAT         "%H:%M:%S"
55
56 enum
57 {
58   PROP_0,
59   PROP_TIMEFORMAT,
60   PROP_LAST
61 };
62
63 #define gst_clock_overlay_parent_class parent_class
64 G_DEFINE_TYPE (GstClockOverlay, gst_clock_overlay, GST_TYPE_BASE_TEXT_OVERLAY);
65
66 static void gst_clock_overlay_finalize (GObject * object);
67 static void gst_clock_overlay_set_property (GObject * object, guint prop_id,
68     const GValue * value, GParamSpec * pspec);
69 static void gst_clock_overlay_get_property (GObject * object, guint prop_id,
70     GValue * value, GParamSpec * pspec);
71
72 static gchar *
73 gst_clock_overlay_render_time (GstClockOverlay * overlay)
74 {
75   struct tm *t;
76   time_t now;
77   gchar buf[256];
78
79 #ifdef HAVE_LOCALTIME_R
80   struct tm dummy;
81 #endif
82
83   now = time (NULL);
84
85 #ifdef HAVE_LOCALTIME_R
86   /* Need to call tzset explicitly when calling localtime_r for changes
87      to the timezone between calls to be visible.  */
88   tzset ();
89   t = localtime_r (&now, &dummy);
90 #else
91   /* on win32 this apparently returns a per-thread struct which would be fine */
92   t = localtime (&now);
93 #endif
94
95   if (t == NULL)
96     return g_strdup ("--:--:--");
97
98   if (strftime (buf, sizeof (buf), overlay->format, t) == 0)
99     return g_strdup ("");
100   return g_strdup (buf);
101 }
102
103 /* Called with lock held */
104 static gchar *
105 gst_clock_overlay_get_text (GstBaseTextOverlay * overlay,
106     GstBuffer * video_frame)
107 {
108   gchar *time_str, *txt, *ret;
109   GstClockOverlay *clock_overlay = GST_CLOCK_OVERLAY (overlay);
110
111   txt = g_strdup (overlay->default_text);
112
113   time_str = gst_clock_overlay_render_time (clock_overlay);
114   if (txt != NULL && *txt != '\0') {
115     ret = g_strdup_printf ("%s %s", txt, time_str);
116   } else {
117     ret = time_str;
118     time_str = NULL;
119   }
120
121   if (g_strcmp0 (ret, clock_overlay->text)) {
122     overlay->need_render = TRUE;
123     g_free (clock_overlay->text);
124     clock_overlay->text = g_strdup (ret);
125   }
126
127   g_free (txt);
128   g_free (time_str);
129
130   return ret;
131 }
132
133 static void
134 gst_clock_overlay_class_init (GstClockOverlayClass * klass)
135 {
136   GObjectClass *gobject_class;
137   GstElementClass *gstelement_class;
138   GstBaseTextOverlayClass *gsttextoverlay_class;
139   PangoContext *context;
140   PangoFontDescription *font_description;
141
142   gobject_class = (GObjectClass *) klass;
143   gstelement_class = (GstElementClass *) klass;
144   gsttextoverlay_class = (GstBaseTextOverlayClass *) klass;
145
146   gobject_class->finalize = gst_clock_overlay_finalize;
147   gobject_class->set_property = gst_clock_overlay_set_property;
148   gobject_class->get_property = gst_clock_overlay_get_property;
149
150   gst_element_class_set_details_simple (gstelement_class, "Clock overlay",
151       "Filter/Editor/Video",
152       "Overlays the current clock time on a video stream",
153       "Tim-Philipp Müller <tim@centricular.net>");
154
155   gsttextoverlay_class->get_text = gst_clock_overlay_get_text;
156
157   g_object_class_install_property (gobject_class, PROP_TIMEFORMAT,
158       g_param_spec_string ("time-format", "Date/Time Format",
159           "Format to use for time and date value, as in strftime.",
160           DEFAULT_PROP_TIMEFORMAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
161
162   g_mutex_lock (gsttextoverlay_class->pango_lock);
163   context = gsttextoverlay_class->pango_context;
164
165   pango_context_set_language (context, pango_language_from_string ("en_US"));
166   pango_context_set_base_dir (context, PANGO_DIRECTION_LTR);
167
168   font_description = pango_font_description_new ();
169   pango_font_description_set_family_static (font_description, "Monospace");
170   pango_font_description_set_style (font_description, PANGO_STYLE_NORMAL);
171   pango_font_description_set_variant (font_description, PANGO_VARIANT_NORMAL);
172   pango_font_description_set_weight (font_description, PANGO_WEIGHT_NORMAL);
173   pango_font_description_set_stretch (font_description, PANGO_STRETCH_NORMAL);
174   pango_font_description_set_size (font_description, 18 * PANGO_SCALE);
175   pango_context_set_font_description (context, font_description);
176   pango_font_description_free (font_description);
177   g_mutex_unlock (gsttextoverlay_class->pango_lock);
178 }
179
180
181 static void
182 gst_clock_overlay_finalize (GObject * object)
183 {
184   GstClockOverlay *overlay = GST_CLOCK_OVERLAY (object);
185
186   g_free (overlay->format);
187   g_free (overlay->text);
188   overlay->format = NULL;
189
190   G_OBJECT_CLASS (parent_class)->finalize (object);
191 }
192
193
194 static void
195 gst_clock_overlay_init (GstClockOverlay * overlay)
196 {
197   GstBaseTextOverlay *textoverlay;
198
199   textoverlay = GST_BASE_TEXT_OVERLAY (overlay);
200
201   textoverlay->valign = GST_BASE_TEXT_OVERLAY_VALIGN_TOP;
202   textoverlay->halign = GST_BASE_TEXT_OVERLAY_HALIGN_LEFT;
203
204   overlay->format = g_strdup (DEFAULT_PROP_TIMEFORMAT);
205 }
206
207
208 static void
209 gst_clock_overlay_set_property (GObject * object, guint prop_id,
210     const GValue * value, GParamSpec * pspec)
211 {
212   GstClockOverlay *overlay = GST_CLOCK_OVERLAY (object);
213
214   GST_OBJECT_LOCK (overlay);
215   switch (prop_id) {
216     case PROP_TIMEFORMAT:
217       g_free (overlay->format);
218       overlay->format = g_value_dup_string (value);
219       break;
220     default:
221       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
222       break;
223   }
224   GST_OBJECT_UNLOCK (overlay);
225 }
226
227
228 static void
229 gst_clock_overlay_get_property (GObject * object, guint prop_id,
230     GValue * value, GParamSpec * pspec)
231 {
232   GstClockOverlay *overlay = GST_CLOCK_OVERLAY (object);
233
234   GST_OBJECT_LOCK (overlay);
235   switch (prop_id) {
236     case PROP_TIMEFORMAT:
237       g_value_set_string (value, overlay->format);
238       break;
239     default:
240       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
241       break;
242   }
243   GST_OBJECT_UNLOCK (overlay);
244 }