1 /*****************************************************************************
2 * video_widgets.c : OSD widgets manipulation functions
3 *****************************************************************************
4 * Copyright (C) 2004-2010 the VideoLAN team
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
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 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 General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, 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>
40 #define STYLE_FILLED 1
43 * Draws a rectangle at the given position in the region.
44 * It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
46 static void DrawRect(subpicture_region_t
*r
, int fill
,
47 int x1
, int y1
, int x2
, int y2
)
49 uint8_t *a
= r
->p_picture
->A_PIXELS
;
50 int pitch
= r
->p_picture
->A_PITCH
;
52 if (fill
== STYLE_FILLED
) {
53 for (int y
= y1
; y
<= y2
; y
++) {
54 for (int x
= x1
; x
<= x2
; x
++)
55 a
[x
+ pitch
* y
] = 0xff;
58 for (int y
= y1
; y
<= y2
; y
++) {
59 a
[x1
+ pitch
* y
] = 0xff;
60 a
[x2
+ pitch
* y
] = 0xff;
62 for (int x
= x1
; x
<= x2
; x
++) {
63 a
[x
+ pitch
* y1
] = 0xff;
64 a
[x
+ pitch
* y2
] = 0xff;
70 * Draws a triangle at the given position in the region.
71 * It may be filled (fill == STYLE_FILLED) or empty (fill == STYLE_EMPTY).
73 static void DrawTriangle(subpicture_region_t
*r
, int fill
,
74 int x1
, int y1
, int x2
, int y2
)
76 uint8_t *a
= r
->p_picture
->A_PIXELS
;
77 int pitch
= r
->p_picture
->A_PITCH
;
78 const int mid
= y1
+ (y2
- y1
) / 2;
80 /* TODO factorize it */
82 if (fill
== STYLE_FILLED
) {
83 for (int y
= y1
; y
<= mid
; y
++) {
85 for (int x
= x1
; x
<= x1
+ h
&& x
<= x2
; x
++) {
86 a
[x
+ pitch
* y
] = 0xff;
87 a
[x
+ pitch
* (y2
- h
)] = 0xff;
91 for (int y
= y1
; y
<= mid
; y
++) {
93 a
[x1
+ pitch
* y
] = 0xff;
94 a
[x1
+ h
+ pitch
* y
] = 0xff;
95 a
[x1
+ pitch
* (y2
- h
)] = 0xff;
96 a
[x1
+ h
+ pitch
* (y2
- h
)] = 0xff;
100 if( fill
== STYLE_FILLED
) {
101 for (int y
= y1
; y
<= mid
; y
++) {
103 for (int x
= x1
; x
>= x1
- h
&& x
>= x2
; x
--) {
104 a
[x
+ pitch
* y
] = 0xff;
105 a
[x
+ pitch
* (y2
- h
)] = 0xff;
109 for (int y
= y1
; y
<= mid
; y
++) {
111 a
[ x1
+ pitch
* y
] = 0xff;
112 a
[ x1
- h
+ pitch
* y
] = 0xff;
113 a
[ x1
+ pitch
* (y2
- h
)] = 0xff;
114 a
[ x1
- h
+ pitch
* (y2
- h
)] = 0xff;
121 * Create a region with a white transparent picture.
123 static subpicture_region_t
*OSDRegion(int x
, int y
, int width
, int height
)
126 video_format_Init(&fmt
, VLC_CODEC_YUVA
);
128 fmt
.i_visible_width
= width
;
130 fmt
.i_visible_height
= height
;
134 subpicture_region_t
*r
= subpicture_region_New(&fmt
);
140 for (int i
= 0; i
< r
->p_picture
->i_planes
; i
++) {
141 plane_t
*p
= &r
->p_picture
->p
[i
];
142 int colors
[PICTURE_PLANE_MAX
] = {
143 0xff, 0x80, 0x80, 0x00
145 memset(p
->p_pixels
, colors
[i
], p
->i_pitch
* height
);
151 * Create the region for an OSD slider.
152 * Types are: OSD_HOR_SLIDER and OSD_VERT_SLIDER.
154 static subpicture_region_t
*OSDSlider(int type
, int position
,
155 const video_format_t
*fmt
)
157 const int size
= __MAX(fmt
->i_visible_width
, fmt
->i_visible_height
);
158 const int margin
= size
* 0.10;
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
- margin
, 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 subpicture_region_t
*r
= OSDRegion(x
, y
, width
, height
);
178 if (type
== OSD_HOR_SLIDER
) {
179 int pos_x
= (width
- 2) * position
/ 100;
180 DrawRect(r
, STYLE_FILLED
, pos_x
- 1, 2, pos_x
+ 1, height
- 3);
181 DrawRect(r
, STYLE_EMPTY
, 0, 0, width
- 1, height
- 1);
183 int pos_mid
= height
/ 2;
184 int pos_y
= height
- (height
- 2) * position
/ 100;
185 DrawRect(r
, STYLE_FILLED
, 2, pos_y
, width
- 3, height
- 3);
186 DrawRect(r
, STYLE_FILLED
, 1, pos_mid
, 1, pos_mid
);
187 DrawRect(r
, STYLE_FILLED
, width
- 2, pos_mid
, width
- 2, pos_mid
);
188 DrawRect(r
, STYLE_EMPTY
, 0, 0, width
- 1, height
- 1);
194 * Create the region for an OSD slider.
195 * Types are: OSD_PLAY_ICON, OSD_PAUSE_ICON, OSD_SPEAKER_ICON, OSD_MUTE_ICON
197 static subpicture_region_t
*OSDIcon(int type
, const video_format_t
*fmt
)
199 const float size_ratio
= 0.05;
200 const float margin_ratio
= 0.07;
202 const int size
= __MAX(fmt
->i_visible_width
, fmt
->i_visible_height
);
203 const int width
= size
* size_ratio
;
204 const int height
= size
* size_ratio
;
205 const int x
= fmt
->i_x_offset
+ fmt
->i_visible_width
- margin_ratio
* size
- width
;
206 const int y
= fmt
->i_y_offset
+ margin_ratio
* size
;
208 subpicture_region_t
*r
= OSDRegion(__MAX(x
, 0),
209 __MIN(y
, (int)fmt
->i_visible_height
- height
),
214 if (type
== OSD_PAUSE_ICON
) {
215 int bar_width
= width
/ 3;
216 DrawRect(r
, STYLE_FILLED
, 0, 0, bar_width
- 1, height
-1);
217 DrawRect(r
, STYLE_FILLED
, width
- bar_width
, 0, width
- 1, height
- 1);
218 } else if (type
== OSD_PLAY_ICON
) {
219 int mid
= height
>> 1;
220 int delta
= (width
- mid
) >> 1;
221 int y2
= ((height
- 1) >> 1) * 2;
222 DrawTriangle(r
, STYLE_FILLED
, delta
, 0, width
- delta
, y2
);
224 int mid
= height
>> 1;
225 int delta
= (width
- mid
) >> 1;
226 int y2
= ((height
- 1) >> 1) * 2;
227 DrawRect(r
, STYLE_FILLED
, delta
, mid
/ 2, width
- delta
, height
- 1 - mid
/ 2);
228 DrawTriangle(r
, STYLE_FILLED
, width
- delta
, 0, delta
, y2
);
229 if (type
== OSD_MUTE_ICON
) {
230 uint8_t *a
= r
->p_picture
->A_PIXELS
;
231 int pitch
= r
->p_picture
->A_PITCH
;
232 for (int i
= 1; i
< pitch
; i
++) {
233 int k
= i
+ (height
- i
- 1) * pitch
;
241 struct subpicture_updater_sys_t
{
246 static int OSDWidgetValidate(subpicture_t
*subpic
,
247 bool has_src_changed
, const video_format_t
*fmt_src
,
248 bool has_dst_changed
, const video_format_t
*fmt_dst
,
251 VLC_UNUSED(subpic
); VLC_UNUSED(ts
); VLC_UNUSED(fmt_src
);
252 VLC_UNUSED(has_dst_changed
); VLC_UNUSED(fmt_dst
);
254 if (!has_src_changed
&& !has_dst_changed
)
259 static void OSDWidgetUpdate(subpicture_t
*subpic
,
260 const video_format_t
*fmt_src
,
261 const video_format_t
*fmt_dst
,
264 subpicture_updater_sys_t
*sys
= subpic
->updater
.p_sys
;
265 VLC_UNUSED(fmt_dst
); VLC_UNUSED(ts
);
267 video_format_t fmt
= *fmt_dst
;
268 fmt
.i_width
= fmt
.i_width
* fmt
.i_sar_num
/ fmt
.i_sar_den
;
269 fmt
.i_visible_width
= fmt
.i_visible_width
* fmt
.i_sar_num
/ fmt
.i_sar_den
;
270 fmt
.i_x_offset
= fmt
.i_x_offset
* fmt
.i_sar_num
/ fmt
.i_sar_den
;
274 subpic
->i_original_picture_width
= fmt
.i_width
;
275 subpic
->i_original_picture_height
= fmt
.i_height
;
276 if (sys
->type
== OSD_HOR_SLIDER
|| sys
->type
== OSD_VERT_SLIDER
)
277 subpic
->p_region
= OSDSlider(sys
->type
, sys
->position
, &fmt
);
279 subpic
->p_region
= OSDIcon(sys
->type
, &fmt
);
282 static void OSDWidgetDestroy(subpicture_t
*subpic
)
284 free(subpic
->updater
.p_sys
);
287 static void OSDWidget(vout_thread_t
*vout
, int channel
, int type
, int position
)
289 if (!var_InheritBool(vout
, "osd"))
291 if (type
== OSD_HOR_SLIDER
|| type
== OSD_VERT_SLIDER
)
292 position
= __MIN(__MAX(position
, 0), 100);
294 subpicture_updater_sys_t
*sys
= malloc(sizeof(*sys
));
298 sys
->position
= position
;
300 subpicture_updater_t updater
= {
301 .pf_validate
= OSDWidgetValidate
,
302 .pf_update
= OSDWidgetUpdate
,
303 .pf_destroy
= OSDWidgetDestroy
,
306 subpicture_t
*subpic
= subpicture_New(&updater
);
312 subpic
->i_channel
= channel
;
313 subpic
->i_start
= mdate();
314 subpic
->i_stop
= subpic
->i_start
+ 1200000;
315 subpic
->b_ephemer
= true;
316 subpic
->b_absolute
= true;
317 subpic
->b_fade
= true;
319 vout_PutSubpicture(vout
, subpic
);
322 void vout_OSDSlider(vout_thread_t
*vout
, int channel
, int position
, short type
)
324 OSDWidget(vout
, channel
, type
, position
);
327 void vout_OSDIcon(vout_thread_t
*vout
, int channel
, short type
)
329 OSDWidget(vout
, channel
, type
, 0);