1 /*****************************************************************************
2 * video_widgets.c : OSD widgets manipulation functions
3 *****************************************************************************
4 * Copyright (C) 2004-2010 VLC authors and VideoLAN
7 * Author: Yoann Peronneau <yoann@videolan.org>
8 * Laurent Aimar <fenrir _AT_ videolan _DOT_ org>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #include <vlc_common.h>
35 #include <vlc_vout_osd.h>
37 #include <vlc_filter.h>
39 #include "vout_spuregion_helper.h"
42 #define STYLE_FILLED 1
44 #define RGB_BLUE 0x2badde
46 #define COL_TRANSPARENT 0
49 #define COL_BLUE_SHADE 3
51 #define SET_PALETTE_COLOR(id, rgb, alpha) \
53 uint8_t color[4] = { HEX2YUV(rgb), alpha };\
54 memcpy( &palette.palette[id], &color, 4 );\
58 * Draws a rectangle at the given position in the region.
59 * It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
61 static void DrawRect(subpicture_region_t
*r
, int fill
, uint8_t color
,
62 int x1
, int y1
, int x2
, int y2
)
64 uint8_t *p
= r
->p_picture
->p
->p_pixels
;
65 int pitch
= r
->p_picture
->p
->i_pitch
;
66 if( x1
> x2
|| y1
> y2
)
69 if (fill
== STYLE_FILLED
) {
70 if(x1
== 0 && x2
+ 1 == r
->p_picture
->p
->i_visible_pitch
) {
71 memset(&p
[pitch
* y1
], color
, pitch
* (y2
- y1
+ 1));
73 for (int y
= y1
; y
<= y2
; y
++)
74 memset(&p
[x1
+ pitch
* y
], color
, x2
- x1
+ 1);
77 DrawRect(r
, STYLE_FILLED
, color
, x1
, y1
, x1
, y2
);
78 DrawRect(r
, STYLE_FILLED
, color
, x2
, y1
, x2
, y2
);
79 DrawRect(r
, STYLE_FILLED
, color
, x1
, y1
, x2
, y1
);
80 DrawRect(r
, STYLE_FILLED
, color
, x1
, y2
, x2
, y2
);
85 * Draws a triangle at the given position in the region.
86 * It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
88 static void DrawTriangle(subpicture_region_t
*r
, int fill
, uint8_t color
,
89 int x1
, int y1
, int x2
, int y2
)
91 uint8_t *p
= r
->p_picture
->p
->p_pixels
;
92 int pitch
= r
->p_picture
->p
->i_pitch
;
93 const int mid
= y1
+ (y2
- y1
) / 2;
94 const bool b_swap
= (x1
> x2
);
96 for (int y
= y1
; y
<= mid
; y
++) {
98 if (fill
== STYLE_FILLED
) {
99 const int w
= b_swap
? __MAX(x1
- h
, x2
) : __MIN(x1
+ h
, x2
);
100 DrawRect(r
, STYLE_FILLED
, color
,
101 (b_swap
) ? w
: x1
, y
, (b_swap
) ? x1
: w
, y
);
102 DrawRect(r
, STYLE_FILLED
, color
,
103 (b_swap
) ? w
: x1
, y2
- h
, (b_swap
) ? x1
: w
, y2
- h
);
105 p
[x1
+ pitch
* y
] = color
;
106 p
[x1
+ (b_swap
? -h
: h
) + pitch
* y
] = color
;
107 p
[x1
+ pitch
* (y2
- h
)] = color
;
108 p
[x1
+ (b_swap
? -h
: h
) + pitch
* (y2
- h
)] = color
;
114 * Create a region with a white transparent picture.
116 static subpicture_region_t
*OSDRegion(int x
, int y
, int width
, int height
)
118 if( width
== 0 || height
== 0 )
121 video_palette_t palette
;
122 SET_PALETTE_COLOR(COL_WHITE
, 0xffffff, STYLE_ALPHA_OPAQUE
)
123 SET_PALETTE_COLOR(COL_TRANSPARENT
, 0xffffff, STYLE_ALPHA_TRANSPARENT
)
124 SET_PALETTE_COLOR(COL_BLUE
, RGB_BLUE
, STYLE_ALPHA_OPAQUE
)
125 SET_PALETTE_COLOR(COL_BLUE_SHADE
, RGB_BLUE
, 0x40)
126 palette
.i_entries
= 4;
129 video_format_Init(&fmt
, VLC_CODEC_YUVP
);
131 fmt
.i_visible_width
= width
;
133 fmt
.i_visible_height
= height
;
136 fmt
.p_palette
= &palette
;
138 subpicture_region_t
*r
= subpicture_region_New(&fmt
);
148 * Create the region for an OSD slider.
149 * Types are: OSD_HOR_SLIDER and OSD_VERT_SLIDER.
151 #define SLIDER_MARGIN_BASE 0.10
152 static subpicture_region_t
*OSDSlider(int type
, int position
,
153 const video_format_t
*fmt
)
155 const int size
= __MAX(fmt
->i_visible_width
, fmt
->i_visible_height
);
156 const int margin
= size
* SLIDER_MARGIN_BASE
;
157 const int marginbottom
= size
* SLIDER_MARGIN_BASE
* 0.6;
158 uint8_t i_padding
= __MIN(5, size
* 0.25); /* small sizes */
162 if (type
== OSD_HOR_SLIDER
) {
163 width
= __MAX(fmt
->i_visible_width
- 2 * margin
, 1);
164 height
= __MAX(fmt
->i_visible_height
* 0.05, 1);
165 x
= __MIN(fmt
->i_x_offset
+ margin
, fmt
->i_visible_width
- width
);
166 y
= __MAX(fmt
->i_y_offset
+ fmt
->i_visible_height
- marginbottom
, 0);
168 width
= __MAX(fmt
->i_visible_width
* 0.025, 1);
169 height
= __MAX(fmt
->i_visible_height
- 2 * margin
, 1);
170 x
= __MAX(fmt
->i_x_offset
+ fmt
->i_visible_width
- margin
, 0);
171 y
= __MIN(fmt
->i_y_offset
+ margin
, fmt
->i_visible_height
- height
);
174 if( (width
< 1 + 2 * i_padding
) || (height
< 1 + 2 * i_padding
) )
177 subpicture_region_t
*r
= OSDRegion(x
, y
, width
, height
);
181 int pos_x
= i_padding
;
183 int pos_yend
= height
- 1 - i_padding
;
185 if (type
== OSD_HOR_SLIDER
) {
187 pos_xend
= pos_x
+ (width
- 2 * i_padding
) * position
/ 100;
189 pos_y
= height
- (height
- 2 * i_padding
) * position
/ 100;
190 pos_xend
= width
- 1 - i_padding
;
193 /* one full fill is faster than drawing outline */
194 DrawRect(r
, STYLE_FILLED
, COL_BLUE_SHADE
, 0, 0, width
- 1, height
- 1);
195 DrawRect(r
, STYLE_FILLED
, COL_BLUE
, pos_x
, pos_y
, pos_xend
, pos_yend
);
201 * Create the region for an OSD slider.
202 * Types are: OSD_PLAY_ICON, OSD_PAUSE_ICON, OSD_SPEAKER_ICON, OSD_MUTE_ICON
204 static subpicture_region_t
*OSDIcon(int type
, const video_format_t
*fmt
)
206 const float size_ratio
= 0.05;
207 const float margin_ratio
= 0.07;
209 const int size
= __MAX(fmt
->i_visible_width
, fmt
->i_visible_height
);
210 const int width
= size
* size_ratio
;
211 const int height
= size
* size_ratio
;
212 const int x
= fmt
->i_x_offset
+ fmt
->i_visible_width
- margin_ratio
* size
- width
;
213 const int y
= fmt
->i_y_offset
+ margin_ratio
* size
;
215 if( width
< 1 || height
< 1 )
218 subpicture_region_t
*r
= OSDRegion(__MAX(x
, 0),
219 __MIN(y
, (int)fmt
->i_visible_height
- height
),
224 DrawRect(r
, STYLE_FILLED
, COL_TRANSPARENT
, 0, 0, width
- 1, height
- 1);
226 if (type
== OSD_PAUSE_ICON
) {
227 int bar_width
= width
/ 3;
228 DrawRect(r
, STYLE_FILLED
, COL_WHITE
, 0, 0, bar_width
- 1, height
-1);
229 DrawRect(r
, STYLE_FILLED
, COL_WHITE
, width
- bar_width
, 0, width
- 1, height
- 1);
230 } else if (type
== OSD_PLAY_ICON
) {
231 int mid
= height
>> 1;
232 int delta
= (width
- mid
) >> 1;
233 int y2
= ((height
- 1) >> 1) * 2;
234 DrawTriangle(r
, STYLE_FILLED
, COL_WHITE
, delta
, 0, width
- delta
, y2
);
236 int mid
= height
>> 1;
237 int delta
= (width
- mid
) >> 1;
238 int y2
= ((height
- 1) >> 1) * 2;
239 DrawRect(r
, STYLE_FILLED
, COL_WHITE
, delta
, mid
/ 2, width
- delta
, height
- 1 - mid
/ 2);
240 DrawTriangle(r
, STYLE_FILLED
, COL_WHITE
, width
- delta
, 0, delta
, y2
);
241 if (type
== OSD_MUTE_ICON
) {
242 for(int y1
= 0; y1
<= height
-1; y1
++)
243 DrawRect(r
, STYLE_FILLED
, COL_BLUE
, y1
, y1
, __MIN(y1
+ delta
, width
- 1), y1
);
252 } osdwidget_spu_updater_sys_t
;
254 static int OSDWidgetValidate(subpicture_t
*subpic
,
255 bool has_src_changed
, const video_format_t
*fmt_src
,
256 bool has_dst_changed
, const video_format_t
*fmt_dst
,
259 VLC_UNUSED(subpic
); VLC_UNUSED(ts
);
260 VLC_UNUSED(fmt_src
); VLC_UNUSED(has_src_changed
);
263 if (!has_dst_changed
)
268 static void OSDWidgetUpdate(subpicture_t
*subpic
,
269 const video_format_t
*fmt_src
,
270 const video_format_t
*fmt_dst
,
273 osdwidget_spu_updater_sys_t
*sys
= subpic
->updater
.p_sys
;
274 VLC_UNUSED(fmt_src
); VLC_UNUSED(ts
);
276 video_format_t fmt
= *fmt_dst
;
277 fmt
.i_width
= fmt
.i_width
* fmt
.i_sar_num
/ fmt
.i_sar_den
;
278 fmt
.i_visible_width
= fmt
.i_visible_width
* fmt
.i_sar_num
/ fmt
.i_sar_den
;
279 fmt
.i_x_offset
= fmt
.i_x_offset
* fmt
.i_sar_num
/ fmt
.i_sar_den
;
283 subpic
->i_original_picture_width
= fmt
.i_visible_width
;
284 subpic
->i_original_picture_height
= fmt
.i_visible_height
;
285 if (sys
->type
== OSD_HOR_SLIDER
|| sys
->type
== OSD_VERT_SLIDER
)
286 subpic
->p_region
= OSDSlider(sys
->type
, sys
->position
, &fmt
);
288 subpic
->p_region
= OSDIcon(sys
->type
, &fmt
);
291 static void OSDWidgetDestroy(subpicture_t
*subpic
)
293 free(subpic
->updater
.p_sys
);
296 static void OSDWidget(vout_thread_t
*vout
, int channel
, int type
, int position
)
298 if (!var_InheritBool(vout
, "osd"))
300 if (type
== OSD_HOR_SLIDER
|| type
== OSD_VERT_SLIDER
)
301 position
= VLC_CLIP(position
, 0, 100);
303 osdwidget_spu_updater_sys_t
*sys
= malloc(sizeof(*sys
));
307 sys
->position
= position
;
309 subpicture_updater_t updater
= {
310 .pf_validate
= OSDWidgetValidate
,
311 .pf_update
= OSDWidgetUpdate
,
312 .pf_destroy
= OSDWidgetDestroy
,
315 subpicture_t
*subpic
= subpicture_New(&updater
);
321 subpic
->i_channel
= channel
;
322 subpic
->i_start
= vlc_tick_now();
323 subpic
->i_stop
= subpic
->i_start
+ VLC_TICK_FROM_MS(1200);
324 subpic
->b_ephemer
= true;
325 subpic
->b_absolute
= true;
326 subpic
->b_fade
= true;
328 vout_PutSubpicture(vout
, subpic
);
331 void vout_OSDSlider(vout_thread_t
*vout
, int channel
, int position
, short type
)
333 OSDWidget(vout
, channel
, type
, position
);
336 void vout_OSDIcon(vout_thread_t
*vout
, int channel
, short type
)
338 OSDWidget(vout
, channel
, type
, 0);