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
43 #define NO_EPG N_( "No EPG found for this program." )
46 static subpicture_region_t * vout_OSDEpgSlider( vout_thread_t *p_vout,
48 int i_width, int i_height,
52 subpicture_region_t *p_region;
54 /* Create a new subpicture region */
55 video_format_Init( &fmt, VLC_CODEC_YUVA );
56 fmt.i_width = fmt.i_visible_width = i_width;
57 fmt.i_height = fmt.i_visible_height = i_height;
59 p_region = subpicture_region_New( &fmt );
62 msg_Err( p_vout, "Cannot allocate SPU region." );
69 picture_t *p_picture = p_region->p_picture;
71 f_ratio = __MIN( __MAX( f_ratio, 0 ), 1 );
72 int i_filled_part_width = f_ratio * i_width;
74 for( int j = 0; j < i_height; j++ )
76 for( int i = 0; i < i_width; i++ )
78 #define WRITE_COMP( plane, value ) \
79 p_picture->p[plane].p_pixels[p_picture->p[plane].i_pitch * j + i] = value
81 /* Draw the slider. */
82 bool is_outline = j == 0 || j == i_height - 1
83 || i == 0 || i == i_width - 1;
84 WRITE_COMP( 0, is_outline ? 0x00 : 0xff );
85 WRITE_COMP( 1, 0x80 );
86 WRITE_COMP( 2, 0x80 );
88 /* We can see the video through the part of the slider
89 which corresponds to the leaving time. */
90 bool is_border = j < 3 || j > i_height - 4
91 || i < 3 || i > i_width - 4
92 || i < i_filled_part_width;
93 WRITE_COMP( 3, is_border ? 0xff : 0x00 );
103 static subpicture_region_t * vout_OSDEpgText( vout_thread_t *p_vout,
104 const char *psz_string,
106 int i_size, uint32_t i_color )
109 subpicture_region_t *p_region;
114 /* Create a new subpicture region */
115 video_format_Init( &fmt, VLC_CODEC_TEXT );
117 p_region = subpicture_region_New( &fmt );
120 msg_Err( p_vout, "Cannot allocate SPU region." );
124 /* Set subpicture parameters */
125 p_region->psz_text = strdup( psz_string );
126 p_region->i_align = 0;
131 p_region->p_style = text_style_New();
132 if( p_region->p_style )
134 p_region->p_style->i_font_size = i_size;
135 p_region->p_style->i_font_color = i_color;
136 p_region->p_style->i_font_alpha = 0;
143 static subpicture_region_t * vout_BuildOSDEpg( vout_thread_t *p_vout,
146 int i_visible_height )
148 subpicture_region_t *p_region_ret;
149 subpicture_region_t **pp_region = &p_region_ret;
151 time_t i_test = time( NULL );
153 /* Display the name of the channel. */
154 *pp_region = vout_OSDEpgText( p_vout,
156 i_visible_width * EPG_LEFT,
157 i_visible_height * EPG_TOP,
158 i_visible_height * EPG_NAME_SIZE,
164 /* Display the name of the current program. */
165 pp_region = &(* pp_region)->p_next;
166 *pp_region = vout_OSDEpgText( p_vout, p_epg->p_current->psz_name,
167 i_visible_width * ( EPG_LEFT + 0.025 ),
168 i_visible_height * ( EPG_TOP + 0.05 ),
169 i_visible_height * EPG_PROGRAM_SIZE,
175 /* Display the current program time slider. */
176 pp_region = &(* pp_region)->p_next;
177 *pp_region = vout_OSDEpgSlider( p_vout,
178 i_visible_width * EPG_LEFT,
179 i_visible_height * ( EPG_TOP + 0.1 ),
180 i_visible_width * ( 1 - 2 * EPG_LEFT ),
181 i_visible_height * 0.05,
182 ( i_test - p_epg->p_current->i_start )
183 / (float)p_epg->p_current->i_duration );
188 /* Format the hours of the beginning and the end of the current program. */
189 struct tm tm_start, tm_end;
190 time_t t_start = p_epg->p_current->i_start;
191 time_t t_end = p_epg->p_current->i_start + p_epg->p_current->i_duration;
192 localtime_r( &t_start, &tm_start );
193 localtime_r( &t_end, &tm_end );
196 snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d",
197 tm_start.tm_hour, tm_start.tm_min );
198 snprintf( psz_end, sizeof(psz_end), "%2.2d:%2.2d",
199 tm_end.tm_hour, tm_end.tm_min );
201 /* Display those hours. */
202 pp_region = &(* pp_region)->p_next;
203 *pp_region = vout_OSDEpgText( p_vout, psz_start,
204 i_visible_width * ( EPG_LEFT + 0.02 ),
205 i_visible_height * ( EPG_TOP + 0.15 ),
206 i_visible_height * EPG_PROGRAM_SIZE,
212 pp_region = &(* pp_region)->p_next;
213 *pp_region = vout_OSDEpgText( p_vout, psz_end,
214 i_visible_width * ( 1 - EPG_LEFT - 0.085 ),
215 i_visible_height * ( EPG_TOP + 0.15 ),
216 i_visible_height * EPG_PROGRAM_SIZE,
224 * \brief Show EPG information about the current program of an input item
225 * \param p_vout pointer to the vout the information is to be showed on
226 * \param p_input pointer to the input item the information is to be showed
228 int vout_OSDEpg( vout_thread_t *p_vout, input_item_t *p_input )
231 mtime_t i_now = mdate();
233 int i_visible_width = p_vout->fmt_in.i_width;
234 int i_visible_height = p_vout->fmt_in.i_height;
239 p_spu = subpicture_New();
243 p_spu->i_channel = DEFAULT_CHAN;
244 p_spu->i_start = i_now;
245 p_spu->i_stop = i_now + 10000 * INT64_C(1000);
246 p_spu->b_ephemer = true;
247 p_spu->b_absolute = true;
248 p_spu->b_fade = false;
250 char *psz_now_playing = input_item_GetNowPlaying( p_input );
251 vlc_epg_t *p_epg = NULL;
253 vlc_mutex_lock( &p_input->lock );
255 /* Look for the current program EPG event */
256 for( int i = 0; i < p_input->i_epg; i++ )
258 vlc_epg_t *p_tmp = p_input->pp_epg[i];
260 if( p_tmp->p_current && p_tmp->p_current->psz_name
261 && psz_now_playing != NULL
262 && !strcmp( p_tmp->p_current->psz_name, psz_now_playing ) )
264 p_epg = vlc_epg_New( p_tmp->psz_name );
265 vlc_epg_Merge( p_epg, p_tmp );
270 vlc_mutex_unlock( &p_input->lock );
274 /* Build the EPG event subpictures. */
275 p_spu->p_region = vout_BuildOSDEpg( p_vout, p_epg,
278 vlc_epg_Delete( p_epg );
282 /* If no EPG event has been found, then display a warning message. */
283 p_spu->p_region = vout_OSDEpgText( p_vout, NO_EPG,
284 i_visible_width * EPG_LEFT,
285 i_visible_height * EPG_TOP,
286 i_visible_height * EPG_NAME_SIZE,
290 spu_DisplaySubpicture( p_vout->p_spu, p_spu );