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_block.h>
30 #include <vlc_filter.h>
32 #include <vlc_events.h>
33 #include <vlc_input_item.h>
37 /* Layout percentage defines */
40 #define EPG_NAME_SIZE 0.05
41 #define EPG_PROGRAM_SIZE 0.03
45 static subpicture_region_t * vout_OSDEpgSlider( vout_thread_t *p_vout,
47 int i_width, int i_height,
51 subpicture_region_t *p_region;
53 /* Create a new subpicture region */
54 video_format_Init( &fmt, VLC_CODEC_YUVA );
55 fmt.i_width = fmt.i_visible_width = i_width;
56 fmt.i_height = fmt.i_visible_height = i_height;
60 p_region = subpicture_region_New( &fmt );
63 msg_Err( p_vout, "Cannot allocate SPU region." );
70 picture_t *p_picture = p_region->p_picture;
72 f_ratio = __MIN( __MAX( f_ratio, 0 ), 1 );
73 int i_filled_part_width = f_ratio * i_width;
75 for( int j = 0; j < i_height; j++ )
77 for( int i = 0; i < i_width; i++ )
79 #define WRITE_COMP( plane, value ) \
80 p_picture->p[plane].p_pixels[p_picture->p[plane].i_pitch * j + i] = value
82 /* Draw the slider. */
83 bool is_outline = j == 0 || j == i_height - 1
84 || i == 0 || i == i_width - 1;
85 WRITE_COMP( 0, is_outline ? 0x00 : 0xff );
86 WRITE_COMP( 1, 0x80 );
87 WRITE_COMP( 2, 0x80 );
89 /* We can see the video through the part of the slider
90 which corresponds to the leaving time. */
91 bool is_border = j < 3 || j > i_height - 4
92 || i < 3 || i > i_width - 4
93 || i < i_filled_part_width;
94 WRITE_COMP( 3, is_border ? 0xff : 0x00 );
104 static subpicture_region_t * vout_OSDEpgText( vout_thread_t *p_vout,
105 const char *psz_string,
107 int i_size, uint32_t i_color )
110 subpicture_region_t *p_region;
115 /* Create a new subpicture region */
116 video_format_Init( &fmt, VLC_CODEC_TEXT );
120 p_region = subpicture_region_New( &fmt );
123 msg_Err( p_vout, "Cannot allocate SPU region." );
127 /* Set subpicture parameters */
128 p_region->psz_text = strdup( psz_string );
129 p_region->i_align = 0;
134 p_region->p_style = text_style_New();
135 if( p_region->p_style )
137 p_region->p_style->i_font_size = i_size;
138 p_region->p_style->i_font_color = i_color;
139 p_region->p_style->i_font_alpha = 0;
146 static subpicture_region_t * vout_BuildOSDEpg( vout_thread_t *p_vout,
149 int i_visible_height )
151 subpicture_region_t *p_region_ret;
152 subpicture_region_t **pp_region = &p_region_ret;
154 time_t i_test = time( NULL );
156 /* Display the name of the channel. */
157 *pp_region = vout_OSDEpgText( p_vout,
159 i_visible_width * EPG_LEFT,
160 i_visible_height * EPG_TOP,
161 i_visible_height * EPG_NAME_SIZE,
167 /* Display the name of the current program. */
168 pp_region = &(* pp_region)->p_next;
169 *pp_region = vout_OSDEpgText( p_vout, p_epg->p_current->psz_name,
170 i_visible_width * ( EPG_LEFT + 0.025 ),
171 i_visible_height * ( EPG_TOP + 0.05 ),
172 i_visible_height * EPG_PROGRAM_SIZE,
178 /* Display the current program time slider. */
179 pp_region = &(* pp_region)->p_next;
180 *pp_region = vout_OSDEpgSlider( p_vout,
181 i_visible_width * EPG_LEFT,
182 i_visible_height * ( EPG_TOP + 0.1 ),
183 i_visible_width * ( 1 - 2 * EPG_LEFT ),
184 i_visible_height * 0.05,
185 ( i_test - p_epg->p_current->i_start )
186 / (float)p_epg->p_current->i_duration );
191 /* Format the hours of the beginning and the end of the current program. */
192 struct tm tm_start, tm_end;
193 time_t t_start = p_epg->p_current->i_start;
194 time_t t_end = p_epg->p_current->i_start + p_epg->p_current->i_duration;
195 localtime_r( &t_start, &tm_start );
196 localtime_r( &t_end, &tm_end );
199 snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d",
200 tm_start.tm_hour, tm_start.tm_min );
201 snprintf( psz_end, sizeof(psz_end), "%2.2d:%2.2d",
202 tm_end.tm_hour, tm_end.tm_min );
204 /* Display those hours. */
205 pp_region = &(* pp_region)->p_next;
206 *pp_region = vout_OSDEpgText( p_vout, psz_start,
207 i_visible_width * ( EPG_LEFT + 0.02 ),
208 i_visible_height * ( EPG_TOP + 0.15 ),
209 i_visible_height * EPG_PROGRAM_SIZE,
215 pp_region = &(* pp_region)->p_next;
216 *pp_region = vout_OSDEpgText( p_vout, psz_end,
217 i_visible_width * ( 1 - EPG_LEFT - 0.085 ),
218 i_visible_height * ( EPG_TOP + 0.15 ),
219 i_visible_height * EPG_PROGRAM_SIZE,
227 * \brief Show EPG information about the current program of an input item
228 * \param p_vout pointer to the vout the information is to be showed on
229 * \param p_input pointer to the input item the information is to be showed
231 int vout_OSDEpg( vout_thread_t *p_vout, input_item_t *p_input )
234 mtime_t i_now = mdate();
236 char *psz_now_playing = input_item_GetNowPlaying( p_input );
237 vlc_epg_t *p_epg = NULL;
239 vlc_mutex_lock( &p_input->lock );
241 /* Look for the current program EPG event */
242 for( int i = 0; i < p_input->i_epg; i++ )
244 vlc_epg_t *p_tmp = p_input->pp_epg[i];
246 if( p_tmp->p_current && p_tmp->p_current->psz_name
247 && psz_now_playing != NULL
248 && !strcmp( p_tmp->p_current->psz_name, psz_now_playing ) )
250 p_epg = vlc_epg_New( p_tmp->psz_name );
251 vlc_epg_Merge( p_epg, p_tmp );
256 vlc_mutex_unlock( &p_input->lock );
258 /* If no EPG event has been found. */
262 p_spu = subpicture_New();
265 vlc_epg_Delete( p_epg );
269 p_spu->i_channel = DEFAULT_CHAN;
270 p_spu->i_start = i_now;
271 p_spu->i_stop = i_now + 3000 * INT64_C(1000);
272 p_spu->b_ephemer = true;
273 p_spu->b_absolute = true;
274 p_spu->b_fade = true;
276 /* Build the EPG event subpictures. */
277 p_spu->p_region = vout_BuildOSDEpg( p_vout, p_epg,
278 p_vout->fmt_in.i_width,
279 p_vout->fmt_in.i_height );
281 vlc_epg_Delete( p_epg );
282 spu_DisplaySubpicture( vout_GetSpu( p_vout ), p_spu );