EGL: destroy the created EGLSurface on Close()
[vlc.git] / src / video_output / video_epg.c
blob624caf198cf04bc4f2adf6b43eadda79a38bd038
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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <time.h>
29 #include <vlc_common.h>
30 #include <vlc_vout.h>
31 #include <vlc_vout_osd.h>
32 #include <vlc_events.h>
33 #include <vlc_input_item.h>
34 #include <vlc_epg.h>
36 /* Layout percentage defines */
37 #define EPG_TOP 0.7
38 #define EPG_LEFT 0.1
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,
44 float ratio)
46 /* Create a new subpicture region */
47 video_palette_t palette = {
48 .i_entries = 4,
49 .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 },
57 video_format_t fmt;
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;
61 fmt.i_sar_num = 1;
62 fmt.i_sar_den = 1;
63 fmt.p_palette = &palette;
65 subpicture_region_t *region = subpicture_region_New(&fmt);
66 if (!region)
67 return NULL;
69 region->i_x = x;
70 region->i_y = y;
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++) {
79 /* Slider border. */
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;
92 return region;
96 static subpicture_region_t * vout_OSDEpgText(const char *text,
97 int x, int y,
98 int size, uint32_t color)
100 video_format_t fmt;
101 subpicture_region_t *region;
103 if (!text)
104 return NULL;
106 /* Create a new subpicture region */
107 video_format_Init(&fmt, VLC_CODEC_TEXT);
108 fmt.i_sar_num = 1;
109 fmt.i_sar_den = 1;
111 region = subpicture_region_New(&fmt);
112 if (!region)
113 return NULL;
115 /* Set subpicture parameters */
116 region->psz_text = strdup(text);
117 region->i_align = 0;
118 region->i_x = x;
119 region->i_y = y;
121 /* Set text style */
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;
129 return region;
133 static subpicture_region_t * vout_BuildOSDEpg(vlc_epg_t *epg,
134 int x, int y,
135 int visible_width,
136 int visible_height)
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,
148 0x00ffffff);
150 if (!*last_ptr)
151 return head;
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,
159 0x00ffffff);
161 if (!*last_ptr)
162 return head;
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);
173 if (!*last_ptr)
174 return head;
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];
183 char text_end[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,
195 0x00ffffff);
197 if (!*last_ptr)
198 return head;
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,
205 0x00ffffff);
207 return head;
210 struct subpicture_updater_sys_t
212 vlc_epg_t *epg;
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,
218 mtime_t ts)
220 VLC_UNUSED(subpic); VLC_UNUSED(ts);
221 VLC_UNUSED(fmt_src); VLC_UNUSED(has_src_changed);
222 VLC_UNUSED(fmt_dst);
224 if (!has_dst_changed)
225 return VLC_SUCCESS;
226 return VLC_EGENERIC;
229 static void OSDEpgUpdate(subpicture_t *subpic,
230 const video_format_t *fmt_src,
231 const video_format_t *fmt_dst,
232 mtime_t ts)
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,
245 fmt.i_x_offset,
246 fmt.i_y_offset,
247 fmt.i_visible_width,
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);
256 free(sys);
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);
280 break;
284 vlc_mutex_unlock(&input->lock);
286 /* If no EPG event has been found. */
287 if (epg == NULL)
288 return VLC_EGENERIC;
290 subpicture_updater_sys_t *sys = malloc(sizeof(*sys));
291 if (!sys) {
292 vlc_epg_Delete(epg);
293 return VLC_EGENERIC;
295 sys->epg = epg;
296 subpicture_updater_t updater = {
297 .pf_validate = OSDEpgValidate,
298 .pf_update = OSDEpgUpdate,
299 .pf_destroy = OSDEpgDestroy,
300 .p_sys = sys
303 const mtime_t now = mdate();
304 subpicture_t *subpic = subpicture_New(&updater);
305 if (!subpic) {
306 vlc_epg_Delete(sys->epg);
307 free(sys);
308 return VLC_EGENERIC;
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);
320 return VLC_SUCCESS;