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
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 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 General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, 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 = __MIN(__MAX(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);