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 *****************************************************************************/
27 #include <vlc_common.h>
29 #include <vlc_vout_osd.h>
30 #include <vlc_events.h>
31 #include <vlc_input_item.h>
34 /* Layout percentage defines */
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
,
44 /* Create a new subpicture region */
45 video_palette_t 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 },
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
;
61 fmt
.p_palette
= &palette
;
63 subpicture_region_t
*region
= subpicture_region_New(&fmt
);
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
++) {
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
;
94 static subpicture_region_t
* vout_OSDEpgText(const char *text
,
96 int size
, uint32_t color
)
99 subpicture_region_t
*region
;
104 /* Create a new subpicture region */
105 video_format_Init(&fmt
, VLC_CODEC_TEXT
);
109 region
= subpicture_region_New(&fmt
);
113 /* Set subpicture parameters */
114 region
->psz_text
= strdup(text
);
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;
131 static subpicture_region_t
* vout_BuildOSDEpg(vlc_epg_t
*epg
,
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
,
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
,
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
);
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];
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
,
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
,
208 struct subpicture_updater_sys_t
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
,
218 VLC_UNUSED(subpic
); VLC_UNUSED(ts
);
219 VLC_UNUSED(fmt_src
); VLC_UNUSED(has_src_changed
);
222 if (!has_dst_changed
)
227 static void OSDEpgUpdate(subpicture_t
*subpic
,
228 const video_format_t
*fmt_src
,
229 const video_format_t
*fmt_dst
,
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
,
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
);
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
);
282 vlc_mutex_unlock(&input
->lock
);
284 /* If no EPG event has been found. */
288 subpicture_updater_sys_t
*sys
= malloc(sizeof(*sys
));
294 subpicture_updater_t updater
= {
295 .pf_validate
= OSDEpgValidate
,
296 .pf_update
= OSDEpgUpdate
,
297 .pf_destroy
= OSDEpgDestroy
,
301 const mtime_t now
= mdate();
302 subpicture_t
*subpic
= subpicture_New(&updater
);
304 vlc_epg_Delete(sys
->epg
);
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
);