1 /*****************************************************************************
2  * video_text.c : OSD text manipulation functions
3  *****************************************************************************
4  * Copyright (C) 1999-2010 VLC authors and VideoLAN
5  * $Id: 58566b4ec60c9a6f6493205136008092739d97b9 $
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 
OSDTextValidate(subpicture_t * subpic,bool has_src_changed,const video_format_t * fmt_src,bool has_dst_changed,const video_format_t * fmt_dst,mtime_t ts)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 
OSDTextUpdate(subpicture_t * subpic,const video_format_t * fmt_src,const video_format_t * fmt_dst,mtime_t ts)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_visible_width * fmt_dst->i_sar_num / fmt_dst->i_sar_den;
66     subpic->i_original_picture_height = fmt_dst->i_visible_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->p_text = text_segment_New( 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_text_align = sys->position;
84     r->i_align = sys->position;
85     r->i_x = 0;
86     if (r->i_align & SUBPICTURE_ALIGN_LEFT)
87         r->i_x += margin_h + fmt_dst->i_x_offset;
88     else if (r->i_align & SUBPICTURE_ALIGN_RIGHT)
89         r->i_x += margin_h - fmt_dst->i_x_offset;
90 
91     r->i_y = 0;
92     if (r->i_align & SUBPICTURE_ALIGN_TOP )
93         r->i_y += margin_v + fmt_dst->i_y_offset;
94     else if (r->i_align & SUBPICTURE_ALIGN_BOTTOM )
95         r->i_y += margin_v - fmt_dst->i_y_offset;
96 }
97 
OSDTextDestroy(subpicture_t * subpic)98 static void OSDTextDestroy(subpicture_t *subpic)
99 {
100     subpicture_updater_sys_t *sys = subpic->updater.p_sys;
101 
102     free(sys->text);
103     free(sys);
104 }
105 
vout_OSDText(vout_thread_t * vout,int channel,int position,mtime_t duration,const char * text)106 void vout_OSDText(vout_thread_t *vout, int channel,
107                    int position, mtime_t duration, const char *text)
108 {
109     assert( (position & ~SUBPICTURE_ALIGN_MASK) == 0);
110     if (!var_InheritBool(vout, "osd") || duration <= 0)
111         return;
112 
113     subpicture_updater_sys_t *sys = malloc(sizeof(*sys));
114     if (!sys)
115         return;
116     sys->position = position;
117     sys->text     = strdup(text);
118 
119     subpicture_updater_t updater = {
120         .pf_validate = OSDTextValidate,
121         .pf_update   = OSDTextUpdate,
122         .pf_destroy  = OSDTextDestroy,
123         .p_sys       = sys,
124     };
125     subpicture_t *subpic = subpicture_New(&updater);
126     if (!subpic) {
127         free(sys->text);
128         free(sys);
129         return;
130     }
131 
132     subpic->i_channel  = channel;
133     subpic->i_start    = mdate();
134     subpic->i_stop     = subpic->i_start + duration;
135     subpic->b_ephemer  = true;
136     subpic->b_absolute = false;
137     subpic->b_fade     = true;
138 
139     vout_PutSubpicture(vout, subpic);
140 }
141 
vout_OSDMessage(vout_thread_t * vout,int channel,const char * format,...)142 void vout_OSDMessage(vout_thread_t *vout, int channel, const char *format, ...)
143 {
144     va_list args;
145     va_start(args, format);
146 
147     char *string;
148     if (vasprintf(&string, format, args) != -1) {
149         vout_OSDText(vout, channel,
150                      SUBPICTURE_ALIGN_TOP|SUBPICTURE_ALIGN_RIGHT, 1000000,
151                      string);
152         free(string);
153     }
154     va_end(args);
155 }
156 
157