1 /*****************************************************************************
2 * video_epg.c : EPG manipulation functions
3 *****************************************************************************
4 * Copyright (C) 2010 Adrien Maglo
6 * Author: Adrien Maglo <magsoft@videolan.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
29 #include <vlc_common.h>
31 #include <vlc_vout_osd.h>
32 #include <vlc_events.h>
33 #include <vlc_input_item.h>
36 /* Layout percentage defines */
39 #define EPG_NAME_SIZE 0.05
40 #define EPG_PROGRAM_SIZE 0.03
42 static subpicture_region_t
* vout_OSDEpgSlider(int x
, int y
,
43 int width
, int height
,
46 /* Create a new subpicture region */
47 video_palette_t palette
= {
50 [0] = { 0xff, 0x80, 0x80, 0x00 },
51 [1] = { 0x00, 0x80, 0x80, 0x00 },
52 [2] = { 0xff, 0x80, 0x80, 0xff },
53 [3] = { 0x00, 0x80, 0x80, 0xff },
58 video_format_Init(&fmt
, VLC_CODEC_YUVP
);
59 fmt
.i_width
= fmt
.i_visible_width
= width
;
60 fmt
.i_height
= fmt
.i_visible_height
= height
;
63 fmt
.p_palette
= &palette
;
65 subpicture_region_t
*region
= subpicture_region_New(&fmt
);
72 picture_t
*picture
= region
->p_picture
;
74 ratio
= VLC_CLIP(ratio
, 0, 1);
75 int filled_part_width
= ratio
* width
;
77 for (int j
= 0; j
< height
; j
++) {
78 for (int i
= 0; i
< width
; i
++) {
80 bool is_outline
= j
== 0 || j
== height
- 1 ||
81 i
== 0 || i
== width
- 1;
82 /* We can see the video through the part of the slider
83 which corresponds to the leaving time. */
84 bool is_border
= j
< 3 || j
> height
- 4 ||
85 i
< 3 || i
> width
- 4 ||
86 i
< filled_part_width
;
88 picture
->p
->p_pixels
[picture
->p
->i_pitch
* j
+ i
] = 2 * is_border
+ is_outline
;
96 static subpicture_region_t
* vout_OSDEpgText(const char *text
,
98 int size
, uint32_t color
)
101 subpicture_region_t
*region
;
106 /* Create a new subpicture region */
107 video_format_Init(&fmt
, VLC_CODEC_TEXT
);
111 region
= subpicture_region_New(&fmt
);
115 /* Set subpicture parameters */
116 region
->psz_text
= strdup(text
);
122 region
->p_style
= text_style_New();
123 if (region
->p_style
) {
124 region
->p_style
->i_font_size
= size
;
125 region
->p_style
->i_font_color
= color
;
126 region
->p_style
->i_font_alpha
= 0;
133 static subpicture_region_t
* vout_BuildOSDEpg(vlc_epg_t
*epg
,
138 subpicture_region_t
*head
;
139 subpicture_region_t
**last_ptr
= &head
;
141 time_t current_time
= time(NULL
);
143 /* Display the name of the channel. */
144 *last_ptr
= vout_OSDEpgText(epg
->psz_name
,
145 x
+ visible_width
* EPG_LEFT
,
146 y
+ visible_height
* EPG_TOP
,
147 visible_height
* EPG_NAME_SIZE
,
153 /* Display the name of the current program. */
154 last_ptr
= &(*last_ptr
)->p_next
;
155 *last_ptr
= vout_OSDEpgText(epg
->p_current
->psz_name
,
156 x
+ visible_width
* (EPG_LEFT
+ 0.025),
157 y
+ visible_height
* (EPG_TOP
+ 0.05),
158 visible_height
* EPG_PROGRAM_SIZE
,
164 /* Display the current program time slider. */
165 last_ptr
= &(*last_ptr
)->p_next
;
166 *last_ptr
= vout_OSDEpgSlider(x
+ visible_width
* EPG_LEFT
,
167 y
+ visible_height
* (EPG_TOP
+ 0.1),
168 visible_width
* (1 - 2 * EPG_LEFT
),
169 visible_height
* 0.05,
170 (current_time
- epg
->p_current
->i_start
)
171 / (float)epg
->p_current
->i_duration
);
176 /* Format the hours of the beginning and the end of the current program. */
177 struct tm tm_start
, tm_end
;
178 time_t t_start
= epg
->p_current
->i_start
;
179 time_t t_end
= epg
->p_current
->i_start
+ epg
->p_current
->i_duration
;
180 localtime_r(&t_start
, &tm_start
);
181 localtime_r(&t_end
, &tm_end
);
182 char text_start
[128];
184 snprintf(text_start
, sizeof(text_start
), "%2.2d:%2.2d",
185 tm_start
.tm_hour
, tm_start
.tm_min
);
186 snprintf(text_end
, sizeof(text_end
), "%2.2d:%2.2d",
187 tm_end
.tm_hour
, tm_end
.tm_min
);
189 /* Display those hours. */
190 last_ptr
= &(*last_ptr
)->p_next
;
191 *last_ptr
= vout_OSDEpgText(text_start
,
192 x
+ visible_width
* (EPG_LEFT
+ 0.02),
193 y
+ visible_height
* (EPG_TOP
+ 0.15),
194 visible_height
* EPG_PROGRAM_SIZE
,
200 last_ptr
= &(*last_ptr
)->p_next
;
201 *last_ptr
= vout_OSDEpgText(text_end
,
202 x
+ visible_width
* (1 - EPG_LEFT
- 0.085),
203 y
+ visible_height
* (EPG_TOP
+ 0.15),
204 visible_height
* EPG_PROGRAM_SIZE
,
210 struct subpicture_updater_sys_t
215 static int OSDEpgValidate(subpicture_t
*subpic
,
216 bool has_src_changed
, const video_format_t
*fmt_src
,
217 bool has_dst_changed
, const video_format_t
*fmt_dst
,
220 VLC_UNUSED(subpic
); VLC_UNUSED(ts
);
221 VLC_UNUSED(fmt_src
); VLC_UNUSED(has_src_changed
);
224 if (!has_dst_changed
)
229 static void OSDEpgUpdate(subpicture_t
*subpic
,
230 const video_format_t
*fmt_src
,
231 const video_format_t
*fmt_dst
,
234 subpicture_updater_sys_t
*sys
= subpic
->updater
.p_sys
;
235 VLC_UNUSED(fmt_src
); VLC_UNUSED(ts
);
237 video_format_t fmt
= *fmt_dst
;
238 fmt
.i_width
= fmt
.i_width
* fmt
.i_sar_num
/ fmt
.i_sar_den
;
239 fmt
.i_visible_width
= fmt
.i_visible_width
* fmt
.i_sar_num
/ fmt
.i_sar_den
;
240 fmt
.i_x_offset
= fmt
.i_x_offset
* fmt
.i_sar_num
/ fmt
.i_sar_den
;
242 subpic
->i_original_picture_width
= fmt
.i_width
;
243 subpic
->i_original_picture_height
= fmt
.i_height
;
244 subpic
->p_region
= vout_BuildOSDEpg(sys
->epg
,
248 fmt
.i_visible_height
);
251 static void OSDEpgDestroy(subpicture_t
*subpic
)
253 subpicture_updater_sys_t
*sys
= subpic
->updater
.p_sys
;
255 vlc_epg_Delete(sys
->epg
);
260 * \brief Show EPG information about the current program of an input item
261 * \param vout pointer to the vout the information is to be showed on
262 * \param p_input pointer to the input item the information is to be showed
264 int vout_OSDEpg(vout_thread_t
*vout
, input_item_t
*input
)
266 char *now_playing
= input_item_GetNowPlaying(input
);
267 vlc_epg_t
*epg
= NULL
;
269 vlc_mutex_lock(&input
->lock
);
271 /* Look for the current program EPG event */
272 for (int i
= 0; i
< input
->i_epg
; i
++) {
273 vlc_epg_t
*tmp
= input
->pp_epg
[i
];
275 if (tmp
->p_current
&&
276 tmp
->p_current
->psz_name
&& now_playing
!= NULL
&&
277 !strcmp(tmp
->p_current
->psz_name
, now_playing
)) {
278 epg
= vlc_epg_New(tmp
->psz_name
);
279 vlc_epg_Merge(epg
, tmp
);
284 vlc_mutex_unlock(&input
->lock
);
286 /* If no EPG event has been found. */
290 subpicture_updater_sys_t
*sys
= malloc(sizeof(*sys
));
296 subpicture_updater_t updater
= {
297 .pf_validate
= OSDEpgValidate
,
298 .pf_update
= OSDEpgUpdate
,
299 .pf_destroy
= OSDEpgDestroy
,
303 const mtime_t now
= mdate();
304 subpicture_t
*subpic
= subpicture_New(&updater
);
306 vlc_epg_Delete(sys
->epg
);
311 subpic
->i_channel
= SPU_DEFAULT_CHANNEL
;
312 subpic
->i_start
= now
;
313 subpic
->i_stop
= now
+ 3000 * INT64_C(1000);
314 subpic
->b_ephemer
= true;
315 subpic
->b_absolute
= true;
316 subpic
->b_fade
= true;
318 vout_PutSubpicture(vout
, subpic
);