LGPL
[vlc.git] / src / video_output / video_text.c
1 /*****************************************************************************
2  * video_text.c : OSD text manipulation functions
3  *****************************************************************************
4  * Copyright (C) 1999-2010 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Author: Sigmund Augdal Helberg <dnumgis@videolan.org>
8  *         Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU Lesser General Public License as published by
12  * the Free Software Foundation; either version 2.1 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this program; if not, write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28 #include <assert.h>
29
30 #include <vlc_common.h>
31 #include <vlc_vout.h>
32 #include <vlc_vout_osd.h>
33
34 struct subpicture_updater_sys_t {
35     int  position;
36     char *text;
37 };
38
39 static int OSDTextValidate(subpicture_t *subpic,
40                            bool has_src_changed, const video_format_t *fmt_src,
41                            bool has_dst_changed, const video_format_t *fmt_dst,
42                            mtime_t ts)
43 {
44     VLC_UNUSED(subpic); VLC_UNUSED(ts);
45     VLC_UNUSED(fmt_src); VLC_UNUSED(has_src_changed);
46     VLC_UNUSED(fmt_dst);
47
48     if( !has_dst_changed )
49         return VLC_SUCCESS;
50     return VLC_EGENERIC;
51 }
52
53 static void OSDTextUpdate(subpicture_t *subpic,
54                           const video_format_t *fmt_src,
55                           const video_format_t *fmt_dst,
56                           mtime_t ts)
57 {
58     subpicture_updater_sys_t *sys = subpic->updater.p_sys;
59     VLC_UNUSED(fmt_src); VLC_UNUSED(ts);
60
61     if( fmt_dst->i_sar_num <= 0 || fmt_dst->i_sar_den <= 0 )
62         return;
63
64     subpic->b_absolute = false;
65     subpic->i_original_picture_width  = fmt_dst->i_width * fmt_dst->i_sar_num / fmt_dst->i_sar_den;
66     subpic->i_original_picture_height = fmt_dst->i_height;
67
68     video_format_t fmt;
69     video_format_Init( &fmt, VLC_CODEC_TEXT);
70     fmt.i_sar_num = 1;
71     fmt.i_sar_den = 1;
72
73     subpicture_region_t *r = subpic->p_region = subpicture_region_New(&fmt);
74     if (!r)
75         return;
76
77     r->psz_text = strdup(sys->text);
78
79     const float margin_ratio = 0.04;
80     const int   margin_h     = margin_ratio * fmt_dst->i_visible_width;
81     const int   margin_v     = margin_ratio * fmt_dst->i_visible_height;
82
83     r->i_align = sys->position;
84     r->i_x = 0;
85     if (r->i_align & SUBPICTURE_ALIGN_LEFT)
86         r->i_x += margin_h + fmt_dst->i_x_offset;
87     else if (r->i_align & SUBPICTURE_ALIGN_RIGHT)
88         r->i_x += margin_h + fmt_dst->i_width - (fmt_dst->i_visible_width + fmt_dst->i_x_offset);
89
90     r->i_y = 0;
91     if (r->i_align & SUBPICTURE_ALIGN_TOP )
92         r->i_y += margin_v + fmt_dst->i_y_offset;
93     else if (r->i_align & SUBPICTURE_ALIGN_BOTTOM )
94         r->i_y += margin_v + fmt_dst->i_height - (fmt_dst->i_visible_height + fmt_dst->i_y_offset);
95 }
96
97 static void OSDTextDestroy(subpicture_t *subpic)
98 {
99     subpicture_updater_sys_t *sys = subpic->updater.p_sys;
100
101     free(sys->text);
102     free(sys);
103 }
104
105 void vout_OSDText(vout_thread_t *vout, int channel,
106                    int position, mtime_t duration, const char *text)
107 {
108     assert( (position & ~SUBPICTURE_ALIGN_MASK) == 0);
109     if (!var_InheritBool(vout, "osd") || duration <= 0)
110         return;
111
112     subpicture_updater_sys_t *sys = malloc(sizeof(*sys));
113     if (!sys)
114         return;
115     sys->position = position;
116     sys->text     = strdup(text);
117
118     subpicture_updater_t updater = {
119         .pf_validate = OSDTextValidate,
120         .pf_update   = OSDTextUpdate,
121         .pf_destroy  = OSDTextDestroy,
122         .p_sys       = sys,
123     };
124     subpicture_t *subpic = subpicture_New(&updater);
125     if (!subpic) {
126         free(sys->text);
127         free(sys);
128         return;
129     }
130
131     subpic->i_channel  = channel;
132     subpic->i_start    = mdate();
133     subpic->i_stop     = subpic->i_start + duration;
134     subpic->b_ephemer  = true;
135     subpic->b_absolute = false;
136     subpic->b_fade     = true;
137
138     vout_PutSubpicture(vout, subpic);
139 }
140
141 void vout_OSDMessage(vout_thread_t *vout, int channel, const char *format, ...)
142 {
143     va_list args;
144     va_start(args, format);
145
146     char *string;
147     if (vasprintf(&string, format, args) != -1) {
148         vout_OSDText(vout, channel,
149                      SUBPICTURE_ALIGN_TOP|SUBPICTURE_ALIGN_RIGHT, 1000000,
150                      string);
151         free(string);
152     }
153     va_end(args);
154 }
155