1 #include <vlc_strings.h>
7 } subpicture_updater_sys_option_t;
9 typedef struct segment_t segment_t;
14 uint32_t i_color; //ARGB
23 /* styles applied to that segment */
24 segment_style_t styles;
27 struct subpicture_updater_sys_t {
30 segment_t *p_htmlsegments;
35 int i_font_height_percent;
36 int i_font_height_abs_to_src;
44 subpicture_updater_sys_option_t style_flags;
45 subpicture_updater_sys_option_t font_color;
46 subpicture_updater_sys_option_t background_color;
48 int16_t i_drop_shadow;
49 int16_t i_drop_shadow_alpha;
52 static void SegmentFree( segment_t *p_segment )
56 free( p_segment->psz_string );
61 static void MakeHtmlNewLines( char **ppsz_src )
63 unsigned int i_nlcount = 0;
64 unsigned i_len = strlen( *ppsz_src );
65 if ( i_len == 0 ) return;
66 for ( unsigned i=0; i<i_len; i++ )
67 if ( (*ppsz_src)[i] == '\n' )
69 if ( !i_nlcount ) return;
71 char *psz_dst = malloc( i_len + 1 + (i_nlcount * 4) );
73 for ( unsigned i=0; i<i_len; i++ )
75 if ( (*ppsz_src)[i] == '\n' )
77 strcpy( ptr, "<br/>" );
80 *ptr++ = (*ppsz_src)[i];
88 static void HtmlAppend( char **ppsz_dst, const char *psz_src,
89 const segment_style_t *p_styles, const float f_scale )
91 if ( !ppsz_dst ) return;
93 char *psz_subtext = NULL;
94 char *psz_text = NULL;
95 char *psz_fontsize = NULL;
96 char *psz_color = NULL;
97 char *psz_encoded = convert_xml_special_chars( psz_src );
98 if ( !psz_encoded ) return;
100 MakeHtmlNewLines( &psz_encoded );
102 if ( p_styles->i_color & 0xFF000000 ) //ARGB
104 i_return = asprintf( &psz_color, " color=\"#%6x\"",
105 p_styles->i_color & 0x00FFFFFF );
106 if ( i_return < 0 ) psz_color = NULL;
109 if ( p_styles->i_fontsize > 0 && f_scale > 0 )
111 i_return = asprintf( &psz_fontsize, " size=\"%u\"",
112 (unsigned) (f_scale * p_styles->i_fontsize) );
113 if ( i_return < 0 ) psz_fontsize = NULL;
116 i_return = asprintf( &psz_subtext, "%s%s%s%s%s%s%s",
117 ( p_styles->i_flags & STYLE_UNDERLINE ) ? "<u>" : "",
118 ( p_styles->i_flags & STYLE_BOLD ) ? "<b>" : "",
119 ( p_styles->i_flags & STYLE_ITALIC ) ? "<i>" : "",
121 ( p_styles->i_flags & STYLE_ITALIC ) ? "</i>" : "",
122 ( p_styles->i_flags & STYLE_BOLD ) ? "</b>" : "",
123 ( p_styles->i_flags & STYLE_UNDERLINE ) ? "</u>" : ""
125 if ( i_return < 0 ) psz_subtext = NULL;
127 if ( psz_color || psz_fontsize )
129 i_return = asprintf( &psz_text, "<font%s%s>%s</font>",
130 psz_color ? psz_color : "",
131 psz_fontsize ? psz_fontsize : "",
133 if ( i_return < 0 ) psz_text = NULL;
138 psz_text = psz_subtext;
141 free( psz_fontsize );
146 char *psz_dst = *ppsz_dst;
147 i_return = asprintf( ppsz_dst, "%s%s", psz_dst, psz_text );
148 if ( i_return < 0 ) ppsz_dst = NULL;
153 *ppsz_dst = psz_text;
156 static char *SegmentsToHtml( segment_t *p_head, const float f_scale )
158 char *psz_dst = NULL;
159 char *psz_ret = NULL;
162 HtmlAppend( &psz_dst, p_head->psz_string, &p_head->styles, f_scale );
163 p_head = p_head->p_next;
165 int i_ret = asprintf( &psz_ret, "<text>%s</text>", psz_dst );
166 if ( i_ret < 0 ) psz_ret = NULL;
171 static int SubpictureTextValidate(subpicture_t *subpic,
172 bool has_src_changed, const video_format_t *fmt_src,
173 bool has_dst_changed, const video_format_t *fmt_dst,
176 subpicture_updater_sys_t *sys = subpic->updater.p_sys;
177 VLC_UNUSED(fmt_src); VLC_UNUSED(fmt_dst); VLC_UNUSED(ts);
179 if (!has_src_changed && !has_dst_changed)
181 if (!sys->is_fixed && subpic->b_absolute && subpic->p_region &&
182 subpic->i_original_picture_width > 0 &&
183 subpic->i_original_picture_height > 0) {
185 sys->is_fixed = true;
186 sys->x = subpic->p_region->i_x;
187 sys->y = subpic->p_region->i_y;
188 sys->fixed_width = subpic->i_original_picture_width;
189 sys->fixed_height = subpic->i_original_picture_height;
193 static void SubpictureTextUpdate(subpicture_t *subpic,
194 const video_format_t *fmt_src,
195 const video_format_t *fmt_dst,
198 subpicture_updater_sys_t *sys = subpic->updater.p_sys;
199 VLC_UNUSED(fmt_src); VLC_UNUSED(ts);
201 if (fmt_dst->i_sar_num <= 0 || fmt_dst->i_sar_den <= 0)
204 subpic->i_original_picture_width = fmt_dst->i_width * fmt_dst->i_sar_num / fmt_dst->i_sar_den;
205 subpic->i_original_picture_height = fmt_dst->i_height;
208 video_format_Init(&fmt, VLC_CODEC_TEXT);
212 subpicture_region_t *r = subpic->p_region = subpicture_region_New(&fmt);
216 r->psz_text = sys->text ? strdup(sys->text) : NULL;
217 if ( sys->p_htmlsegments )
218 r->psz_html = SegmentsToHtml( sys->p_htmlsegments,
219 (float) fmt_dst->i_height / fmt_src->i_height );
220 else if ( sys->html )
221 r->psz_html = strdup(sys->html);
224 r->i_align = sys->align;
225 r->b_renderbg = sys->renderbg;
226 if (!sys->is_fixed) {
227 const float margin_ratio = 0.04;
228 const int margin_h = margin_ratio * fmt_dst->i_visible_width;
229 const int margin_v = margin_ratio * fmt_dst->i_visible_height;
232 if (r->i_align & SUBPICTURE_ALIGN_LEFT)
233 r->i_x += margin_h + fmt_dst->i_x_offset;
234 else if (r->i_align & SUBPICTURE_ALIGN_RIGHT)
235 r->i_x += margin_h + fmt_dst->i_width - (fmt_dst->i_visible_width + fmt_dst->i_x_offset);
238 if (r->i_align & SUBPICTURE_ALIGN_TOP )
239 r->i_y += margin_v + fmt_dst->i_y_offset;
240 else if (r->i_align & SUBPICTURE_ALIGN_BOTTOM )
241 r->i_y += margin_v + fmt_dst->i_height - (fmt_dst->i_visible_height + fmt_dst->i_y_offset);
243 /* FIXME it doesn't adapt on crop settings changes */
244 r->i_x = sys->x * fmt_dst->i_width / sys->fixed_width;
245 r->i_y = sys->y * fmt_dst->i_height / sys->fixed_height;
248 if (sys->i_font_height_percent || sys->i_alpha ||
249 sys->style_flags.b_set ||
250 sys->font_color.b_set ||
251 sys->background_color.b_set )
253 r->p_style = text_style_New();
254 if (!r->p_style) return;
256 if (sys->i_font_height_abs_to_src)
257 sys->i_font_height_percent = sys->i_font_height_abs_to_src * 100 /
258 fmt_src->i_visible_height;
260 if (sys->i_font_height_percent)
262 r->p_style->i_font_size = sys->i_font_height_percent *
263 subpic->i_original_picture_height / 100;
264 r->p_style->i_font_color = 0xffffff;
265 r->p_style->i_font_alpha = 0xff;
268 if (sys->style_flags.b_set)
269 r->p_style->i_style_flags = sys->style_flags.i_value;
270 if (sys->font_color.b_set)
271 r->p_style->i_font_color = sys->font_color.i_value;
272 if (sys->background_color.b_set)
273 r->p_style->i_background_color = sys->background_color.i_value;
275 r->p_style->i_font_alpha = sys->i_alpha;
276 if (sys->i_drop_shadow)
277 r->p_style->i_shadow_width = sys->i_drop_shadow;
278 if (sys->i_drop_shadow_alpha)
279 r->p_style->i_shadow_alpha = sys->i_drop_shadow_alpha;
282 static void SubpictureTextDestroy(subpicture_t *subpic)
284 subpicture_updater_sys_t *sys = subpic->updater.p_sys;
288 while( sys->p_htmlsegments )
290 segment_t *p_segment = sys->p_htmlsegments;
291 sys->p_htmlsegments = sys->p_htmlsegments->p_next;
292 SegmentFree( p_segment );
297 static inline subpicture_t *decoder_NewSubpictureText(decoder_t *decoder)
299 subpicture_updater_sys_t *sys = calloc(1, sizeof(*sys));
300 subpicture_updater_t updater = {
301 .pf_validate = SubpictureTextValidate,
302 .pf_update = SubpictureTextUpdate,
303 .pf_destroy = SubpictureTextDestroy,
306 subpicture_t *subpic = decoder_NewSubpicture(decoder, &updater);