MacOS: remove some callbacks
[vlc.git] / src / video_output / video_epg.c
blob05116a49421e15e82fbd132b67163d63ca234500
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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <vlc_common.h>
28 #include <vlc_vout.h>
29 #include <vlc_vout_osd.h>
30 #include <vlc_events.h>
31 #include <vlc_input_item.h>
32 #include <vlc_epg.h>
34 /* Layout percentage defines */
35 #define EPG_TOP 0.7
36 #define EPG_LEFT 0.1
37 #define EPG_NAME_SIZE 0.05
38 #define EPG_PROGRAM_SIZE 0.03
40 static subpicture_region_t * vout_OSDEpgSlider(int x, int y,
41 int width, int height,
42 float ratio)
44 /* Create a new subpicture region */
45 video_palette_t palette = {
46 .i_entries = 4,
47 .palette = {
48 [0] = { 0xff, 0x80, 0x80, 0x00 },
49 [1] = { 0x00, 0x80, 0x80, 0x00 },
50 [2] = { 0xff, 0x80, 0x80, 0xff },
51 [3] = { 0x00, 0x80, 0x80, 0xff },
55 video_format_t fmt;
56 video_format_Init(&fmt, VLC_CODEC_YUVP);
57 fmt.i_width = fmt.i_visible_width = width;
58 fmt.i_height = fmt.i_visible_height = height;
59 fmt.i_sar_num = 1;
60 fmt.i_sar_den = 1;
61 fmt.p_palette = &palette;
63 subpicture_region_t *region = subpicture_region_New(&fmt);
64 if (!region)
65 return NULL;
67 region->i_x = x;
68 region->i_y = y;
70 picture_t *picture = region->p_picture;
72 ratio = __MIN(__MAX(ratio, 0), 1);
73 int filled_part_width = ratio * width;
75 for (int j = 0; j < height; j++) {
76 for (int i = 0; i < width; i++) {
77 /* Slider border. */
78 bool is_outline = j == 0 || j == height - 1 ||
79 i == 0 || i == width - 1;
80 /* We can see the video through the part of the slider
81 which corresponds to the leaving time. */
82 bool is_border = j < 3 || j > height - 4 ||
83 i < 3 || i > width - 4 ||
84 i < filled_part_width;
86 picture->p->p_pixels[picture->p->i_pitch * j + i] = 2 * is_border + is_outline;
90 return region;
94 static subpicture_region_t * vout_OSDEpgText(const char *text,
95 int x, int y,
96 int size, uint32_t color)
98 video_format_t fmt;
99 subpicture_region_t *region;
101 if (!text)
102 return NULL;
104 /* Create a new subpicture region */
105 video_format_Init(&fmt, VLC_CODEC_TEXT);
106 fmt.i_sar_num = 1;
107 fmt.i_sar_den = 1;
109 region = subpicture_region_New(&fmt);
110 if (!region)
111 return NULL;
113 /* Set subpicture parameters */
114 region->psz_text = strdup(text);
115 region->i_align = 0;
116 region->i_x = x;
117 region->i_y = y;
119 /* Set text style */
120 region->p_style = text_style_New();
121 if (region->p_style) {
122 region->p_style->i_font_size = size;
123 region->p_style->i_font_color = color;
124 region->p_style->i_font_alpha = 0;
127 return region;
131 static subpicture_region_t * vout_BuildOSDEpg(vlc_epg_t *epg,
132 int x, int y,
133 int visible_width,
134 int visible_height)
136 subpicture_region_t *head;
137 subpicture_region_t **last_ptr = &head;
139 time_t current_time = time(NULL);
141 /* Display the name of the channel. */
142 *last_ptr = vout_OSDEpgText(epg->psz_name,
143 x + visible_width * EPG_LEFT,
144 y + visible_height * EPG_TOP,
145 visible_height * EPG_NAME_SIZE,
146 0x00ffffff);
148 if (!*last_ptr)
149 return head;
151 /* Display the name of the current program. */
152 last_ptr = &(*last_ptr)->p_next;
153 *last_ptr = vout_OSDEpgText(epg->p_current->psz_name,
154 x + visible_width * (EPG_LEFT + 0.025),
155 y + visible_height * (EPG_TOP + 0.05),
156 visible_height * EPG_PROGRAM_SIZE,
157 0x00ffffff);
159 if (!*last_ptr)
160 return head;
162 /* Display the current program time slider. */
163 last_ptr = &(*last_ptr)->p_next;
164 *last_ptr = vout_OSDEpgSlider(x + visible_width * EPG_LEFT,
165 y + visible_height * (EPG_TOP + 0.1),
166 visible_width * (1 - 2 * EPG_LEFT),
167 visible_height * 0.05,
168 (current_time - epg->p_current->i_start)
169 / (float)epg->p_current->i_duration);
171 if (!*last_ptr)
172 return head;
174 /* Format the hours of the beginning and the end of the current program. */
175 struct tm tm_start, tm_end;
176 time_t t_start = epg->p_current->i_start;
177 time_t t_end = epg->p_current->i_start + epg->p_current->i_duration;
178 localtime_r(&t_start, &tm_start);
179 localtime_r(&t_end, &tm_end);
180 char text_start[128];
181 char text_end[128];
182 snprintf(text_start, sizeof(text_start), "%2.2d:%2.2d",
183 tm_start.tm_hour, tm_start.tm_min);
184 snprintf(text_end, sizeof(text_end), "%2.2d:%2.2d",
185 tm_end.tm_hour, tm_end.tm_min);
187 /* Display those hours. */
188 last_ptr = &(*last_ptr)->p_next;
189 *last_ptr = vout_OSDEpgText(text_start,
190 x + visible_width * (EPG_LEFT + 0.02),
191 y + visible_height * (EPG_TOP + 0.15),
192 visible_height * EPG_PROGRAM_SIZE,
193 0x00ffffff);
195 if (!*last_ptr)
196 return head;
198 last_ptr = &(*last_ptr)->p_next;
199 *last_ptr = vout_OSDEpgText(text_end,
200 x + visible_width * (1 - EPG_LEFT - 0.085),
201 y + visible_height * (EPG_TOP + 0.15),
202 visible_height * EPG_PROGRAM_SIZE,
203 0x00ffffff);
205 return head;
208 struct subpicture_updater_sys_t
210 vlc_epg_t *epg;
213 static int OSDEpgValidate(subpicture_t *subpic,
214 bool has_src_changed, const video_format_t *fmt_src,
215 bool has_dst_changed, const video_format_t *fmt_dst,
216 mtime_t ts)
218 VLC_UNUSED(subpic); VLC_UNUSED(ts);
219 VLC_UNUSED(fmt_src); VLC_UNUSED(has_src_changed);
220 VLC_UNUSED(fmt_dst);
222 if (!has_dst_changed)
223 return VLC_SUCCESS;
224 return VLC_EGENERIC;
227 static void OSDEpgUpdate(subpicture_t *subpic,
228 const video_format_t *fmt_src,
229 const video_format_t *fmt_dst,
230 mtime_t ts)
232 subpicture_updater_sys_t *sys = subpic->updater.p_sys;
233 VLC_UNUSED(fmt_src); VLC_UNUSED(ts);
235 video_format_t fmt = *fmt_dst;
236 fmt.i_width = fmt.i_width * fmt.i_sar_num / fmt.i_sar_den;
237 fmt.i_visible_width = fmt.i_visible_width * fmt.i_sar_num / fmt.i_sar_den;
238 fmt.i_x_offset = fmt.i_x_offset * fmt.i_sar_num / fmt.i_sar_den;
240 subpic->i_original_picture_width = fmt.i_width;
241 subpic->i_original_picture_height = fmt.i_height;
242 subpic->p_region = vout_BuildOSDEpg(sys->epg,
243 fmt.i_x_offset,
244 fmt.i_y_offset,
245 fmt.i_visible_width,
246 fmt.i_visible_height);
249 static void OSDEpgDestroy(subpicture_t *subpic)
251 subpicture_updater_sys_t *sys = subpic->updater.p_sys;
253 vlc_epg_Delete(sys->epg);
254 free(sys);
258 * \brief Show EPG information about the current program of an input item
259 * \param vout pointer to the vout the information is to be showed on
260 * \param p_input pointer to the input item the information is to be showed
262 int vout_OSDEpg(vout_thread_t *vout, input_item_t *input)
264 char *now_playing = input_item_GetNowPlaying(input);
265 vlc_epg_t *epg = NULL;
267 vlc_mutex_lock(&input->lock);
269 /* Look for the current program EPG event */
270 for (int i = 0; i < input->i_epg; i++) {
271 vlc_epg_t *tmp = input->pp_epg[i];
273 if (tmp->p_current &&
274 tmp->p_current->psz_name && now_playing != NULL &&
275 !strcmp(tmp->p_current->psz_name, now_playing)) {
276 epg = vlc_epg_New(tmp->psz_name);
277 vlc_epg_Merge(epg, tmp);
278 break;
282 vlc_mutex_unlock(&input->lock);
284 /* If no EPG event has been found. */
285 if (epg == NULL)
286 return VLC_EGENERIC;
288 subpicture_updater_sys_t *sys = malloc(sizeof(*sys));
289 if (!sys) {
290 vlc_epg_Delete(epg);
291 return VLC_EGENERIC;
293 sys->epg = epg;
294 subpicture_updater_t updater = {
295 .pf_validate = OSDEpgValidate,
296 .pf_update = OSDEpgUpdate,
297 .pf_destroy = OSDEpgDestroy,
298 .p_sys = sys
301 const mtime_t now = mdate();
302 subpicture_t *subpic = subpicture_New(&updater);
303 if (!subpic) {
304 vlc_epg_Delete(sys->epg);
305 free(sys);
306 return VLC_EGENERIC;
309 subpic->i_channel = SPU_DEFAULT_CHANNEL;
310 subpic->i_start = now;
311 subpic->i_stop = now + 3000 * INT64_C(1000);
312 subpic->b_ephemer = true;
313 subpic->b_absolute = true;
314 subpic->b_fade = true;
316 vout_PutSubpicture(vout, subpic);
318 return VLC_SUCCESS;