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 *****************************************************************************/
28 #include <vlc_common.h>
30 #include <vlc_block.h>
31 #include <vlc_filter.h>
33 #include <vlc_events.h>
34 #include <vlc_input_item.h>
37 /* TODO remove access to private vout data */
38 #include "vout_internal.h"
40 /* Layout percentage defines */
43 #define EPG_NAME_SIZE 0.05
44 #define EPG_PROGRAM_SIZE 0.03
48 static subpicture_region_t * vout_OSDEpgSlider( vout_thread_t *p_vout,
50 int i_width, int i_height,
54 subpicture_region_t *p_region;
56 /* Create a new subpicture region */
57 video_format_Init( &fmt, VLC_CODEC_YUVA );
58 fmt.i_width = fmt.i_visible_width = i_width;
59 fmt.i_height = fmt.i_visible_height = i_height;
63 p_region = subpicture_region_New( &fmt );
66 msg_Err( p_vout, "Cannot allocate SPU region." );
73 picture_t *p_picture = p_region->p_picture;
75 f_ratio = __MIN( __MAX( f_ratio, 0 ), 1 );
76 int i_filled_part_width = f_ratio * i_width;
78 for( int j = 0; j < i_height; j++ )
80 for( int i = 0; i < i_width; i++ )
82 #define WRITE_COMP( plane, value ) \
83 p_picture->p[plane].p_pixels[p_picture->p[plane].i_pitch * j + i] = value
85 /* Draw the slider. */
86 bool is_outline = j == 0 || j == i_height - 1
87 || i == 0 || i == i_width - 1;
88 WRITE_COMP( 0, is_outline ? 0x00 : 0xff );
89 WRITE_COMP( 1, 0x80 );
90 WRITE_COMP( 2, 0x80 );
92 /* We can see the video through the part of the slider
93 which corresponds to the leaving time. */
94 bool is_border = j < 3 || j > i_height - 4
95 || i < 3 || i > i_width - 4
96 || i < i_filled_part_width;
97 WRITE_COMP( 3, is_border ? 0xff : 0x00 );
107 static subpicture_region_t * vout_OSDEpgText( vout_thread_t *p_vout,
108 const char *psz_string,
110 int i_size, uint32_t i_color )
113 subpicture_region_t *p_region;
118 /* Create a new subpicture region */
119 video_format_Init( &fmt, VLC_CODEC_TEXT );
123 p_region = subpicture_region_New( &fmt );
126 msg_Err( p_vout, "Cannot allocate SPU region." );
130 /* Set subpicture parameters */
131 p_region->psz_text = strdup( psz_string );
132 p_region->i_align = 0;
137 p_region->p_style = text_style_New();
138 if( p_region->p_style )
140 p_region->p_style->i_font_size = i_size;
141 p_region->p_style->i_font_color = i_color;
142 p_region->p_style->i_font_alpha = 0;
149 static subpicture_region_t * vout_BuildOSDEpg( vout_thread_t *p_vout,
152 int i_visible_height )
154 subpicture_region_t *p_region_ret;
155 subpicture_region_t **pp_region = &p_region_ret;
157 time_t i_test = time( NULL );
159 /* Display the name of the channel. */
160 *pp_region = vout_OSDEpgText( p_vout,
162 i_visible_width * EPG_LEFT,
163 i_visible_height * EPG_TOP,
164 i_visible_height * EPG_NAME_SIZE,
170 /* Display the name of the current program. */
171 pp_region = &(* pp_region)->p_next;
172 *pp_region = vout_OSDEpgText( p_vout, p_epg->p_current->psz_name,
173 i_visible_width * ( EPG_LEFT + 0.025 ),
174 i_visible_height * ( EPG_TOP + 0.05 ),
175 i_visible_height * EPG_PROGRAM_SIZE,
181 /* Display the current program time slider. */
182 pp_region = &(* pp_region)->p_next;
183 *pp_region = vout_OSDEpgSlider( p_vout,
184 i_visible_width * EPG_LEFT,
185 i_visible_height * ( EPG_TOP + 0.1 ),
186 i_visible_width * ( 1 - 2 * EPG_LEFT ),
187 i_visible_height * 0.05,
188 ( i_test - p_epg->p_current->i_start )
189 / (float)p_epg->p_current->i_duration );
194 /* Format the hours of the beginning and the end of the current program. */
195 struct tm tm_start, tm_end;
196 time_t t_start = p_epg->p_current->i_start;
197 time_t t_end = p_epg->p_current->i_start + p_epg->p_current->i_duration;
198 localtime_r( &t_start, &tm_start );
199 localtime_r( &t_end, &tm_end );
202 snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d",
203 tm_start.tm_hour, tm_start.tm_min );
204 snprintf( psz_end, sizeof(psz_end), "%2.2d:%2.2d",
205 tm_end.tm_hour, tm_end.tm_min );
207 /* Display those hours. */
208 pp_region = &(* pp_region)->p_next;
209 *pp_region = vout_OSDEpgText( p_vout, psz_start,
210 i_visible_width * ( EPG_LEFT + 0.02 ),
211 i_visible_height * ( EPG_TOP + 0.15 ),
212 i_visible_height * EPG_PROGRAM_SIZE,
218 pp_region = &(* pp_region)->p_next;
219 *pp_region = vout_OSDEpgText( p_vout, psz_end,
220 i_visible_width * ( 1 - EPG_LEFT - 0.085 ),
221 i_visible_height * ( EPG_TOP + 0.15 ),
222 i_visible_height * EPG_PROGRAM_SIZE,
230 * \brief Show EPG information about the current program of an input item
231 * \param p_vout pointer to the vout the information is to be showed on
232 * \param p_input pointer to the input item the information is to be showed
234 int vout_OSDEpg( vout_thread_t *p_vout, input_item_t *p_input )
237 mtime_t i_now = mdate();
239 char *psz_now_playing = input_item_GetNowPlaying( p_input );
240 vlc_epg_t *p_epg = NULL;
242 vlc_mutex_lock( &p_input->lock );
244 /* Look for the current program EPG event */
245 for( int i = 0; i < p_input->i_epg; i++ )
247 vlc_epg_t *p_tmp = p_input->pp_epg[i];
249 if( p_tmp->p_current && p_tmp->p_current->psz_name
250 && psz_now_playing != NULL
251 && !strcmp( p_tmp->p_current->psz_name, psz_now_playing ) )
253 p_epg = vlc_epg_New( p_tmp->psz_name );
254 vlc_epg_Merge( p_epg, p_tmp );
259 vlc_mutex_unlock( &p_input->lock );
261 /* If no EPG event has been found. */
265 p_spu = subpicture_New( NULL );
268 vlc_epg_Delete( p_epg );
272 p_spu->i_channel = DEFAULT_CHAN;
273 p_spu->i_start = i_now;
274 p_spu->i_stop = i_now + 3000 * INT64_C(1000);
275 p_spu->b_ephemer = true;
276 p_spu->b_absolute = true;
277 p_spu->b_fade = true;
279 /* Build the EPG event subpictures. */
280 p_spu->p_region = vout_BuildOSDEpg( p_vout, p_epg,
281 p_vout->p->fmt_in.i_width,
282 p_vout->p->fmt_in.i_height );
284 vlc_epg_Delete( p_epg );
285 spu_DisplaySubpicture( vout_GetSpu( p_vout ), p_spu );